From a71ab3313d29379f61f9282baad9dd41eeb380f7 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Fri, 16 Feb 2024 13:03:50 +0100 Subject: [PATCH 01/91] switch to building from development branches Signed-off-by: Arturo Buzarra --- .../trustfence/nativesdk-trustfence-sign-tools_2023.04.bb | 4 ++-- .../trustfence/trustfence-sign-tools-native_2023.04.bb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/meta-digi-arm/recipes-digi/trustfence/nativesdk-trustfence-sign-tools_2023.04.bb b/meta-digi-arm/recipes-digi/trustfence/nativesdk-trustfence-sign-tools_2023.04.bb index 19a36e532..5261af903 100644 --- a/meta-digi-arm/recipes-digi/trustfence/nativesdk-trustfence-sign-tools_2023.04.bb +++ b/meta-digi-arm/recipes-digi/trustfence/nativesdk-trustfence-sign-tools_2023.04.bb @@ -2,5 +2,5 @@ require nativesdk-trustfence-sign-tools_git.bb -SRCBRANCH = "v2023.04/maint" -SRCREV = "d27aefc1691a14c6edaadf35ab147ac8afe5c98a" +SRCBRANCH = "v2023.04/master" +SRCREV = "${AUTOREV}" diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools-native_2023.04.bb b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools-native_2023.04.bb index a3d99728e..86b97b32f 100644 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools-native_2023.04.bb +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools-native_2023.04.bb @@ -2,5 +2,5 @@ require trustfence-sign-tools-native_git.bb -SRCBRANCH = "v2023.04/maint" -SRCREV = "d27aefc1691a14c6edaadf35ab147ac8afe5c98a" +SRCBRANCH = "v2023.04/master" +SRCREV = "${AUTOREV}" From 637c392cd56b3f7f00e4087fff67bcd8dafd0668 Mon Sep 17 00:00:00 2001 From: Stephan Klatt Date: Wed, 14 Feb 2024 17:14:15 +0100 Subject: [PATCH 02/91] bootcount: fix typo in INITSCRIPT_PARAMS Add missing curly brace Signed-off-by: Arturo Buzarra --- meta-digi-dey/recipes-digi/bootcount/bootcount.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-digi-dey/recipes-digi/bootcount/bootcount.bb b/meta-digi-dey/recipes-digi/bootcount/bootcount.bb index e1b720d8e..cc3113f90 100644 --- a/meta-digi-dey/recipes-digi/bootcount/bootcount.bb +++ b/meta-digi-dey/recipes-digi/bootcount/bootcount.bb @@ -39,6 +39,6 @@ FILES:${PN} += " \ INITSCRIPT_PACKAGES += "${PN}" INITSCRIPT_NAME:${PN} = "bootcount-init" -INITSCRIPT_PARAMS:${PN = "start 19 2 3 4 5 . stop 21 0 1 6 ." +INITSCRIPT_PARAMS:${PN} = "start 19 2 3 4 5 . stop 21 0 1 6 ." SYSTEMD_SERVICE:${PN} = "bootcount-init.service" From 5e1b0ab8302ac28c165f4e402817aff2e348b35a Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Fri, 16 Feb 2024 13:06:48 +0100 Subject: [PATCH 03/91] meta-digi-dey: bump distro version to 4.0-r6 Signed-off-by: Arturo Buzarra --- README.md | 2 +- meta-digi-dey/conf/distro/dey.conf | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8f37a301a..26501324b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Digi Embedded Yocto (DEY) 4.0 -## Release 4.0-r5 +## Release 4.0-r6 This document provides information about Digi Embedded Yocto, Digi International's professional embedded Yocto development environment. diff --git a/meta-digi-dey/conf/distro/dey.conf b/meta-digi-dey/conf/distro/dey.conf index b808a8ef5..2b9d3f639 100644 --- a/meta-digi-dey/conf/distro/dey.conf +++ b/meta-digi-dey/conf/distro/dey.conf @@ -3,8 +3,8 @@ require conf/distro/poky.conf # Discrete version values. YOCTO_MAJOR = "4" YOCTO_MINOR = "0" -DEY_RELEASE = "5" -DEY_BUILD = "2" +DEY_RELEASE = "6" +DEY_BUILD = "1" # Firmware version of the system. DEY_FIRMWARE_VERSION ?= "${YOCTO_MAJOR}.${YOCTO_MINOR}.${DEY_RELEASE}.${DEY_BUILD}" From 0f56eab0523623147b2b94f86ed7ddc1e1846e0e Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Tue, 17 Oct 2023 08:31:25 +0200 Subject: [PATCH 04/91] rename firmware-murata to firmware-murata-infineon Murata provides this FW recipe for the infineon chip on the ccmpx products. Now we are going to have more FW provided by Murata, but for other chips which recipe is completely different. Therefore, rename the recipe to explicitily indicate the FW it provides. https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- meta-digi-arm/conf/machine/ccmp13-dvk.conf | 2 +- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 2 +- .../firmware-murata-infineon.bb} | 4 ++-- .../cyfmac4373-sdio_US.clm_blob | Bin 4 files changed, 4 insertions(+), 4 deletions(-) rename meta-digi-arm/recipes-bsp/{firmware-murata/firmware-murata.bb => firmware-murata-infineon/firmware-murata-infineon.bb} (96%) rename meta-digi-arm/recipes-bsp/{firmware-murata/firmware-murata => firmware-murata-infineon/firmware-murata-infineon}/cyfmac4373-sdio_US.clm_blob (100%) diff --git a/meta-digi-arm/conf/machine/ccmp13-dvk.conf b/meta-digi-arm/conf/machine/ccmp13-dvk.conf index a9ae07f8d..54fabbc80 100644 --- a/meta-digi-arm/conf/machine/ccmp13-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp13-dvk.conf @@ -60,7 +60,7 @@ MACHINE_FEATURES += "wifi" # ========================================================================= # Firmware # ========================================================================= -MACHINE_FIRMWARE:append = " firmware-murata firmware-murata-mfgtest" +MACHINE_FIRMWARE:append = " firmware-murata-infineon firmware-murata-infineon-mfgtest" MACHINE_EXTRA_RRECOMMENDS += " \ ${MACHINE_FIRMWARE} \ diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index a4bf1d40b..bf6b83680 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -68,7 +68,7 @@ MACHINE_FEATURES += "gpu" # ========================================================================= # Firmware # ========================================================================= -MACHINE_FIRMWARE:append = " firmware-murata firmware-murata-mfgtest" +MACHINE_FIRMWARE:append = " firmware-murata-infineon firmware-murata-infineon-mfgtest" MACHINE_EXTRA_RRECOMMENDS += " \ ${MACHINE_FIRMWARE} \ diff --git a/meta-digi-arm/recipes-bsp/firmware-murata/firmware-murata.bb b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb similarity index 96% rename from meta-digi-arm/recipes-bsp/firmware-murata/firmware-murata.bb rename to meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb index 168b12219..3d44a8620 100644 --- a/meta-digi-arm/recipes-bsp/firmware-murata/firmware-murata.bb +++ b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb @@ -1,6 +1,6 @@ # Copyright (C) 2022,2023 Digi International. -SUMMARY = "Murata firmware binaries" +SUMMARY = "Murata Infineon firmware binaries" SECTION = "base" LICENSE = "CYPRESS-EULA" LIC_FILES_CHKSUM = "file://${S}/cyw-bt-patch/LICENCE.cypress;md5=cbc5f665d04f741f1e006d2096236ba7" @@ -27,7 +27,7 @@ S = "${WORKDIR}" DEPENDS = "libnl" do_install () { - bbnote "Installing Murata firmware binaries: " + bbnote "Installing Murata Infineon firmware binaries: " install -d ${D}${base_libdir}/firmware/cypress install -d ${D}${base_libdir}/firmware/brcm install -d ${D}${sbindir} diff --git a/meta-digi-arm/recipes-bsp/firmware-murata/firmware-murata/cyfmac4373-sdio_US.clm_blob b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyfmac4373-sdio_US.clm_blob similarity index 100% rename from meta-digi-arm/recipes-bsp/firmware-murata/firmware-murata/cyfmac4373-sdio_US.clm_blob rename to meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyfmac4373-sdio_US.clm_blob From ae0062f9ac4d39e36139c694eb009fae3bc938c4 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Mon, 9 Oct 2023 11:48:47 +0200 Subject: [PATCH 05/91] firmware-murata: add support for ccimx93 https://onedigi.atlassian.net/browse/DEL-8327 https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- .../firmware-murata-nxp.bb | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb diff --git a/meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb b/meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb new file mode 100644 index 000000000..f2898dbe3 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb @@ -0,0 +1,26 @@ +# Copyright (C) 2023 Digi International. + +SUMMARY = "Murata NXP firmware binaries" +LICENSE = "GPL-2.0-only" +LIC_FILES_CHKSUM = "file://LICENSE;md5=ffa10f40b98be2c2bc9608f56827ed23" + +SRCBRANCH = "imx-6-1-1" +SRCREV = "6103e224be638f5b421c323993f29bb6c0ada44a" +SRC_URI = "git://github.com/murata-wireless/nxp-linux-calibration;protocol=http;branch=${SRCBRANCH}" + +S = "${WORKDIR}/git" + +do_configure[noexec] = "1" +do_compile[noexec] = "1" + +do_install () { + install -d ${D}${nonarch_base_libdir}/firmware/nxp + install -m 0644 murata/files/2DL/txpower_US.bin ${D}${nonarch_base_libdir}/firmware/nxp + install -m 0644 murata/files/2DL/rutxpower_US.bin ${D}${nonarch_base_libdir}/firmware/nxp + install -m 0755 murata/files/2DL/bt_power_config_US_CA_JP.sh ${D}${nonarch_base_libdir}/firmware/nxp +} + +FILES:${PN} = "${nonarch_base_libdir}/firmware" + +PACKAGE_ARCH = "${MACHINE_ARCH}" +COMPATIBLE_MACHINE = "ccimx93" From 23ffb5c1bc0d771987ce84733d9e6ab1c438121e Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Mon, 9 Oct 2023 13:17:07 +0200 Subject: [PATCH 06/91] ccimx93: wifi: include firmware-murata Add firmware-murata as a requirement for the HAVE_WIFI modules. https://onedigi.atlassian.net/browse/DEL-8327 https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- meta-digi-arm/conf/machine/ccimx93-dvk.conf | 2 +- .../kernel-modules/kernel-module-nxp-wlan.bbappend | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/meta-digi-arm/conf/machine/ccimx93-dvk.conf b/meta-digi-arm/conf/machine/ccimx93-dvk.conf index 96f2160a2..1d370b24e 100644 --- a/meta-digi-arm/conf/machine/ccimx93-dvk.conf +++ b/meta-digi-arm/conf/machine/ccimx93-dvk.conf @@ -32,7 +32,7 @@ WIRELESS_MODULE:append = " ${@oe.utils.conditional('HAVE_WIFI', '1', 'kernel-mod HAS_WIFI_VIRTWLANS = "true" # Machine firmware -MACHINE_FIRMWARE:append = " ${@oe.utils.conditional('HAVE_WIFI', '1', 'firmware-nxp-wifi-nxpiw612', '', d)}" +MACHINE_FIRMWARE:append = " ${@oe.utils.conditional('HAVE_WIFI', '1', 'firmware-nxp-wifi-nxpiw612 firmware-murata-nxp', '', d)}" MACHINE_EXTRA_RRECOMMENDS += "${WIRELESS_MODULE}" diff --git a/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan.bbappend b/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan.bbappend index e1a0c245a..c719f0fe6 100644 --- a/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan.bbappend +++ b/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan.bbappend @@ -20,3 +20,4 @@ FILES:${PN}:append = " \ " RDEPENDS:${PN}:remove = "wireless-tools" +RDEPENDS:${PN}:append = " firmware-murata-nxp" From f44ae189e5533fd7a1f8a48ae58f120966b60170 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Mon, 9 Oct 2023 13:18:16 +0200 Subject: [PATCH 07/91] bluetooth-init: ccimx93: adjust power levels https://onedigi.atlassian.net/browse/DEL-8327 https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- .../bluez/bluez5-init/ccimx93/bluetooth-init | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init b/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init index ec2361970..7d4b630d9 100644 --- a/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init +++ b/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init @@ -40,6 +40,10 @@ set_btaddr() { hciconfig ${HCI_IFACE} up } +set_power_config() { + sh -e /lib/firmware/nxp/bt_power_config_US_CA_JP.sh +} + is_kernel_module_loaded() { lsmod | grep -qs -w "^${MODULE_NAME}" } @@ -56,8 +60,8 @@ bluetooth_start() { power 0 && sleep 0.2 && power 1 # Load manually the kernel module modprobe "${MODULE_NAME}" - # Reconfigure the HCI interface with the expected MAC address - is_kernel_module_loaded && set_btaddr && log "Bluetooth activated" && return 0 + # Reconfigure the HCI interface with the expected MAC address and power levels + is_kernel_module_loaded && set_btaddr && set_power_config && log "Bluetooth activated" && return 0 log "[ERROR] Cannot initialize Bluetooth correctly" && return 1 } From d58ade3a481969ad1170cf29fe349a52cf79a942 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Mon, 9 Oct 2023 13:20:40 +0200 Subject: [PATCH 08/91] ccimx93: iw612: configure the power limit to US The txpower_US.bin and rutxpower_US.bin files are included in the rootfs as part of the firmware-murata packet, which is a requirement of this recipe. https://onedigi.atlassian.net/browse/DEL-8327 https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- .../kernel-modules/kernel-module-nxp-wlan/load_iw612.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh b/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh index 678b8f292..769b989ad 100644 --- a/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh +++ b/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh @@ -20,6 +20,8 @@ host_mlme=1 \ drv_mode=${DRIVER_MODE} \ drvdbg=${DRIVER_DEBUG} \ sta_name=wlan \ +txpwrlimit_cfg=nxp/txpower_US.bin \ +init_hostcmd_cfg=nxp/rutxpower_US.bin \ fw_name=nxp/sd_w61x_v1.bin.se\ " From 129e023548f7a056816aba3d35d60039eee5c4c6 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Mon, 9 Oct 2023 13:23:42 +0200 Subject: [PATCH 09/91] ccimx93: iw612: force the Regulatory Domain to US The iw612 driver, by default, follows the beacon from the AP. In order to work on a fixed country, is required to manually force it, and indicate the driver not to follow the AP. https://onedigi.atlassian.net/browse/DEL-8327 https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- .../kernel-modules/kernel-module-nxp-wlan/load_iw612.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh b/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh index 769b989ad..4aeb58f26 100644 --- a/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh +++ b/meta-digi-arm/recipes-kernel/kernel-modules/kernel-module-nxp-wlan/load_iw612.sh @@ -20,6 +20,7 @@ host_mlme=1 \ drv_mode=${DRIVER_MODE} \ drvdbg=${DRIVER_DEBUG} \ sta_name=wlan \ +country_ie_ignore=1 \ txpwrlimit_cfg=nxp/txpower_US.bin \ init_hostcmd_cfg=nxp/rutxpower_US.bin \ fw_name=nxp/sd_w61x_v1.bin.se\ @@ -35,6 +36,8 @@ if ! [ -e "/proc/device-tree/wireless/mac-address" ]; then fi WLANADDR=$(hexdump -ve '1/1 "%02X" ":"' /proc/device-tree/wireless/mac-address 2>/dev/null | sed 's/:$//g') + +iw reg set US && \ modprobe mlan && \ modprobe moal ${MOAL_PARAMS} mac_addr=${WLANADDR} && \ [ -d "/sys/class/net/wlan0" ] && log "Wi-Fi activated" && exit 0 From c5b53c976507b17b13f8de5ebe4a99372d73f647 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Fri, 5 Jan 2024 13:09:45 +0100 Subject: [PATCH 10/91] ccimx93: bluetooth-init: re-initilize the LE support after hci reset for the IW61x, when the FW is instructed with an hci reset command, the LE stack is not correctly reset. It can be workaround-ed by SW doing a SW power cycle. Signed-off-by: Isaac Hermida --- .../bluez/bluez5-init/ccimx93/bluetooth-init | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init b/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init index 7d4b630d9..ac3469e05 100644 --- a/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init +++ b/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init @@ -42,6 +42,12 @@ set_btaddr() { set_power_config() { sh -e /lib/firmware/nxp/bt_power_config_US_CA_JP.sh + + # The bash script resets the HCI interface, and currenlty it breaks + # the LE support. Until it is fixed in the FW, workaround it by doing + # a SW power cycle of the stack. + btmgmt -i ${HCI_IFACE} power off + btmgmt -i ${HCI_IFACE} power on } is_kernel_module_loaded() { From 81059a9707b9569a381704db8bfb15a01c9f4e9e Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Tue, 13 Feb 2024 11:42:59 +0100 Subject: [PATCH 11/91] ccimx93: include _ov_som_bt-dtm_ccimx93.dtbo file https://onedigi.atlassian.net/browse/DEL-8327 https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- meta-digi-arm/conf/machine/ccimx93-dvk.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/meta-digi-arm/conf/machine/ccimx93-dvk.conf b/meta-digi-arm/conf/machine/ccimx93-dvk.conf index 1d370b24e..8dea1961a 100644 --- a/meta-digi-arm/conf/machine/ccimx93-dvk.conf +++ b/meta-digi-arm/conf/machine/ccimx93-dvk.conf @@ -22,6 +22,7 @@ KERNEL_DEVICETREE ?= " \ digi/_ov_board_mikroe-accel2-click_ccimx93-dvk.dtbo \ digi/_ov_board_mikroe-gyro-click_ccimx93-dvk.dtbo \ digi/_ov_som_bt_ccimx93.dtbo \ + digi/_ov_som_bt-dtm_ccimx93.dtbo \ digi/_ov_som_npu_ccimx93.dtbo \ digi/_ov_som_wifi_ccimx93.dtbo \ " From 4372eaba017d2f7a683bab91c24a16a786a7efec Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Thu, 25 Jan 2024 11:19:26 +0100 Subject: [PATCH 12/91] u-boot-dey: unify installation scripts https://onedigi.atlassian.net/browse/DEL-8860 Signed-off-by: Isaac Hermida --- .../ccimx6qpsbc/install_linux_fw_sd.txt | 12 +++--- .../ccimx6qpsbc/install_linux_fw_usb.txt | 12 +++--- .../ccimx6qpsbc/install_linux_fw_uuu.sh | 15 ++++--- .../ccimx6sbc/install_linux_fw_sd.txt | 20 ++++----- .../ccimx6sbc/install_linux_fw_usb.txt | 20 ++++----- .../ccimx6sbc/install_linux_fw_uuu.sh | 41 ++++++++----------- .../ccimx6ul/install_linux_fw_sd.txt | 15 ++++--- .../ccimx6ul/install_linux_fw_usb.txt | 15 ++++--- 8 files changed, 67 insertions(+), 83 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt index b72f6d685..fa3fcf71f 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt @@ -8,13 +8,13 @@ install_abort=0 BASEFILENAME=0 # Determine U-Boot file to program basing on module variant -if test -n "${module_variant}"; then - if test "${module_variant}" = "0x01" || test "${module_variant}" = "0x02"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##2GB.imx; - elif test "${module_variant}" = "0x03"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; - fi +# If module_variant is unknown or not set, return error asking the user +if test "${module_variant}" = "0x01" || test "${module_variant}" = "0x02"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##2GB.imx; +elif test "${module_variant}" = "0x03"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; fi + # Use 'test -n ...' because 'test -z ...' does not work well on old versions of # u-boot when the checked value is empty. if test -n "${INSTALL_UBOOT_FILENAME}"; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt index 9cb620a30..6825d13bd 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt @@ -8,13 +8,13 @@ install_abort=0 BASEFILENAME=0 # Determine U-Boot file to program basing on module variant -if test -n "${module_variant}"; then - if test "${module_variant}" = "0x01" || test "${module_variant}" = "0x02"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##2GB.imx; - elif test "${module_variant}" = "0x03"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; - fi +# If module_variant is unknown or not set, return error asking the user +if test "${module_variant}" = "0x01" || test "${module_variant}" = "0x02"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##2GB.imx; +elif test "${module_variant}" = "0x03"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; fi + # Use 'test -n ...' because 'test -z ...' does not work well on old versions of # u-boot when the checked value is empty. if test -n "${INSTALL_UBOOT_FILENAME}"; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index eb59fb5ee..5a22ff55d 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -1,7 +1,7 @@ #!/bin/sh #=============================================================================== # -# Copyright (C) 2021-2023 by Digi International Inc. +# Copyright (C) 2021-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -100,13 +100,12 @@ echo "Determining image files to use..." if [ -z ${INSTALL_UBOOT_FILENAME} ]; then module_variant=$(getenv "module_variant") # Determine U-Boot file to program basing on SOM's variant - if [ -n "$module_variant" ]; then - if [ "$module_variant" = "0x01" ] || \ - [ "$module_variant" = "0x02" ]; then - INSTALL_UBOOT_FILENAME="u-boot-##MACHINE##2GB.imx" - elif [ "$module_variant" = "0x03" ]; then - INSTALL_UBOOT_FILENAME="u-boot-##MACHINE##1GB.imx" - fi + # If module_variant is unknown or not set, return error asking the user + if [ "$module_variant" = "0x01" ] || \ + [ "$module_variant" = "0x02" ]; then + INSTALL_UBOOT_FILENAME="u-boot-##MACHINE##2GB.imx" + elif [ "$module_variant" = "0x03" ] || \ + INSTALL_UBOOT_FILENAME="u-boot-##MACHINE##1GB.imx" fi # U-Boot when the checked value is empty. diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt index aeddcf636..b587cfe7f 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt @@ -8,19 +8,15 @@ install_abort=0 BASEFILENAME=0 # Determine U-Boot file to program basing on module variant -if test -n "${module_variant}"; then - if test "${module_variant}" = "0x12"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc2GB.imx; - elif test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x11" || test "${module_variant}" = "0x14" || test "${module_variant}" = "0x16"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc.imx; - elif test "${module_variant}" = "0x03" || test "${module_variant}" = "0x0e" || test "${module_variant}" = "0x0f"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc512MB.imx; - elif test "${module_variant}" = "0x0b" || test "${module_variant}" = "0x15"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6dlsbc.imx; - elif test "${module_variant}" = "0x0c" || test "${module_variant}" = "0x13"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6dlsbc512MB.imx; - fi +# If module_variant is unknown or not set, return error asking the user +if test "${module_variant}" = "0x12"; then + setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc2GB.imx; +elif test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x0b" || test "${module_variant}" = "0x11" || test "${module_variant}" = "0x14" || test "${module_variant}" = "0x15" || test "${module_variant}" = "0x16"; then + setenv INSTALL_UBOOT_FILENAME u-boot-cc${soc_family}sbc.imx; +elif test "${module_variant}" = "0x03" || test "${module_variant}" = "0x0c" || test "${module_variant}" = "0x0e" || test "${module_variant}" = "0x0f" || test "${module_variant}" = "0x13"; then + setenv INSTALL_UBOOT_FILENAME u-boot-cc${soc_family}sbc512MB.imx; fi + # Use 'test -n ...' because 'test -z ...' does not work well on old versions of # u-boot when the checked value is empty. if test -n "${INSTALL_UBOOT_FILENAME}"; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt index 7edd7e4a5..367c7ae7c 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt @@ -8,19 +8,15 @@ install_abort=0 BASEFILENAME=0 # Determine U-Boot file to program basing on module variant -if test -n "${module_variant}"; then - if test "${module_variant}" = "0x12"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc2GB.imx; - elif test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x11" || test "${module_variant}" = "0x14" || test "${module_variant}" = "0x16"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc.imx; - elif test "${module_variant}" = "0x03" || test "${module_variant}" = "0x0e" || test "${module_variant}" = "0x0f"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc512MB.imx; - elif test "${module_variant}" = "0x0b" || test "${module_variant}" = "0x15"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6dlsbc.imx; - elif test "${module_variant}" = "0x0c" || test "${module_variant}" = "0x13"; then - setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6dlsbc512MB.imx; - fi +# If module_variant is unknown or not set, return error asking the user +if test "${module_variant}" = "0x12"; then + setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6qsbc2GB.imx; +elif test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x0b" || test "${module_variant}" = "0x11" || test "${module_variant}" = "0x14" || test "${module_variant}" = "0x15" || test "${module_variant}" = "0x16"; then + setenv INSTALL_UBOOT_FILENAME u-boot-cc${soc_family}sbc.imx; +elif test "${module_variant}" = "0x03" || test "${module_variant}" = "0x0c" || test "${module_variant}" = "0x0e" || test "${module_variant}" = "0x0f" || test "${module_variant}" = "0x13"; then + setenv INSTALL_UBOOT_FILENAME u-boot-cc${soc_family}sbc512MB.imx; fi + # Use 'test -n ...' because 'test -z ...' does not work well on old versions of # u-boot when the checked value is empty. if test -n "${INSTALL_UBOOT_FILENAME}"; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index c7feaf45d..1b30133ff 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -1,7 +1,7 @@ #!/bin/sh #=============================================================================== # -# Copyright (C) 2021-2023 by Digi International Inc. +# Copyright (C) 2021-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -102,28 +102,23 @@ if [ -z ${INSTALL_UBOOT_FILENAME} ]; then if [ -n "$soc_family" ]; then module_variant=$(getenv "module_variant") # Determine U-Boot file to program basing on SOM's variant - if [ -n "$module_variant" ]; then - if [ "$module_variant" = "0x12" ]; then - INSTALL_UBOOT_FILENAME="u-boot-cc${soc_family}sbc2GB.imx" - elif [ "$module_variant" = "0x01" ] || \ - [ "$module_variant" = "0x02" ] || \ - [ "$module_variant" = "0x04" ] || \ - [ "$module_variant" = "0x05" ] || \ - [ "$module_variant" = "0x0b" ] || \ - [ "$module_variant" = "0x0d" ] || \ - [ "$module_variant" = "0x10" ] || \ - [ "$module_variant" = "0x11" ] || \ - [ "$module_variant" = "0x14" ] || \ - [ "$module_variant" = "0x15" ] || \ - [ "$module_variant" = "0x16" ]; then - INSTALL_UBOOT_FILENAME="u-boot-cc${soc_family}sbc.imx" - elif [ "$module_variant" = "0x03" ] || \ - [ "$module_variant" = "0x0c" ] || \ - [ "$module_variant" = "0x0e" ] || \ - [ "$module_variant" = "0x0f" ] || \ - [ "$module_variant" = "0x13" ]; then - INSTALL_UBOOT_FILENAME="u-boot-cc${soc_family}sbc512MB.imx" - fi + if [ "$module_variant" = "0x12" ]; then + INSTALL_UBOOT_FILENAME="u-boot-cc${soc_family}sbc2GB.imx" + elif [ "$module_variant" = "0x02" ] || \ + [ "$module_variant" = "0x04" ] || \ + [ "$module_variant" = "0x05" ] || \ + [ "$module_variant" = "0x0b" ] || \ + [ "$module_variant" = "0x11" ] || \ + [ "$module_variant" = "0x14" ] || \ + [ "$module_variant" = "0x15" ] || \ + [ "$module_variant" = "0x16" ]; then + INSTALL_UBOOT_FILENAME="u-boot-cc${soc_family}sbc.imx" + elif [ "$module_variant" = "0x03" ] || \ + [ "$module_variant" = "0x0c" ] || \ + [ "$module_variant" = "0x0e" ] || \ + [ "$module_variant" = "0x0f" ] || \ + [ "$module_variant" = "0x13" ]; then + INSTALL_UBOOT_FILENAME="u-boot-cc${soc_family}sbc512MB.imx" fi fi diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt index b1f792351..b2486c79d 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt @@ -8,14 +8,13 @@ install_abort=0 BASEFILENAME=0 # Determine U-Boot file to program basing on module variant -if test -n "${module_variant}"; then - if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03" || test "${module_variant}" = "0x06" || test "${module_variant}" = "0x09"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##.imx; - elif test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x07"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; - elif test "${module_variant}" = "0x08" || test "${module_variant}" = "0x0a"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##512MB.imx - fi +# If module_variant is unknown or not set, return error asking the user +if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03" || test "${module_variant}" = "0x06" || test "${module_variant}" = "0x09"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##.imx; +elif test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x07"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; +elif test "${module_variant}" = "0x08" || test "${module_variant}" = "0x0a"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##512MB.imx fi # Use 'test -n ...' because 'test -z ...' does not work well on old versions of diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt index 1e5350fad..440709c04 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt @@ -8,14 +8,13 @@ install_abort=0 BASEFILENAME=0 # Determine U-Boot file to program basing on module variant -if test -n "${module_variant}"; then - if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03" || test "${module_variant}" = "0x06" || test "${module_variant}" = "0x09"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##.imx; - elif test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x07"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; - elif test "${module_variant}" = "0x08" || test "${module_variant}" = "0x0a"; then - setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##512MB.imx - fi +# If module_variant is unknown or not set, return error asking the user +if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03" || test "${module_variant}" = "0x06" || test "${module_variant}" = "0x09"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##.imx; +elif test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05" || test "${module_variant}" = "0x07"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##1GB.imx; +elif test "${module_variant}" = "0x08" || test "${module_variant}" = "0x0a"; then + setenv INSTALL_UBOOT_FILENAME u-boot-##MACHINE##512MB.imx fi # Use 'test -n ...' because 'test -z ...' does not work well on old versions of From 4a057144eec65188a9a8f92067c9d59242ec26d6 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Thu, 25 Jan 2024 17:41:04 +0100 Subject: [PATCH 13/91] u-boot-dey: installation scripts: do not check recovery image for dual systems Recovery image is not required for dual systems, so do not check it. https://onedigi.atlassian.net/browse/DEL-8859 Signed-off-by: Isaac Hermida --- .../u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt | 6 +++++- .../u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh | 5 ++++- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 5 ++++- .../u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh | 7 +++++-- .../u-boot/u-boot-dey/ccimx8m/install_linux_fw_sd.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx8m/install_linux_fw_usb.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh | 7 +++++-- .../u-boot/u-boot-dey/ccimx8x/install_linux_fw_sd.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx8x/install_linux_fw_usb.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh | 7 +++++-- .../u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt | 6 +++++- .../u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh | 7 +++++-- .../u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt | 6 +++++- .../u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt | 6 +++++- .../u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh | 8 ++++++-- 21 files changed, 104 insertions(+), 26 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt index fa3fcf71f..b83524d0a 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_sd.txt @@ -56,7 +56,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the SD card -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e mmc ${INSTALL_MMCDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt index 6825d13bd..1881db30e 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_usb.txt @@ -56,7 +56,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the USB -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e usb ${INSTALL_USBDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index 5a22ff55d..3aefbabf0 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -166,7 +166,10 @@ if [ -f ${COMPRESSED_ROOTFS_IMAGE} ] && [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; the fi # Verify existence of files before starting the update -FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}" +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if [ "${DUALBOOT}" != true ]; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi for f in ${FILES}; do if [ ! -f ${f} ]; then echo "\033[31m[ERROR] Could not find file '${f}'\033[0m" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt index b587cfe7f..aa426b077 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_sd.txt @@ -63,7 +63,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the SD card -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e mmc ${INSTALL_MMCDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt index 367c7ae7c..ddc141d94 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_usb.txt @@ -63,7 +63,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the USB -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e usb ${INSTALL_USBDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index 1b30133ff..499762a32 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -185,7 +185,10 @@ if [ -f ${COMPRESSED_ROOTFS_IMAGE} ] && [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; the fi # Verify existence of files before starting the update -FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}" +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if [ "${DUALBOOT}" != true ]; then + FILES"${INSTALL_RECOVERY_FILENAME}" +fi for f in ${FILES}; do if [ ! -f ${f} ]; then echo "\033[31m[ERROR] Could not find file '${f}'\033[0m" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt index b2486c79d..6beae5bcf 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_sd.txt @@ -59,7 +59,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.ubifs setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ubifs # Check for presence of firmware files on the SD card -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e mmc ${INSTALL_MMCDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt index 440709c04..3a88ce753 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_usb.txt @@ -59,7 +59,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.ubifs setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ubifs # Check for presence of firmware files on the USB -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e usb ${INSTALL_USBDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh index 390e9c713..79e306ec0 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh @@ -1,7 +1,7 @@ #!/bin/sh #=============================================================================== # -# Copyright (C) 2020-2023 by Digi International Inc. +# Copyright (C) 2020-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -178,7 +178,10 @@ INSTALL_RECOVERY_FILENAME="${BASEFILENAME}-##MACHINE##.recovery.ubifs" INSTALL_ROOTFS_FILENAME="${BASEFILENAME}-##MACHINE##.ubifs" # Verify existence of files before starting the update -FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}" +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if [ "${DUALBOOT}" != true ]; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi for f in ${FILES}; do if [ ! -f ${f} ]; then echo "\033[31m[ERROR] Could not find file '${f}'\033[0m" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_sd.txt index 01bd2a074..466f98c81 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_sd.txt @@ -27,7 +27,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the SD card -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e mmc ${INSTALL_MMCDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_usb.txt index 41e894c18..4635ae21c 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_usb.txt @@ -27,7 +27,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the USB -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e usb ${INSTALL_USBDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index 1ee6c2f79..e8377be78 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -1,7 +1,7 @@ #!/bin/sh #=============================================================================== # -# Copyright (C) 2020-2023 by Digi International Inc. +# Copyright (C) 2020-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -134,7 +134,10 @@ if [ -f ${COMPRESSED_ROOTFS_IMAGE} ] && [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; the fi # Verify existence of files before starting the update -FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}" +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if [ "${DUALBOOT}" != true ]; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi for f in ${FILES}; do if [ ! -f ${f} ]; then echo "\033[31m[ERROR] Could not find file '${f}'\033[0m" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_sd.txt index 3f621311a..4ff66b973 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_sd.txt @@ -39,7 +39,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the SD card -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e mmc ${INSTALL_MMCDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_usb.txt index 1438c0739..f75804f65 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_usb.txt @@ -39,7 +39,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the USB -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e usb ${INSTALL_USBDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index 068e09ac0..8c4c0399b 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -1,7 +1,7 @@ #!/bin/sh #=============================================================================== # -# Copyright (C) 2020-2023 by Digi International Inc. +# Copyright (C) 2020-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -141,7 +141,10 @@ if [ -f ${COMPRESSED_ROOTFS_IMAGE} ] && [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; the fi # Verify existence of files before starting the update -FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}" +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if [ "${DUALBOOT}" != true ]; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi for f in ${FILES}; do if [ ! -f ${f} ]; then echo "\033[31m[ERROR] Could not find file '${f}'\033[0m" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt index 153f27aa3..31f7bd298 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt @@ -40,7 +40,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the SD card -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e mmc ${INSTALL_MMCDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt index 5e536006b..d1a80f0d7 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt @@ -40,7 +40,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.vfat setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ext4 # Check for presence of firmware files on the USB -for install_f in ${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e usb ${INSTALL_USBDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh index fcf342151..7e1e51786 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh @@ -1,7 +1,7 @@ #!/bin/sh #=============================================================================== # -# Copyright (C) 2020-2023 by Digi International Inc. +# Copyright (C) 2020-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -144,7 +144,10 @@ if [ -f ${COMPRESSED_ROOTFS_IMAGE} ] && [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; the fi # Verify existence of files before starting the update -FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}" +FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" +if [ "${DUALBOOT}" != true ]; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi for f in ${FILES}; do if [ ! -f ${f} ]; then echo "\033[31m[ERROR] Could not find file '${f}'\033[0m" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt index 798a42ea1..6029d27b0 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt @@ -28,7 +28,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.ubifs setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ubifs # Check for presence of firmware files on the SD card -for install_f in ${INSTALL_ATF_FILENAME} ${INSTALL_FIP_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_ATF_FILENAME} ${INSTALL_FIP_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e mmc ${INSTALL_MMCDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt index 03415add1..7792fb112 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt @@ -28,7 +28,11 @@ setenv INSTALL_RECOVERY_FILENAME ${BASEFILENAME}-##MACHINE##.recovery.ubifs setenv INSTALL_ROOTFS_FILENAME ${BASEFILENAME}-##MACHINE##.ubifs # Check for presence of firmware files on the USB -for install_f in ${INSTALL_ATF_FILENAME} ${INSTALL_FIP_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}; do +FILES="${INSTALL_ATF_FILENAME} ${INSTALL_FIP_FILENAME} ${INSTALL_LINUX_FILENAME}" +if test "${dualboot}" != "yes"; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi +for install_f in ${FILES}; do if test ! -e usb ${INSTALL_USBDEV} ${install_f}; then echo "ERROR: Could not find file ${install_f}"; install_abort=1; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh index f08aaf979..2373e4587 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh @@ -1,7 +1,7 @@ #!/bin/sh #=============================================================================== # -# Copyright (C) 2022-2023 by Digi International Inc. +# Copyright (C) 2022-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -145,7 +145,11 @@ INSTALL_RECOVERY_FILENAME="${BASEFILENAME}-##MACHINE##.recovery.ubifs" INSTALL_ROOTFS_FILENAME="${BASEFILENAME}-##MACHINE##.ubifs" # Verify existence of files before starting the update -FILES="${INSTALL_ATF_FILENAME} ${INSTALL_FIP_FILENAME} ${INSTALL_LINUX_FILENAME} ${INSTALL_RECOVERY_FILENAME}" +FILES="${INSTALL_ATF_FILENAME} ${INSTALL_FIP_FILENAME} ${INSTALL_LINUX_FILENAME}" +if [ "${DUALBOOT}" != true ]; then + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" +fi + for f in ${FILES}; do if [ ! -f ${f} ]; then echo "\033[31m[ERROR] Could not find file '${f}'\033[0m" From 81d0ce168f8a86dd4fc33c872f79341370df386e Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Thu, 25 Jan 2024 17:42:38 +0100 Subject: [PATCH 14/91] u-boot-dey: installation scripts: minor fixes Some minor fixes: * return error code if installation fails * cosmetic: update comment with options * just exit after error and do not execute boolimit command Signed-off-by: Isaac Hermida --- .../u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh | 9 +++++---- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 9 +++++---- .../u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh | 9 +++++---- .../u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh | 7 ++++--- .../u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh | 7 ++++--- .../u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh | 7 ++++--- .../u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh | 5 +++-- 7 files changed, 30 insertions(+), 23 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index 3aefbabf0..7ece2d006 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -70,8 +70,9 @@ echo "# Linux firmware install through USB OTG #" echo "############################################################" # Command line admits the following parameters: -# -u +# -b, -d, -n (booleans) # -i +# -u while getopts 'bdhi:nu:' c do case $c in @@ -129,7 +130,7 @@ if [ -z ${INSTALL_UBOOT_FILENAME} ]; then echo "" echo "Aborted" echo "" - exit + exit 1 fi fi @@ -188,13 +189,13 @@ if [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; then fi fi +[ "${ABORT}" = true ] && exit 1 + # Enable bootcount mechanism by setting a bootlimit if [ "${BOOTCOUNT}" = true ]; then bootlimit_cmd="setenv bootlimit 3" fi -[ "${ABORT}" = true ] && exit 1 - # parts names LINUX_NAME="linux" RECOVERY_NAME="recovery" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index 499762a32..940bf8a40 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -70,8 +70,9 @@ echo "# Linux firmware install through USB OTG #" echo "############################################################" # Command line admits the following parameters: -# -u +# -b, -d, -n (booleans) # -i +# -u while getopts 'bdhi:nu:' c do case $c in @@ -148,7 +149,7 @@ if [ -z ${INSTALL_UBOOT_FILENAME} ]; then echo "" echo "Aborted" echo "" - exit + exit 1 fi fi @@ -207,13 +208,13 @@ if [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; then fi fi +[ "${ABORT}" = true ] && exit 1 + # Enable bootcount mechanism by setting a bootlimit if [ "${BOOTCOUNT}" = true ]; then bootlimit_cmd="setenv bootlimit 3" fi -[ "${ABORT}" = true ] && exit 1 - # parts names LINUX_NAME="linux" RECOVERY_NAME="recovery" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh index 79e306ec0..cc34c97ae 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh @@ -79,8 +79,9 @@ echo "# Linux firmware install through USB OTG #" echo "############################################################" # Command line admits the following parameters: -# -u +# -b, -d, -n (booleans) # -i +# -u while getopts 'bdhi:nu:' c do case $c in @@ -153,7 +154,7 @@ if [ -z "${INSTALL_UBOOT_FILENAME}" ]; then echo "" echo "Aborted" echo "" - exit + exit 1 fi fi @@ -202,13 +203,13 @@ if [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; then fi fi +[ "${ABORT}" = true ] && exit 1 + # Enable bootcount mechanism by setting a bootlimit if [ "${BOOTCOUNT}" = true ]; then bootlimit_cmd="setenv bootlimit 3" fi -[ "${ABORT}" = true ] && exit 1 - # parts names LINUX_NAME="linux" RECOVERY_NAME="recovery" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index e8377be78..aceb658e1 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -70,8 +70,9 @@ echo "# Linux firmware install through USB OTG #" echo "############################################################" # Command line admits the following parameters: -# -u +# -b, -d, -n (booleans) # -i +# -u while getopts 'bdhi:nu:' c do case $c in @@ -156,13 +157,13 @@ if [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; then fi fi +[ "${ABORT}" = true ] && exit 1 + # Enable bootcount mechanism by setting a bootlimit if [ "${BOOTCOUNT}" = true ]; then bootlimit_cmd="setenv bootlimit 3" fi -[ "${ABORT}" = true ] && exit 1 - # parts names LINUX_NAME="linux" RECOVERY_NAME="recovery" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index 8c4c0399b..0eae8737c 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -70,8 +70,9 @@ echo "# Linux firmware install through USB OTG #" echo "############################################################" # Command line admits the following parameters: -# -u +# -b, -d, -n (booleans) # -i +# -u while getopts 'bdhi:nu:' c do case $c in @@ -163,13 +164,13 @@ if [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; then fi fi +[ "${ABORT}" = true ] && exit 1 + # Enable bootcount mechanism by setting a bootlimit if [ "${BOOTCOUNT}" = true ]; then bootlimit_cmd="setenv bootlimit 3" fi -[ "${ABORT}" = true ] && exit 1 - # parts names LINUX_NAME="linux" RECOVERY_NAME="recovery" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh index 7e1e51786..fd1336cbd 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh @@ -70,8 +70,9 @@ echo "# Linux firmware install through USB OTG #" echo "############################################################" # Command line admits the following parameters: -# -u +# -b, -d, -n (booleans) # -i +# -u while getopts 'bdhi:nu:' c do case $c in @@ -166,13 +167,13 @@ if [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; then fi fi +[ "${ABORT}" = true ] && exit 1 + # Enable bootcount mechanism by setting a bootlimit if [ "${BOOTCOUNT}" = true ]; then bootlimit_cmd="setenv bootlimit 3" fi -[ "${ABORT}" = true ] && exit 1 - # parts names LINUX_NAME="linux" RECOVERY_NAME="recovery" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh index 2373e4587..02f28b37d 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh @@ -80,6 +80,7 @@ echo "############################################################" # Command line admits the following parameters: # -a +# -b, -d, -n (booleans) # -f # -i while getopts 'a:bdf:hi:n' c @@ -170,13 +171,13 @@ if [ ! -f ${INSTALL_ROOTFS_FILENAME} ]; then fi fi +[ "${ABORT}" = true ] && exit 1 + # Enable bootcount mechanism by setting a bootlimit if [ "${BOOTCOUNT}" = true ]; then bootlimit_cmd="setenv bootlimit 3" fi -[ "${ABORT}" = true ] && exit 1 - # parts names LINUX_NAME="linux" RECOVERY_NAME="recovery" From a8f5951578d500ea614d72b58c916d66bba3b472 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Tue, 5 Dec 2023 15:26:54 +0100 Subject: [PATCH 15/91] u-boot-dey: add support to installation script for Trustfence This commit adds support to installation script for Trustfence artifacts. https://onedigi.atlassian.net/browse/DEL-8271 Signed-off-by: Mike Engel --- .../recipes-bsp/u-boot/u-boot-dey.inc | 20 +++++++++++ .../ccimx6qpsbc/install_linux_fw_uuu.sh | 29 ++++++++++++--- .../ccimx6sbc/install_linux_fw_uuu.sh | 30 +++++++++++++--- .../ccimx6ul/install_linux_fw_uuu.sh | 27 +++++++++++--- .../ccimx8m/install_linux_fw_uuu.sh | 33 +++++++++++++---- .../ccimx8x/install_linux_fw_uuu.sh | 35 +++++++++++++++---- .../u-boot-dey/ccmp1/install_linux_fw_uuu.sh | 4 +-- 7 files changed, 150 insertions(+), 28 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 75199b0b0..9d92fdc40 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -81,6 +81,26 @@ build_uboot_scripts() { -e 's,##GRAPHICAL_IMAGES##,${GRAPHICAL_IMAGES},g' \ -e 's,##DEFAULT_IMAGE_NAME##,${DEFAULT_IMAGE_NAME},g' \ ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + # Change the u-boot name when TrustFence is enabled + if [ "${TRUSTFENCE_SIGN}" == "1" ]; then + if [ "${DEY_SOC_VENDOR}" == "NXP" ]; then + if [ "${TRUSTFENCE_DEK_PATH}" != "0" ]; then + sed -e 's,##SIGNED##,-encrypted,g' \ + ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + else + sed -e 's,##SIGNED##,-signed,g' \ + ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + fi + else + sed -e 's,##SIGNED##,_Signed,g' \ + ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + sed -e 's,##SIGNED_TFA##,_signed,g' \ + ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + fi + else + sed -e 's,##SIGNED##,,g' \ + ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + fi if [ "${f_ext}" = "txt" ]; then mkimage -T script -n "DEY firmware install script" -C none -d ${TMP_INSTALL_SCR} ${DEPLOYDIR}/${f%.*}.scr else diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index 7ece2d006..db5f31316 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -39,7 +39,10 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." + echo " -k Update includes dek blob file." + echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." + echo " -t Install Trustfence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 @@ -49,6 +52,7 @@ show_usage() # Params: # 1. partition # 2. file +# 3. dek blob file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -57,10 +61,23 @@ part_update() echo "=====================================================================================" echo "\033[0m" - if [ "${1}" = "bootloader" ]; then - uuu fb: flash "${1}" "${2}" + if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then + uuu fb: download -f "${2}" + if [ -n "${DEK_BLOB_FILE}" ]; then + uuu fb: ucmd setenv uboot_size $filesize + uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: download -f "${3}" + uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + else + uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} + fi else - uuu fb: flash -raw2sparse "${1}" "${2}" + if [ "${1}" = "bootloader" ]; then + uuu fb: flash "${1}" "${2}" + else + uuu fb: flash -raw2sparse "${1}" "${2}" + fi fi } @@ -73,14 +90,16 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:nu:' c +while getopts 'bdhi:k:ntu:' c do case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; + k) DEK_BLOB_FILE=${OPTARG} ;; n) NOWAIT=true ;; + t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; esac done @@ -243,7 +262,7 @@ fi uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_FILE}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index 940bf8a40..8403a19b7 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -39,7 +39,10 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." + echo " -k Update includes dek blob file." + echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." + echo " -t Install Trustfence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 @@ -49,6 +52,7 @@ show_usage() # Params: # 1. partition # 2. file +# 3. dek blob file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -57,10 +61,23 @@ part_update() echo "=====================================================================================" echo "\033[0m" - if [ "${1}" = "bootloader" ]; then - uuu fb: flash "${1}" "${2}" + if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then + uuu fb: download -f "${2}" + if [ -n "${DEK_BLOB_FILE}" ]; then + uuu fb: ucmd setenv uboot_size $filesize + uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: download -f "${3}" + uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + else + uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} + fi else - uuu fb: flash -raw2sparse "${1}" "${2}" + if [ "${1}" = "bootloader" ]; then + uuu fb: flash "${1}" "${2}" + else + uuu fb: flash -raw2sparse "${1}" "${2}" + fi fi } @@ -73,14 +90,17 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:nu:' c +# -k +while getopts 'bdhi:k:ntu:' c do case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; + k) DEK_BLOB_FILE=${OPTARG} ;; n) NOWAIT=true ;; + t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; esac done @@ -262,7 +282,7 @@ fi uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_FILE}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh index cc34c97ae..446ccc150 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh @@ -39,7 +39,10 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." + echo " -k Update includes dek blob file." + echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." + echo " -t Install Trustfence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 @@ -53,6 +56,7 @@ show_usage() # Description: # - downloads image to RAM # - runs 'update' command from RAM +# 4. dek blob file when updating an encrypted u-boot part_update() { echo "\033[36m" @@ -70,7 +74,19 @@ part_update() ERASE="-e" fi uuu fb: download -f "${2}" - uuu "fb[-t ${3}]:" ucmd update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} ${ERASE} + if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "uboot" ]; then + if [ -n "${DEK_BLOB_FILE}" ]; then + uuu fb: ucmd setenv uboot_size $filesize + uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: download -f "${4}" + uuu fb: ucmd setenv dek_size $filesize + uuu "fb[-t ${3}]:" ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + else + uuu "fb[-t ${3}]:" ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} + fi + else + uuu "fb[-t ${3}]:" ucmd update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} ${ERASE} + fi } clear @@ -82,14 +98,17 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:nu:' c +# -k +while getopts 'bdhi:k:ntu:' c do case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; + k) DEK_BLOB_FILE=${OPTARG} ;; n) NOWAIT=true ;; + t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; esac done @@ -119,7 +138,7 @@ if [ -z "${INSTALL_UBOOT_FILENAME}" ]; then if [ -n "$module_variant" ]; then if [ "$module_variant" = "0x08" ] || \ [ "$module_variant" = "0x0a" ]; then - INSTALL_UBOOT_FILENAME="u-boot-##MACHINE##512MB.imx" + INSTALL_UBOOT_FILENAME="u-boot-##SIGNED##-##MACHINE##512MB.imx" elif [ "$module_variant" = "0x04" ] || \ [ "$module_variant" = "0x05" ] || \ [ "$module_variant" = "0x07" ]; then @@ -260,7 +279,7 @@ uuu fb: ucmd setenv fastboot_buffer \${loadaddr} uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "uboot" "${INSTALL_UBOOT_FILENAME}" 5000 +part_update "uboot" "${INSTALL_UBOOT_FILENAME}" 5000 "${DEK_BLOB_FILE}" # Set 'bootcmd' for the second part of the script that will # - Reset environment to defaults diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index aceb658e1..6e93187c6 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -39,7 +39,10 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." + echo " -k Update includes dek blob file." + echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." + echo " -t Install Trustfence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 @@ -49,6 +52,7 @@ show_usage() # Params: # 1. partition # 2. file +# 3. dek blob file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -57,10 +61,24 @@ part_update() echo "=====================================================================================" echo "\033[0m" - if [ "${1}" = "bootloader" ]; then - uuu fb: flash "${1}" "${2}" + if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then + uuu fb: download -f "${2}" + if [ -n "${DEK_BLOB_KEY}" ]; then + uuu fb: ucmd setenv uboot_size $filesize + uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: download -f "${3}" + uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + else + uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} + fi + fi else - uuu fb: flash -raw2sparse "${1}" "${2}" + if [ "${1}" = "bootloader" ]; then + uuu fb: flash "${1}" "${2}" + else + uuu fb: flash -raw2sparse "${1}" "${2}" + fi fi } @@ -73,14 +91,17 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:nu:' c +# -k +while getopts 'bdhi:k:ntu:' c do case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; + k) DEK_BLOB_KEY=${OPTARG} ;; n) NOWAIT=true ;; + t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; esac done @@ -102,7 +123,7 @@ echo "Determining image files to use..." # Determine U-Boot file to program basing on SOM's SOC type (linked to bus width) if [ -z "${INSTALL_UBOOT_FILENAME}" ]; then - INSTALL_UBOOT_FILENAME="imx-boot-##MACHINE##.bin" + INSTALL_UBOOT_FILENAME="imx-boot-##SIGNED##-##MACHINE##.bin" fi # Determine linux, recovery, and rootfs image filenames to update @@ -214,7 +235,7 @@ uuu fb: ucmd setenv fastboot_buffer \${loadaddr} uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_KEY}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index 0eae8737c..760cfd8e4 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -39,7 +39,10 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." + echo " -k Update includes dek blob file." + echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." + echo " -t Install Trustfence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 @@ -49,6 +52,7 @@ show_usage() # Params: # 1. partition # 2. file +# 3. dek blob file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -57,10 +61,23 @@ part_update() echo "=====================================================================================" echo "\033[0m" - if [ "${1}" = "bootloader" ]; then - uuu fb: flash "${1}" "${2}" + if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then + uuu fb: download -f "${2}" + if [ -n "${DEK_BLOB_KEY}" ]; then + uuu fb: ucmd setenv uboot_size $filesize + uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: download -f "${3}" + uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + else + uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} + fi else - uuu fb: flash -raw2sparse "${1}" "${2}" + if [ "${1}" = "bootloader" ]; then + uuu fb: flash "${1}" "${2}" + else + uuu fb: flash -raw2sparse "${1}" "${2}" + fi fi } @@ -73,14 +90,17 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:nu:' c +# -k +while getopts 'bdhi:k:ntu:' c do case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; + k) DEK_BLOB_KEY=${OPTARG} ;; n) NOWAIT=true ;; + t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; esac done @@ -106,7 +126,7 @@ if [ -z ${INSTALL_UBOOT_FILENAME} ]; then soc_rev="B0" fi - INSTALL_UBOOT_FILENAME="imx-boot-##MACHINE##-${soc_rev}.bin" + INSTALL_UBOOT_FILENAME="imx-boot-##SIGNED##-##MACHINE##-${soc_rev}.bin" fi # remove redirect @@ -214,11 +234,14 @@ if [ "${NOWAIT}" != true ]; then printf " Starting update process\n" fi +# Set fastboot buffer address to $loadaddr, just in case +uuu fb: ucmd setenv fastboot_buffer \${loadaddr} + # Skip user confirmation for U-Boot update uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_KEY}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh index 02f28b37d..68d7fb680 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh @@ -120,12 +120,12 @@ echo "Determining image files to use..." # Determine ATF file to program if [ -z "${INSTALL_ATF_FILENAME}" ]; then - INSTALL_ATF_FILENAME="tf-a-##MACHINE##-nand.stm32" + INSTALL_ATF_FILENAME="tf-a-##MACHINE##-nand##SIGNED_TFA##.stm32" fi # Determine FIP file to program if [ -z "${INSTALL_FIP_FILENAME}" ]; then - INSTALL_FIP_FILENAME="fip-##MACHINE##-optee.bin" + INSTALL_FIP_FILENAME="fip-##MACHINE##-optee##SIGNED##.bin" fi # Determine linux, recovery, and rootfs image filenames to update From 46a3f7b529ffa94f319ff322b244dfdf522cc919 Mon Sep 17 00:00:00 2001 From: Gonzalo Ruiz Date: Wed, 14 Feb 2024 11:54:50 +0100 Subject: [PATCH 16/91] firmware-murata: update US-only CLM blob Replace the US-only default CLM blob with the latest one, generated by Infineon based on the results from Digi Certification of the CCMP1. New file: - cyfmac4373-sdio_US.clm_blob (92225a8bccf0c7c9d7df6cdd64670fa1) https://onedigi.atlassian.net/browse/DEL-8598 Signed-off-by: Gonzalo Ruiz --- .../cyfmac4373-sdio_US.clm_blob | Bin 941 -> 941 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyfmac4373-sdio_US.clm_blob b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyfmac4373-sdio_US.clm_blob index 00a4b51e416fa7608640cbfba77621e693157dcf..c3901c923caba293fcb0137402997c3963ebf719 100644 GIT binary patch delta 203 zcmZ3>zLs6Z$;aQxhJk@0{@&6eMj*`u#2^3?%VlO@D0{qm_CytJPG@Ib-vC41(BO#? zR_rGF21fb@787UI2{Ey`F)(T|GI=pGy0I{6u`;<$)?{q5H_a6SEp4gBuHj+GIzjpQ21aLm1t-811+jt#}yScp0tu7~LlOGsgh{1ZE-; delta 203 zcmW-ZJ8Hu~7=-8FU1{ToWC)~5r9uH2$9QEuSVSOyL@+KAl+w6xlR8&OksFAuatQej zK9W1Tv+RM7fsbK2-RZdgXzCXLEB@Y6-=gQ5tNW3_>1ls# Date: Tue, 13 Feb 2024 13:57:32 +0100 Subject: [PATCH 17/91] linux-virtualization: fix compilation https://onedigi.atlassian.net/browse/DEL-8835 https://onedigi.atlassian.net/browse/DEL-8896 Signed-off-by: Mike Engel Signed-off-by: Isaac Hermida --- .../recipes-kernel/linux/linux-dey.inc | 2 +- .../linux/linux-dey/docker_conf.cfg | 50 +++++++++++++++++++ .../linux/linux-virtualization.inc | 50 ------------------- 3 files changed, 51 insertions(+), 51 deletions(-) create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg delete mode 100644 meta-digi-arm/recipes-kernel/linux/linux-virtualization.inc diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey.inc b/meta-digi-arm/recipes-kernel/linux/linux-dey.inc index afda6fa1e..d9c4603c1 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey.inc +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey.inc @@ -5,7 +5,6 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" inherit kernel inherit ${@oe.utils.conditional('DEY_SOC_VENDOR', 'NXP', 'fsl-kernel-localversion', '', d)} -require ${@bb.utils.contains('DISTRO_FEATURES', 'virtualization', 'linux-virtualization.inc', '', d)} require ${@oe.utils.conditional('TRUSTFENCE_SIGN', '1', 'recipes-kernel/linux/linux-trustfence.inc', '', d)} # CONFIG_KERNEL_LZO in defconfig @@ -18,6 +17,7 @@ LINUX_GIT_URI ?= "${@oe.utils.conditional('DIGI_INTERNAL_GIT', '1', '${LINUX_URI SRC_URI = " \ ${LINUX_GIT_URI};branch=${SRCBRANCH} \ ${@oe.utils.conditional('KERNEL_DEFCONFIG', '', 'file://defconfig', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'virtualization', 'file://docker_conf.cfg', '', d)} \ " S = "${WORKDIR}/git" diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg b/meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg new file mode 100644 index 000000000..345ef04e1 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg @@ -0,0 +1,50 @@ +.......................................................................... +. WARNING +. +. This file is a kernel configuration fragment, and not a full kernel +. configuration file. The final kernel configuration is made up of +. an assembly of processed fragments, each of which is designed to +. capture a specific part of the final configuration (e.g. platform +. configuration, feature configuration, and board specific hardware +. configuration). For more information on kernel configuration, please +. consult the product documentation. +. +.......................................................................... +CONFIG_COMPAT=y +CONFIG_NETFILTER_NETLINK=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_NAT=y +CONFIG_NF_TABLES=y +CONFIG_NFT_NAT=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_XTABLES_COMPAT=y +CONFIG_NETFILTER_XT_NAT=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=y +CONFIG_NETFILTER_XT_MARK=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_VETH=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_NS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_BLK_CGROUP=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_CHECKPOINT_RESTORE=y diff --git a/meta-digi-arm/recipes-kernel/linux/linux-virtualization.inc b/meta-digi-arm/recipes-kernel/linux/linux-virtualization.inc deleted file mode 100644 index 00a00fdda..000000000 --- a/meta-digi-arm/recipes-kernel/linux/linux-virtualization.inc +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (C) 2019 Digi International - -# Apply kernel configuration required for Docker -do_configure:prepend() { - mkdir -p ${B} - - kernel_conf_variable NAMESPACES y - kernel_conf_variable MULTIUSER y - kernel_conf_variable NET_NS y - kernel_conf_variable NET y - kernel_conf_variable PID_NS y - kernel_conf_variable IPC_NS y - kernel_conf_variable POSIX_MQUEUE y - kernel_conf_variable UTS_NS y - kernel_conf_variable CGROUPS y - kernel_conf_variable CGROUP_CPUACCT y - kernel_conf_variable CGROUP_DEVICE y - kernel_conf_variable CGROUP_FREEZER y - kernel_conf_variable CGROUP_SCHED y - kernel_conf_variable CPUSETS y - kernel_conf_variable SMP y - kernel_conf_variable MEMCG y - kernel_conf_variable KEYS y - kernel_conf_variable VETH y - kernel_conf_variable NETDEVICES y - kernel_conf_variable NET_CORE y - kernel_conf_variable BRIDGE y - kernel_conf_variable BRIDGE_NETFILTER y - kernel_conf_variable NETFILTER y - kernel_conf_variable INET y - kernel_conf_variable NETFILTER_ADVANCED y - kernel_conf_variable NF_NAT_IPV4 y - kernel_conf_variable NF_CONNTRACK_IPV4 y - kernel_conf_variable NF_CONNTRACK y - kernel_conf_variable IP_NF_FILTER y - kernel_conf_variable IP_NF_IPTABLES y - kernel_conf_variable IP_NF_TARGET_MASQUERADE y - kernel_conf_variable IP_NF_NAT y - kernel_conf_variable NETFILTER_XT_MATCH_ADDRTYPE y - kernel_conf_variable NETFILTER_XT_MATCH_CONNTRACK y - kernel_conf_variable NETFILTER_XT_MATCH_IPVS y - kernel_conf_variable IP_VS y - kernel_conf_variable IP_NF_NAT y - kernel_conf_variable POSIX_MQUEUE y - kernel_conf_variable OVERLAY_FS y - - sed -e "${CONF_SED_SCRIPT}" < '${WORKDIR}/defconfig' >> '${B}/.config' -} - -KERNEL_MODULE_AUTOLOAD += "nf_conntrack_ipv6 openvswitch" From 9778490a30b274544662a9916e0a9fd04d0acdfb Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Fri, 2 Feb 2024 13:40:35 +0100 Subject: [PATCH 18/91] u-boot-dey: ccmp1: disable CMD_BOOTZ when secure boot with FIT image is enabled Command 'bootz' allows boot unsigned Linux zImages, so disable it when secure boot is enabled using FIT images. https://onedigi.atlassian.net/browse/DEL-8769 Signed-off-by: Arturo Buzarra --- .../recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg index eb5d7d683..362903338 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg @@ -2,3 +2,4 @@ CONFIG_FIT_SIGNATURE=y CONFIG_RSA=y CONFIG_ECDSA=y CONFIG_ECDSA_VERIFY=y +# CONFIG_CMD_BOOTZ is not set From e7d90794f86fd0576ff3b9092e850c84476d45c6 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Thu, 7 Dec 2023 11:03:07 +0100 Subject: [PATCH 19/91] ccmp1: support different DDR3 configurations This commit implements the support to allow different memory configurations for the CCMP1 platforms, adding support to 512MB and 1GB memory variants for the CCMP15. https://onedigi.atlassian.net/browse/DEL-8752 Signed-off-by: Arturo Buzarra --- meta-digi-arm/conf/machine/ccmp13-dvk.conf | 20 +++++---- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 25 +++++++---- meta-digi-arm/conf/machine/include/ccmp1.inc | 1 - .../recipes-bsp/u-boot/u-boot-dey.inc | 42 ++++++++++++++++--- .../u-boot-dey/ccmp1/install_linux_fw_sd.txt | 4 +- .../u-boot-dey/ccmp1/install_linux_fw_usb.txt | 4 +- .../u-boot-dey/ccmp1/install_linux_fw_uuu.sh | 10 ++++- .../wic/{ccmp1.wks.in => ccmp1-1GB.wks.in} | 8 ++-- meta-digi-arm/wic/ccmp1-256MB.wks.in | 37 ++++++++++++++++ meta-digi-arm/wic/ccmp1-512MB.wks.in | 37 ++++++++++++++++ 10 files changed, 153 insertions(+), 35 deletions(-) rename meta-digi-arm/wic/{ccmp1.wks.in => ccmp1-1GB.wks.in} (81%) create mode 100644 meta-digi-arm/wic/ccmp1-256MB.wks.in create mode 100644 meta-digi-arm/wic/ccmp1-512MB.wks.in diff --git a/meta-digi-arm/conf/machine/ccmp13-dvk.conf b/meta-digi-arm/conf/machine/ccmp13-dvk.conf index 54fabbc80..a4df2b433 100644 --- a/meta-digi-arm/conf/machine/ccmp13-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp13-dvk.conf @@ -18,8 +18,8 @@ MACHINEOVERRIDES = "arm:armv7ve:stcommon:stm32mpcommon:stm32mp1common:${DIGI_FAM # boot device # ========================================================================= # Configure the list of boards that enable NAND/SDCARD -DEVICE_BOARD_ENABLE:NAND += "ccmp13-dvk" -DEVICE_BOARD_ENABLE:SDCARD += "${@bb.utils.contains('BOOTDEVICE_LABELS', 'sdcard', 'ccmp13-dvk', '', d)}" +DEVICE_BOARD_ENABLE:NAND += "${STM32MP_DEVICETREE}" +DEVICE_BOARD_ENABLE:SDCARD += "${@bb.utils.contains('BOOTDEVICE_LABELS', 'sdcard', '${STM32MP_DEVICETREE}', '', d)}" # ========================================================================= # U-Boot configs @@ -28,14 +28,11 @@ DEVICE_BOARD_ENABLE:SDCARD += "${@bb.utils.contains('BOOTDEVICE_LABELS', 'sdcard UBOOT_CONFIG = "ccmp13-dvk" UBOOT_CONFIG[ccmp13-dvk] = "ccmp13-dvk_defconfig,,u-boot-dtb.${UBOOT_SUFFIX}" -# Platform U-Boot settings -UBOOT_DTB_NAME = "ccmp13-dvk.dtb" - # ========================================================================= # Machine settings # ========================================================================= # Define list of devicetree per board -STM32MP_DEVICETREE ??= "ccmp13-dvk" +STM32MP_DEVICETREE ??= "ccmp13-dvk-256MB" # Extra DTB for board - need to specify it with .dtb ... STM32MP_KERNEL_DEVICETREE:ccmp13-dvk += " \ ccmp133-dvk.dtb \ @@ -50,6 +47,8 @@ STM32MP_KERNEL_DEVICETREE:ccmp13-dvk += " \ " # Set DTB load address to U-Boot fdt_addr_r UBOOT_DTB_LOADADDRESS = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', '0xc4000000', '', d)}" +# List of U-Boot device tree to use +UBOOT_DEVICETREE = "${STM32MP_DEVICETREE}" # ========================================================================= # Machine features @@ -77,6 +76,9 @@ IMAGE_FSTYPES += '${@bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs", \ # Default image for install scripts DEFAULT_IMAGE_NAME ?= "core-image-base" +# Wic files +WKS_FILE += "ccmp1-256MB.wks.in" + # For populate_sdk, gcc-arm-none-eabi_9 has a python2 dependency, so we remove it. ST_TOOLS_FOR_SDK:remove = "nativesdk-gcc-arm-none-eabi" @@ -100,7 +102,7 @@ ST_DEBUG_TRACE = "0" # optee # ========================================================================= # Map OPTEE configuration to device tree list -OPTEE_CONF = "ccmp13-dvk" +OPTEE_CONF = "${STM32MP_DEVICETREE}" # ========================================================================= # Flashlayouts @@ -158,8 +160,8 @@ ST_VENDORFS = "0" # Boot artifacts to be copied from the deploy dir to the installer ZIP BOOTABLE_ARTIFACTS = " \ - arm-trusted-firmware/tf-a-ccmp13-dvk-nand.stm32 \ - fip/fip-ccmp13-dvk-optee.bin \ + arm-trusted-firmware/tf-a-ccmp13-dvk-256MB-nand.stm32 \ + fip/fip-ccmp13-dvk-256MB-optee.bin \ " # TRUSTFENCE basic support diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index bf6b83680..cdcf53aad 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -18,8 +18,8 @@ MACHINEOVERRIDES = "arm:armv7ve:stcommon:stm32mpcommon:stm32mp1common:${DIGI_FAM # boot device # ========================================================================= # Configure the list of boards that enable NAND/SDCARD -DEVICE_BOARD_ENABLE:NAND += "ccmp15-dvk" -DEVICE_BOARD_ENABLE:SDCARD += "${@bb.utils.contains('BOOTDEVICE_LABELS', 'sdcard', 'ccmp15-dvk', '', d)}" +DEVICE_BOARD_ENABLE:NAND += "${STM32MP_DEVICETREE}" +DEVICE_BOARD_ENABLE:SDCARD += "${@bb.utils.contains('BOOTDEVICE_LABELS', 'sdcard', '${STM32MP_DEVICETREE}', '', d)}" # ========================================================================= # U-Boot configs @@ -28,14 +28,11 @@ DEVICE_BOARD_ENABLE:SDCARD += "${@bb.utils.contains('BOOTDEVICE_LABELS', 'sdcard UBOOT_CONFIG = "ccmp15-dvk" UBOOT_CONFIG[ccmp15-dvk] = "ccmp15-dvk_defconfig,,u-boot-dtb.${UBOOT_SUFFIX}" -# Platform U-Boot settings -UBOOT_DTB_NAME = "ccmp15-dvk.dtb" - # ========================================================================= # Machine settings # ========================================================================= # Define list of devicetree per board -STM32MP_DEVICETREE ??= "ccmp15-dvk" +STM32MP_DEVICETREE ??= "ccmp15-dvk-512MB ccmp15-dvk-1GB" # Extra DTB for board - need to specify it with .dtb ... STM32MP_KERNEL_DEVICETREE:ccmp15-dvk += " \ ccmp157-dvk.dtb \ @@ -57,6 +54,8 @@ STM32MP_KERNEL_DEVICETREE:ccmp15-dvk += " \ " # Set DTB load address to U-Boot fdt_addr_r UBOOT_DTB_LOADADDRESS = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', '0xc4000000', '', d)}" +# List of U-Boot device tree to use +UBOOT_DEVICETREE = "${STM32MP_DEVICETREE}" # ========================================================================= # Machine features @@ -85,6 +84,12 @@ IMAGE_FSTYPES += '${@bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs", \ # Default image for install scripts DEFAULT_IMAGE_NAME ?= "dey-image-webkit" +# Wic files +WKS_FILES += " \ + ccmp1-512MB.wks.in \ + ccmp1-1GB.wks.in \ +" + # For populate_sdk, gcc-arm-none-eabi_9 has a python2 dependency, so we remove it. ST_TOOLS_FOR_SDK:remove = "nativesdk-gcc-arm-none-eabi" @@ -108,7 +113,7 @@ ST_DEBUG_TRACE = "0" # optee # ========================================================================= # Map OPTEE configuration to device tree list -OPTEE_CONF = "ccmp15-dvk" +OPTEE_CONF = "${STM32MP_DEVICETREE}" # ========================================================================= # Flashlayouts @@ -163,8 +168,10 @@ ST_VENDORFS = "0" # Boot artifacts to be copied from the deploy dir to the installer ZIP BOOTABLE_ARTIFACTS = " \ - arm-trusted-firmware/tf-a-ccmp15-dvk-nand.stm32 \ - fip/fip-ccmp15-dvk-optee.bin \ + arm-trusted-firmware/tf-a-ccmp15-dvk-512MB-nand.stm32 \ + arm-trusted-firmware/tf-a-ccmp15-dvk-1GB-nand.stm32 \ + fip/fip-ccmp15-dvk-512MB-optee.bin \ + fip/fip-ccmp15-dvk-1GB-optee.bin \ " # TRUSTFENCE basic support diff --git a/meta-digi-arm/conf/machine/include/ccmp1.inc b/meta-digi-arm/conf/machine/include/ccmp1.inc index 89a433978..e298e91f6 100644 --- a/meta-digi-arm/conf/machine/include/ccmp1.inc +++ b/meta-digi-arm/conf/machine/include/ccmp1.inc @@ -62,7 +62,6 @@ MULTIUBI_BUILD:remove = "nand_4_256" IMAGE_FSTYPES:remove = "stmultiubi" # Wic files -WKS_FILE += "ccmp1.wks.in" WKS_FILE_DEPENDS ?= " \ virtual/bootloader \ virtual/trusted-firmware-a \ diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 9d92fdc40..82e760feb 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2023 Digi International +# Copyright (C) 2018-2024 Digi International require recipes-bsp/u-boot/u-boot.inc @@ -188,10 +188,35 @@ sign_uboot() { fi } +# ----------------------------------------------------------------------------- +# Append compile to handle specific device tree compilation +# +do_compile:append:ccmp1() { + if [ -n "${UBOOT_DEVICETREE}" ]; then + unset i j + for config in ${UBOOT_MACHINE}; do + i=$(expr $i + 1); + for devicetree in ${UBOOT_DEVICETREE}; do + # Cleanup previous build artifact + [ -f "${B}/${config}/dts/dt.dtb" ] && rm "${B}/${config}/dts/dt.dtb" + # Build target for specific device tree + oe_runmake -C ${S} O=${B}/${config} DEVICE_TREE=${devicetree} DEVICE_TREE_EXT=${devicetree}.dtb + # Install specific binary + for binary in ${UBOOT_BINARIES}; do + j=$(expr $j + 1); + if [ $j -eq $i ]; then + binarysuffix=$(echo ${binary} | cut -d'.' -f2) + install -m 644 ${B}/${config}/${binary} ${B}/${config}/u-boot-${devicetree}.${binarysuffix} + fi + done + unset j + done + done + fi +} + BOOT_TOOLS = "imx-boot-tools" BOOT_TOOLS:ccmp1 = "u-boot" -FIP_UBOOT_HEADER = "ccmp15-dvk" -FIP_UBOOT_HEADER:ccmp13 = "ccmp13-dvk" do_deploy:append:ccimx8m() { # Deploy u-boot-nodtb.bin and ccimx8m[m|n]-dvk.dtb, to be packaged in boot binary by imx-boot @@ -215,15 +240,20 @@ do_deploy:append:ccimx8m() { } do_deploy:append:ccmp1() { - # Deploy u-boot-nodtb.bin and ccmp1x-dvk.dtb, to be packaged in fip binary by tf-a + # Deploy u-boot-nodtb.bin and ccmp1x-dvk-xxxx.dtb, to be packaged in fip binary by tf-a install -d ${DEPLOYDIR}/${BOOT_TOOLS} - install -m 0777 ${B}/${config}/arch/arm/dts/${UBOOT_DTB_NAME} ${DEPLOYDIR}/${BOOT_TOOLS}/${FIP_UBOOT_DTB}-${FIP_UBOOT_HEADER}.dtb + if [ -n "${UBOOT_DEVICETREE}" ]; then + for devicetree in ${UBOOT_DEVICETREE}; do + # Install u-boot dtb + install -m 644 ${B}/${config}/arch/arm/dts/${devicetree}.dtb ${DEPLOYDIR}/${BOOT_TOOLS}/${FIP_UBOOT_DTB}-${devicetree}.dtb + done + fi install -m 0777 ${B}/${config}/u-boot-nodtb.bin ${DEPLOYDIR}/${BOOT_TOOLS}/u-boot-nodtb.bin # Append signature to u-boot DT if [ "x${UBOOT_SIGN_ENABLE}" = "x1" ] ; then # get name of u-boot devicetree without signature - ubootdevicetree="${DEPLOYDIR}/${BOOT_TOOLS}/u-boot-${UBOOT_DTB_NAME}" + ubootdevicetree=`ls -1 ${DEPLOYDIR}/${BOOT_TOOLS}/*.dtb | head -n 1` namewithoutsignature=`echo $ubootdevicetree | sed "s/\.dtb/-without-signature.dtb/g"` namewithsignature=`echo $ubootdevicetree | sed "s/\.dtb/-with-signature.dtb/g"` mv $ubootdevicetree $namewithoutsignature diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt index 6029d27b0..0c201f1e4 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_sd.txt @@ -7,8 +7,8 @@ install_abort=0 BASEFILENAME=0 -setenv INSTALL_ATF_FILENAME tf-a-##MACHINE##-nand.stm32 -setenv INSTALL_FIP_FILENAME fip-##MACHINE##-optee.bin +setenv INSTALL_ATF_FILENAME tf-a-##MACHINE##-${module_ram}-nand.stm32 +setenv INSTALL_FIP_FILENAME fip-##MACHINE##-${module_ram}-optee.bin setenv INSTALL_MMCDEV 1 if test -z "${image-name}"; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt index 7792fb112..eb0432506 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_usb.txt @@ -7,8 +7,8 @@ install_abort=0 BASEFILENAME=0 -setenv INSTALL_ATF_FILENAME tf-a-##MACHINE##-nand.stm32 -setenv INSTALL_FIP_FILENAME fip-##MACHINE##-optee.bin +setenv INSTALL_ATF_FILENAME tf-a-##MACHINE##-${module_ram}-nand.stm32 +setenv INSTALL_FIP_FILENAME fip-##MACHINE##-${module_ram}-optee.bin setenv INSTALL_USBDEV 0 if test -z "${image-name}"; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh index 68d7fb680..91d3a989a 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh @@ -112,6 +112,12 @@ if [ "${check}" = "1" ]; then RUNVOLS=true fi +# Check module_ram variable exists +module_ram=$(getenv "module_ram") +if [ -z "${module_ram}" ]; then + module_ram="512MB" # Default variant +fi + # remove redirect uuu fb: ucmd setenv stdout serial @@ -120,12 +126,12 @@ echo "Determining image files to use..." # Determine ATF file to program if [ -z "${INSTALL_ATF_FILENAME}" ]; then - INSTALL_ATF_FILENAME="tf-a-##MACHINE##-nand##SIGNED_TFA##.stm32" + INSTALL_ATF_FILENAME="tf-a-##MACHINE##-${module_ram}-nand##SIGNED_TFA##.stm32" fi # Determine FIP file to program if [ -z "${INSTALL_FIP_FILENAME}" ]; then - INSTALL_FIP_FILENAME="fip-##MACHINE##-optee##SIGNED##.bin" + INSTALL_FIP_FILENAME="fip-##MACHINE##-${module_ram}-optee##SIGNED##.bin" fi # Determine linux, recovery, and rootfs image filenames to update diff --git a/meta-digi-arm/wic/ccmp1.wks.in b/meta-digi-arm/wic/ccmp1-1GB.wks.in similarity index 81% rename from meta-digi-arm/wic/ccmp1.wks.in rename to meta-digi-arm/wic/ccmp1-1GB.wks.in index a2d3e8835..417b4946b 100644 --- a/meta-digi-arm/wic/ccmp1.wks.in +++ b/meta-digi-arm/wic/ccmp1-1GB.wks.in @@ -12,16 +12,16 @@ # # FSBL partitions aka TF-A BL2 -part fsbl1 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl1 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K --align 17 -part fsbl2 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl2 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K +part fsbl1 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl1 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-1GB-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K --align 17 +part fsbl2 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl2 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-1GB-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K # Metadata partitions part metadata1 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=metadata1 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/metadata.bin" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K part metadata2 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=metadata2 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/metadata.bin" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K # Fip partitions -part fip-a --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-a --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 4fd84c93-54ef-463f-a7ef-ae25ff887087 -part fip-b --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-b --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 09c54952-d5bf-45af-acee-335303766fb3 +part fip-a --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-a --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-1GB-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 4fd84c93-54ef-463f-a7ef-ae25ff887087 +part fip-b --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-b --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-1GB-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 09c54952-d5bf-45af-acee-335303766fb3 # U-BOOT env part u-boot-env --source empty --part-name=uboot-env --ondisk mmcblk --part-type 0x8301 --fixed-size 512K diff --git a/meta-digi-arm/wic/ccmp1-256MB.wks.in b/meta-digi-arm/wic/ccmp1-256MB.wks.in new file mode 100644 index 000000000..f11997d57 --- /dev/null +++ b/meta-digi-arm/wic/ccmp1-256MB.wks.in @@ -0,0 +1,37 @@ +# short-description: Create SD card image with a boot partition (1GB) +# long-description: Creates a partitioned SD card image (1GB) +# +# - -------- ------------- ------ ------ ------------ -------- --------- -------- +# | | TFA(2) | Metadata(2) | FIPA | FIPB | U-BOOT ENV | linux | rootfs | data | +# - -------- ------------- ------ ------ ------------ -------- --------- -------- +# ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ +# | | | | | | | | | | +# 0 17kB 542kB 1.06MB 5.26MB 9.45MB 9.97MB 77.1MB 898MB 1032MB +# +# Warning: the first stage of boot (here fsbl1, fsbl2, metadata1, metadata2, fipa, fipb) MUST be on GPT partition to be detected. +# + +# FSBL partitions aka TF-A BL2 +part fsbl1 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl1 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-256MB-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K --align 17 +part fsbl2 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl2 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-256MB-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K + +# Metadata partitions +part metadata1 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=metadata1 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/metadata.bin" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K +part metadata2 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=metadata2 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/metadata.bin" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K + +# Fip partitions +part fip-a --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-a --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-256MB-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 4fd84c93-54ef-463f-a7ef-ae25ff887087 +part fip-b --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-b --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-256MB-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 09c54952-d5bf-45af-acee-335303766fb3 + +# U-BOOT env +part u-boot-env --source empty --part-name=uboot-env --ondisk mmcblk --part-type 0x8301 --fixed-size 512K + +# linux +part --source rawcopy --sourceparams="file=${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.boot.vfat" --ondisk mmcblk --fstype=vfat --part-name=linux --active --fixed-size 64M + +# Rootfs +part / --source rootfs --ondisk mmcblk --fstype=ext4 --label rootfs --fixed-size 783M --uuid e91c4e10-16e6-4c0e-bd0e-77becf4a3582 --part-name=rootfs +# data +part data --ondisk mmcblk --fstype=ext4 --label data --fixed-size 128M --part-name=data + +bootloader --ptable gpt diff --git a/meta-digi-arm/wic/ccmp1-512MB.wks.in b/meta-digi-arm/wic/ccmp1-512MB.wks.in new file mode 100644 index 000000000..11357d0b2 --- /dev/null +++ b/meta-digi-arm/wic/ccmp1-512MB.wks.in @@ -0,0 +1,37 @@ +# short-description: Create SD card image with a boot partition (1GB) +# long-description: Creates a partitioned SD card image (1GB) +# +# - -------- ------------- ------ ------ ------------ -------- --------- -------- +# | | TFA(2) | Metadata(2) | FIPA | FIPB | U-BOOT ENV | linux | rootfs | data | +# - -------- ------------- ------ ------ ------------ -------- --------- -------- +# ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ +# | | | | | | | | | | +# 0 17kB 542kB 1.06MB 5.26MB 9.45MB 9.97MB 77.1MB 898MB 1032MB +# +# Warning: the first stage of boot (here fsbl1, fsbl2, metadata1, metadata2, fipa, fipb) MUST be on GPT partition to be detected. +# + +# FSBL partitions aka TF-A BL2 +part fsbl1 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl1 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-512MB-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K --align 17 +part fsbl2 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fsbl2 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/tf-a-${MACHINE}-512MB-sdcard.stm32" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K + +# Metadata partitions +part metadata1 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=metadata1 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/metadata.bin" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K +part metadata2 --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=metadata2 --sourceparams="file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware/metadata.bin" --ondisk mmcblk --part-type 0x8301 --fixed-size 256K + +# Fip partitions +part fip-a --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-a --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-512MB-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 4fd84c93-54ef-463f-a7ef-ae25ff887087 +part fip-b --source rawcopy --fstype=ext4 --fsoptions "noauto" --part-name=fip-b --sourceparams="file=${DEPLOY_DIR_IMAGE}/fip/fip-${MACHINE}-512MB-optee.bin" --ondisk mmcblk --part-type 19d5df83-11b0-457b-be2c-7559c13142a5 --fixed-size 4096K --uuid 09c54952-d5bf-45af-acee-335303766fb3 + +# U-BOOT env +part u-boot-env --source empty --part-name=uboot-env --ondisk mmcblk --part-type 0x8301 --fixed-size 512K + +# linux +part --source rawcopy --sourceparams="file=${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.boot.vfat" --ondisk mmcblk --fstype=vfat --part-name=linux --active --fixed-size 64M + +# Rootfs +part / --source rootfs --ondisk mmcblk --fstype=ext4 --label rootfs --fixed-size 783M --uuid e91c4e10-16e6-4c0e-bd0e-77becf4a3582 --part-name=rootfs +# data +part data --ondisk mmcblk --fstype=ext4 --label data --fixed-size 128M --part-name=data + +bootloader --ptable gpt From 7c76b0c35119b1a283884df25051676d50598cac Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Thu, 7 Dec 2023 11:03:53 +0100 Subject: [PATCH 20/91] ccmp1: add support to sign different DDR3 configurations for U-Boot DTB This commit implements the support to sign the different memory configurations for the CCMP1 platforms, when trustfence is enabled, using FIT images. https://onedigi.atlassian.net/browse/DEL-8752 Signed-off-by: Arturo Buzarra --- .../recipes-bsp/u-boot/u-boot-dey.inc | 22 +- .../recipes-bsp/u-boot/u-boot-dey_2021.10.bb | 26 +- .../0001-tools-add-fdt_add_pubkey.patch | 233 ++++++++++++++++++ ...plicit-fallthrough-in-fdt_add_pubkey.patch | 48 ++++ .../u-boot/u-boot-tools_%.bbappend | 21 ++ .../recipes-kernel/linux/linux-dey_5.15.bb | 43 +++- 6 files changed, 374 insertions(+), 19 deletions(-) create mode 100644 meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0001-tools-add-fdt_add_pubkey.patch create mode 100644 meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0002-tools-avoid-implicit-fallthrough-in-fdt_add_pubkey.patch create mode 100644 meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 82e760feb..0fd2d0f55 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -251,15 +251,17 @@ do_deploy:append:ccmp1() { install -m 0777 ${B}/${config}/u-boot-nodtb.bin ${DEPLOYDIR}/${BOOT_TOOLS}/u-boot-nodtb.bin # Append signature to u-boot DT - if [ "x${UBOOT_SIGN_ENABLE}" = "x1" ] ; then - # get name of u-boot devicetree without signature - ubootdevicetree=`ls -1 ${DEPLOYDIR}/${BOOT_TOOLS}/*.dtb | head -n 1` - namewithoutsignature=`echo $ubootdevicetree | sed "s/\.dtb/-without-signature.dtb/g"` - namewithsignature=`echo $ubootdevicetree | sed "s/\.dtb/-with-signature.dtb/g"` - mv $ubootdevicetree $namewithoutsignature - # get name of U-Boot device tree from DEPLOY_DIR - nameonkernel="${DEPLOY_DIR_IMAGE}/u-boot-${MACHINE}*.dtb" - cp $nameonkernel $namewithsignature - cp $nameonkernel $ubootdevicetree + if [ "x${UBOOT_SIGN_ENABLE}" = "x1" ] && [ -n "${UBOOT_DEVICETREE}" ] ; then + for devicetree in ${UBOOT_DEVICETREE}; do + # get name of u-boot devicetree without signature + ubootdevicetree="${DEPLOYDIR}/${BOOT_TOOLS}/${FIP_UBOOT_DTB}-${devicetree}.dtb" + namewithoutsignature=`echo $ubootdevicetree | sed "s/\.dtb/-without-signature.dtb/g"` + namewithsignature=`echo $ubootdevicetree | sed "s/\.dtb/-with-signature.dtb/g"` + mv $ubootdevicetree $namewithoutsignature + # get name of U-Boot device tree from DEPLOY_DIR + nameonkernel="${DEPLOY_DIR_IMAGE}/${FIP_UBOOT_DTB}-${devicetree}-with-signature.dtb" + cp $nameonkernel $namewithsignature + cp $nameonkernel $ubootdevicetree + done fi } diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb index 8f0dca3e6..1d0e04099 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb @@ -1,4 +1,4 @@ -# Copyright (C) 2022,2023 Digi International +# Copyright (C) 2022-2024 Digi International require u-boot-dey.inc LIC_FILES_CHKSUM = "file://Licenses/README;md5=5a7450c57ffe5ae63fd732446b988025" @@ -17,22 +17,32 @@ UBOOT_FIT_CFG_FRAGMENTS = " \ SRC_URI += " \ ${@oe.utils.conditional('TRUSTFENCE_SIGN', '1', '${UBOOT_FIT_CFG_FRAGMENTS}', '', d)} \ " -# Install UBOOT_ENV_BINARY to datadir, so that kernel can use it -# to include it into the FIT image. -install_helper_bootscr() { + +install_helper_files() { + # Install UBOOT_ENV_BINARY to datadir, so that kernel can use it + # to include it into the FIT image. if [ -f "${D}/boot/${UBOOT_ENV_BINARY}" ]; then - # Install UBOOT_ENV_BINARY into datadir to share it with the kernel install -Dm 0644 ${D}/boot/${UBOOT_ENV_BINARY} ${D}${datadir}/${UBOOT_ENV_IMAGE} ln -sf ${UBOOT_ENV_IMAGE} ${D}${datadir}/${UBOOT_ENV_BINARY} else bbwarn "${D}/boot/${UBOOT_ENV_BINARY} not found" fi + + # Install dtbs from UBOOT_DEVICETREE to datadir, so that kernel + # can use it for signing, and kernel will deploy after signs it. + if [ -n "${UBOOT_DEVICETREE}" ]; then + for devicetree in ${UBOOT_DEVICETREE}; do + install -Dm 0644 ${B}/${config}/arch/arm/dts/${devicetree}.dtb ${D}${datadir}/${devicetree}.dtb + done + else + bbwarn "${UBOOT_DEVICETREE} not found" + fi } do_install:append() { - # Copy boot script, so kernel can include it when creating the FIT image - if [ "${TRUSTFENCE_FIT_IMG}" = "1" ] && [ -n "${UBOOT_ENV_BINARY}" ]; then - install_helper_bootscr + # Copy additional files, so kernel can use it when creating the FIT image + if [ "${TRUSTFENCE_FIT_IMG}" = "1" ]; then + install_helper_files fi } diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0001-tools-add-fdt_add_pubkey.patch b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0001-tools-add-fdt_add_pubkey.patch new file mode 100644 index 000000000..911bf3dc1 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0001-tools-add-fdt_add_pubkey.patch @@ -0,0 +1,233 @@ +From: Roman Kopytin +Date: Wed, 8 Mar 2023 01:13:41 +0000 +Subject: [PATCH] tools: add fdt_add_pubkey + +Having to use the -K option to mkimage to populate U-Boot's .dtb with the +public key while signing the kernel FIT image is often a little +awkward. In particular, when using a meta-build system such as +bitbake/Yocto, having the tasks of the kernel and U-Boot recipes +intertwined, modifying deployed artifacts and rebuilding U-Boot with +an updated .dtb is quite cumbersome. Also, in some scenarios one may +wish to build U-Boot complete with the public key(s) embedded in the +.dtb without the corresponding private keys being present on the same +build host. + +So this adds a simple tool that allows one to disentangle the kernel +and U-Boot builds, by simply copy-pasting just enough of the mkimage +code to allow one to add a public key to a .dtb. When using mkimage, +some of the information is taken from the .its used to build the +kernel (algorithm and key name), so that of course needs to be +supplied on the command line. + +Signed-off-by: Roman Kopytin +Signed-off-by: Ivan Mikhaylov +Signed-off-by: Jan Kiszka +Cc: Rasmus Villemoes + +--- + tools/.gitignore | 1 + + tools/Makefile | 3 + + tools/fdt_add_pubkey.c | 138 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 142 insertions(+) + create mode 100644 tools/fdt_add_pubkey.c + +diff --git a/tools/.gitignore b/tools/.gitignore +index a88453f64d..f312b760e4 100644 +--- a/tools/.gitignore ++++ b/tools/.gitignore +@@ -4,10 +4,11 @@ + /bmp_logo + /common/ + /dumpimage + /easylogo/easylogo + /envcrc ++/fdt_add_pubkey + /fdtgrep + /file2include + /fit_check_sign + /fit_info + /gdb/gdbcont +diff --git a/tools/Makefile b/tools/Makefile +index 1763f44cac..ce7a49ff61 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -71,10 +71,11 @@ HOSTCFLAGS_xway-swap-bytes.o := -pedantic + hostprogs-y += mkenvimage + mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o + + hostprogs-y += dumpimage mkimage + hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fit_info fit_check_sign ++hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fdt_add_pubkey + + hostprogs-$(CONFIG_CMD_BOOTEFI_SELFTEST) += file2include + + FIT_OBJS-y := fit_common.o fit_image.o image-host.o boot/image-fit.o + FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o boot/image-fit-sig.o +@@ -152,10 +153,11 @@ dumpimage-mkimage-objs := aisimage.o \ + + dumpimage-objs := $(dumpimage-mkimage-objs) dumpimage.o + mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o + fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o + fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o ++fdt_add_pubkey-objs := $(dumpimage-mkimage-objs) fdt_add_pubkey.o + file2include-objs := file2include.o + + ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),) + # Add CONFIG_MXS into host CFLAGS, so we can check whether or not register + # the mxsimage support within tools/mxsimage.c . +@@ -189,10 +191,11 @@ endif + HOSTCFLAGS_fit_image.o += -DMKIMAGE_DTC=\"$(CONFIG_MKIMAGE_DTC_PATH)\" + + HOSTLDLIBS_dumpimage := $(HOSTLDLIBS_mkimage) + HOSTLDLIBS_fit_info := $(HOSTLDLIBS_mkimage) + HOSTLDLIBS_fit_check_sign := $(HOSTLDLIBS_mkimage) ++HOSTLDLIBS_fdt_add_pubkey := $(HOSTLDLIBS_mkimage) + + hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl + hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl + HOSTCFLAGS_mkexynosspl.o := -pedantic + +diff --git a/tools/fdt_add_pubkey.c b/tools/fdt_add_pubkey.c +new file mode 100644 +index 0000000000..999f5a7e83 +--- /dev/null ++++ b/tools/fdt_add_pubkey.c +@@ -0,0 +1,138 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++#include ++#include "fit_common.h" ++ ++static const char *cmdname; ++ ++static const char *algo_name = "sha1,rsa2048"; /* -a */ ++static const char *keydir = "."; /* -k */ ++static const char *keyname = "key"; /* -n */ ++static const char *require_keys; /* -r */ ++static const char *keydest; /* argv[n] */ ++ ++static void print_usage(const char *msg) ++{ ++ fprintf(stderr, "Error: %s\n", msg); ++ fprintf(stderr, "Usage: %s [-a ] [-k ] [-n ] [-r ]" ++ " \n", cmdname); ++ fprintf(stderr, "Help information: %s [-h]\n", cmdname); ++ exit(EXIT_FAILURE); ++} ++ ++static void print_help(void) ++{ ++ fprintf(stderr, "Options:\n" ++ "\t-a Cryptographic algorithm. Optional parameter, default value: sha1,rsa2048\n" ++ "\t-k Directory with public key. Optional parameter, default value: .\n" ++ "\t-n Public key name. Optional parameter, default value: key\n" ++ "\t-r Required: If present this indicates that the key must be verified for the image / configuration to be considered valid.\n" ++ "\t FDT blob file for adding of the public key. Required parameter.\n"); ++ exit(EXIT_FAILURE); ++} ++ ++static void process_args(int argc, char *argv[]) ++{ ++ int opt; ++ ++ while ((opt = getopt(argc, argv, "a:k:n:r:h")) != -1) { ++ switch (opt) { ++ case 'k': ++ keydir = optarg; ++ break; ++ case 'a': ++ algo_name = optarg; ++ break; ++ case 'n': ++ keyname = optarg; ++ break; ++ case 'r': ++ require_keys = optarg; ++ break; ++ case 'h': ++ print_help(); ++ default: ++ print_usage("Invalid option"); ++ } ++ } ++ /* The last parameter is expected to be the .dtb to add the public key to */ ++ if (optind < argc) ++ keydest = argv[optind]; ++ ++ if (!keydest) ++ print_usage("Missing dtb file to update"); ++} ++ ++static void reset_info(struct image_sign_info *info) ++{ ++ if (!info) ++ fprintf(stderr, "Error: info is NULL in %s\n", __func__); ++ ++ memset(info, 0, sizeof(struct image_sign_info)); ++ ++ info->keydir = keydir; ++ info->keyname = keyname; ++ info->name = algo_name; ++ info->require_keys = require_keys; ++ info->crypto = image_get_crypto_algo(algo_name); ++ ++ if (!info->crypto) { ++ fprintf(stderr, "Unsupported signature algorithm '%s'\n", ++ algo_name); ++ exit(EXIT_FAILURE); ++ } ++} ++ ++static int add_pubkey(struct image_sign_info *info) ++{ ++ int destfd = -1, ret; ++ void *dest_blob = NULL; ++ struct stat dest_sbuf; ++ size_t size_inc = 0; ++ ++ if (!info) ++ fprintf(stderr, "Error: info is NULL in %s\n", __func__); ++ ++ do { ++ if (destfd >= 0) { ++ munmap(dest_blob, dest_sbuf.st_size); ++ close(destfd); ++ ++ fprintf(stderr, ".dtb too small, increasing size by 1024 bytes\n"); ++ size_inc = 1024; ++ } ++ ++ destfd = mmap_fdt(cmdname, keydest, size_inc, &dest_blob, ++ &dest_sbuf, false, false); ++ if (destfd < 0) ++ exit(EXIT_FAILURE); ++ ++ ret = info->crypto->add_verify_data(info, dest_blob); ++ if (ret == -ENOSPC) ++ continue; ++ else if (ret < 0) ++ break; ++ } while (ret == -ENOSPC); ++ ++ return ret; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ struct image_sign_info info; ++ int ret; ++ ++ cmdname = argv[0]; ++ ++ process_args(argc, argv); ++ reset_info(&info); ++ ret = add_pubkey(&info); ++ ++ if (ret < 0) { ++ fprintf(stderr, "%s: Cannot add public key to FIT blob: %s\n", ++ cmdname, strerror(ret)); ++ exit(EXIT_FAILURE); ++ } ++ ++ exit(EXIT_SUCCESS); ++} ++ diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0002-tools-avoid-implicit-fallthrough-in-fdt_add_pubkey.patch b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0002-tools-avoid-implicit-fallthrough-in-fdt_add_pubkey.patch new file mode 100644 index 000000000..55e5be235 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools/0002-tools-avoid-implicit-fallthrough-in-fdt_add_pubkey.patch @@ -0,0 +1,48 @@ +From: Heinrich Schuchardt +Date: Sat, 1 Apr 2023 08:09:34 +0200 +Subject: [PATCH] tools: avoid implicit fallthrough in fdt_add_pubkey + +When building with -Wimplicit-fallthrough we get a warning + + tools/fdt_add_pubkey.c:52:25: warning: + this statement may fall through [-Wimplicit-fallthrough=] + 52 | print_help(); + | + +Explicitly declare which functions don't return. + +Fixes: 30238e99619c ("tools: add fdt_add_pubkey") +Signed-off-by: Heinrich Schuchardt +Reviewed-by: Simon Glass + +--- + tools/fdt_add_pubkey.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/fdt_add_pubkey.c b/tools/fdt_add_pubkey.c +index 999f5a7e83..5582d7a8ef 100644 +--- a/tools/fdt_add_pubkey.c ++++ b/tools/fdt_add_pubkey.c +@@ -8,20 +8,20 @@ static const char *algo_name = "sha1,rsa2048"; /* -a */ + static const char *keydir = "."; /* -k */ + static const char *keyname = "key"; /* -n */ + static const char *require_keys; /* -r */ + static const char *keydest; /* argv[n] */ + +-static void print_usage(const char *msg) ++static void __attribute__((__noreturn__)) print_usage(const char *msg) + { + fprintf(stderr, "Error: %s\n", msg); + fprintf(stderr, "Usage: %s [-a ] [-k ] [-n ] [-r ]" + " \n", cmdname); + fprintf(stderr, "Help information: %s [-h]\n", cmdname); + exit(EXIT_FAILURE); + } + +-static void print_help(void) ++static void __attribute__((__noreturn__)) print_help(void) + { + fprintf(stderr, "Options:\n" + "\t-a Cryptographic algorithm. Optional parameter, default value: sha1,rsa2048\n" + "\t-k Directory with public key. Optional parameter, default value: .\n" + "\t-n Public key name. Optional parameter, default value: key\n" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend new file mode 100644 index 000000000..18505972c --- /dev/null +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend @@ -0,0 +1,21 @@ +# Copyright (C) 2024 Digi International + +FILESEXTRAPATHS:prepend := "${THISDIR}/${BPN}:" + +# Backport from v2023.07 +SRC_URI:append = " \ + file://0001-tools-add-fdt_add_pubkey.patch \ + file://0002-tools-avoid-implicit-fallthrough-in-fdt_add_pubkey.patch \ +" + +do_install:append () { + install -d ${D}${bindir} + + # fdt_add_pubkey + if [ -f tools/fdt_add_pubkey ]; then + install -m 0755 tools/fdt_add_pubkey ${D}${bindir}/uboot-fdt_add_pubkey + ln -sf uboot-fdt_add_pubkey ${D}${bindir}/fdt_add_pubkey + fi +} + +FILES:${PN}-mkimage += "${bindir}/uboot-fdt_add_pubkey" diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb index 1f6141a39..e219c7709 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb @@ -1,4 +1,4 @@ -# Copyright (C) 2022,2023 Digi International +# Copyright (C) 2022-2024 Digi International require recipes-kernel/linux/linux-dey.inc @@ -13,4 +13,45 @@ do_assemble_fitimage:prepend:ccmp1() { install -m 0644 ${RECIPE_SYSROOT}/${datadir}/${UBOOT_ENV_BINARY} ${STAGING_DIR_HOST}/boot/ } +do_assemble_fitimage:append:ccmp1() { + # + # Step 9: Add public keys to the different U-Boot dtb files + # + if [ "${UBOOT_SIGN_ENABLE}" = "1" ] && [ -n "${UBOOT_DEVICETREE}" ]; then + for devicetree in ${UBOOT_DEVICETREE}; do + if [ -f "${STAGING_DATADIR}/${devicetree}.dtb" ]; then + cp -P "${STAGING_DATADIR}/${devicetree}.dtb" ${B} + + # Add image public key in U-Boot dtb file + fdt_add_pubkey -a "${FIT_HASH_ALG},${FIT_SIGN_ALG}" \ + -k "${UBOOT_SIGN_KEYDIR}" \ + -n "${UBOOT_SIGN_IMG_KEYNAME}" \ + -r "image" \ + "${B}/${devicetree}.dtb" + + # Add configuration public key in U-Boot dtb file + fdt_add_pubkey -a "${FIT_HASH_ALG},${FIT_SIGN_ALG}" \ + -k "${UBOOT_SIGN_KEYDIR}" \ + -n "${UBOOT_SIGN_KEYNAME}" \ + -r "conf" \ + "${B}/${devicetree}.dtb" + fi + done + fi +} + +kernel_do_deploy:append:ccmp1() { + if [ "${UBOOT_SIGN_ENABLE}" = "1" -o "${UBOOT_FITIMAGE_ENABLE}" = "1" ] && \ + [ -n "${UBOOT_DTB_BINARY}" ] ; then + # Install device tree files with signature + if [ -n "${UBOOT_DEVICETREE}" ]; then + for devicetree in ${UBOOT_DEVICETREE}; do + if [ -f "${B}/${devicetree}.dtb" ]; then + install -m 0644 ${B}/${devicetree}.dtb "${DEPLOYDIR}/${FIP_UBOOT_DTB}-${devicetree}-with-signature.dtb" + fi + done + fi + fi +} + COMPATIBLE_MACHINE = "(ccimx6|ccimx6ul|ccimx8m|ccimx8x|ccmp1)" From ea35016831ee63580f599aeb588137c7d40f3f1e Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Tue, 20 Feb 2024 20:39:11 +0100 Subject: [PATCH 21/91] firmware-murata: install all FW files Not only install the US but all the FW files. Apart of that, some scripts need a little adjustement such as: * Modify the BT baudrate to 3Mbps for EU power configuration, as it is the baudrate used by the btnxpuart driver. * Replace the way to reset the interface on each hcitool command to avoid missleading BT behaviour. https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- .../firmware-murata-nxp/firmware-murata-nxp.bb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb b/meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb index f2898dbe3..c21a9a036 100644 --- a/meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb +++ b/meta-digi-arm/recipes-bsp/firmware-murata-nxp/firmware-murata-nxp.bb @@ -1,4 +1,4 @@ -# Copyright (C) 2023 Digi International. +# Copyright (C) 2023-2024, Digi International. SUMMARY = "Murata NXP firmware binaries" LICENSE = "GPL-2.0-only" @@ -15,9 +15,13 @@ do_compile[noexec] = "1" do_install () { install -d ${D}${nonarch_base_libdir}/firmware/nxp - install -m 0644 murata/files/2DL/txpower_US.bin ${D}${nonarch_base_libdir}/firmware/nxp - install -m 0644 murata/files/2DL/rutxpower_US.bin ${D}${nonarch_base_libdir}/firmware/nxp - install -m 0755 murata/files/2DL/bt_power_config_US_CA_JP.sh ${D}${nonarch_base_libdir}/firmware/nxp + install -m 0644 murata/files/2DL/* ${D}${nonarch_base_libdir}/firmware/nxp + # For the EU BT power file, set the baudrate to 3Mbps (as used by the btnxpuart driver) + sed -i -e "s,00 C2 01 00 00 00 00 00 00 00 00 00,C0 C6 2D 00 00 00 00 00 00 00 00 00,g" \ + ${D}${nonarch_base_libdir}/firmware/nxp/bt_power_config_EU.sh + # For all the BT power scripts, replace the hcitool reset command to avoid misleading BT behaviour. + sed -i -e "s,hcitool -i hci0 cmd 0x03 0x003,hciconfig hci0 reset,g" \ + ${D}${nonarch_base_libdir}/firmware/nxp/bt_power_config*.sh } FILES:${PN} = "${nonarch_base_libdir}/firmware" From 5588c30a7b513ae9463cfb69b1c97913c80a833e Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Wed, 21 Feb 2024 12:49:06 +0100 Subject: [PATCH 22/91] Revert "ccimx93: bluetooth-init: re-initilize the LE support after hci reset" This reverts commit c5b53c976507b17b13f8de5ebe4a99372d73f647. The HCI reset interface is fixed inside each BT power calibration shell script, so this workaround is not needed anymore. https://onedigi.atlassian.net/browse/DEL-8458 Signed-off-by: Isaac Hermida --- .../bluez/bluez5-init/ccimx93/bluetooth-init | 6 ------ 1 file changed, 6 deletions(-) diff --git a/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init b/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init index ac3469e05..7d4b630d9 100644 --- a/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init +++ b/meta-digi-dey/recipes-connectivity/bluez/bluez5-init/ccimx93/bluetooth-init @@ -42,12 +42,6 @@ set_btaddr() { set_power_config() { sh -e /lib/firmware/nxp/bt_power_config_US_CA_JP.sh - - # The bash script resets the HCI interface, and currenlty it breaks - # the LE support. Until it is fixed in the FW, workaround it by doing - # a SW power cycle of the stack. - btmgmt -i ${HCI_IFACE} power off - btmgmt -i ${HCI_IFACE} power on } is_kernel_module_loaded() { From 2a8403940d4417cbec21e90f631a8f2ec4aff565 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Thu, 22 Feb 2024 09:16:32 +0100 Subject: [PATCH 23/91] u-boot-tools: add the fdt_add_pubkey script to the list of files to be shipped This commit fixes a build issue when this script is installed but not shipped in the u-boot-tools package. Signed-off-by: Arturo Buzarra --- meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend index 18505972c..54948e247 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-tools_%.bbappend @@ -18,4 +18,7 @@ do_install:append () { fi } -FILES:${PN}-mkimage += "${bindir}/uboot-fdt_add_pubkey" +FILES:${PN}-mkimage += " \ + ${bindir}/uboot-fdt_add_pubkey \ + ${bindir}/fdt_add_pubkey \ +" From 6b5b341a3826dab946544f73b8379a19e03ce705 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Fri, 23 Feb 2024 13:21:10 +0100 Subject: [PATCH 24/91] psplash: fix bbappend for different distro than "dey" This commit fixes a build issue using meta-digi layer with a different distro than "dey". Also simplified the bbappend to avoid creating a custom do_patch_png() task before do_configure(). Reported-by: Stephan Klatt Signed-off-by: Arturo Buzarra --- .../recipes-core/psplash/psplash_git.bbappend | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meta-digi-dey/recipes-core/psplash/psplash_git.bbappend b/meta-digi-dey/recipes-core/psplash/psplash_git.bbappend index faec597c5..0adb42245 100644 --- a/meta-digi-dey/recipes-core/psplash/psplash_git.bbappend +++ b/meta-digi-dey/recipes-core/psplash/psplash_git.bbappend @@ -1,12 +1,12 @@ -# Copyright (C) 2016 Digi International +# Copyright (C) 2016-2024 Digi International Inc. FILESEXTRAPATHS:prepend:dey := "${THISDIR}/files:" -SRC_URI += " \ +SRC_URI:append:dey = " \ file://0001-colors-modify-psplash-colors-to-match-Digi-scheme.patch \ file://psplash-digi-bar.png \ " -do_patch_png () { - cp ${WORKDIR}/psplash-digi-bar.png ${S}/base-images/psplash-bar.png + +do_configure:prepend:dey() { + \cp --remove-destination ${WORKDIR}/psplash-digi-bar.png ${S}/base-images/psplash-bar.png } -addtask patch_png after do_patch before do_configure From 5457c89a9e88cff0905f948fb180bcbec4e05d7b Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Tue, 26 Dec 2023 17:34:42 +0100 Subject: [PATCH 25/91] Revert "dey.conf: continue using stable versions of swupdate and libubootenv" Prepare to support the latest versions of these packages This reverts commit a22d21ab843b35d398de5373f4f62c3252108ee6. https://onedigi.atlassian.net/browse/DEL-8885 Signed-off-by: Gabriel Valcazar --- meta-digi-dey/conf/distro/dey.conf | 7 ------- 1 file changed, 7 deletions(-) diff --git a/meta-digi-dey/conf/distro/dey.conf b/meta-digi-dey/conf/distro/dey.conf index 2b9d3f639..d83d6d05d 100644 --- a/meta-digi-dey/conf/distro/dey.conf +++ b/meta-digi-dey/conf/distro/dey.conf @@ -57,13 +57,6 @@ FEATURE_PACKAGES_dey-wireless = "packagegroup-dey-wireless" # 5.65 version should be used, which is provided by the poky layer. PREFERRED_VERSION_bluez5 ?= "5.65" -# The latest available versions of swupdate and libubootenv are 2023.12 and -# 0.3.5, respectively. However, our custom patches haven't been ported or -# tested for these versions yet, so until then, continue using the versions -# we've been using in DEY 4.0 (2023.05 and 0.3.2) to guarantee stability. -PREFERRED_VERSION_swupdate ?= "2023.05" -PREFERRED_VERSION_libubootenv ?= "0.3.2" - # There's a generic opencl-headers recipe in the thud branch of # meta-openembedded, but we should use the package provided by the imx-gpu-viv # recipe in case there are NXP-specific changes in it From 148b4974a4c8f29333d498a39d65fc94871b6302 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Tue, 26 Dec 2023 14:24:34 +0100 Subject: [PATCH 26/91] libubootenv: adapt patches to v0.3.5 https://onedigi.atlassian.net/browse/DEL-8885 Signed-off-by: Gabriel Valcazar --- ...t-for-environment-encryption-by-CAAM.patch | 32 +-- ...-U-Boot-environment-access-functions.patch | 10 +- ...pport-to-set-dynamic-location-of-env.patch | 18 +- ...d-HWID-from-nvmem-device-if-not-avai.patch | 8 +- ...t-for-environment-encryption-for-CCM.patch | 192 +++++++++--------- 5 files changed, 128 insertions(+), 132 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch index a2e25acf2..d08d3f4e4 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch @@ -28,10 +28,10 @@ Signed-off-by: Gabriel Valcazar create mode 100644 src/md5.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 4b71bc588827..d7e38a12feed 100644 +index ababe0f..fb1efa2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt -@@ -1,6 +1,8 @@ +@@ -4,6 +4,8 @@ cmake_minimum_required (VERSION 2.6) # Sources and private headers SET(libubootenv_SOURCES @@ -42,7 +42,7 @@ index 4b71bc588827..d7e38a12feed 100644 ) diff --git a/src/caam_keyblob.h b/src/caam_keyblob.h new file mode 100644 -index 000000000000..e313e87a3854 +index 0000000..e313e87 --- /dev/null +++ b/src/caam_keyblob.h @@ -0,0 +1,42 @@ @@ -90,7 +90,7 @@ index 000000000000..e313e87a3854 +#endif /* CAAM_KEYBLOB_H */ diff --git a/src/md5.c b/src/md5.c new file mode 100644 -index 000000000000..47ae8bf34a4d +index 0000000..47ae8bf --- /dev/null +++ b/src/md5.c @@ -0,0 +1,275 @@ @@ -371,7 +371,7 @@ index 000000000000..47ae8bf34a4d +} diff --git a/src/md5.h b/src/md5.h new file mode 100644 -index 000000000000..02a9a9d23e34 +index 0000000..02a9a9d --- /dev/null +++ b/src/md5.h @@ -0,0 +1,24 @@ @@ -400,13 +400,13 @@ index 000000000000..02a9a9d23e34 + +#endif /* _MD5_H */ diff --git a/src/uboot_env.c b/src/uboot_env.c -index 30c39ebf6fa9..2fd08f5a07db 100644 +index ae85c7e..750b736 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -33,11 +33,21 @@ - #include +@@ -34,11 +34,21 @@ #include #include + #include +#include #include #include @@ -425,8 +425,8 @@ index 30c39ebf6fa9..2fd08f5a07db 100644 #define UBI_MAX_VOLUME 128 #define DEVICE_MTD_NAME "/dev/mtd" -@@ -844,6 +854,105 @@ static int set_obsolete_flag(struct uboot_flash_env *dev) - return ret; +@@ -1028,6 +1038,105 @@ const struct uboot_version_info *libuboot_version_info(void) + return &libinfo; } +static int is_env_encrypted(void) @@ -531,7 +531,7 @@ index 30c39ebf6fa9..2fd08f5a07db 100644 int libuboot_env_store(struct uboot_ctx *ctx) { struct var_entry *entry; -@@ -919,6 +1028,15 @@ int libuboot_env_store(struct uboot_ctx *ctx) +@@ -1103,6 +1212,15 @@ int libuboot_env_store(struct uboot_ctx *ctx) ((struct uboot_env_redund *)image)->flags = flags; } @@ -547,7 +547,7 @@ index 30c39ebf6fa9..2fd08f5a07db 100644 *(uint32_t *)image = crc32(0, (uint8_t *)data, ctx->size - offsetdata); copy = ctx->redundant ? (ctx->current ? 0 : 1) : 0; -@@ -984,6 +1102,13 @@ static int libuboot_load(struct uboot_ctx *ctx) +@@ -1167,6 +1285,13 @@ static int libuboot_load(struct uboot_ctx *ctx) } crc = *(uint32_t *)(buf[i] + offsetcrc); dev->crc = crc32(0, (uint8_t *)data, usable_envsize); @@ -561,7 +561,7 @@ index 30c39ebf6fa9..2fd08f5a07db 100644 crcenv[i] = dev->crc == crc; if (ctx->redundant) dev->flags = *(uint8_t *)(buf[i] + offsetflags); -@@ -1264,6 +1389,11 @@ int libuboot_read_config(struct uboot_ctx *ctx, const char *config) +@@ -1773,6 +1898,11 @@ int libuboot_read_config_ext(struct uboot_ctx **ctxlist, const char *config) break; } } @@ -573,7 +573,7 @@ index 30c39ebf6fa9..2fd08f5a07db 100644 if (ndev == 0) retval = -EINVAL; -@@ -1461,6 +1591,7 @@ int libuboot_initialize(struct uboot_ctx **out, +@@ -2042,6 +2172,7 @@ int libuboot_initialize(struct uboot_ctx **out, return -ENOMEM; ctx->valid = false; @@ -582,10 +582,10 @@ index 30c39ebf6fa9..2fd08f5a07db 100644 if (ret < 0) { diff --git a/src/uboot_private.h b/src/uboot_private.h -index 4b7a9f9602a6..22c8c14ce8cc 100644 +index 40e5446..ee2d305 100644 --- a/src/uboot_private.h +++ b/src/uboot_private.h -@@ -111,10 +111,14 @@ LIST_HEAD(vars, var_entry); +@@ -114,10 +114,14 @@ LIST_HEAD(vars, var_entry); struct uboot_ctx { /** true if the environment is redundant */ bool redundant; diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch index 065db6515..d585a18ad 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch @@ -18,10 +18,10 @@ Signed-off-by: Gabriel Valcazar 2 files changed, 119 insertions(+) diff --git a/src/libuboot.h b/src/libuboot.h -index bfcaeb1d609f..b15969f89174 100644 +index 3ed3244..e83b3a5 100644 --- a/src/libuboot.h +++ b/src/libuboot.h -@@ -159,6 +159,29 @@ const char *libuboot_getname(void *entry); +@@ -201,6 +201,29 @@ const char *libuboot_getname(void *entry); */ const char *libuboot_getvalue(void *entry); @@ -52,11 +52,11 @@ index bfcaeb1d609f..b15969f89174 100644 } #endif diff --git a/src/uboot_env.c b/src/uboot_env.c -index 2fd08f5a07db..87f831b0cdc7 100644 +index 750b736..b7ad4c4 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -1632,3 +1632,99 @@ void libuboot_close(struct uboot_ctx *ctx) { - void libuboot_exit(struct uboot_ctx *ctx) { +@@ -2234,3 +2234,99 @@ void libuboot_exit(struct uboot_ctx *ctx) + free(ctx); } + diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch index f4e744757..5bf01172a 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch @@ -27,10 +27,10 @@ Signed-off-by: Gabriel Valcazar 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/uboot_env.c b/src/uboot_env.c -index 87f831b0cdc7..539e22f9a8ac 100644 +index b7ad4c4..924a6cf 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -431,6 +431,73 @@ static int check_env_device(struct uboot_ctx *ctx, struct uboot_flash_env *dev) +@@ -591,6 +591,73 @@ static int check_env_device(struct uboot_flash_env *dev) return 0; } @@ -104,9 +104,9 @@ index 87f831b0cdc7..539e22f9a8ac 100644 static bool check_compatible_devices(struct uboot_ctx *ctx) { if (!ctx->redundant) -@@ -442,6 +509,12 @@ static bool check_compatible_devices(struct uboot_ctx *ctx) +@@ -602,6 +669,12 @@ static bool check_compatible_devices(struct uboot_ctx *ctx) return false; - if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize) + if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize) return false; + if (ctx->envdevs[0].offset == ctx->envdevs[1].offset) { + ctx->dynamic_env = true; @@ -117,7 +117,7 @@ index 87f831b0cdc7..539e22f9a8ac 100644 return true; } -@@ -488,7 +561,7 @@ static int fileread(struct uboot_flash_env *dev, void *data) +@@ -648,7 +721,7 @@ static int fileread(struct uboot_flash_env *dev, void *data) return ret; } @@ -126,7 +126,7 @@ index 87f831b0cdc7..539e22f9a8ac 100644 { size_t count; size_t blocksize; -@@ -507,6 +580,17 @@ static int mtdread(struct uboot_flash_env *dev, void *data) +@@ -667,6 +740,17 @@ static int mtdread(struct uboot_flash_env *dev, void *data) ret = read(dev->fd, data, dev->envsize); break; case MTD_NANDFLASH: @@ -144,7 +144,7 @@ index 87f831b0cdc7..539e22f9a8ac 100644 if (dev->offset) if (lseek(dev->fd, dev->offset, SEEK_SET) < 0) { ret = -EIO; -@@ -582,7 +666,7 @@ static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data) +@@ -742,7 +826,7 @@ static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data) ret = fileread(dev, data); break; case DEVICE_MTD: @@ -154,10 +154,10 @@ index 87f831b0cdc7..539e22f9a8ac 100644 case DEVICE_UBI: ret = ubiread(dev, data); diff --git a/src/uboot_private.h b/src/uboot_private.h -index 22c8c14ce8cc..591df20d6936 100644 +index ee2d305..84bd1bc 100644 --- a/src/uboot_private.h +++ b/src/uboot_private.h -@@ -113,10 +113,14 @@ struct uboot_ctx { +@@ -116,10 +116,14 @@ struct uboot_ctx { bool redundant; /** true if the environment is encrypted */ bool encrypted; diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch index 08cb1ab43..0f369f5b7 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch @@ -21,10 +21,10 @@ https://onedigi.atlassian.net/browse/DEL-8444 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/uboot_env.c b/src/uboot_env.c -index 539e22f9a8ac..86f9b9ebfec2 100644 +index 924a6cf..d507cac 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -945,6 +945,32 @@ static int is_env_encrypted(void) +@@ -1129,6 +1129,32 @@ static int is_env_encrypted(void) return access(dt_prop, F_OK) != -1; } @@ -57,7 +57,7 @@ index 539e22f9a8ac..86f9b9ebfec2 100644 #define MAX_HWID_WORDS 4 static int env_caam_get_keymod(unsigned char output[16]) { -@@ -953,12 +979,11 @@ static int env_caam_get_keymod(unsigned char output[16]) +@@ -1137,12 +1163,11 @@ static int env_caam_get_keymod(unsigned char output[16]) int fd; uint32_t ocotp_hwid[MAX_HWID_WORDS]; char dt_prop[32]; @@ -71,7 +71,7 @@ index 539e22f9a8ac..86f9b9ebfec2 100644 fd = open(dt_prop, O_RDONLY); if (fd < 0) return fd; -@@ -969,6 +994,31 @@ static int env_caam_get_keymod(unsigned char output[16]) +@@ -1153,6 +1178,31 @@ static int env_caam_get_keymod(unsigned char output[16]) } ocotp_hwid[i] = ntohl(*(uint32_t *)buf); close(fd); diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch index 023cb1d8c..83c262155 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch @@ -1,4 +1,3 @@ -From 768cac09ee47729e3ef38b477c7a69e5b3d10c60 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Fri, 26 May 2023 11:21:43 +0200 Subject: [PATCH] Implement support for environment encryption for CCMP1 @@ -32,10 +31,10 @@ Signed-off-by: Mike Engel create mode 100644 src/teec_trace.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index d7e38a1..15dad7a 100644 +index fb1efa2..04353e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt -@@ -1,6 +1,10 @@ +@@ -4,6 +4,10 @@ cmake_minimum_required (VERSION 2.6) # Sources and private headers SET(libubootenv_SOURCES @@ -48,93 +47,93 @@ index d7e38a1..15dad7a 100644 uboot_env.c diff --git a/src/ta_ccmp1_aes.h b/src/ta_ccmp1_aes.h new file mode 100644 -index 0000000..9110cda +index 0000000..ceab07d --- /dev/null +++ b/src/ta_ccmp1_aes.h @@ -0,0 +1,84 @@ -+/* -+ * Copyright 2023 Digi International Inc -+ * -+ * SPDX-License-Identifier: GPL-2.0+ -+ */ -+ -+#ifndef __TA_CCMP1_AES_H__ -+#define __TA_CCMP1_AES_H__ -+ -+/* -+ * AES is a stream cipher which works a block at a time, with each block -+ * in this case being AES_BLOCK_LENGTH bytes. -+ */ -+ -+enum { -+ AES_STATECOLS = 4, /* columns in the state & expanded key */ -+ AES128_KEYCOLS = 4, /* columns in a key for aes128 */ -+ AES192_KEYCOLS = 6, /* columns in a key for aes128 */ -+ AES256_KEYCOLS = 8, /* columns in a key for aes128 */ -+ AES128_ROUNDS = 10, /* rounds in encryption for aes128 */ -+ AES192_ROUNDS = 12, /* rounds in encryption for aes192 */ -+ AES256_ROUNDS = 14, /* rounds in encryption for aes256 */ -+ AES128_KEY_LENGTH = 128 / 8, -+ AES192_KEY_LENGTH = 192 / 8, -+ AES256_KEY_LENGTH = 256 / 8, -+ AES128_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES128_ROUNDS + 1), -+ AES192_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES192_ROUNDS + 1), -+ AES256_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES256_ROUNDS + 1), -+ AES_BLOCK_LENGTH = 128 / 8, -+}; -+ -+struct aes_ctx { -+ TEEC_Context ctx; -+ TEEC_Session sess; -+}; -+ -+/* The function IDs implemented in the associated TA */ -+ -+/* -+ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering -+ * param[0] (value) Algorithmus -+ * param[1] (value) Key size -+ * param[2] (value) encryption mode (encrypt/decrypt) -+ * param[3] unused -+ */ -+#define TA_AES_CMD_PREPARE 0 -+ -+/* -+ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering -+ * param[0] (memref) key data, size shall equal key length -+ * param[1] unused -+ * param[2] unused -+ * param[3] unused -+ */ -+#define TA_AES_CMD_SET_KEY 1 -+ -+/* -+ * TA_AES_CMD_SET_IV - reset IV -+ * param[0] (memref) initial vector, size shall equal block length -+ * param[1] unused -+ * param[2] unused -+ * param[3] unused -+ */ -+#define TA_AES_CMD_SET_IV 2 -+ -+/* -+ * TA_AES_CMD_CIPHER - Cipher input buffer into output buffer -+ * param[0] (memref) input buffer -+ * param[1] (memref) output buffer (shall be bigger than input buffer) -+ * param[2] unused -+ * param[3] unused -+ */ -+#define TA_AES_CMD_CIPHER 3 -+ -+#define TA_AES_MODE_ENCODE 1 -+#define TA_AES_MODE_DECODE 0 -+ -+#define TA_AES_ALGO_CTR 2 -+ -+/* UUID of the TA */ -+#define TA_STM32MP_CRYP_UUID { 0xc2fad363, 0x5d9f, 0x4fc4, \ -+ { 0xa4, 0x17, 0x55, 0x58, 0x41, 0xe0, 0x57, 0x45 } } -+ ++/* ++ * Copyright 2023 Digi International Inc ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#ifndef __TA_CCMP1_AES_H__ ++#define __TA_CCMP1_AES_H__ ++ ++/* ++ * AES is a stream cipher which works a block at a time, with each block ++ * in this case being AES_BLOCK_LENGTH bytes. ++ */ ++ ++enum { ++ AES_STATECOLS = 4, /* columns in the state & expanded key */ ++ AES128_KEYCOLS = 4, /* columns in a key for aes128 */ ++ AES192_KEYCOLS = 6, /* columns in a key for aes128 */ ++ AES256_KEYCOLS = 8, /* columns in a key for aes128 */ ++ AES128_ROUNDS = 10, /* rounds in encryption for aes128 */ ++ AES192_ROUNDS = 12, /* rounds in encryption for aes192 */ ++ AES256_ROUNDS = 14, /* rounds in encryption for aes256 */ ++ AES128_KEY_LENGTH = 128 / 8, ++ AES192_KEY_LENGTH = 192 / 8, ++ AES256_KEY_LENGTH = 256 / 8, ++ AES128_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES128_ROUNDS + 1), ++ AES192_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES192_ROUNDS + 1), ++ AES256_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES256_ROUNDS + 1), ++ AES_BLOCK_LENGTH = 128 / 8, ++}; ++ ++struct aes_ctx { ++ TEEC_Context ctx; ++ TEEC_Session sess; ++}; ++ ++/* The function IDs implemented in the associated TA */ ++ ++/* ++ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering ++ * param[0] (value) Algorithmus ++ * param[1] (value) Key size ++ * param[2] (value) encryption mode (encrypt/decrypt) ++ * param[3] unused ++ */ ++#define TA_AES_CMD_PREPARE 0 ++ ++/* ++ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering ++ * param[0] (memref) key data, size shall equal key length ++ * param[1] unused ++ * param[2] unused ++ * param[3] unused ++ */ ++#define TA_AES_CMD_SET_KEY 1 ++ ++/* ++ * TA_AES_CMD_SET_IV - reset IV ++ * param[0] (memref) initial vector, size shall equal block length ++ * param[1] unused ++ * param[2] unused ++ * param[3] unused ++ */ ++#define TA_AES_CMD_SET_IV 2 ++ ++/* ++ * TA_AES_CMD_CIPHER - Cipher input buffer into output buffer ++ * param[0] (memref) input buffer ++ * param[1] (memref) output buffer (shall be bigger than input buffer) ++ * param[2] unused ++ * param[3] unused ++ */ ++#define TA_AES_CMD_CIPHER 3 ++ ++#define TA_AES_MODE_ENCODE 1 ++#define TA_AES_MODE_DECODE 0 ++ ++#define TA_AES_ALGO_CTR 2 ++ ++/* UUID of the TA */ ++#define TA_STM32MP_CRYP_UUID { 0xc2fad363, 0x5d9f, 0x4fc4, \ ++ { 0xa4, 0x17, 0x55, 0x58, 0x41, 0xe0, 0x57, 0x45 } } ++ +#endif /* __TA_CCMP1_AES_H__ */ \ No newline at end of file diff --git a/src/tee.h b/src/tee.h @@ -2576,10 +2575,10 @@ index 0000000..b1e37ec + +#endif diff --git a/src/uboot_env.c b/src/uboot_env.c -index 86f9b9e..45b356f 100644 +index d507cac..aa33930 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -41,6 +41,9 @@ +@@ -42,6 +42,9 @@ #include "md5.h" #include "uboot_private.h" @@ -2589,7 +2588,7 @@ index 86f9b9e..45b356f 100644 /* * The BLOB includes a random AES-256 key (32 bytes) and a * Message Authentication Code (MAC) (16 bytes) -@@ -972,7 +975,7 @@ static bool machine_is_compatible(char *machine) +@@ -1156,7 +1159,7 @@ static bool machine_is_compatible(char *machine) } #define MAX_HWID_WORDS 4 @@ -2598,7 +2597,7 @@ index 86f9b9e..45b356f 100644 { int i; int len; -@@ -1040,7 +1043,7 @@ static int env_caam_crypt(char *data, unsigned int size, const int enc) +@@ -1224,7 +1227,7 @@ static int env_caam_crypt(char *data, unsigned int size, const int enc) char *buffer; unsigned char key_modifier[16]; @@ -2607,7 +2606,7 @@ index 86f9b9e..45b356f 100644 if (ret) return ret; -@@ -1087,6 +1090,165 @@ free: +@@ -1271,6 +1274,165 @@ free: return ret; } @@ -2667,7 +2666,7 @@ index 86f9b9e..45b356f 100644 + TEEC_Result res; + + memset(&op, 0, sizeof(op)); -+ ++ + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, + TEEC_NONE, TEEC_NONE, TEEC_NONE); + @@ -2773,7 +2772,7 @@ index 86f9b9e..45b356f 100644 int libuboot_env_store(struct uboot_ctx *ctx) { struct var_entry *entry; -@@ -1163,7 +1325,12 @@ int libuboot_env_store(struct uboot_ctx *ctx) +@@ -1347,7 +1509,12 @@ int libuboot_env_store(struct uboot_ctx *ctx) } if (ctx->encrypted) { @@ -2787,7 +2786,7 @@ index 86f9b9e..45b356f 100644 if (ret) { fprintf(stderr, "Error: can't encrypt env for flash\n"); -@@ -1237,7 +1404,12 @@ static int libuboot_load(struct uboot_ctx *ctx) +@@ -1420,7 +1587,12 @@ static int libuboot_load(struct uboot_ctx *ctx) crc = *(uint32_t *)(buf[i] + offsetcrc); dev->crc = crc32(0, (uint8_t *)data, usable_envsize); if (ctx->encrypted) { @@ -2801,6 +2800,3 @@ index 86f9b9e..45b356f 100644 if (ret) { fprintf(stderr, "Error: can't decrypt environment\n"); return ret; --- -2.34.1 - From 8430114f4c4c17cbe619dbd430db535325783a3c Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Tue, 26 Dec 2023 13:33:04 +0100 Subject: [PATCH 27/91] swupdate: adapt patches to 2023.12.1 https://onedigi.atlassian.net/browse/DEL-8885 Signed-off-by: Gabriel Valcazar --- ...ange-Makefile-to-build-swupdate-library-s.patch | 6 +++--- ...d-on-the-fly-build-configuration-variable.patch | 8 ++++---- ...iff-handler-for-applying-librsync-s-rdiff.patch | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/0001-Makefile-change-Makefile-to-build-swupdate-library-s.patch b/meta-digi-dey/recipes-support/swupdate/swupdate/0001-Makefile-change-Makefile-to-build-swupdate-library-s.patch index dc7485828..66244556f 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate/0001-Makefile-change-Makefile-to-build-swupdate-library-s.patch +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/0001-Makefile-change-Makefile-to-build-swupdate-library-s.patch @@ -17,18 +17,18 @@ Signed-off-by: Mike Engel create mode 120000 ipc-static/progress_ipc.c diff --git a/Makefile b/Makefile -index 09d03a3..f34810b 100644 +index cdcab69..9065a40 100644 --- a/Makefile +++ b/Makefile @@ -364,6 +364,7 @@ include $(srctree)/Makefile.flags objs-y := core handlers bootloader suricatta - libs-y := corelib mongoose parser fs + libs-y := corelib mongoose parser fs containers +libs-y += ipc-static bindings-y := bindings tools-y := tools -@@ -480,6 +481,7 @@ install: all +@@ -479,6 +480,7 @@ install: all install -m 0644 $(srctree)/include/progress_ipc.h ${DESTDIR}/${INCLUDEDIR} install -m 0755 $(objtree)/${swupdate-ipc-lib} ${DESTDIR}/${LIBDIR} ln -sfr ${DESTDIR}/${LIBDIR}/${swupdate-ipc-lib} ${DESTDIR}/${LIBDIR}/libswupdate.so diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch b/meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch index 5370861f1..75805e89b 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch @@ -13,10 +13,10 @@ Signed-off-by: Mike Engel 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Kconfig b/Kconfig -index 85fa5fd71c4c..5ad2026c675c 100644 +index 5a3dc9a..17fa27c 100644 --- a/Kconfig +++ b/Kconfig -@@ -258,6 +258,13 @@ config FEATURE_SYSLOG +@@ -262,6 +262,13 @@ config FEATURE_SYSLOG # This option is auto-selected when you select any applet which may # send its output to syslog. You do not need to select it manually. @@ -31,10 +31,10 @@ index 85fa5fd71c4c..5ad2026c675c 100644 menu 'Build Options' diff --git a/core/network_thread.c b/core/network_thread.c -index 88042f1238cb..4bc100055e42 100644 +index ca23908..c539d27 100644 --- a/core/network_thread.c +++ b/core/network_thread.c -@@ -106,7 +106,9 @@ static bool is_selection_allowed(const char *software_set, char *running_mode, +@@ -102,7 +102,9 @@ static bool is_selection_allowed(const char *software_set, char *running_mode, } free(swset); } diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch b/meta-digi-dey/recipes-support/swupdate/swupdate/0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch index 8784f33ad..0a93088ee 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate/0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch @@ -19,10 +19,10 @@ Signed-off-by: David Escalona create mode 100644 handlers/ubivol_rdiff_handler.c diff --git a/Makefile.flags b/Makefile.flags -index 2a021c8..b542358 100644 +index 95c785c..5bdf520 100644 --- a/Makefile.flags +++ b/Makefile.flags -@@ -209,6 +209,10 @@ ifeq ($(CONFIG_RDIFFHANDLER),y) +@@ -202,6 +202,10 @@ ifeq ($(CONFIG_RDIFFHANDLER),y) LDLIBS += rsync endif @@ -34,10 +34,10 @@ index 2a021c8..b542358 100644 LDLIBS += zmq endif diff --git a/configs/all_handlers_defconfig b/configs/all_handlers_defconfig -index 8f6f8e0..9077220 100644 +index da4b28f..5da2d0d 100644 --- a/configs/all_handlers_defconfig +++ b/configs/all_handlers_defconfig -@@ -31,5 +31,6 @@ CONFIG_SHELLSCRIPTHANDLER=y +@@ -30,5 +30,6 @@ CONFIG_SHELLSCRIPTHANDLER=y CONFIG_SWUFORWARDER_HANDLER=y CONFIG_SSBLSWITCH=y CONFIG_UBIVOL=y @@ -45,10 +45,10 @@ index 8f6f8e0..9077220 100644 CONFIG_UCFWHANDLER=y CONFIG_UNIQUEUUID=y diff --git a/handlers/Config.in b/handlers/Config.in -index 107ffeb..62d54bd 100644 +index 9f4e177..129e972 100644 --- a/handlers/Config.in +++ b/handlers/Config.in -@@ -166,6 +166,19 @@ config RDIFFHANDLER +@@ -158,6 +158,19 @@ config RDIFFHANDLER comment "rdiff support needs librsync" depends on !HAVE_LIBRSYNC @@ -69,7 +69,7 @@ index 107ffeb..62d54bd 100644 bool "readback" depends on HASH_VERIFY diff --git a/handlers/Makefile b/handlers/Makefile -index b5203f9..bd47d3b 100644 +index eb24a49..e74dacb 100644 --- a/handlers/Makefile +++ b/handlers/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_CFIHAMMING1)+= flash_hamming1_handler.o From 6e220fa0793a2d96f5d114dfd81619599eb47980 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Mon, 26 Feb 2024 16:33:48 +0100 Subject: [PATCH 28/91] digi-sc-firmware: update to v1.15.0.1 This update fixes an initialization issue with devices without HWID programmed. https://onedigi.atlassian.net/browse/DUB-1066 Signed-off-by: Arturo Buzarra --- ...i-sc-firmware_1.15.0.bb => digi-sc-firmware_1.15.0.1.bb} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename meta-digi-arm/recipes-bsp/digi-sc-firmware/{digi-sc-firmware_1.15.0.bb => digi-sc-firmware_1.15.0.1.bb} (84%) diff --git a/meta-digi-arm/recipes-bsp/digi-sc-firmware/digi-sc-firmware_1.15.0.bb b/meta-digi-arm/recipes-bsp/digi-sc-firmware/digi-sc-firmware_1.15.0.1.bb similarity index 84% rename from meta-digi-arm/recipes-bsp/digi-sc-firmware/digi-sc-firmware_1.15.0.bb rename to meta-digi-arm/recipes-bsp/digi-sc-firmware/digi-sc-firmware_1.15.0.1.bb index b1b3055e8..243bbd112 100644 --- a/meta-digi-arm/recipes-bsp/digi-sc-firmware/digi-sc-firmware_1.15.0.bb +++ b/meta-digi-arm/recipes-bsp/digi-sc-firmware/digi-sc-firmware_1.15.0.1.bb @@ -1,6 +1,6 @@ # Copyright (C) 2016 Freescale Semiconductor # Copyright 2017-2018 NXP -# Copyright (C) 2018-2023 Digi International. +# Copyright (C) 2018-2024 Digi International. DESCRIPTION = "i.MX System Controller Firmware, customized for Digi platforms" LICENSE = "Proprietary" @@ -11,8 +11,8 @@ inherit pkgconfig deploy SRC_URI = "${DIGI_PKG_SRC}/${BPN}-${PV}.tar.gz" -SRC_URI[md5sum] = "d7d74493bb04ff73341481a9fbc551eb" -SRC_URI[sha256sum] = "aa4acd333bb8fc137854d276d12961a9bdf29064a94bcf4d3c76761d79afaca9" +SRC_URI[md5sum] = "b7b9b5598b9ffc3a0f1663b41992aac0" +SRC_URI[sha256sum] = "59ebc2ebbf75c0b96f4fb70f8209f796543c5932e58f09031b9df99f110edcc9" S = "${WORKDIR}/${PN}-${PV}" From b2d9d33cf950a6323052cdd45b0bf1dd0b6f5bf7 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Tue, 27 Feb 2024 10:40:43 +0100 Subject: [PATCH 29/91] swupdate: reduce default log level in runtime config file The current log level is very verbose and generates way too much output in some cases, such as a binary diff update. Reduce the default log level to avoid this. Signed-off-by: Gabriel Valcazar --- .../recipes-support/swupdate/swupdate/swupdate.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/swupdate.config b/meta-digi-dey/recipes-support/swupdate/swupdate/swupdate.config index 6b754a834..ffb382788 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate/swupdate.config +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/swupdate.config @@ -9,8 +9,8 @@ # globals : { - verbose = true; - loglevel = 5; + verbose = false; + loglevel = 3; syslog = true; #mtd-blacklist #public-key-file From 948e55bde969d8f815370adf8c348db443ee34e3 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Tue, 27 Feb 2024 11:28:56 +0100 Subject: [PATCH 30/91] swupdate: replace on-the-fly patch with a clearer, equivalent one The patch we were using comes from the time during dualboot support development where said feature was selectable at build time. The patch adds a new build option, giving the impression that it only gets enabled under certain circumstances, when in reality: * The option is never enabled anywhere in our code * It's a string option that is treated like a boolean, meaning its respective conditional compilation is always getting compiled even when disabled Our current dualboot support is enabled at runtime, so it doesn't make sense to have a build-time option related to it, especially one that's broken. Replace the patch with a functionally equivalent one that is less confusing. Also, remove the related config option from our defconfig. Signed-off-by: Gabriel Valcazar --- ...the-fly-build-configuration-variable.patch | 47 ------------------- ...etwork_thread-always-allow-selection.patch | 27 +++++++++++ .../swupdate/swupdate/defconfig | 1 - .../swupdate/swupdate_%.bbappend | 4 +- 4 files changed, 29 insertions(+), 50 deletions(-) delete mode 100644 meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch create mode 100644 meta-digi-dey/recipes-support/swupdate/swupdate/0002-network_thread-always-allow-selection.patch diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch b/meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch deleted file mode 100644 index 75805e89b..000000000 --- a/meta-digi-dey/recipes-support/swupdate/swupdate/0002-config-add-on-the-fly-build-configuration-variable.patch +++ /dev/null @@ -1,47 +0,0 @@ -From: Mike Engel -Date: Wed, 23 Jun 2021 15:11:12 +0200 -Subject: [PATCH] config: add on the fly build configuration variable - -This commit adds on the fly configuration to the swupdate -build system to correct an issue when using sw-description -files that support different images and installation locations. - -Signed-off-by: Mike Engel ---- - Kconfig | 7 +++++++ - core/network_thread.c | 4 +++- - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/Kconfig b/Kconfig -index 5a3dc9a..17fa27c 100644 ---- a/Kconfig -+++ b/Kconfig -@@ -262,6 +262,13 @@ config FEATURE_SYSLOG - # This option is auto-selected when you select any applet which may - # send its output to syslog. You do not need to select it manually. - -+config DIGI_ON_THE_FLY -+ string "Add Digi on the fly support" -+ default n -+ #help -+ # This option is used in on the fly support to skip selection -+ # verification. -+ - endmenu - - menu 'Build Options' -diff --git a/core/network_thread.c b/core/network_thread.c -index ca23908..c539d27 100644 ---- a/core/network_thread.c -+++ b/core/network_thread.c -@@ -102,7 +102,9 @@ static bool is_selection_allowed(const char *software_set, char *running_mode, - } - free(swset); - } -- -+#ifdef CONFIG_DIGI_ON_THE_FLY -+ allowed = true; -+#endif - if (allowed) { - INFO("Accepted selection %s,%s", software_set, running_mode); - }else diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/0002-network_thread-always-allow-selection.patch b/meta-digi-dey/recipes-support/swupdate/swupdate/0002-network_thread-always-allow-selection.patch new file mode 100644 index 000000000..0cb91e49a --- /dev/null +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/0002-network_thread-always-allow-selection.patch @@ -0,0 +1,27 @@ +From: Mike Engel +Date: Wed, 23 Jun 2021 15:11:12 +0200 +Subject: [PATCH] network_thread: always allow selection + +This is needed for on-the-fly updates to avoid errors when using sw-description +files with multiple image/installation sets. Make sure to keep returning +"false" in case of an OOM error. + +Signed-off-by: Mike Engel +Signed-off-by: Gabriel Valcazar +--- + core/network_thread.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/core/network_thread.c b/core/network_thread.c +index ca23908d..b0767ab2 100644 +--- a/core/network_thread.c ++++ b/core/network_thread.c +@@ -80,7 +80,7 @@ static bool is_selection_allowed(const char *software_set, char *running_mode, + char *swset = NULL; + struct dict_list *sets; + struct dict_list_elem *selection; +- bool allowed = false; ++ bool allowed = true; + + /* + * No attempt to change software set diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate/defconfig b/meta-digi-dey/recipes-support/swupdate/swupdate/defconfig index 464fe703f..7c980d1de 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate/defconfig +++ b/meta-digi-dey/recipes-support/swupdate/swupdate/defconfig @@ -27,7 +27,6 @@ CONFIG_SOCKET_PROGRESS_PATH="" # CONFIG_MTD is not set # CONFIG_LUA is not set # CONFIG_FEATURE_SYSLOG is not set -CONFIG_DIGI_ON_THE_FLY="n" # # Build Options diff --git a/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend b/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend index 2e3b33e6c..26cbd2c2c 100644 --- a/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend +++ b/meta-digi-dey/recipes-support/swupdate/swupdate_%.bbappend @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2023 Digi International Inc. +# Copyright (C) 2016-2024 Digi International Inc. FILESEXTRAPATHS:prepend := "${THISDIR}/${BPN}:" @@ -7,7 +7,7 @@ RDEPENDS:${PN} += "libgcc" SRC_URI += " \ file://0001-Makefile-change-Makefile-to-build-swupdate-library-s.patch \ - file://0002-config-add-on-the-fly-build-configuration-variable.patch \ + file://0002-network_thread-always-allow-selection.patch \ file://0003-handlers-rdiff-handler-for-applying-librsync-s-rdiff.patch \ ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'file://systemd.cfg', '', d)} \ ${@bb.utils.contains('STORAGE_MEDIA', 'mtd', 'file://mtd.cfg', '', d)} \ From c66be227f6e65620923a2f439a388dddbdd2ea02 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Tue, 20 Feb 2024 15:21:31 +0100 Subject: [PATCH 31/91] u-boot-dey: fix generation of uuu script when Trustfence is enabled. Signed-off-by: Mike Engel --- .../recipes-bsp/u-boot/u-boot-dey.inc | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 0fd2d0f55..0ecbccb2f 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -82,24 +82,22 @@ build_uboot_scripts() { -e 's,##DEFAULT_IMAGE_NAME##,${DEFAULT_IMAGE_NAME},g' \ ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} # Change the u-boot name when TrustFence is enabled - if [ "${TRUSTFENCE_SIGN}" == "1" ]; then - if [ "${DEY_SOC_VENDOR}" == "NXP" ]; then + if [ "${TRUSTFENCE_SIGN}" = "1" ]; then + if [ "${DEY_SOC_VENDOR}" = "NXP" ]; then if [ "${TRUSTFENCE_DEK_PATH}" != "0" ]; then - sed -e 's,##SIGNED##,-encrypted,g' \ - ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + sed -i -e 's,##SIGNED##,-encrypted,g' ${TMP_INSTALL_SCR} else - sed -e 's,##SIGNED##,-signed,g' \ - ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + sed -i -e 's,##SIGNED##,-signed,g' ${TMP_INSTALL_SCR} fi else - sed -e 's,##SIGNED##,_Signed,g' \ - ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} - sed -e 's,##SIGNED_TFA##,_signed,g' \ - ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + sed -i -e 's,##SIGNED##,_Signed,g' ${TMP_INSTALL_SCR} + sed -i -e 's,##SIGNED_TFA##,_signed,g' ${TMP_INSTALL_SCR} fi else - sed -e 's,##SIGNED##,,g' \ - ${WORKDIR}/${f} > ${TMP_INSTALL_SCR} + sed -i -e 's,##SIGNED##,,g' ${TMP_INSTALL_SCR} + if [ "${DEY_SOC_VENDOR}" = "STM" ]; then + sed -i -e 's,##SIGNED_TFA##,,g' ${TMP_INSTALL_SCR} + fi fi if [ "${f_ext}" = "txt" ]; then mkimage -T script -n "DEY firmware install script" -C none -d ${TMP_INSTALL_SCR} ${DEPLOYDIR}/${f%.*}.scr From 9f9d016f5d7994e54010ac15343a3f0dbcdd8d09 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Fri, 23 Feb 2024 11:04:31 +0100 Subject: [PATCH 32/91] ccmp1: fix the TFA naming with Trustfence enabled. Signed-off-by: Mike Engel --- .../recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh index 91d3a989a..969b1b054 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh @@ -126,7 +126,7 @@ echo "Determining image files to use..." # Determine ATF file to program if [ -z "${INSTALL_ATF_FILENAME}" ]; then - INSTALL_ATF_FILENAME="tf-a-##MACHINE##-${module_ram}-nand##SIGNED_TFA##.stm32" + INSTALL_ATF_FILENAME="tf-a-##MACHINE##-${module_ram}-nand.stm32##SIGNED_TFA##" fi # Determine FIP file to program From c5c9838e54847624886198d4c6665566a4f3e979 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Thu, 29 Feb 2024 11:08:03 +0100 Subject: [PATCH 33/91] packagegroup-imx-ml: imx93: only install tensorflow-lite Not installing all the ML packages but just tensorflow-lite saves space. We are not including onnxruntime and torchvision, which are not supported by the i.mx93 (see NXP user guide for details). The ext4.gz size is decreased from 430MB to 217MB. Signed-off-by: Isaac Hermida --- .../recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend b/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend index b9b63a1e7..e187c97cb 100644 --- a/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend +++ b/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend @@ -2,7 +2,8 @@ ML_NNSTREAMER_PKGS_LIST:remove = "nnstreamer-deepview-rt" -ML_PKGS:mx9-nxp-bsp:remove = "deepview-rt-examples" +# Only install tensorflow-lite to save space +ML_PKGS:mx9-nxp-bsp:mx93-nxp-bsp = "tensorflow-lite" # ARM ethos-u package ETHOS_U_PKGS:append:mx93-nxp-bsp = " \ From e915a14b4b1e457620b2aad8aa821d4b06b7da4a Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Tue, 27 Feb 2024 16:59:56 +0100 Subject: [PATCH 34/91] u-boot-dey: add /boot directory to the recipe sysroot Other recipes may access SYSROOT_DIRS content by adding a dependence on do_populate_sysroot. We need this specific directory for the kernel fitImage support. Signed-off-by: Javier Viguera --- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 0ecbccb2f..6d39f2e6e 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -263,3 +263,5 @@ do_deploy:append:ccmp1() { done fi } + +SYSROOT_DIRS += "/boot" From 3eed042d80aac1786220691d357afabf3c022253 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Tue, 27 Feb 2024 17:00:26 +0100 Subject: [PATCH 35/91] image_types_digi: restrict boot image artifacts using KERNEL_IMAGETYPE When we use a fitImage kernel type, all the boot artifacts are inside the FIT image, so there is no need to add them to the boot image additionally. We were using TRUSTFENCE_FIT_IMG to do this filtering, which uses a fitImage kernel type underneath. This commit uses KERNEL_IMAGETYPE instead, as this way, we can use kernel FIT images out of Trustfence and still prevent polluting the boot images with not-needed artifacts. Signed-off-by: Javier Viguera --- meta-digi-arm/classes/image_types_digi.bbclass | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/meta-digi-arm/classes/image_types_digi.bbclass b/meta-digi-arm/classes/image_types_digi.bbclass index db641ac69..0b677fe44 100644 --- a/meta-digi-arm/classes/image_types_digi.bbclass +++ b/meta-digi-arm/classes/image_types_digi.bbclass @@ -22,7 +22,7 @@ IMAGE_CMD:boot.vfat() { BOOTIMG_FILES="$(readlink -e ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${MACHINE}.bin)" BOOTIMG_FILES_SYMLINK="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${MACHINE}.bin" # Exclude DTB and DTBO from VFAT image when creating a FIT image - if [ "${TRUSTFENCE_FIT_IMG}" != "1" ]; then + if [ "${KERNEL_IMAGETYPE}" != "fitImage" ]; then if [ -n "${KERNEL_DEVICETREE}" ]; then for DTB in ${KERNEL_DEVICETREE}; do # Remove potential sub-folders @@ -61,7 +61,7 @@ IMAGE_CMD:boot.vfat() { mcopy -i ${IMGDEPLOYDIR}/${IMAGE_NAME}.boot.vfat ${BOOTIMG_FILES_SYMLINK} ::/ # Exclude boot scripts from VFAT image when creating a FIT image - if [ "${TRUSTFENCE_FIT_IMG}" != "1" ]; then + if [ "${KERNEL_IMAGETYPE}" != "fitImage" ]; then # Copy boot scripts into the VFAT image for item in ${BOOT_SCRIPTS}; do src=`echo $item | awk -F':' '{ print $1 }'` @@ -90,7 +90,7 @@ do_image_boot_ubifs[depends] += " \ IMAGE_CMD:boot.ubifs() { BOOTIMG_FILES_SYMLINK="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${MACHINE}.bin" # Exclude DTB and DTBO from UBIFS image when creating a FIT image - if [ "${TRUSTFENCE_FIT_IMG}" != "1" ]; then + if [ "${KERNEL_IMAGETYPE}" != "fitImage" ]; then if [ -n "${KERNEL_DEVICETREE}" ]; then for DTB in ${KERNEL_DEVICETREE}; do # Remove potential sub-folders @@ -117,7 +117,7 @@ IMAGE_CMD:boot.ubifs() { done # Exclude boot scripts from UBIFS image when creating a FIT image - if [ "${TRUSTFENCE_FIT_IMG}" != "1" ]; then + if [ "${KERNEL_IMAGETYPE}" != "fitImage" ]; then # Hard-link boot scripts into the temporary folder for item in ${BOOT_SCRIPTS}; do src="$(echo ${item} | awk -F':' '{ print $1 }')" @@ -148,7 +148,7 @@ IMAGE_CMD:recovery.vfat() { cp --remove-destination ${IMGDEPLOYDIR}/${IMAGE_NAME}.boot.vfat ${IMGDEPLOYDIR}/${IMAGE_NAME}.recovery.vfat # Exclude initRAMFS from VFAT image when creating a FIT image - if [ "${TRUSTFENCE_FIT_IMG}" != "1" ]; then + if [ "${KERNEL_IMAGETYPE}" != "fitImage" ]; then # Copy the recovery initramfs into the VFAT image mcopy -i ${IMGDEPLOYDIR}/${IMAGE_NAME}.recovery.vfat -s ${DEPLOY_DIR_IMAGE}/${RECOVERY_INITRAMFS_IMAGE}-${MACHINE}.cpio.gz.u-boot.tf ::/uramdisk-recovery.img fi @@ -169,7 +169,7 @@ do_image_recovery_ubifs[depends] += " \ IMAGE_CMD:recovery.ubifs() { RECOVERYIMG_FILES_SYMLINK="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${MACHINE}.bin" # Exclude DTB and DTBO from VFAT image when creating a FIT image - if [ "${TRUSTFENCE_FIT_IMG}" != "1" ]; then + if [ "${KERNEL_IMAGETYPE}" != "fitImage" ]; then if [ -n "${KERNEL_DEVICETREE}" ]; then for DTB in ${KERNEL_DEVICETREE}; do # Remove potential sub-folders @@ -191,7 +191,7 @@ IMAGE_CMD:recovery.ubifs() { done # Exclude bootscript from VFAT image when creating a FIT image - if [ "${TRUSTFENCE_FIT_IMG}" != "1" ]; then + if [ "${KERNEL_IMAGETYPE}" != "fitImage" ]; then # Hard-link boot scripts into the temporary folder for item in ${BOOT_SCRIPTS}; do src="$(echo ${item} | awk -F':' '{ print $1 }')" From be04b21ecd3fb71ddbaa19b66075f703fe6fb5ae Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Tue, 27 Feb 2024 17:00:56 +0100 Subject: [PATCH 36/91] ccimx93: add support to build FIT images Signed-off-by: Javier Viguera --- meta-digi-arm/conf/machine/include/ccimx93.inc | 7 +++++++ .../recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/meta-digi-arm/conf/machine/include/ccimx93.inc b/meta-digi-arm/conf/machine/include/ccimx93.inc index 4360a96ee..768ff8ce1 100644 --- a/meta-digi-arm/conf/machine/include/ccimx93.inc +++ b/meta-digi-arm/conf/machine/include/ccimx93.inc @@ -8,9 +8,16 @@ require conf/machine/include/imx-digi-base.inc require conf/machine/include/arm/armv8-2a/tune-cortexa55.inc # Platform u-boot settings +UBOOT_DTB_LOADADDRESS = "0x83000000" +UBOOT_DTBO_LOADADDRESS = "0x83000000" +UBOOT_ENTRYPOINT = "0x80400000" +UBOOT_ENV = "boot" UBOOT_PREFIX = "imx-boot" UBOOT_SUFFIX = "bin" +# Platform kernel settings +KERNEL_CLASSES = "kernel-fitimage" + # The bootloader image that gets flashed consists of U-Boot and several fw binaries EXTRA_IMAGEDEPENDS += "imx-boot" BOOTLOADER_IMAGE_RECIPE = "imx-boot" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt index 60f89ef0e..0dc69b973 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt @@ -84,6 +84,10 @@ if test "${module_has_npu}" = "1" && test -z "${disable_npu}"; then setenv overlays _ov_som_npu_ccimx93.dtbo,${overlays} fi +if test "${dboot_kernel_var}" = "fitimage"; then + # Set temp var to avoid re-loading fitimage + setenv temp-fitimg-loaded yes +fi dboot linux mmc ${mmcbootdev}:${mmcpart} # From d013c4c0b1174f2a00d12a26d4d8533664ba6f5d Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Tue, 27 Feb 2024 09:24:18 +0100 Subject: [PATCH 37/91] linux-virtualization: expand docker config extract expand the docker defconfig excerpt to add more default options, as some of them might be enable in some platform defconfigs but not in other ones, so just set all of them, as it is safe, and nothing happens if they are already set in the original default defconfig. To check if all LXC/docker options are enabled for a kernel, run lxc-checkconfig in the system. https://onedigi.atlassian.net/browse/DEL-8924 Signed-off-by: Isaac Hermida --- meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg b/meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg index 345ef04e1..60ab5875a 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/docker_conf.cfg @@ -48,3 +48,8 @@ CONFIG_BRIDGE_NETFILTER=m CONFIG_BRIDGE=m CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_CHECKPOINT_RESTORE=y +CONFIG_PACKET_DIAG=m +CONFIG_UNIX_DIAG=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETLINK_DIAG=m +CONFIG_MACVLAN=y From 190e7a8df16a219365ac56adb5b362c9225c0147 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Mon, 11 Mar 2024 14:51:58 +0100 Subject: [PATCH 38/91] build.sh: change name of class used for CVE scan depending on layers used Our CVE layer now includes a new bbclass that extends the logic of the "vigiles" bbclass. Use this new class if we are building images with the CVE layer. https://onedigi.atlassian.net/browse/DEL-8939 Signed-off-by: Gabriel Valcazar --- sdk/build.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/build.sh b/sdk/build.sh index 649ecfa99..d6c0fc3aa 100755 --- a/sdk/build.sh +++ b/sdk/build.sh @@ -51,7 +51,7 @@ unset do_vigiles_check[noexec] VIGILES_KEY_FILE = \"${DY_VIGILES_DIR}/linuxlink_key.json\" VIGILES_DASHBOARD_CONFIG = \"##VIGILES_CONF_PATH##\" VIGILES_SUBFOLDER_NAME = \"${DY_REVISION}\" -INHERIT += \"vigiles\" +INHERIT += \"##VIGILES_BBCLASS##\" " ZIP_INSTALLER_CFG=" @@ -285,11 +285,12 @@ for platform in ${DY_PLATFORMS}; do if [ "${DY_CVE_REPORT}" = "true" ]; then # Build Vigiles config path using platform and patch status status="non-patched" - [ "${DY_USE_CVE_LAYER}" = "true" ] && status="patched" + bbclass="vigiles" + [ "${DY_USE_CVE_LAYER}" = "true" ] && { status="patched"; bbclass="digi_ccss"; } VIGILES_CONF_PATH="${DY_VIGILES_DIR}/configs/${platform}_${status}_config" # Return error if config file doesn't exist [ ! -f "${VIGILES_CONF_PATH}" ] && error "Cannot find Vigiles config file ${VIGILES_CONF_PATH}" - printf "%s" "${VIGILES_CFG}" | sed -e "s,##VIGILES_CONF_PATH##,${VIGILES_CONF_PATH},g" >> conf/local.conf + printf "%s" "${VIGILES_CFG}" | sed -e "s,##VIGILES_CONF_PATH##,${VIGILES_CONF_PATH},g" -e "s,##VIGILES_BBCLASS##,${bbclass},g" >> conf/local.conf fi # Apply CVE layer if needed [ "${DY_USE_CVE_LAYER}" = "true" ] && bitbake-layers add-layer ${YOCTO_INST_DIR}/sources/meta-digi-security From 8ce2fddc7f5a9abe3cc9a718e9398b54197b0efa Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Mon, 11 Mar 2024 18:28:08 +0100 Subject: [PATCH 39/91] build.sh: fix error when applying CVE layer In our previous commit, we changed the CVE scan class from "vigiles" to "digi_ccss" if we plan on building images with the CVE layer. However, we make this change in conf/local.conf and then run "bitbake-layers add-layer" to add said layer. Since the bbclass is exclusive to the CVE layer, bitbake isn't able to recognize it and fails. Add the CVE layer to the project before adding the Vigiles configuration template to conf/local.conf. Signed-off-by: Gabriel Valcazar --- sdk/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/build.sh b/sdk/build.sh index d6c0fc3aa..5bb1e5455 100755 --- a/sdk/build.sh +++ b/sdk/build.sh @@ -281,6 +281,8 @@ for platform in ${DY_PLATFORMS}; do if [ "${DY_MFG_IMAGE}" = "true" ] && ! grep -qs "meta-digi-mfg" conf/bblayers.conf; then sed -i -e "/meta-digi-dey/a\ ${YOCTO_INST_DIR}/sources/meta-digi-mfg \\\\" conf/bblayers.conf fi + # Apply CVE layer if needed (do so before potentially inheriting "digi_ccss" to avoid errors) + [ "${DY_USE_CVE_LAYER}" = "true" ] && bitbake-layers add-layer ${YOCTO_INST_DIR}/sources/meta-digi-security # If we want to generate a CVE report, update conf/local.conf if [ "${DY_CVE_REPORT}" = "true" ]; then # Build Vigiles config path using platform and patch status @@ -292,8 +294,6 @@ for platform in ${DY_PLATFORMS}; do [ ! -f "${VIGILES_CONF_PATH}" ] && error "Cannot find Vigiles config file ${VIGILES_CONF_PATH}" printf "%s" "${VIGILES_CFG}" | sed -e "s,##VIGILES_CONF_PATH##,${VIGILES_CONF_PATH},g" -e "s,##VIGILES_BBCLASS##,${bbclass},g" >> conf/local.conf fi - # Apply CVE layer if needed - [ "${DY_USE_CVE_LAYER}" = "true" ] && bitbake-layers add-layer ${YOCTO_INST_DIR}/sources/meta-digi-security printf "\n[INFO] Show customized local.conf.\n" cat conf/local.conf From d8454cecc7cf9e42a6a8922fbeede1ffe7ac9ecd Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Fri, 8 Mar 2024 15:08:07 +0100 Subject: [PATCH 40/91] trustfence-sign-artifact: create a table for platform-specific data It is a cosmetic change, as there is no change in functionality, but convert the if..elif..fi structure to a table with the platform-specific data, so it's easier to maintain and extend. https://onedigi.atlassian.net/browse/DEL-8704 Signed-off-by: Javier Viguera --- .../trustfence-sign-artifact-nxp.sh | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh index 0f22934f2..60671a57c 100755 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh @@ -3,7 +3,7 @@ # # trustfence-sign-artifact.sh # -# Copyright (C) 2016-2022 by Digi International Inc. +# Copyright (C) 2016-2024 by Digi International Inc. # All rights reserved. # # This program is free software; you can redistribute it and/or modify it @@ -80,36 +80,36 @@ if [ -z "${CONFIG_SIGN_KEYS_PATH}" ]; then fi [ -d "${CONFIG_SIGN_KEYS_PATH}" ] || mkdir "${CONFIG_SIGN_KEYS_PATH}" -# Get RAM_START address -if [ "${PLATFORM}" = "ccimx6" ] || [ "${PLATFORM}" = "ccimx6qp" ]; then - CONFIG_FDT_LOADADDR="0x18000000" - CONFIG_RAMDISK_LOADADDR="0x19000000" - CONFIG_KERNEL_LOADADDR="0x12000000" - CONFIG_CSF_SIZE="0x4000" - CONFIG_SIGN_MODE="HAB" -elif [ "${PLATFORM}" = "ccimx6ul" ]; then - CONFIG_FDT_LOADADDR="0x83000000" - CONFIG_RAMDISK_LOADADDR="0x83800000" - CONFIG_KERNEL_LOADADDR="0x80800000" - CONFIG_CSF_SIZE="0x4000" - CONFIG_SIGN_MODE="HAB" -elif [ "${PLATFORM}" = "ccimx8x" ]; then - CONFIG_FDT_LOADADDR="0x82000000" - CONFIG_RAMDISK_LOADADDR="0x82100000" - CONFIG_KERNEL_LOADADDR="0x80280000" - CONFIG_SIGN_MODE="AHAB" -elif [ "${PLATFORM}" = "ccimx8mn" ] || [ "${PLATFORM}" = "ccimx8mm" ]; then - CONFIG_FDT_LOADADDR="0x43000000" - CONFIG_RAMDISK_LOADADDR="0x43800000" - CONFIG_KERNEL_LOADADDR="0x40480000" - CONFIG_CSF_SIZE="0x2000" - CONFIG_SIGN_MODE="HAB" -else +while read -r pl kaddr raddr fdtaddr fitaddr mode csf; do + AVAILABLE_PLATFORMS="${AVAILABLE_PLATFORMS:+${AVAILABLE_PLATFORMS} }${pl}" + eval "${pl}_kernel_addr=\"${kaddr}\"" + eval "${pl}_ramdisk_addr=\"${raddr}\"" + eval "${pl}_fdt_addr=\"${fdtaddr}\"" + eval "${pl}_fit_addr=\"${fitaddr}\"" + eval "${pl}_mode=\"${mode}\"" + eval "${pl}_csf_size=\"${csf}\"" +done<<-_EOF_ + ccimx6 0x12000000 0x19000000 0x18000000 - HAB 0x4000 + ccimx6qp 0x12000000 0x19000000 0x18000000 - HAB 0x4000 + ccimx6ul 0x80800000 0x83800000 0x83000000 - HAB 0x4000 + ccimx8mm 0x40480000 0x43800000 0x43000000 - HAB 0x2000 + ccimx8mn 0x40480000 0x43800000 0x43000000 - HAB 0x2000 + ccimx8x 0x80280000 0x82100000 0x82000000 - AHAB - +_EOF_ + +if ! echo "${AVAILABLE_PLATFORMS}" | grep -qs -F -w "${PLATFORM}"; then echo "Invalid platform: ${PLATFORM}" - echo "Supported platforms: ccimx6, ccimx6ul, ccimx8x, ccimx8mn, ccimx8mm" + echo "Supported platforms: ${AVAILABLE_PLATFORMS}" exit 1 fi +eval "CONFIG_KERNEL_LOADADDR=\"\${${PLATFORM}_kernel_addr}\"" +eval "CONFIG_RAMDISK_LOADADDR=\"\${${PLATFORM}_ramdisk_addr}\"" +eval "CONFIG_FDT_LOADADDR=\"\${${PLATFORM}_fdt_addr}\"" +eval "CONFIG_FIT_LOADADDR=\"\${${PLATFORM}_fit_addr}\"" +eval "CONFIG_SIGN_MODE=\"\${${PLATFORM}_mode}\"" +eval "CONFIG_CSF_SIZE=\"\${${PLATFORM}_csf_size}\"" + [ "${ARTIFACT_DTB}" = "y" ] && CONFIG_RAM_START="${CONFIG_FDT_LOADADDR}" [ "${ARTIFACT_INITRAMFS}" = "y" ] && CONFIG_RAM_START="${CONFIG_RAMDISK_LOADADDR}" [ "${ARTIFACT_KERNEL}" = "y" ] && CONFIG_RAM_START="${CONFIG_KERNEL_LOADADDR}" From 765fa48acce8dce8e670351af594ae5f17f6d3fc Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Fri, 8 Mar 2024 15:08:37 +0100 Subject: [PATCH 41/91] trustfence-sign-artifact: move srktool parameters to the platform data With the introduction of the ccimx93 support in the following commits, the srktool parameters not only differ for HAB/AHAB devices but also between devices using AHAB (for example, different parameters for ccimx8x and ccimx93). Thus, move this information to the platform-specific data table. https://onedigi.atlassian.net/browse/DEL-8704 Signed-off-by: Javier Viguera --- .../trustfence-sign-artifact-nxp.sh | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh index 60671a57c..bb5f6a03c 100755 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh @@ -80,7 +80,7 @@ if [ -z "${CONFIG_SIGN_KEYS_PATH}" ]; then fi [ -d "${CONFIG_SIGN_KEYS_PATH}" ] || mkdir "${CONFIG_SIGN_KEYS_PATH}" -while read -r pl kaddr raddr fdtaddr fitaddr mode csf; do +while read -r pl kaddr raddr fdtaddr fitaddr mode csf srk; do AVAILABLE_PLATFORMS="${AVAILABLE_PLATFORMS:+${AVAILABLE_PLATFORMS} }${pl}" eval "${pl}_kernel_addr=\"${kaddr}\"" eval "${pl}_ramdisk_addr=\"${raddr}\"" @@ -88,13 +88,14 @@ while read -r pl kaddr raddr fdtaddr fitaddr mode csf; do eval "${pl}_fit_addr=\"${fitaddr}\"" eval "${pl}_mode=\"${mode}\"" eval "${pl}_csf_size=\"${csf}\"" + eval "${pl}_srk_params=${srk}" done<<-_EOF_ - ccimx6 0x12000000 0x19000000 0x18000000 - HAB 0x4000 - ccimx6qp 0x12000000 0x19000000 0x18000000 - HAB 0x4000 - ccimx6ul 0x80800000 0x83800000 0x83000000 - HAB 0x4000 - ccimx8mm 0x40480000 0x43800000 0x43000000 - HAB 0x2000 - ccimx8mn 0x40480000 0x43800000 0x43000000 - HAB 0x2000 - ccimx8x 0x80280000 0x82100000 0x82000000 - AHAB - + ccimx6 0x12000000 0x19000000 0x18000000 - HAB 0x4000 "-h 4 -d sha256" + ccimx6qp 0x12000000 0x19000000 0x18000000 - HAB 0x4000 "-h 4 -d sha256" + ccimx6ul 0x80800000 0x83800000 0x83000000 - HAB 0x4000 "-h 4 -d sha256" + ccimx8mm 0x40480000 0x43800000 0x43000000 - HAB 0x2000 "-h 4 -d sha256" + ccimx8mn 0x40480000 0x43800000 0x43000000 - HAB 0x2000 "-h 4 -d sha256" + ccimx8x 0x80280000 0x82100000 0x82000000 - AHAB - "-a -d sha512 -s sha512" _EOF_ if ! echo "${AVAILABLE_PLATFORMS}" | grep -qs -F -w "${PLATFORM}"; then @@ -224,10 +225,6 @@ get_image_size() SRK_TABLE="$(pwd)/SRK_table.bin" if [ "${CONFIG_SIGN_MODE}" = "HAB" ]; then - HAB_VER="hab_ver 4" - DIGEST="digest" - DIGEST_ALGO="sha256" - # Other constants GAP_FILLER="0x00" @@ -302,10 +299,6 @@ elif [ "${CONFIG_SIGN_MODE}" = "AHAB" ]; then KERNEL_START_OFFSET="0x0" KERNEL_SIG_BLOCK_OFFSET="0x90" - HAB_VER="ahab" - DIGEST="sign_digest" - DIGEST_ALGO="sha512" - # Prepare the image container mkimage_imx8 -soc "QX" -rev "B0" -c -ap ${UIMAGE_PATH} a35 ${CONFIG_RAM_START} -out temp-mkimg KERNEL_NAME="$(readlink -e temp-mkimg)" @@ -338,8 +331,8 @@ elif [ "${CONFIG_SIGN_MODE}" = "AHAB" ]; then fi fi -# Generate SRK tables -srktool --${HAB_VER} --certs "${SRK_KEYS}" --table "${SRK_TABLE}" --efuses /dev/null --${DIGEST} "${DIGEST_ALGO}" +eval "PDATA_SRKTOOL=\"\${${PLATFORM}_srk_params}\"" +srktool ${PDATA_SRKTOOL} --certs "${SRK_KEYS}" --table "${SRK_TABLE}" --efuses /dev/null if [ $? -ne 0 ]; then echo "[ERROR] Could not generate SRK tables" exit 1 From 15211c3133a1c1e35119430a28b14672a78e3a00 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Fri, 8 Mar 2024 15:09:07 +0100 Subject: [PATCH 42/91] trustfence-sign-artifact: implement support for ccimx93 https://onedigi.atlassian.net/browse/DEL-8704 Signed-off-by: Javier Viguera --- .../trustfence-sign-artifact-nxp.sh | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh index bb5f6a03c..4a6e222e9 100755 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh @@ -90,12 +90,13 @@ while read -r pl kaddr raddr fdtaddr fitaddr mode csf srk; do eval "${pl}_csf_size=\"${csf}\"" eval "${pl}_srk_params=${srk}" done<<-_EOF_ - ccimx6 0x12000000 0x19000000 0x18000000 - HAB 0x4000 "-h 4 -d sha256" - ccimx6qp 0x12000000 0x19000000 0x18000000 - HAB 0x4000 "-h 4 -d sha256" - ccimx6ul 0x80800000 0x83800000 0x83000000 - HAB 0x4000 "-h 4 -d sha256" - ccimx8mm 0x40480000 0x43800000 0x43000000 - HAB 0x2000 "-h 4 -d sha256" - ccimx8mn 0x40480000 0x43800000 0x43000000 - HAB 0x2000 "-h 4 -d sha256" - ccimx8x 0x80280000 0x82100000 0x82000000 - AHAB - "-a -d sha512 -s sha512" + ccimx6 0x12000000 0x19000000 0x18000000 - HAB 0x4000 "-h 4 -d sha256" + ccimx6qp 0x12000000 0x19000000 0x18000000 - HAB 0x4000 "-h 4 -d sha256" + ccimx6ul 0x80800000 0x83800000 0x83000000 - HAB 0x4000 "-h 4 -d sha256" + ccimx8mm 0x40480000 0x43800000 0x43000000 - HAB 0x2000 "-h 4 -d sha256" + ccimx8mn 0x40480000 0x43800000 0x43000000 - HAB 0x2000 "-h 4 -d sha256" + ccimx8x 0x80280000 0x82100000 0x82000000 - AHAB - "-a -d sha512 -s sha512" + ccimx93 - - - 0x84000000 AHAB - "-a -d sha256 -s sha512" _EOF_ if ! echo "${AVAILABLE_PLATFORMS}" | grep -qs -F -w "${PLATFORM}"; then @@ -121,6 +122,9 @@ eval "CONFIG_CSF_SIZE=\"\${${PLATFORM}_csf_size}\"" # Rootfs is loaded to $initrd_addr, just like the ramdisk [ "${ARTIFACT_ROOTFS}" = "y" ] && CONFIG_RAM_START="${CONFIG_RAMDISK_LOADADDR}" +# For ccimx93 do not require image type (assume FIT image) +[ "${PLATFORM}" = "ccimx93" ] && CONFIG_RAM_START="${CONFIG_FIT_LOADADDR}" + if [ -z "${CONFIG_RAM_START}" ]; then echo "Specify the type of image to process (-b, -i, -d, -l, -r, or -o)" exit 1 @@ -300,7 +304,12 @@ elif [ "${CONFIG_SIGN_MODE}" = "AHAB" ]; then KERNEL_SIG_BLOCK_OFFSET="0x90" # Prepare the image container - mkimage_imx8 -soc "QX" -rev "B0" -c -ap ${UIMAGE_PATH} a35 ${CONFIG_RAM_START} -out temp-mkimg + if [ "${PLATFORM}" = "ccimx93" ]; then + # Only FIT image supported for CC93 + mkimage_imx8 -soc IMX9 -c -ap ${UIMAGE_PATH} a55 ${CONFIG_FIT_LOADADDR} -out temp-mkimg + else + mkimage_imx8 -soc "QX" -rev "B0" -c -ap ${UIMAGE_PATH} a35 ${CONFIG_RAM_START} -out temp-mkimg + fi KERNEL_NAME="$(readlink -e temp-mkimg)" # Compute the layout: sizes and offsets. From f67d59d7b8e8fbf0cf646def9075d528cb452ca2 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Fri, 8 Mar 2024 15:09:37 +0100 Subject: [PATCH 43/91] meta-digi: support SRK revocation mask when signing boot artifacts The script to sign the boot artifacts lacked the support to configure the revocation mask. The at-the-moment supported platforms did not need it, but the ccimx93 does need it, so implement it in this commit. https://onedigi.atlassian.net/browse/DEL-8704 Signed-off-by: Javier Viguera --- .../trustfence/trustfence-sign-tools/encrypt_ahab | 2 +- .../trustfence/trustfence-sign-tools/sign_ahab | 2 +- .../trustfence-sign-artifact-nxp.sh | 13 +++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/encrypt_ahab b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/encrypt_ahab index f7df7b86c..8705ff5b4 100644 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/encrypt_ahab +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/encrypt_ahab @@ -14,7 +14,7 @@ # Type of SRK set (NXP or OEM) Source set = OEM # bitmask of the revoked SRKs - Revocations = 0x0 + Revocations = %srk_rvk_mask% [Authenticate Data] # Binary to be signed generated by mkimage diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/sign_ahab b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/sign_ahab index 0d43a64b3..c25212976 100644 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/sign_ahab +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/sign_ahab @@ -14,7 +14,7 @@ # Type of SRK set (NXP or OEM) Source set = OEM # bitmask of the revoked SRKs - Revocations = 0x0 + Revocations = %srk_rvk_mask% [Authenticate Data] # Binary to be signed generated by mkimage diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh index 4a6e222e9..3413d0121 100755 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-sign-artifact-nxp.sh @@ -17,6 +17,7 @@ # The following environment variables define the script behaviour: # CONFIG_SIGN_KEYS_PATH: (mandatory) path to the CST folder by NXP with keys generated. # CONFIG_KEY_INDEX: (optional) key index to use for signing. Default is 0. +# SRK_REVOKE_MASK: (optional) bitmask of the revoked SRKs. # CONFIG_DEK_PATH: (optional) Path to keyfile. Define it to generate # encrypted images # @@ -63,6 +64,10 @@ Supported platforms: ccimx6, ccimx6qp, ccimx6ul, ccimx8x, ccimx8mn, ccimx8mm EOF } +to_hex() { + printf '0x%x' "${1}" +} + if [ "${#}" != "2" ]; then usage exit 1 @@ -157,6 +162,12 @@ if [ "${CONFIG_SIGN_MODE}" = "HAB" ]; then DEK_BLOB_OFFSET="0x100" fi +[ -z "${SRK_REVOKE_MASK}" ] && SRK_REVOKE_MASK="0x0" +if [ "$((SRK_REVOKE_MASK & 0x8))" != 0 ]; then + echo "Key 3 cannot be revoked. Removed from mask." + SRK_REVOKE_MASK="$((SRK_REVOKE_MASK - 8))" +fi + # Function to generate a PKI tree (with lock dir protection) GENPKI_LOCK_DIR="${CONFIG_SIGN_KEYS_PATH}/.genpki.lock" gen_pki_tree() { @@ -324,6 +335,7 @@ elif [ "${CONFIG_SIGN_MODE}" = "AHAB" ]; then -e "s,%cert_img%,${SRK_CERT_KEY_IMG},g" \ -e "s,%kernel-img%,${KERNEL_NAME},g" \ -e "s,%key_index%,${CONFIG_KEY_INDEX},g" \ + -e "s,%srk_rvk_mask%,$(to_hex "${SRK_REVOKE_MASK}"),g" \ -e "s,%container_offset%,${container_header_offset},g" \ -e "s,%block_offset%,${signature_block_offset},g" \ -e "s,%dek_path%,${CONFIG_DEK_PATH},g" \ @@ -334,6 +346,7 @@ elif [ "${CONFIG_SIGN_MODE}" = "AHAB" ]; then -e "s,%cert_img%,${SRK_CERT_KEY_IMG},g" \ -e "s,%kernel-img%,${KERNEL_NAME},g" \ -e "s,%key_index%,${CONFIG_KEY_INDEX},g" \ + -e "s,%srk_rvk_mask%,$(to_hex "${SRK_REVOKE_MASK}"),g" \ -e "s,%container_offset%,${container_header_offset},g" \ -e "s,%block_offset%,${signature_block_offset},g" \ "${SCRIPT_PATH}/csf_templates/sign_ahab" > csf_descriptor From 1d0631ef96920e0a79b33c7225496b5fbe9bea9c Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Tue, 12 Mar 2024 18:02:37 +0100 Subject: [PATCH 44/91] u-boot-dey: support Trustfence config options with spaces The standard string split() function does not support splitting a string by spaces but preserving quoted strings, so it does not work for build options disabling functionality, as they have this format: "# CONFIG_OPTION is not set" On the other hand, the "shlex" module provides a split function that allows splitting strings by spaces and, at the same time, preserves quoted strings. In Trustfence, we need this functionality to disable default options that would allow the booting of non-authenticated images. https://onedigi.atlassian.net/browse/DEL-8704 Signed-off-by: Javier Viguera --- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 6d39f2e6e..c36d8f3da 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -49,9 +49,13 @@ python __anonymous() { do_configure[prefuncs] += "${@oe.utils.ifelse(d.getVar('UBOOT_TF_CONF'), 'trustfence_config', '')}" python trustfence_config() { + import shlex config_path = d.expand('${WORKDIR}/uboot-trustfence.cfg') with open(config_path, 'w') as f: - for cfg in d.getVar('UBOOT_TF_CONF').split(): + for cfg in shlex.split(d.getVar('UBOOT_TF_CONF'), posix=False): + # strip quotes for "is not set" options + if 'is not set' in cfg: + cfg = cfg.strip('"\'') f.write('%s\n' % cfg) d.appendVar('SRC_URI', ' file://%s' % config_path) } From e6b67b6bf82403da697ded818b30a059b65e815a Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Fri, 8 Mar 2024 15:10:07 +0100 Subject: [PATCH 45/91] meta-digi: trustfence: support signing a FIT boot artifact And enable it for the ccimx93. https://onedigi.atlassian.net/browse/DEL-8704 Signed-off-by: Javier Viguera --- meta-digi-arm/classes/image_types_digi.bbclass | 3 ++- meta-digi-arm/conf/machine/include/ccimx93.inc | 4 +++- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc | 5 +++-- .../recipes-kernel/linux/linux-trustfence.inc | 5 ++++- meta-digi-dey/classes/trustfence.bbclass | 12 ++++++++---- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/meta-digi-arm/classes/image_types_digi.bbclass b/meta-digi-arm/classes/image_types_digi.bbclass index 0b677fe44..d5fded013 100644 --- a/meta-digi-arm/classes/image_types_digi.bbclass +++ b/meta-digi-arm/classes/image_types_digi.bbclass @@ -221,10 +221,11 @@ trustence_sign_cpio() { # Image generation code for image type 'cpio.gz.u-boot.tf' # (signed/encrypted ramdisk) # - if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ]; then + if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ] && [ "${TRUSTFENCE_SIGN_FIT_ARTIFACT}" = "0" ]; then # Set environment variables for trustfence configuration export CONFIG_SIGN_KEYS_PATH="${TRUSTFENCE_SIGN_KEYS_PATH}" [ -n "${TRUSTFENCE_KEY_INDEX}" ] && export CONFIG_KEY_INDEX="${TRUSTFENCE_KEY_INDEX}" + [ -n "${TRUSTFENCE_SRK_REVOKE_MASK}" ] && export SRK_REVOKE_MASK="${TRUSTFENCE_SRK_REVOKE_MASK}" [ -n "${TRUSTFENCE_DEK_PATH}" ] && [ "${TRUSTFENCE_DEK_PATH}" != "0" ] && export CONFIG_DEK_PATH="${TRUSTFENCE_DEK_PATH}" # Sign/encrypt the ramdisk trustfence-sign-artifact.sh -p "${DIGI_SOM}" -i "${1}" "${1}.tf" diff --git a/meta-digi-arm/conf/machine/include/ccimx93.inc b/meta-digi-arm/conf/machine/include/ccimx93.inc index 768ff8ce1..278911589 100644 --- a/meta-digi-arm/conf/machine/include/ccimx93.inc +++ b/meta-digi-arm/conf/machine/include/ccimx93.inc @@ -15,8 +15,10 @@ UBOOT_ENV = "boot" UBOOT_PREFIX = "imx-boot" UBOOT_SUFFIX = "bin" -# Platform kernel settings +# Platform kernel settings (keep the override as otherwise KERNEL_IMAGETYPE +# from imx-digi-base.inc takes precedence) KERNEL_CLASSES = "kernel-fitimage" +KERNEL_IMAGETYPE:ccimx93 = "${@oe.utils.vartrue('TRUSTFENCE_SIGN_ARTIFACTS', 'fitImage', 'Image.gz', d)}" # The bootloader image that gets flashed consists of U-Boot and several fw binaries EXTRA_IMAGEDEPENDS += "imx-boot" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index c36d8f3da..30b6c55b3 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -117,10 +117,11 @@ build_uboot_scripts() { mkimage -T script -n bootscript -C none -d ${TMP_BOOTSCR} ${DEPLOYDIR}/boot.scr rm -f ${TMP_BOOTSCR} - # Sign the boot script - if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ]; then + # Sign the boot script if not contained in a FIT image + if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ] && [ "${TRUSTFENCE_SIGN_FIT_ARTIFACT}" = "0" ]; then export CONFIG_SIGN_KEYS_PATH="${TRUSTFENCE_SIGN_KEYS_PATH}" [ -n "${TRUSTFENCE_KEY_INDEX}" ] && export CONFIG_KEY_INDEX="${TRUSTFENCE_KEY_INDEX}" + [ -n "${TRUSTFENCE_SRK_REVOKE_MASK}" ] && export SRK_REVOKE_MASK="${TRUSTFENCE_SRK_REVOKE_MASK}" [ -n "${TRUSTFENCE_DEK_PATH}" ] && [ "${TRUSTFENCE_DEK_PATH}" != "0" ] && export CONFIG_DEK_PATH="${TRUSTFENCE_DEK_PATH}" # Sign boot script diff --git a/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc b/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc index 6d2b06ee3..4fca51f2c 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc +++ b/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc @@ -7,8 +7,8 @@ trustfence_sign() { # Set environment variables for trustfence configuration export CONFIG_SIGN_KEYS_PATH="${TRUSTFENCE_SIGN_KEYS_PATH}" [ -n "${TRUSTFENCE_KEY_INDEX}" ] && export CONFIG_KEY_INDEX="${TRUSTFENCE_KEY_INDEX}" + [ -n "${TRUSTFENCE_SRK_REVOKE_MASK}" ] && export SRK_REVOKE_MASK="${TRUSTFENCE_SRK_REVOKE_MASK}" [ -n "${TRUSTFENCE_DEK_PATH}" ] && [ "${TRUSTFENCE_DEK_PATH}" != "0" ] && export CONFIG_DEK_PATH="${TRUSTFENCE_DEK_PATH}" - [ -n "${TRUSTFENCE_SIGN_MODE}" ] && export CONFIG_SIGN_MODE="${TRUSTFENCE_SIGN_MODE}" # Sign/encrypt the kernel images for type in ${KERNEL_IMAGETYPES}; do @@ -31,6 +31,9 @@ trustfence_sign() { mv "${TMP_KERNEL_IMAGE_SIGNED}" "${KERNEL_IMAGE}" done + # For FIT images there is no need to sign the rest of artifacts + [ "${TRUSTFENCE_SIGN_FIT_ARTIFACT}" = "1" ] && return 0 + # Sign/encrypt the device tree blobs for DTB in ${KERNEL_DEVICETREE}; do DTB=`normalize_dtb "${DTB}"` diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index 0db6afa1d..6d10ec992 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -30,6 +30,8 @@ TRUSTFENCE_ENCRYPT_ENVIRONMENT ?= "1" TRUSTFENCE_ENCRYPT_ENVIRONMENT:ccimx93 ?= "0" TRUSTFENCE_SRK_REVOKE_MASK ?= "0x0" TRUSTFENCE_KEY_INDEX ?= "0" +TRUSTFENCE_SIGN_ARTIFACTS = "1" +TRUSTFENCE_SIGN_ARTIFACTS:ccmp1 = "0" TRUSTFENCE_FIT_IMG:ccmp1 ?= "1" # Partition encryption configuration @@ -45,10 +47,9 @@ TRUSTFENCE_READ_ONLY_ROOTFS ?= "${@bb.utils.contains("IMAGE_FEATURES", "read-onl # NOTHING TO CUSTOMIZE BELOW THIS LINE # -# TrustFence sign artifacts is not supported on all platforms -TRUSTFENCE_SIGN_ARTIFACTS = "1" -TRUSTFENCE_SIGN_ARTIFACTS:ccmp1 = "0" -TRUSTFENCE_SIGN_ARTIFACTS:ccimx93 = "0" +# NXP-based sign a FIT-format boot artifact +TRUSTFENCE_SIGN_FIT_ARTIFACT = "0" +TRUSTFENCE_SIGN_FIT_ARTIFACT:ccimx93 = "${TRUSTFENCE_SIGN_ARTIFACTS}" IMAGE_FEATURES += "dey-trustfence" @@ -184,6 +185,9 @@ python () { d.appendVar("UBOOT_TF_CONF", "CONFIG_SIGN_IMAGE=y ") if (d.getVar("TRUSTFENCE_SIGN_ARTIFACTS") == "1"): d.appendVar("UBOOT_TF_CONF", "CONFIG_AUTH_ARTIFACTS=y ") + if (d.getVar("TRUSTFENCE_SIGN_FIT_ARTIFACT") == "1"): + d.appendVar("UBOOT_TF_CONF", '"# CONFIG_CMD_BOOTI is not set" ') + d.appendVar("UBOOT_TF_CONF", '"# CONFIG_LEGACY_IMAGE_FORMAT is not set" ') if (d.getVar("TRUSTFENCE_READ_ONLY_ROOTFS") == "1"): d.appendVar("UBOOT_TF_CONF", "CONFIG_AUTHENTICATE_SQUASHFS_ROOTFS=y ") if d.getVar("TRUSTFENCE_SIGN_KEYS_PATH"): From 67be7da934c860903c6a75348437607403e8002c Mon Sep 17 00:00:00 2001 From: Gonzalo Ruiz Date: Thu, 14 Mar 2024 16:41:56 +0100 Subject: [PATCH 46/91] u-boot-dey: cc6: fix typo in uuu install script Signed-off-by: Gonzalo Ruiz --- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index 8403a19b7..ccd0b05c6 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -208,7 +208,7 @@ fi # Verify existence of files before starting the update FILES="${INSTALL_UBOOT_FILENAME} ${INSTALL_LINUX_FILENAME}" if [ "${DUALBOOT}" != true ]; then - FILES"${INSTALL_RECOVERY_FILENAME}" + FILES="${FILES} ${INSTALL_RECOVERY_FILENAME}" fi for f in ${FILES}; do if [ ! -f ${f} ]; then From ecd77dece937865000c3aa233b19b48eb1ebfee5 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Wed, 20 Dec 2023 16:38:21 +0100 Subject: [PATCH 47/91] firmware-murata: update firmware binaries to version imx-kirkstone-hedorah_r1.0 This commit updates the required firmware binaries for Bluetooth and Wireless interfaces, hostapd and wpa_supplicant recipes based on the Cypress Linux WiFi Driver (FMAC) release v5.15.58-2023_1128 (Wireless firmware v13.10.246.334). This change also includes a custom defconfig file for the hostapd and wpa_supplicant recipes including the changes from the patches and the Digi customizations. Also are updated the Murata firmware repositories to match with the latest Murata release imx-kirkstone-hedorah_r1.0, which is based in the same Cypress Linux Wifi Driver release v5.15.58-2023_1128. https://onedigi.atlassian.net/browse/DEL-8667 Signed-off-by: Arturo Buzarra --- .../firmware-murata-infineon.bb | 22 +- .../hostapd/hostapd/ccmp1/defconfig | 421 ++++++++++ ...connection-authorized-in-EVENT_ASSOC.patch | 2 +- ...OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch | 2 +- ...k-SAE-authentication-offload-support.patch | 2 +- ...n-connect-for-SAE-authenticat.murata.patch | 2 +- ...4-way-handshake-offload-for-WPA-WPA2.patch | 2 +- ...y-handshake-offload-for-WPA-WPA2-PSK.patch | 2 +- ...SAE-authentication-offload-in-AP-mod.patch | 2 +- ...AE-authentication-offload-in-AP-mode.patch | 2 +- ...config_base-Add-Infineon-default-con.patch | 2 +- ...x-to-check-Invalid-GTK-IE-length-in-.patch | 2 +- ...UTH_EARLY_SET-flags-and-codes.murata.patch | 2 +- ...t-WPA-Versions-for-FT-SAE-key-manage.patch | 2 +- ...WPA_KEY_MGMT_FT-for-eapol-off.murata.patch | 2 +- ...-deauth-for-PMKSA-caching-dis.murata.patch | 2 +- ...tion-issue-through-supplicant.murata.patch | 2 +- ...cating-STA-if-the-reason-for-freeing.patch | 2 +- .../0022-wpa_supplicant-support-bgscan.patch | 2 +- ...ate-interface-to-support-driv.murata.patch | 2 +- ...cmd-create-wl_do_cmd-as-an-entry-doi.patch | 2 +- ...cmd-create-ops-table-to-do-wl-comman.patch | 2 +- ...-wl-cmd-add-more-compile-flag.murata.patch | 2 +- ...027-Fix-dpp-config-parameter-setting.patch | 2 +- ...ilure-of-dpp-configurator-exchange-f.patch | 2 +- ...SUITEB192-and-SUITEB-compile-options.patch | 2 +- ..._EDIT-option-for-enrollee-plus-respo.patch | 2 +- ...-disconnect-after-PMKSA-cache-expire.patch | 2 +- ...et-PMKSA-to-driver-while-key-mgmt-is.patch | 2 +- ...N_FLAG_COLOCATED_6GHZ-in-scan.murata.patch | 2 +- .../0037-Enabling-OWE-in-wpa_supplicant.patch | 2 +- ...39-FT-Sync-nl80211-ext-feature-index.patch | 2 +- ...e-a-vendor-header-for-vendor-NL-ifac.patch | 2 +- ...TWT-setup-request-handling-to.murata.patch | 2 +- ...TWT-Teardown-request-handling.murata.patch | 2 +- ...e-TWT-of-a-session-using-offs.murata.patch | 2 +- ...ailed-when-PMK-lifetime-is-set-to-1.patch} | 2 +- ...cli-mbo-command-by-IFX-vendorID.digi.patch | 381 +++++++++ ...-support-to-be-enabled-with-bui.digi.patch | 48 ++ ...able-4-way-handshake-offload-for-DPP.patch | 31 + ...cli-wnm_maxilde-command-by-IFX-.digi.patch | 283 +++++++ ...ntent-of-nl80211_copy.h-for-BSS_COLO.patch | 170 ++++ ...nl_connect-socket-while-WPA_DRIVER_F.patch | 37 + ...E-compile-option-for-hostapd-executi.patch | 31 + ...PP2.0-and-add-pfs-init-flow-on-EVENT.patch | 232 ++++++ ...vent-invalid-akm-key-mgmt-when-MFP-r.patch | 31 + ...and-encryption-parameters-while.digi.patch | 49 ++ .../hostapd/hostapd_%.bbappend | 14 +- .../wpa-supplicant/ccmp1/defconfig | 655 +++++++++++++++ ...upport-4-way-handshake-offload-for-F.patch | 2 +- ...otify-Neighbor-Report-for-driver-tri.patch | 2 +- ...connection-authorized-in-EVENT_ASSOC.patch | 2 +- ...dd-PMKSA-cache-for-802.1X-4-way-hand.patch | 2 +- ...OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch | 2 +- ...k-SAE-authentication-offload-support.patch | 2 +- ...sword-on-connect-for-SAE-authenticat.patch | 2 +- ...4-way-handshake-offload-for-WPA-WPA2.patch | 2 +- ...y-handshake-offload-for-WPA-WPA2-PSK.patch | 2 +- ...SAE-authentication-offload-in-AP-mod.patch | 2 +- ...AE-authentication-offload-in-AP-mode.patch | 2 +- ...dition-test-for-AKM-type-DPP-offload.patch | 2 +- ...config_base-Add-Infineon-default-con.patch | 2 +- ...x-to-check-Invalid-GTK-IE-length-in-.patch | 2 +- ...UTH_EARLY_SET-flags-and-codes.murata.patch | 2 +- ...t-WPA-Versions-for-FT-SAE-key-manage.patch | 2 +- ...upport-WPA_KEY_MGMT_FT-for-eapol-off.patch | 2 +- ...uppress-deauth-for-PMKSA-caching-dis.patch | 2 +- ...tion-issue-through-supplicant.murata.patch | 2 +- ...ache-after-receiving-specific-deauth.patch | 2 +- ...cating-STA-if-the-reason-for-freeing.patch | 2 +- .../0022-wpa_supplicant-support-bgscan.patch | 2 +- ...ate-interface-to-support-driv.murata.patch | 2 +- ...cmd-create-wl_do_cmd-as-an-entry-doi.patch | 2 +- ...cmd-create-ops-table-to-do-wl-comman.patch | 2 +- ...pstream-wl-cmd-add-more-compile-flag.patch | 2 +- ...027-Fix-dpp-config-parameter-setting.patch | 2 +- ...ilure-of-dpp-configurator-exchange-f.patch | 2 +- ...SUITEB192-and-SUITEB-compile-options.patch | 2 +- ..._EDIT-option-for-enrollee-plus-respo.patch | 2 +- ...trigger-failed-once-GC-invited-by-GO.patch | 2 +- ...-disconnect-after-PMKSA-cache-expire.patch | 2 +- ...-Add-support-for-beacon-loss-roaming.patch | 2 +- ...et-PMKSA-to-driver-while-key-mgmt-is.patch | 2 +- ...211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.patch | 2 +- ...to-disable-6-GHz-collocated-scanning.patch | 2 +- .../0037-Enabling-OWE-in-wpa_supplicant.patch | 2 +- ...8-Add-link-loss-timer-on-beacon-loss.patch | 2 +- ...39-FT-Sync-nl80211-ext-feature-index.patch | 2 +- ...e-a-vendor-header-for-vendor-NL-ifac.patch | 2 +- ...ffload-TWT-setup-request-handling-to.patch | 2 +- ...ffload-TWT-Teardown-request-handling.patch | 2 +- ...onfigure-TWT-of-a-session-using-offs.patch | 2 +- ...ult-TWT-session-in-the-STA-after-ass.patch | 2 +- ...-parameters-exponent-and-mantissa-pa.patch | 2 +- ...sending-open-auth-instead-of-SAE-aut.patch | 2 +- ...AMOFFLOAD-raises-portValid-too-early.patch | 54 -- ...ailed-when-PMK-lifetime-is-set-to-1.patch} | 4 +- ...m-p2p_add_group-command-unification.patch} | 4 +- ...-wpa_cli-mbo-command-by-IFX-vendorID.patch | 765 ++++++++++++++++++ ...Sv1.3-support-to-be-enabled-with-bui.patch | 94 +++ .../0051-Enabling-TLS-v1.3-by-default.patch | 27 + ...able-4-way-handshake-offload-for-DPP.patch | 31 + ...-wpa_cli-wnm_maxilde-command-by-IFX-.patch | 382 +++++++++ ...ntent-of-nl80211_copy.h-for-BSS_COLO.patch | 170 ++++ ...nl_connect-socket-while-WPA_DRIVER_F.patch | 37 + ...E-compile-option-for-hostapd-executi.patch | 31 + ...PP2.0-and-add-pfs-init-flow-on-EVENT.patch | 232 ++++++ ...vent-invalid-akm-key-mgmt-when-MFP-r.patch | 31 + ...tion-and-encryption-parameters-while.patch | 70 ++ ...onfigurable-link_loss-parameter-for-.patch | 117 +++ .../wpa-supplicant/wpa-supplicant_%.bbappend | 19 +- 111 files changed, 4479 insertions(+), 156 deletions(-) create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/ccmp1/defconfig rename meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/{0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch => 0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch} (97%) create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.digi.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.digi.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.digi.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch create mode 100644 meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0059-Reset-authentication-and-encryption-parameters-while.digi.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/ccmp1/defconfig delete mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0047-Fix-ROAMOFFLOAD-raises-portValid-too-early.patch rename meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/{0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch => 0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch} (94%) rename meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/{0049-non-upstream-p2p_add_group-command-unification.patch => 0048-non-upstream-p2p_add_group-command-unification.patch} (95%) create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0051-Enabling-TLS-v1.3-by-default.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0059-Reset-authentication-and-encryption-parameters-while.patch create mode 100644 meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0060-brcmfmac-add-a-configurable-link_loss-parameter-for-.patch diff --git a/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb index 3d44a8620..4377c33f2 100644 --- a/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb +++ b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb @@ -1,4 +1,4 @@ -# Copyright (C) 2022,2023 Digi International. +# Copyright (C) 2022,2024 Digi International Inc. SUMMARY = "Murata Infineon firmware binaries" SECTION = "base" @@ -6,19 +6,19 @@ LICENSE = "CYPRESS-EULA" LIC_FILES_CHKSUM = "file://${S}/cyw-bt-patch/LICENCE.cypress;md5=cbc5f665d04f741f1e006d2096236ba7" SRC_URI = " \ - git://github.com/murata-wireless/cyw-fmac-fw;protocol=http;branch=fafnir;destsuffix=cyw-fmac-fw;name=cyw-fmac-fw \ - git://github.com/murata-wireless/cyw-fmac-nvram;protocol=http;branch=fafnir;destsuffix=cyw-fmac-nvram;name=cyw-fmac-nvram \ - git://github.com/murata-wireless/cyw-bt-patch;protocol=http;branch=master;destsuffix=cyw-bt-patch;name=cyw-bt-patch \ - git://github.com/murata-wireless/cyw-fmac-utils-imx32;protocol=http;branch=fafnir;destsuffix=cyw-fmac-utils-imx32;name=cyw-fmac-utils-imx32 \ - git://github.com/murata-wireless/cyw-fmac-utils-imx64;protocol=http;branch=fafnir;destsuffix=cyw-fmac-utils-imx64;name=cyw-fmac-utils-imx64 \ + git://github.com/murata-wireless/cyw-fmac-fw;protocol=http;branch=hedorah;destsuffix=cyw-fmac-fw;name=cyw-fmac-fw \ + git://github.com/murata-wireless/cyw-fmac-nvram;protocol=http;branch=hedorah;destsuffix=cyw-fmac-nvram;name=cyw-fmac-nvram \ + git://github.com/murata-wireless/cyw-bt-patch;protocol=http;branch=mickledore-hedorah;destsuffix=cyw-bt-patch;name=cyw-bt-patch \ + git://github.com/murata-wireless/cyw-fmac-utils-imx32;protocol=http;branch=master;destsuffix=cyw-fmac-utils-imx32;name=cyw-fmac-utils-imx32 \ + git://github.com/murata-wireless/cyw-fmac-utils-imx64;protocol=http;branch=master;destsuffix=cyw-fmac-utils-imx64;name=cyw-fmac-utils-imx64 \ file://cyfmac4373-sdio_US.clm_blob \ " -SRCREV_cyw-fmac-fw="1f83e807b8187508c811a7d91a353a768fef2d37" -SRCREV_cyw-fmac-nvram="303acf1b04441f62fbc48d278a70a099fabacb4a" -SRCREV_cyw-bt-patch="9d24c254dae92af99ddfd661a4ea30af69190038" -SRCREV_cyw-fmac-utils-imx32="e248804b6ba386fedcd462ddd9394f42f73a17af" -SRCREV_cyw-fmac-utils-imx64="1bc78d68f9609290b2f6578516011c57691f7815" +SRCREV_cyw-fmac-fw="db8deb03b8d24e5069ac4581d1c35b767012e926" +SRCREV_cyw-fmac-nvram="9b7d93eb3e13b2d2ed8ce3a01338ceb54151b77a" +SRCREV_cyw-bt-patch="3275a7036dd0d6eacecccccc760b7e7fe91a9e32" +SRCREV_cyw-fmac-utils-imx32="fcdd231e9bb23db3c93c10e5dff43a1182f220c5" +SRCREV_cyw-fmac-utils-imx64="52cc4cc6be8629781014505aa276b67e18cf6e8d" SRCREV_default = "${AUTOREV}" diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/ccmp1/defconfig b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/ccmp1/defconfig new file mode 100644 index 000000000..8bc9c7f9f --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/ccmp1/defconfig @@ -0,0 +1,421 @@ +# Example hostapd build time configuration +# +# This file lists the configuration options that are used when building the +# hostapd binary. All lines starting with # are ignored. Configuration option +# lines must be commented out complete, if they are not to be included, i.e., +# just setting VARIABLE=n is not disabling that variable. +# +# This file is included in Makefile, so variables like CFLAGS and LIBS can also +# be modified from here. In most cass, these lines should use += in order not +# to override previous values of the variables. + +# Driver interface for Host AP driver +CONFIG_DRIVER_HOSTAP=y + +# Driver interface for wired authenticator +#CONFIG_DRIVER_WIRED=y + +# Driver interface for drivers using the nl80211 kernel interface +CONFIG_DRIVER_NL80211=y + +# QCA vendor extensions to nl80211 +#CONFIG_DRIVER_NL80211_QCA=y + +CONFIG_DRIVER_BRCM_WL=y + +# driver_nl80211.c requires libnl. If you are compiling it yourself +# you may need to point hostapd to your version of libnl. +# +#CFLAGS += -I$ +#LIBS += -L$ + +# Use libnl v2.0 (or 3.0) libraries. +#CONFIG_LIBNL20=y + +# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) +CONFIG_LIBNL32=y + + +# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) +#CONFIG_DRIVER_BSD=y +#CFLAGS += -I/usr/local/include +#LIBS += -L/usr/local/lib +#LIBS_p += -L/usr/local/lib +#LIBS_c += -L/usr/local/lib + +# Driver interface for no driver (e.g., RADIUS server only) +#CONFIG_DRIVER_NONE=y + +# WPA2/IEEE 802.11i RSN pre-authentication +CONFIG_RSN_PREAUTH=y + +# Support Operating Channel Validation +#CONFIG_OCV=y + +# Integrated EAP server +CONFIG_EAP=y + +# EAP Re-authentication Protocol (ERP) in integrated EAP server +CONFIG_ERP=y + +# EAP-MD5 for the integrated EAP server +CONFIG_EAP_MD5=y + +# EAP-TLS for the integrated EAP server +CONFIG_EAP_TLS=y + +# EAP-MSCHAPv2 for the integrated EAP server +CONFIG_EAP_MSCHAPV2=y + +# EAP-PEAP for the integrated EAP server +CONFIG_EAP_PEAP=y + +# EAP-GTC for the integrated EAP server +CONFIG_EAP_GTC=y + +# EAP-TTLS for the integrated EAP server +CONFIG_EAP_TTLS=y + +# EAP-SIM for the integrated EAP server +#CONFIG_EAP_SIM=y + +# EAP-AKA for the integrated EAP server +#CONFIG_EAP_AKA=y + +# EAP-AKA' for the integrated EAP server +# This requires CONFIG_EAP_AKA to be enabled, too. +#CONFIG_EAP_AKA_PRIME=y + +# EAP-PAX for the integrated EAP server +#CONFIG_EAP_PAX=y + +# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK) +#CONFIG_EAP_PSK=y + +# EAP-pwd for the integrated EAP server (secure authentication with a password) +#CONFIG_EAP_PWD=y + +# EAP-SAKE for the integrated EAP server +#CONFIG_EAP_SAKE=y + +# EAP-GPSK for the integrated EAP server +#CONFIG_EAP_GPSK=y +# Include support for optional SHA256 cipher suite in EAP-GPSK +#CONFIG_EAP_GPSK_SHA256=y + +# EAP-FAST for the integrated EAP server +#CONFIG_EAP_FAST=y + +# EAP-TEAP for the integrated EAP server +# Note: The current EAP-TEAP implementation is experimental and should not be +# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number +# of conflicting statements and missing details and the implementation has +# vendor specific workarounds for those and as such, may not interoperate with +# any other implementation. This should not be used for anything else than +# experimentation and interoperability testing until those issues has been +# resolved. +#CONFIG_EAP_TEAP=y + +# Wi-Fi Protected Setup (WPS) +#CONFIG_WPS=y +# Enable UPnP support for external WPS Registrars +#CONFIG_WPS_UPNP=y +# Enable WPS support with NFC config method +#CONFIG_WPS_NFC=y + +# EAP-IKEv2 +#CONFIG_EAP_IKEV2=y + +# Trusted Network Connect (EAP-TNC) +#CONFIG_EAP_TNC=y + +# EAP-EKE for the integrated EAP server +#CONFIG_EAP_EKE=y + +# PKCS#12 (PFX) support (used to read private key and certificate file from +# a file that usually has extension .p12 or .pfx) +CONFIG_PKCS12=y + +# RADIUS authentication server. This provides access to the integrated EAP +# server from external hosts using RADIUS. +#CONFIG_RADIUS_SERVER=y + +# Build IPv6 support for RADIUS operations +CONFIG_IPV6=y + +# IEEE Std 802.11r-2008 (Fast BSS Transition) +#CONFIG_IEEE80211R=y + +# Use the hostapd's IEEE 802.11 authentication (ACL), but without +# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211) +#CONFIG_DRIVER_RADIUS_ACL=y + +# Wireless Network Management (IEEE Std 802.11v-2011) +# Note: This is experimental and not complete implementation. +#CONFIG_WNM=y + +# IEEE 802.11ac (Very High Throughput) support +CONFIG_IEEE80211AC=y + +# IEEE 802.11ax HE support +# Note: This is experimental and work in progress. The definitions are still +# subject to change and this should not be expected to interoperate with the +# final IEEE 802.11ax version. +#CONFIG_IEEE80211AX=y + +# Remove debugging code that is printing out debug messages to stdout. +# This can be used to reduce the size of the hostapd considerably if debugging +# code is not needed. +#CONFIG_NO_STDOUT_DEBUG=y + +# Add support for writing debug log to a file: -f /tmp/hostapd.log +# Disabled by default. +#CONFIG_DEBUG_FILE=y + +# Send debug messages to syslog instead of stdout +#CONFIG_DEBUG_SYSLOG=y + +# Add support for sending all debug messages (regardless of debug verbosity) +# to the Linux kernel tracing facility. This helps debug the entire stack by +# making it easy to record everything happening from the driver up into the +# same file, e.g., using trace-cmd. +#CONFIG_DEBUG_LINUX_TRACING=y + +# Remove support for RADIUS accounting +#CONFIG_NO_ACCOUNTING=y + +# Remove support for RADIUS +#CONFIG_NO_RADIUS=y + +# Remove support for VLANs +#CONFIG_NO_VLAN=y + +# Enable support for fully dynamic VLANs. This enables hostapd to +# automatically create bridge and VLAN interfaces if necessary. +#CONFIG_FULL_DYNAMIC_VLAN=y + +# Use netlink-based kernel API for VLAN operations instead of ioctl() +# Note: This requires libnl 3.1 or newer. +#CONFIG_VLAN_NETLINK=y + +# Remove support for dumping internal state through control interface commands +# This can be used to reduce binary size at the cost of disabling a debugging +# option. +#CONFIG_NO_DUMP_STATE=y + +# Enable tracing code for developer debugging +# This tracks use of memory allocations and other registrations and reports +# incorrect use with a backtrace of call (or allocation) location. +#CONFIG_WPA_TRACE=y +# For BSD, comment out these. +#LIBS += -lexecinfo +#LIBS_p += -lexecinfo +#LIBS_c += -lexecinfo + +# Use libbfd to get more details for developer debugging +# This enables use of libbfd to get more detailed symbols for the backtraces +# generated by CONFIG_WPA_TRACE=y. +#CONFIG_WPA_TRACE_BFD=y +# For BSD, comment out these. +#LIBS += -lbfd -liberty -lz +#LIBS_p += -lbfd -liberty -lz +#LIBS_c += -lbfd -liberty -lz + +# hostapd depends on strong random number generation being available from the +# operating system. os_get_random() function is used to fetch random data when +# needed, e.g., for key generation. On Linux and BSD systems, this works by +# reading /dev/urandom. It should be noted that the OS entropy pool needs to be +# properly initialized before hostapd is started. This is important especially +# on embedded devices that do not have a hardware random number generator and +# may by default start up with minimal entropy available for random number +# generation. +# +# As a safety net, hostapd is by default trying to internally collect +# additional entropy for generating random data to mix in with the data +# fetched from the OS. This by itself is not considered to be very strong, but +# it may help in cases where the system pool is not initialized properly. +# However, it is very strongly recommended that the system pool is initialized +# with enough entropy either by using hardware assisted random number +# generator or by storing state over device reboots. +# +# hostapd can be configured to maintain its own entropy store over restarts to +# enhance random number generation. This is not perfect, but it is much more +# secure than using the same sequence of random numbers after every reboot. +# This can be enabled with -e command line option. The specified +# file needs to be readable and writable by hostapd. +# +# If the os_get_random() is known to provide strong random data (e.g., on +# Linux/BSD, the board in question is known to have reliable source of random +# data from /dev/urandom), the internal hostapd random pool can be disabled. +# This will save some in binary size and CPU use. However, this should only be +# considered for builds that are known to be used on devices that meet the +# requirements described above. +#CONFIG_NO_RANDOM_POOL=y + +# Should we attempt to use the getrandom(2) call that provides more reliable +# yet secure randomness source than /dev/random on Linux 3.17 and newer. +# Requires glibc 2.25 to build, falls back to /dev/random if unavailable. +#CONFIG_GETRANDOM=y + +# Should we use poll instead of select? Select is used by default. +#CONFIG_ELOOP_POLL=y + +# Should we use epoll instead of select? Select is used by default. +#CONFIG_ELOOP_EPOLL=y + +# Should we use kqueue instead of select? Select is used by default. +#CONFIG_ELOOP_KQUEUE=y + +# Select TLS implementation +# openssl = OpenSSL (default) +# gnutls = GnuTLS +# internal = Internal TLSv1 implementation (experimental) +# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental) +# none = Empty template +CONFIG_TLS=openssl +CONFIG_TLS_ADD_DL=y + +# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1) +# can be enabled to get a stronger construction of messages when block ciphers +# are used. +#CONFIG_TLSV11=y + +# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2) +# can be enabled to enable use of stronger crypto algorithms. +#CONFIG_TLSV12=y + +# Select which ciphers to use by default with OpenSSL if the user does not +# specify them. +#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW" + +# If CONFIG_TLS=internal is used, additional library and include paths are +# needed for LibTomMath. Alternatively, an integrated, minimal version of +# LibTomMath can be used. See beginning of libtommath.c for details on benefits +# and drawbacks of this option. +#CONFIG_INTERNAL_LIBTOMMATH=y +#ifndef CONFIG_INTERNAL_LIBTOMMATH +#LTM_PATH=/usr/src/libtommath-0.39 +#CFLAGS += -I$(LTM_PATH) +#LIBS += -L$(LTM_PATH) +#LIBS_p += -L$(LTM_PATH) +#endif +# At the cost of about 4 kB of additional binary size, the internal LibTomMath +# can be configured to include faster routines for exptmod, sqr, and div to +# speed up DH and RSA calculation considerably +#CONFIG_INTERNAL_LIBTOMMATH_FAST=y + +# Interworking (IEEE 802.11u) +# This can be used to enable functionality to improve interworking with +# external networks. +#CONFIG_INTERWORKING=y + +# Hotspot 2.0 +#CONFIG_HS20=y + +# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file +#CONFIG_SQLITE=y + +# Enable Fast Session Transfer (FST) +#CONFIG_FST=y + +# Enable CLI commands for FST testing +#CONFIG_FST_TEST=y + +# Testing options +# This can be used to enable some testing options (see also the example +# configuration file) that are really useful only for testing clients that +# connect to this hostapd. These options allow, for example, to drop a +# certain percentage of probe requests or auth/(re)assoc frames. +# +#CONFIG_TESTING_OPTIONS=y + +# Automatic Channel Selection +# This will allow hostapd to pick the channel automatically when channel is set +# to "acs_survey" or "0". Eventually, other ACS algorithms can be added in +# similar way. +# +# Automatic selection is currently only done through initialization, later on +# we hope to do background checks to keep us moving to more ideal channels as +# time goes by. ACS is currently only supported through the nl80211 driver and +# your driver must have survey dump capability that is filled by the driver +# during scanning. +# +# You can customize the ACS survey algorithm with the hostapd.conf variable +# acs_num_scans. +# +# Supported ACS drivers: +# * ath9k +# * ath5k +# * ath10k +# +# For more details refer to: +# https://wireless.wiki.kernel.org/en/users/documentation/acs +# +#CONFIG_ACS=y + +# Multiband Operation support +# These extensions facilitate efficient use of multiple frequency bands +# available to the AP and the devices that may associate with it. +#CONFIG_MBO=y + +# Client Taxonomy +# Has the AP retain the Probe Request and (Re)Association Request frames from +# a client, from which a signature can be produced which can identify the model +# of client device like "Nexus 6P" or "iPhone 5s". +#CONFIG_TAXONOMY=y + +# Fast Initial Link Setup (FILS) (IEEE 802.11ai) +#CONFIG_FILS=y +# FILS shared key authentication with PFS +#CONFIG_FILS_SK_PFS=y + +# Include internal line edit mode in hostapd_cli. This can be used to provide +# limited command line editing and history support. +#CONFIG_WPA_CLI_EDIT=y + +# Opportunistic Wireless Encryption (OWE) +# Experimental implementation of draft-harkins-owe-07.txt +CONFIG_OWE=y + +# Airtime policy support +#CONFIG_AIRTIME_POLICY=y + +# Override default value for the wpa_disable_eapol_key_retries configuration +# parameter. See that parameter in hostapd.conf for more details. +#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1 + +# Wired equivalent privacy (WEP) +# WEP is an obsolete cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used for anything anymore. The +# functionality needed to use WEP is available in the current hostapd +# release under this optional build parameter. This functionality is subject to +# be completely removed in a future release. +#CONFIG_WEP=y + +# Remove all TKIP functionality +# TKIP is an old cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used anymore. For now, the default hostapd +# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but +# that functionality is subject to be removed in the future. +#CONFIG_NO_TKIP=y + +# Pre-Association Security Negotiation (PASN) +# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol +# design is still subject to change. As such, this should not yet be enabled in +# production use. +# This requires CONFIG_IEEE80211W=y to be enabled, too. +#CONFIG_PASN=y + +# Simultaneous Authentication of Equals (SAE), WPA3-Personal +CONFIG_SAE=y + +# Set SAE Auth status early +CONFIG_WPA3_SAE_AUTH_EARLY_SET=y + +# Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect) +CONFIG_DPP=y +# DPP version 2 support +CONFIG_DPP2=y +# DPP version 3 support (experimental and still changing; do not enable for +# production use) +#CONFIG_DPP3=y diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch index 8de33d112..b203b71df 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch @@ -1,7 +1,7 @@ From 21271c00b29db8c178aa704daaf665967e141d47 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 15:55:21 +0800 -Subject: [PATCH 03/49] nl80211: Report connection authorized in EVENT_ASSOC +Subject: [PATCH 03/60] nl80211: Report connection authorized in EVENT_ASSOC When roaming in a network that requires 802.1X authentication, device driver could set the authorized flag if 4-way handshake offload or FT diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch index 879bc9ba7..8517fbf02 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch @@ -1,7 +1,7 @@ From 78e7373ad2cf51a881a12e55c3db01580932539e Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Fri, 8 Nov 2019 13:23:05 -0600 -Subject: [PATCH 05/49] OpenSSL: Fix build with OpenSSL 1.0.1 +Subject: [PATCH 05/60] OpenSSL: Fix build with OpenSSL 1.0.1 The openssl_debug_dump_certificate_chains() implementation used SSL_CERT_SET_FIRST and SSL_CERT_SET_NEXT, which were added in OpenSSL diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch index 9be859305..297791252 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch @@ -1,7 +1,7 @@ From f6eed1d9e56502fd8cbab309e94f9787795c3e35 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 17:13:27 +0800 -Subject: [PATCH 06/49] nl80211: Check SAE authentication offload support +Subject: [PATCH 06/60] nl80211: Check SAE authentication offload support Set WPA_DRIVER_FLAGS2_SAE_OFFLOAD flag if driver indicates SAE authentication offload support. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.murata.patch index 16d2d8ced..7f6a98dec 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.murata.patch @@ -1,7 +1,7 @@ From 417097c87d7027ad319d7e8c9931deb666779533 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 17:22:18 +0800 -Subject: [PATCH 07/49] SAE: Pass SAE password on connect for SAE +Subject: [PATCH 07/60] SAE: Pass SAE password on connect for SAE authentication offload support Pass SAE password on connect if driver advertises SAE authentication diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch index 43b4e31f3..2bffa1708 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch @@ -1,7 +1,7 @@ From 0bdd3f507d5dc92e42c72df7f4b79ffdab514fe1 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:02:39 -0600 -Subject: [PATCH 08/49] nl80211: Support 4-way handshake offload for +Subject: [PATCH 08/60] nl80211: Support 4-way handshake offload for WPA/WPA2-PSK in AP mode If driver advertises support for WPA/WPA2-PSK 4-way handshake offload in diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch index 654fad8e6..442b1a6e7 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch @@ -1,7 +1,7 @@ From 2f8529ec491389bdb41911edcf084bc643d7c9ee Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:03:57 -0600 -Subject: [PATCH 09/49] AP: Support 4-way handshake offload for WPA/WPA2-PSK +Subject: [PATCH 09/60] AP: Support 4-way handshake offload for WPA/WPA2-PSK Add support for WPA/WPA2-PSK 4-way handshake offload in AP mode. In this case, the 4-way handshake is handled by driver instead of user space. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch index 1a3eef521..2d1636e0a 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch @@ -1,7 +1,7 @@ From 89d2f8b07c948cc5fbe8767948128f487eae2ed5 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:05:16 -0600 -Subject: [PATCH 10/49] nl80211: Support SAE authentication offload in AP mode +Subject: [PATCH 10/60] nl80211: Support SAE authentication offload in AP mode If driver advertises support for SAE authentication offload, pass SAE password in NL80211_CMD_NEW_BEACON command for AP mode. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch index 6667844f7..2ec008ea6 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch @@ -1,7 +1,7 @@ From dfa364f9970f1d88782cc9a9b7292afadbf2358b Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:06:20 -0600 -Subject: [PATCH 11/49] SAE: Support SAE authentication offload in AP mode +Subject: [PATCH 11/60] SAE: Support SAE authentication offload in AP mode Add support for SAE authentication offload in AP mode. In this case, the SAE authentication process is handled by driver instead of user space. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch index dff70c0d3..6e99d6fa9 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch @@ -1,7 +1,7 @@ From 69d18183a1df9e72371e33937c91af5b5b79a110 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Mon, 2 Aug 2021 14:15:06 -0500 -Subject: [PATCH 13/49] non-upstream: defconfig_base: Add Infineon default +Subject: [PATCH 13/60] non-upstream: defconfig_base: Add Infineon default configuration Add Infineon default configuration files (defconfig_base). diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch index 1cc5dc822..6be08c05c 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch @@ -1,7 +1,7 @@ From 28c5794ff336f3ec29be79197198071be9add4ac Mon Sep 17 00:00:00 2001 From: Suresh Sanaboina Date: Tue, 1 Feb 2022 13:02:07 +0000 -Subject: [PATCH 14/49] [CVE_2019_9501] Fix to check Invalid GTK IE length in +Subject: [PATCH 14/60] [CVE_2019_9501] Fix to check Invalid GTK IE length in M3 at STA --- diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch index eb24cd711..edb1d3d63 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch @@ -1,7 +1,7 @@ From ab61a3dd6d968c62b407c170079a236194357931 Mon Sep 17 00:00:00 2001 From: Danny Chiu Date: Thu, 4 Nov 2021 02:44:17 -0500 -Subject: [PATCH 15/49] Add CONFIG_WPA3_SAE_AUTH_EARLY_SET flags and codes +Subject: [PATCH 15/60] Add CONFIG_WPA3_SAE_AUTH_EARLY_SET flags and codes Enable this flags allow the AP to set authorization to firmware earier as the SAE confirm from is ok. --- diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch index 6843ed4ee..add017ef6 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch @@ -1,7 +1,7 @@ From 32ee9150ccf3f6c242ba2809aab9b9e115a9d1b5 Mon Sep 17 00:00:00 2001 From: Darren Li Date: Fri, 26 Nov 2021 02:09:03 -0600 -Subject: [PATCH 16/49] SAE: Set the right WPA Versions for FT-SAE key +Subject: [PATCH 16/60] SAE: Set the right WPA Versions for FT-SAE key management Set the right WPA Versions for FT-SAE key management diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.murata.patch index f4f9aede6..0d9433088 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.murata.patch @@ -1,7 +1,7 @@ From 6fa06f214ba1cfc4e80dc7413874175146b9c2a5 Mon Sep 17 00:00:00 2001 From: Chien-Chia Chen Date: Tue, 23 Nov 2021 21:29:08 -0600 -Subject: [PATCH 17/49] wpa_supplicant: Support WPA_KEY_MGMT_FT for eapol +Subject: [PATCH 17/60] wpa_supplicant: Support WPA_KEY_MGMT_FT for eapol offloading and driver base roaming Add WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK / WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X / diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.murata.patch index ce6cb5754..61d629a09 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.murata.patch @@ -1,7 +1,7 @@ From 9af850cef2007cabe1bbffad3ef1d2b13396832d Mon Sep 17 00:00:00 2001 From: Darren Li Date: Tue, 22 Feb 2022 00:34:47 -0600 -Subject: [PATCH 18/49] wpa_supplicant: suppress deauth for PMKSA caching +Subject: [PATCH 18/60] wpa_supplicant: suppress deauth for PMKSA caching disabled wpa_supplicant: Need a command/parameter suppress deauth for PMKSA caching disabled diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch index 213edd2c2..dd57edbf4 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch @@ -1,7 +1,7 @@ From 5604eb8aaf8382376e6511850e70b66c6e2a22b8 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Sun, 13 Feb 2022 21:34:09 -0600 -Subject: [PATCH 19/49] Fix for PMK expiration issue through supplicant +Subject: [PATCH 19/60] Fix for PMK expiration issue through supplicant Description : Sending Deauth from AP once PMK timeout occurs, So that STA will initiate the Auth process. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch index bb1b85bf7..6521a585f 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch @@ -1,7 +1,7 @@ From ed487600a81fa99688201a50176072555c90e690 Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 25 Apr 2022 18:35:14 +0530 -Subject: [PATCH 21/49] Avoid deauthenticating STA if the reason for freeing +Subject: [PATCH 21/60] Avoid deauthenticating STA if the reason for freeing PMK entry isn't expiry The PMK cache entry for a STA in the SoftAP managed by wpa_supplicant diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0022-wpa_supplicant-support-bgscan.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0022-wpa_supplicant-support-bgscan.patch index 6899b06f4..0842fe358 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0022-wpa_supplicant-support-bgscan.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0022-wpa_supplicant-support-bgscan.patch @@ -1,7 +1,7 @@ From cfa528ffe320ac638ca72e87751f76444669c48e Mon Sep 17 00:00:00 2001 From: Ian Lin Date: Fri, 20 May 2022 03:00:37 -0500 -Subject: [PATCH 22/49] wpa_supplicant: support bgscan +Subject: [PATCH 22/60] wpa_supplicant: support bgscan Modify defconfig_base to support bgscan feature diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch index 066799a9f..d1fb3194d 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch @@ -1,7 +1,7 @@ From 1cfe2ac93a1b50a6fd2f6d0022ece6e0f2a91259 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Sun, 10 Apr 2022 22:10:51 -0500 -Subject: [PATCH 23/49] non-upstream: wl-cmd: create interface to support +Subject: [PATCH 23/60] non-upstream: wl-cmd: create interface to support driver priv command 1. Create "wl" command interface to set/get driver information diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch index cdc0e9b2b..acce18fe6 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch @@ -1,7 +1,7 @@ From ea5cd91f744dc3c5ebf8e5b8cf1746bec41c1d19 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Tue, 26 Apr 2022 03:02:12 -0500 -Subject: [PATCH 24/49] non-upstream: wl-cmd: create wl_do_cmd as an entry +Subject: [PATCH 24/60] non-upstream: wl-cmd: create wl_do_cmd as an entry doing wl commands Create wl_do_cmd as an entry doing wl commands diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch index c9037f18e..1a6279412 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch @@ -1,7 +1,7 @@ From 05b1387d4dc2e74a02cf524733d809acc4fd46fb Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Wed, 27 Apr 2022 22:50:25 -0500 -Subject: [PATCH 25/49] non-upstream: wl-cmd: create ops table to do wl +Subject: [PATCH 25/60] non-upstream: wl-cmd: create ops table to do wl commands Creeate wl_cmds to handle wl commands diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.murata.patch index 0f7410345..7943e7ec9 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.murata.patch @@ -1,7 +1,7 @@ From a6028c58032672f86c9fe87ba3abbd31c79166e3 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Wed, 25 May 2022 19:12:47 -0500 -Subject: [PATCH 26/49] non-upstream: wl-cmd: add more compile flag +Subject: [PATCH 26/60] non-upstream: wl-cmd: add more compile flag add more CONFIG_DRIVER_BRCM_WL to separeta this feature diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0027-Fix-dpp-config-parameter-setting.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0027-Fix-dpp-config-parameter-setting.patch index 894a71616..8d66427e5 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0027-Fix-dpp-config-parameter-setting.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0027-Fix-dpp-config-parameter-setting.patch @@ -1,7 +1,7 @@ From e2fb675883cf00992ce51e91a3e2055c898ae3e6 Mon Sep 17 00:00:00 2001 From: "Shankar Amar (CSTIPL CSS ICW SW WFS 1)" Date: Mon, 20 Jun 2022 05:57:46 +0000 -Subject: [PATCH 27/49] Fix dpp config parameter setting +Subject: [PATCH 27/60] Fix dpp config parameter setting --- src/common/dpp.c | 7 ++++--- diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch index 4d8448982..b9bdaf617 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch @@ -1,7 +1,7 @@ From b19b6f1165800106ccd941b6042ea804bfa95d5f Mon Sep 17 00:00:00 2001 From: "Shankar Amar (CSTIPL CSS ICW SW WFS 1)" Date: Thu, 30 Jun 2022 08:01:45 +0000 -Subject: [PATCH 28/49] DPP: Resolving failure of dpp configurator exchange for +Subject: [PATCH 28/60] DPP: Resolving failure of dpp configurator exchange for configurator plus initiator in AP role with fmac --- diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch index 49c53d64b..2adecd704 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch @@ -1,7 +1,7 @@ From 7d621a129690b061afd61e8bd21d9b816f09d8ac Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Mon, 4 Jul 2022 02:19:48 -0500 -Subject: [PATCH 29/49] Enabling SUITEB192 and SUITEB compile options +Subject: [PATCH 29/60] Enabling SUITEB192 and SUITEB compile options Enabling the compile options for SUITEB and SUITEB-192 related configurations and wpa_cli commands. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch index ea78e16dd..aa98785fa 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch @@ -1,7 +1,7 @@ From 621de92cbd36719e3febe385411a65ccfa646344 Mon Sep 17 00:00:00 2001 From: "Shankar Amar (CSTIPL CSS ICW SW WFS 1)" Date: Fri, 22 Jul 2022 07:52:30 +0000 -Subject: [PATCH 30/49] DPP: Enabling CLI_EDIT option for enrollee plus +Subject: [PATCH 30/60] DPP: Enabling CLI_EDIT option for enrollee plus responder in STA role with fmac --- diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch index 3381303ca..d14dfdfcc 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch @@ -1,7 +1,7 @@ From 65ed1eadc11b838a4ba223648bfd3d87bf492319 Mon Sep 17 00:00:00 2001 From: Ian Lin Date: Mon, 18 Jul 2022 00:49:49 -0500 -Subject: [PATCH 32/49] non-upstream: SAE: disconnect after PMKSA cache expire +Subject: [PATCH 32/60] non-upstream: SAE: disconnect after PMKSA cache expire If the dot11RSNAConfigPMKLifetime is set, skip the flow of postponing the expiration in b0f457b6 and run disconnect flow. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch index 743a338bb..bcd9b3132 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch @@ -1,7 +1,7 @@ From da53435d4d11db827e3661be372e7b9773eaa842 Mon Sep 17 00:00:00 2001 From: JasonHuang Date: Thu, 8 Sep 2022 03:26:23 -0500 -Subject: [PATCH 34/49] wpa_supplicant: Set PMKSA to driver while key mgmt is +Subject: [PATCH 34/60] wpa_supplicant: Set PMKSA to driver while key mgmt is FT When the fast roaming is determined by the firmware, the diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.murata.patch index 3d0ad0b00..7bb5525d1 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.murata.patch @@ -1,7 +1,7 @@ From 2173b4648a59f7ab499b7974189f2ba025b6a25e Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Sun, 24 Apr 2022 12:57:52 +0300 -Subject: [PATCH 35/49] nl80211: Set NL80211_SCAN_FLAG_COLOCATED_6GHZ in scan +Subject: [PATCH 35/60] nl80211: Set NL80211_SCAN_FLAG_COLOCATED_6GHZ in scan Set NL80211_SCAN_FLAG_COLOCATED_6GHZ in the scan parameters to enable scanning for co-located APs discovered based on neighbor reports from diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0037-Enabling-OWE-in-wpa_supplicant.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0037-Enabling-OWE-in-wpa_supplicant.patch index 27e02add8..f95ebd8a2 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0037-Enabling-OWE-in-wpa_supplicant.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0037-Enabling-OWE-in-wpa_supplicant.patch @@ -1,7 +1,7 @@ From 4a920e2446cff3f215614d63798e675bb5e25549 Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Wed, 19 Oct 2022 03:29:39 -0500 -Subject: [PATCH 37/49] Enabling OWE in wpa_supplicant +Subject: [PATCH 37/60] Enabling OWE in wpa_supplicant Enabling the compile options for OWE. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0039-FT-Sync-nl80211-ext-feature-index.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0039-FT-Sync-nl80211-ext-feature-index.patch index 91ecd85cf..691ca6e7b 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0039-FT-Sync-nl80211-ext-feature-index.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0039-FT-Sync-nl80211-ext-feature-index.patch @@ -1,7 +1,7 @@ From 7076f7634cc9d7a88f009c448ada307841b42a2a Mon Sep 17 00:00:00 2001 From: JasonHuang Date: Sun, 30 Oct 2022 21:58:34 -0500 -Subject: [PATCH 39/49] FT: Sync nl80211 ext feature index +Subject: [PATCH 39/60] FT: Sync nl80211 ext feature index The backports-5.15.58 has been used. Supplicant should sync the nl80211_ext_feature_index with backports to avoid unexpected fail. diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch index 4aa8a8767..66df83dbc 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch @@ -1,7 +1,7 @@ From 62c82984916623e6e00053dcb148de71d24bdaf5 Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:15:25 +0530 -Subject: [PATCH 40/49] nl80211: Introduce a vendor header for vendor NL iface +Subject: [PATCH 40/60] nl80211: Introduce a vendor header for vendor NL iface to DRV with OUI_IFX So far, the proprietary configurations are done either through the private diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.murata.patch index cff1286f3..31e38916e 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.murata.patch @@ -1,7 +1,7 @@ From 013beb7bc5036bf627fce3707a7a83344ffa05aa Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:16:37 +0530 -Subject: [PATCH 41/49] add support to offload TWT setup request handling to +Subject: [PATCH 41/60] add support to offload TWT setup request handling to the Firmware With "TWT_SETUP" control sock cmd interface currently available in the diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.murata.patch index 9a97f17fb..18354c584 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.murata.patch @@ -1,7 +1,7 @@ From 9a87c940340e1c665ce7172e7df147d53d1daabe Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:16:50 +0530 -Subject: [PATCH 42/49] add support to offload TWT Teardown request handling to +Subject: [PATCH 42/60] add support to offload TWT Teardown request handling to the Firmware With "TWT_TEARDOWN" control sock cmd interface currently available in the diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.murata.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.murata.patch index 6d5492898..1e221d156 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.murata.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.murata.patch @@ -1,7 +1,7 @@ From e03937fecb74cf50d70721ea2a0b14fa5e12153a Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:17:04 +0530 -Subject: [PATCH 43/49] Add support to configure TWT of a session using offset +Subject: [PATCH 43/60] Add support to configure TWT of a session using offset in microseconds Introduce a new cmd line argument "twt_offset=" in the existing list diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch similarity index 97% rename from meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch rename to meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch index de1124705..aa615dcdf 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch @@ -1,7 +1,7 @@ From 897917008b37a16985d0f1ae9d768c6450741574 Mon Sep 17 00:00:00 2001 From: Owen Huang Date: Wed, 30 Nov 2022 01:35:58 -0600 -Subject: [PATCH 48/49] Fix associating failed when PMK lifetime is set to 1 +Subject: [PATCH 48/60] Fix associating failed when PMK lifetime is set to 1 In WPA3 11.1 STAUT server certificate validation test * set dot11RSNAConfigPMKLifetime to 1 diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.digi.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.digi.patch new file mode 100644 index 000000000..757fc0acc --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.digi.patch @@ -0,0 +1,381 @@ +From 67be9ce68d84e2800b481123a0c140e5ad912619 Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Wed, 14 Dec 2022 01:34:23 -0600 +Subject: [PATCH 49/60] non-upstream: MBO: wpa_cli mbo command by IFX vendorID + +Signed-off-by: Carter Chen +Signed-off-by: Shelley Yang +--- + src/common/ifx_vendor.h | 52 +++++++++++ + src/drivers/driver.h | 46 ++++++++++ + src/drivers/driver_nl80211.c | 141 ++++++++++++++++++++++++++++++ + src/drivers/driver_nl80211.h | 1 + + src/drivers/driver_nl80211_capa.c | 3 + + 5 files changed, 243 insertions(+) + +diff --git a/src/common/ifx_vendor.h b/src/common/ifx_vendor.h +index aa8e83b..6cd3b87 100644 +--- a/src/common/ifx_vendor.h ++++ b/src/common/ifx_vendor.h +@@ -54,10 +54,12 @@ + * + * @IFX_VENDOR_SCMD_AMSDU: Vendor command to enable/disable AMSDU on all the TID queues + * + * @IFX_VENDOR_SCMD_TWT: Vendor subcommand to configure TWT + * Uses attributes defined in enum ifx_vendor_attr_twt. ++ * @IFX_VENDOR_SCMD_MBO: Vendor subcommand to configure MBO ++ * Uses attribute IFX_VENDOR_ATTR_MBO to configure. + * + * @IFX_VENDOR_SCMD_MAX: This acts as a the tail of cmds list. + * Make sure it located at the end of the list. + */ + enum ifx_nl80211_vendor_subcmds { +@@ -72,10 +74,12 @@ enum ifx_nl80211_vendor_subcmds { + /* Reserved 7-10 */ + IFX_VENDOR_SCMD_MUEDCA_OPT_ENABLE = 11, + IFX_VENDOR_SCMD_LDPC_CAP = 12, + IFX_VENDOR_SCMD_AMSDU = 13, + IFX_VENDOR_SCMD_TWT = 14, ++ /* Reserved 15-17 */ ++ IFX_VENDOR_SCMD_MBO = 18, + IFX_VENDOR_SCMD_MAX + }; + + /* + * enum ifx_vendor_attr - IFX nl80211 vendor attributes +@@ -94,10 +98,17 @@ enum ifx_vendor_attr { + IFX_VENDOR_ATTR_UNSPEC = 0, + /* Reserved 1-10 */ + IFX_VENDOR_ATTR_MAX = 11 + }; + ++enum ifx_vendor_attr_mbo { ++ IFX_VENDOR_ATTR_MBO_UNSPEC, ++ IFX_VENDOR_ATTR_MBO_CMD, ++ IFX_VENDOR_ATTR_MBO_PARAMS, ++ IFX_VENDOR_ATTR_MBO_MAX ++}; ++ + /* + * enum ifx_vendor_attr_twt - Attributes for the TWT vendor command + * + * @IFX_VENDOR_ATTR_TWT_UNSPEC: Reserved value 0 + * +@@ -258,6 +269,47 @@ enum ifx_twt_oper_setup_cmd_type { + IFX_TWT_OPER_SETUP_CMD_TYPE_DICTATE = 6, + IFX_TWT_OPER_SETUP_CMD_TYPE_REJECT = 7, + IFX_TWT_OPER_SETUP_CMD_TYPE_MAX = 8 + }; + ++enum ifx_mbo_config_cmd_type { ++ IFX_MBO_CONFIG_CMD_TYPE_INVALID = -1, ++ //align internal definition ++ IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF = 1, ++ IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF = 2, ++ IFX_MBO_CONFIG_CMD_LIST_CHAN_PREF = 3, ++ IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP = 4, ++ IFX_MBO_CONFIG_CMD_DUMP_COUNTER = 5, ++ IFX_MBO_CONFIG_CMD_CLEAR_COUNTER = 6, ++ IFX_MBO_CONFIG_CMD_FORCE_ASSOC = 7, ++ IFX_MBO_CONFIG_CMD_BSSTRANS_REJ = 8, ++ IFX_MBO_CONFIG_CMD_SEND_NOTIF = 9, ++ IFX_MBO_CONFIG_CMD_CLR_CHAN_PREF = 10, ++ IFX_MBO_CONFIG_CMD_NBR_INFO_CACHE = 11, ++ IFX_MBO_CONFIG_CMD_ANQPO_SUPPORT = 12, ++ IFX_MBO_CONFIG_CMD_DBG_EVENT_CHECK = 13, ++ IFX_MBO_CONFIG_CMD_EVENT_MASK = 14, ++ IFX_MBO_CONFIG_CMD_ASSOC_DISALLOWED = 15, ++ IFX_MBO_CONFIG_CMD_CELLULAR_DATA_PREF = 16, ++ IFX_MBO_CONFIG_CMD_TYPE_MAX = 17 ++}; ++ ++enum ifx_vendor_attr_mbo_param { ++ IFX_VENDOR_ATTR_MBO_PARAM_UNSPEC, ++ IFX_VENDOR_ATTR_MBO_PARAM_OPCLASS, ++ IFX_VENDOR_ATTR_MBO_PARAM_CHAN, ++ IFX_VENDOR_ATTR_MBO_PARAM_PREFERENCE, ++ IFX_VENDOR_ATTR_MBO_PARAM_REASON_CODE, ++ IFX_VENDOR_ATTR_MBO_PARAM_CELL_DATA_CAP, ++ IFX_VENDOR_ATTR_MBO_PARAM_COUNTERS, ++ IFX_VENDOR_ATTR_MBO_PARAM_ENABLE, ++ IFX_VENDOR_ATTR_MBO_PARAM_SUB_ELEM_TYPE, ++ IFX_VENDOR_ATTR_MBO_PARAM_BTQ_TRIG_START_OFFSET, ++ IFX_VENDOR_ATTR_MBO_PARAM_BTQ_TRIG_RSSI_DELTA, ++ IFX_VENDOR_ATTR_MBO_PARAM_ANQP_CELL_SUPP, ++ IFX_VENDOR_ATTR_MBO_PARAM_BIT_MASK, ++ IFX_VENDOR_ATTR_MBO_PARAM_ASSOC_DISALLOWED, ++ IFX_VENDOR_ATTR_MBO_PARAM_CELLULAR_DATA_PREF, ++ IFX_VENDOR_ATTR_MBO_PARAM_MAX ++}; ++ + #endif /* IFX_VENDOR_H */ +diff --git a/src/drivers/driver.h b/src/drivers/driver.h +index 23f599b..996614e 100644 +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -2551,10 +2551,55 @@ struct drv_teardown_twt_params { + u8 flow_id; + u8 bcast_twt_id; + u8 teardown_all_twt; + }; + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ ++struct drv_config_mbo_params { ++ u8 cmd; ++ union { ++ struct { ++ u8 op_class; ++ u8 chan; ++ u8 pref_val; ++ u8 reason; ++ } add_chan_pref; ++ struct { ++ u8 op_class; ++ u8 chan; ++ } del_chan_pref; ++ struct { ++ u8 cap; ++ } cell_data_cap; ++ struct { ++ u8 enable; ++ } force_assoc; ++ struct { ++ u8 enable; ++ u8 reason; ++ } bsstrans_reject; ++ struct { ++ u8 type; ++ } send_notif; ++ struct { ++ u8 enable; ++ u8 t_offset; ++ u8 trig_delta; ++ } nbr_info_cache; ++ struct { ++ u8 enable; ++ u8 value; ++ } anqpo_support; ++ struct { ++ u8 disallow; ++ u8 reason; ++ } assoc_disallow; ++ struct { ++ u8 pref_value; ++ } cellular_pref; ++ } u; ++}; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + struct wpa_bss_trans_info { + u8 mbo_transition_reason; + u8 n_candidates; +@@ -4679,10 +4724,11 @@ struct wpa_driver_ops { + * teardown_twt - Teardown the already negotiated TWT session + * @params: Teardown TWT params + */ + int (*teardown_twt)(void *priv, struct drv_teardown_twt_params *params); + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ int (*config_mbo)(void *priv, struct drv_config_mbo_params *params); + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + }; + + /** +diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c +index 3d98e59..506b1e4 100644 +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -12471,10 +12471,150 @@ fail: + nl80211_nlmsg_clear(msg); + nlmsg_free(msg); + return ret; + } + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ ++static int wpa_driver_nl80211_config_mbo(void *priv, struct drv_config_mbo_params *params) ++{ ++ struct i802_bss *bss = priv; ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ struct nl_msg *msg = NULL; ++ struct nlattr *data, *mbo_param_attrs; ++ int ret = -1; ++ ++ if (!drv->ifx_mbo_offload) ++ goto fail; ++ ++ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_IFX) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, IFX_VENDOR_SCMD_MBO)) ++ goto fail; ++ ++ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); ++ if (!data) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_CMD, params->cmd)) ++ goto fail; ++ ++ switch (params->cmd) { ++ case IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_OPCLASS, ++ params->u.add_chan_pref.op_class) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_CHAN, ++ params->u.add_chan_pref.chan) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_PREFERENCE, ++ params->u.add_chan_pref.pref_val) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_REASON_CODE, ++ params->u.add_chan_pref.reason)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_OPCLASS, ++ params->u.del_chan_pref.op_class) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_CHAN, ++ params->u.del_chan_pref.chan)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_CELL_DATA_CAP, ++ params->u.cell_data_cap.cap)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_FORCE_ASSOC: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_ENABLE, ++ params->u.force_assoc.enable)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_FORCE_ASSOC msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_BSSTRANS_REJ: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_ENABLE, ++ params->u.bsstrans_reject.enable) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_REASON_CODE, ++ params->u.bsstrans_reject.reason)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_SEND_NOTIF: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_SUB_ELEM_TYPE, ++ params->u.send_notif.type)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_FORCE_ASSOC msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_LIST_CHAN_PREF: ++ case IFX_MBO_CONFIG_CMD_DUMP_COUNTER: ++ case IFX_MBO_CONFIG_CMD_CLEAR_COUNTER: ++ wpa_printf(MSG_DEBUG, ++ "MBO config: cmd %d doesn't need extra attribute", ++ params->cmd); ++ break; ++ default: ++ break; ++ } ++ ++ nla_nest_end(msg, data); ++ ++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); ++ if (ret) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: Failed to invoke driver " ++ "MBO config function: %s", ++ strerror(-ret)); ++ } ++ ++ return ret; ++fail: ++ nl80211_nlmsg_clear(msg); ++ nlmsg_free(msg); ++ return ret; ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { + .name = "nl80211", + .desc = "Linux nl80211/cfg80211", +@@ -12622,7 +12762,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { + #ifdef CONFIG_DRIVER_NL80211_IFX + #ifdef CONFIG_TWT_OFFLOAD_IFX + .setup_twt = wpa_driver_nl80211_setup_twt, + .teardown_twt = wpa_driver_nl80211_teardown_twt, + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ .config_mbo = wpa_driver_nl80211_config_mbo, + #endif /* CONFIG_DRIVER_NL80211_IFX */ + }; +diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h +index f681afb..6d2c094 100644 +--- a/src/drivers/driver_nl80211.h ++++ b/src/drivers/driver_nl80211.h +@@ -180,10 +180,11 @@ struct wpa_driver_nl80211_data { + unsigned int unsol_bcast_probe_resp:1; + unsigned int qca_do_acs:1; + unsigned int brcm_do_acs:1; + #ifdef CONFIG_DRIVER_NL80211_IFX + unsigned int ifx_twt_offload:1; ++ unsigned int ifx_mbo_offload:1; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + u64 vendor_scan_cookie; + u64 remain_on_chan_cookie; + u64 send_frame_cookie; +diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c +index 19d1569..b0807a7 100644 +--- a/src/drivers/driver_nl80211_capa.c ++++ b/src/drivers/driver_nl80211_capa.c +@@ -1057,10 +1057,13 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) + } else if (vinfo->vendor_id == OUI_IFX) { + switch (vinfo->subcmd) { + case IFX_VENDOR_SCMD_TWT: + drv->ifx_twt_offload = 1; + break; ++ case IFX_VENDOR_SCMD_MBO: ++ drv->ifx_mbo_offload = 1; ++ break; + } + #endif /* CONFIG_DRIVER_NL80211_IFX */ + } + + wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.digi.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.digi.patch new file mode 100644 index 000000000..f54390a51 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.digi.patch @@ -0,0 +1,48 @@ +From cfaf2f6273ddd9ac618c61bc2294fb60297100a7 Mon Sep 17 00:00:00 2001 +From: Jouni Malinen +Date: Wed, 6 Apr 2022 16:13:22 +0300 +Subject: [PATCH 50/60] EAP-TLS: Allow TLSv1.3 support to be enabled with build + config + +The default behavior in wpa_supplicant is to disable use of TLSv1.3 in +EAP-TLS unless explicitly enabled in network configuration. The new +CONFIG_EAP_TLSV1_3=y build parameter can be used to change this to +enable TLSv1.3 by default (if supported by the TLS library). + +Signed-off-by: Jouni Malinen +--- + src/eap_peer/eap_tls_common.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c +index c1837db..5fb8945 100644 +--- a/src/eap_peer/eap_tls_common.c ++++ b/src/eap_peer/eap_tls_common.c +@@ -192,18 +192,20 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, + * TLS v1.3 changes, so disable this by default for now. */ + params->flags |= TLS_CONN_DISABLE_TLSv1_3; + } ++#ifndef EAP_TLSV1_3 + if (data->eap_type == EAP_TYPE_TLS || + data->eap_type == EAP_UNAUTH_TLS_TYPE || + data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) { + /* While the current EAP-TLS implementation is more or less +- * complete for TLS v1.3, there has been no interoperability +- * testing with other implementations, so disable for by default +- * for now until there has been chance to confirm that no +- * significant interoperability issues show up with TLS version +- * update. ++ * complete for TLS v1.3, there has been only minimal ++ * interoperability testing with other implementations, so ++ * disable it by default for now until there has been chance to ++ * confirm that no significant interoperability issues show up ++ * with TLS version update. + */ + params->flags |= TLS_CONN_DISABLE_TLSv1_3; + } ++#endif /* EAP_TLSV1_3 */ + if (phase2 && sm->use_machine_cred) { + wpa_printf(MSG_DEBUG, "TLS: using machine config options"); + eap_tls_params_from_conf2m(params, config); +-- +2.43.0 diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch new file mode 100644 index 000000000..14df86fa1 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch @@ -0,0 +1,31 @@ +From e533a201ebe00eb208509117b3b69b3e58f34633 Mon Sep 17 00:00:00 2001 +From: avishad verma +Date: Tue, 7 Mar 2023 04:44:25 -0600 +Subject: [PATCH 52/60] Disable 4-way handshake offload for DPP + +H1 combo is using internal supplicant and 4-way handshake is offloaded +to firmware for softap mode. +For DPP Softap role external supplicant will be used. + +Signed-off-by: avishad verma +--- + src/ap/wpa_auth_glue.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c +index c8dee2aef..7e3b8384f 100644 +--- a/src/ap/wpa_auth_glue.c ++++ b/src/ap/wpa_auth_glue.c +@@ -1529,6 +1529,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) + !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG); + + if (!hapd->conf->p2p && ++#ifdef CONFIG_DPP ++ (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP)) && ++#endif /* CONFIG_DPP */ + (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) + _conf.psk_4way_hs_offload = 1; + +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.digi.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.digi.patch new file mode 100644 index 000000000..bd1ca6b57 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.digi.patch @@ -0,0 +1,283 @@ +From 54929427eb8af4affaf8017bc8d127cc7c629581 Mon Sep 17 00:00:00 2001 +From: Shelley Yang +Date: Wed, 29 Mar 2023 03:28:59 -0500 +Subject: [PATCH 53/60] non-upstream: WNM: wpa_cli wnm_maxilde command by IFX + vendorID + +1. set +before: wl wnm_maxidle 10 1 +after: wpa_cli wnm_maxidle period=10 option=1 +2. get +before: wl wnm_maxidle +after: wpa_cli wnm_maxidle + +Fixes: SWWLAN-145213 + +Signed-off-by: Shelley Yang +--- + src/common/ifx_vendor.h | 55 ++++++++++++++++++ + src/drivers/driver.h | 7 +++ + src/drivers/driver_nl80211.c | 92 +++++++++++++++++++++++++++++++ + src/drivers/driver_nl80211.h | 1 + + src/drivers/driver_nl80211_capa.c | 3 + + 5 files changed, 158 insertions(+) + +diff --git a/src/common/ifx_vendor.h b/src/common/ifx_vendor.h +index 6cd3b87..2fed69c 100644 +--- a/src/common/ifx_vendor.h ++++ b/src/common/ifx_vendor.h +@@ -76,10 +76,11 @@ enum ifx_nl80211_vendor_subcmds { + IFX_VENDOR_SCMD_LDPC_CAP = 12, + IFX_VENDOR_SCMD_AMSDU = 13, + IFX_VENDOR_SCMD_TWT = 14, + /* Reserved 15-17 */ + IFX_VENDOR_SCMD_MBO = 18, ++ IFX_VENDOR_SCMD_WNM = 25, + IFX_VENDOR_SCMD_MAX + }; + + /* + * enum ifx_vendor_attr - IFX nl80211 vendor attributes +@@ -310,6 +311,60 @@ enum ifx_vendor_attr_mbo_param { + IFX_VENDOR_ATTR_MBO_PARAM_ASSOC_DISALLOWED, + IFX_VENDOR_ATTR_MBO_PARAM_CELLULAR_DATA_PREF, + IFX_VENDOR_ATTR_MBO_PARAM_MAX + }; + ++enum ifx_vendor_attr_wnm { ++ IFX_VENDOR_ATTR_WNM_UNSPEC, ++ IFX_VENDOR_ATTR_WNM_CMD, ++ IFX_VENDOR_ATTR_WNM_PARAMS, ++ IFX_VENDOR_ATTR_WNM_MAX ++}; ++ ++enum ifx_wnm_config_cmd_type { ++ IFX_WNM_CONFIG_CMD_TYPE_INVALID = -1, ++ //align internal definition ++ IFX_WNM_CONFIG_CMD_IOV_WNM = 1, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_MAXIDLE = 2, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TIMBC_OFFSET = 3, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_URL = 4, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_REQ = 5, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_TCLASTYPE = 6, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_PARP_DISCARD = 7, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_PARP_ALLNODE = 8, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TIMBC_SET = 9, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TIMBC_STATUS = 10, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_SET = 11, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_TERM = 12, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_SERVICE_TERM = 13, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_SLEEP_INTV = 14, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_SLEEP_MODE = 15, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_QUERY = 16, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_RESP = 17, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TCLAS_ADD = 18, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TCLAS_DEL = 19, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TCLAS_LIST = 20, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_STATUS = 21, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_KEEPALIVES_MAX_IDLE = 22, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_PM_IGNORE_BCMC = 23, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_DEPENDENCY = 24, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_ROAMTHROTTLE = 25, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_SET = 26, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_TERM = 27, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_STATUS = 28, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BTQ_NBR_ADD = 29, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BTQ_NBR_DEL = 30, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BTQ_NBR_LIST = 31, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_RSSI_RATE_MAP = 32, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_KEEPALIVE_PKT_TYPE = 33, ++ IFX_WNM_CONFIG_CMD_TYPE_MAX ++}; ++ ++enum ifx_vendor_attr_wnm_maxidle_param { ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_UNSPEC, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_GET_INFO, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_MAX ++}; ++ + #endif /* IFX_VENDOR_H */ +diff --git a/src/drivers/driver.h b/src/drivers/driver.h +index 996614e..d75abbd 100644 +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -2596,10 +2596,16 @@ struct drv_config_mbo_params { + struct { + u8 pref_value; + } cellular_pref; + } u; + }; ++ ++struct drv_maxidle_wnm_params { ++ u8 get_info; ++ int period; ++ int protect; ++}; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + struct wpa_bss_trans_info { + u8 mbo_transition_reason; + u8 n_candidates; +@@ -4725,10 +4731,11 @@ struct wpa_driver_ops { + * @params: Teardown TWT params + */ + int (*teardown_twt)(void *priv, struct drv_teardown_twt_params *params); + #endif /* CONFIG_TWT_OFFLOAD_IFX */ + int (*config_mbo)(void *priv, struct drv_config_mbo_params *params); ++ int (*maxidle_wnm)(void *priv, struct drv_maxidle_wnm_params *params); + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + }; + + /** +diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c +index 506b1e4..ed7c969 100644 +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -12611,10 +12611,101 @@ static int wpa_driver_nl80211_config_mbo(void *priv, struct drv_config_mbo_param + fail: + nl80211_nlmsg_clear(msg); + nlmsg_free(msg); + return ret; + } ++ ++static int wpa_driver_nl80211_maxidle_wnm_reply_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ char *buf = arg; ++ char *data; ++ int len; ++ ++ wpa_printf(MSG_INFO, "nl80211: maxidle_wnm command reply handler"); ++ ++ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ if (tb_msg[NL80211_ATTR_VENDOR_DATA]) { ++ data = (char *)((char *)tb_msg[NL80211_ATTR_VENDOR_DATA] + GENL_HDRLEN); ++ len = nla_len(tb_msg[NL80211_ATTR_VENDOR_DATA]); ++ os_memcpy(buf, data, len); ++ } ++ return NL_SKIP; ++} ++ ++static int wpa_driver_nl80211_config_maxidle_wnm(void *priv, struct drv_maxidle_wnm_params *params) ++{ ++ struct i802_bss *bss = priv; ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ struct nl_msg *msg = NULL; ++ struct nlattr *data, *wnm_param_attrs; ++ int ret = -1, get_period = 0; ++ ++ if (!drv->ifx_wnm_offload) ++ goto fail; ++ ++ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_IFX) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, IFX_VENDOR_SCMD_WNM)) ++ goto fail; ++ ++ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); ++ if (!data) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_CMD, IFX_WNM_CONFIG_CMD_IOV_WNM_MAXIDLE)) ++ goto fail; ++ ++ wnm_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_WNM_PARAMS); ++ if (!wnm_param_attrs) ++ goto fail; ++ ++ if (params->get_info) { ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_GET_INFO, ++ params->get_info)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: WNM config: build msg ATTR:%d failed", ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_GET_INFO); ++ goto fail; ++ } ++ } else { ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD, ++ params->period) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT, ++ params->protect)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: WNM config: build ATTR:%d %d failed", ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT); ++ goto fail; ++ } ++ } ++ nla_nest_end(msg, wnm_param_attrs); ++ nla_nest_end(msg, data); ++ ++ if (params->get_info) ++ ret = send_and_recv_msgs(drv, msg, wpa_driver_nl80211_maxidle_wnm_reply_handler, ++ &get_period, NULL, NULL); ++ else ++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); ++ ++ if (ret) ++ wpa_printf(MSG_ERROR, "nl80211: WNM maxidle: Failed to invoke driver %s", ++ strerror(-ret)); ++ else ++ if (params->get_info) ++ params->period = get_period; ++ ++ return ret; ++fail: ++ nl80211_nlmsg_clear(msg); ++ nlmsg_free(msg); ++ return ret; ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { + .name = "nl80211", + .desc = "Linux nl80211/cfg80211", +@@ -12763,7 +12854,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { + #ifdef CONFIG_TWT_OFFLOAD_IFX + .setup_twt = wpa_driver_nl80211_setup_twt, + .teardown_twt = wpa_driver_nl80211_teardown_twt, + #endif /* CONFIG_TWT_OFFLOAD_IFX */ + .config_mbo = wpa_driver_nl80211_config_mbo, ++ .maxidle_wnm = wpa_driver_nl80211_config_maxidle_wnm, + #endif /* CONFIG_DRIVER_NL80211_IFX */ + }; +diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h +index 6d2c094..6d9945c 100644 +--- a/src/drivers/driver_nl80211.h ++++ b/src/drivers/driver_nl80211.h +@@ -181,10 +181,11 @@ struct wpa_driver_nl80211_data { + unsigned int qca_do_acs:1; + unsigned int brcm_do_acs:1; + #ifdef CONFIG_DRIVER_NL80211_IFX + unsigned int ifx_twt_offload:1; + unsigned int ifx_mbo_offload:1; ++ unsigned int ifx_wnm_offload:1; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + u64 vendor_scan_cookie; + u64 remain_on_chan_cookie; + u64 send_frame_cookie; +diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c +index b0807a7..21b9c03 100644 +--- a/src/drivers/driver_nl80211_capa.c ++++ b/src/drivers/driver_nl80211_capa.c +@@ -1060,10 +1060,13 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) + drv->ifx_twt_offload = 1; + break; + case IFX_VENDOR_SCMD_MBO: + drv->ifx_mbo_offload = 1; + break; ++ case IFX_VENDOR_SCMD_WNM: ++ drv->ifx_wnm_offload = 1; ++ break; + } + #endif /* CONFIG_DRIVER_NL80211_IFX */ + } + + wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch new file mode 100644 index 000000000..0e0400b14 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch @@ -0,0 +1,170 @@ +From b3165e0a92a3090a99ef396e77fa90b7e61d6558 Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Wed, 3 May 2023 21:13:26 -0500 +Subject: [PATCH 54/60] brcmfmac: sync content of nl80211_copy.h for BSS_COLOR + attributes + +sync the nl80211.h as of 0d2ab3aea in brcm80211 + +Signed-off-by: Carter Chen +--- + src/drivers/driver_nl80211_event.c | 5 +++ + src/drivers/nl80211_copy.h | 56 ++++++++++++++++++++++++++++-- + 2 files changed, 59 insertions(+), 2 deletions(-) + +diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c +index fe91fff90..d3cb8d882 100644 +--- a/src/drivers/driver_nl80211_event.c ++++ b/src/drivers/driver_nl80211_event.c +@@ -172,6 +172,11 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) + C2S(NL80211_CMD_UNPROT_BEACON) + C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS) + C2S(NL80211_CMD_SET_SAR_SPECS) ++ C2S(NL80211_CMD_OBSS_COLOR_COLLISION) ++ C2S(NL80211_CMD_COLOR_CHANGE_REQUEST) ++ C2S(NL80211_CMD_COLOR_CHANGE_STARTED) ++ C2S(NL80211_CMD_COLOR_CHANGE_ABORTED) ++ C2S(NL80211_CMD_COLOR_CHANGE_COMPLETED) + C2S(__NL80211_CMD_AFTER_LAST) + } + #undef C2S +diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h +index db5b1503d..ee80ae025 100644 +--- a/src/drivers/nl80211_copy.h ++++ b/src/drivers/nl80211_copy.h +@@ -11,7 +11,7 @@ + * Copyright 2008 Jouni Malinen + * Copyright 2008 Colin McCabe + * Copyright 2015-2017 Intel Deutschland GmbH +- * Copyright (C) 2018-2020 Intel Corporation ++ * Copyright (C) 2018-2021 Intel Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -1185,6 +1185,21 @@ + * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to + * specify the wiphy index to be applied to. + * ++ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever ++ * mac80211/drv detects a bss color collision. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that ++ * userspace wants to change the BSS color. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has ++ * started ++ * ++ * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has ++ * been aborted ++ * ++ * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change ++ * has completed ++ * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +@@ -1417,6 +1432,14 @@ enum nl80211_commands { + + NL80211_CMD_SET_SAR_SPECS, + ++ NL80211_CMD_OBSS_COLOR_COLLISION, ++ ++ NL80211_CMD_COLOR_CHANGE_REQUEST, ++ ++ NL80211_CMD_COLOR_CHANGE_STARTED, ++ NL80211_CMD_COLOR_CHANGE_ABORTED, ++ NL80211_CMD_COLOR_CHANGE_COMPLETED, ++ + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ +@@ -2403,7 +2426,10 @@ enum nl80211_commands { + * in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it + * wants to use the supported offload of the 4-way handshake. + * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT. +- * @NL80211_ATTR_PORT_AUTHORIZED: (reserved) ++ * @NL80211_ATTR_PORT_AUTHORIZED: flag attribute used in %NL80211_CMD_ROAMED ++ * notification indicating that that 802.1X authentication was done by ++ * the driver or is not needed (because roaming used the Fast Transition ++ * protocol). + * + * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external + * authentication operation (u32 attribute with an +@@ -2560,6 +2586,16 @@ enum nl80211_commands { + * disassoc events to indicate that an immediate reconnect to the AP + * is desired. + * ++ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the ++ * %NL80211_CMD_OBSS_COLOR_COLLISION event. ++ * ++ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's ++ * until the color switch event. ++ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are ++ * switching to ++ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE ++ * information for the time while performing a color switch. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3057,6 +3093,12 @@ enum nl80211_attrs { + + NL80211_ATTR_DISABLE_HE, + ++ NL80211_ATTR_OBSS_COLOR_BITMAP, ++ ++ NL80211_ATTR_COLOR_CHANGE_COUNT, ++ NL80211_ATTR_COLOR_CHANGE_COLOR, ++ NL80211_ATTR_COLOR_CHANGE_ELEMS, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -3654,6 +3696,8 @@ enum nl80211_mpath_info { + * defined + * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16), + * given for all 6 GHz band channels ++ * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are ++ * advertised on this band/for this iftype (binary) + * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use + */ + enum nl80211_band_iftype_attr { +@@ -3665,6 +3709,7 @@ enum nl80211_band_iftype_attr { + NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, + NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, ++ NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, + + /* keep last */ + __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, +@@ -5950,6 +5995,9 @@ enum nl80211_feature_flags { + * frame protection for all management frames exchanged during the + * negotiation and range measurement procedure. + * ++ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision ++ * detection and change announcemnts. ++ * + * @NUM_NL80211_EXT_FEATURES: number of extended features. + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. + */ +@@ -6914,6 +6962,9 @@ enum nl80211_peer_measurement_ftm_capa { + * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only + * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set. ++ * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the ++ * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED ++ * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set. + * + * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal + * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number +@@ -6933,6 +6984,7 @@ enum nl80211_peer_measurement_ftm_req { + NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, ++ NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, + + /* keep last */ + NUM_NL80211_PMSR_FTM_REQ_ATTR, +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch new file mode 100644 index 000000000..90ac1dd4f --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch @@ -0,0 +1,37 @@ +From 2d7ff191ddcea8740b6fb48094b87de12150c88f Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Wed, 3 May 2023 20:43:09 -0500 +Subject: [PATCH 55/60] WPA3-SAE: enable nl_connect socket while + WPA_DRIVER_FLAGS_BSS_SELECTION + +The driver-base roaming uses WPA_DRIVER_FLAGS_BSS_SELECTION flag. + +As the SAE is handled by wpa_supplicant, +the driver will report send_req of auth req frame. + +WPA3-CERT 5.8.3 connects to PSK AP first, then roaming to SAE AP. +the nl_connect needs to keep opening to listen the event for process +auth frames. + +Fixes: SWLINUX-3420 + +Signed-off-by: Carter Chen +--- + src/drivers/driver_nl80211.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c +index ed7c969c1..55b4d07dc 100644 +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -557,6 +557,7 @@ send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv, + struct nl_sock * get_connect_handle(struct i802_bss *bss) + { + if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) || ++ (bss->drv->capa.flags & WPA_DRIVER_FLAGS_BSS_SELECTION) || + bss->use_nl_connect) + return bss->nl_connect; + +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch new file mode 100644 index 000000000..b7e0c451f --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch @@ -0,0 +1,31 @@ +From 8a905fcddca5936ba8873c7f0dacab7188dc6eac Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Mon, 17 Jul 2023 22:31:46 -0500 +Subject: [PATCH 56/60] OWE AP: enable OWE compile option for hostapd executing + OWE + +Enabling OWE compile option + +Fixes: SWLINUX-3620 + +Signed-off-by: Carter Chen +--- + hostapd/defconfig_base | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hostapd/defconfig_base b/hostapd/defconfig_base +index 16e8c645a..571ab6eda 100644 +--- a/hostapd/defconfig_base ++++ b/hostapd/defconfig_base +@@ -374,7 +374,7 @@ CONFIG_WPA_CLI_EDIT=y + + # Opportunistic Wireless Encryption (OWE) + # Experimental implementation of draft-harkins-owe-07.txt +-#CONFIG_OWE=y ++CONFIG_OWE=y + + # Airtime policy support + #CONFIG_AIRTIME_POLICY=y +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch new file mode 100644 index 000000000..dc1d7eecf --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch @@ -0,0 +1,232 @@ +From 8a6154044994dbeac362d76bbe5822612af64067 Mon Sep 17 00:00:00 2001 +From: "Lin Ian (IFTW CSS ICW SW WFS 1)" +Date: Mon, 16 Oct 2023 09:18:19 +0000 +Subject: [PATCH 57/60] DPP2.0: support DPP2.0 and add pfs init flow on + EVENT_UPDATE_DH + +--- + hostapd/defconfig_base | 1 + + src/ap/drv_callbacks.c | 55 ++++++++++++++++----------- + src/ap/ieee802_11.c | 70 ++++++++++++++++++++++++++++++++++- + src/ap/ieee802_11.h | 3 ++ + wpa_supplicant/defconfig_base | 1 + + 5 files changed, 107 insertions(+), 23 deletions(-) + +diff --git a/hostapd/defconfig_base b/hostapd/defconfig_base +index 571ab6eda..eae36af0b 100644 +--- a/hostapd/defconfig_base ++++ b/hostapd/defconfig_base +@@ -406,3 +406,4 @@ CONFIG_WPA3_SAE_AUTH_EARLY_SET=y + + # Device Provisioning Protocol (DPP) + CONFIG_DPP=y ++CONFIG_DPP2=y +diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c +index a50e6f2af..989ba735d 100644 +--- a/src/ap/drv_callbacks.c ++++ b/src/ap/drv_callbacks.c +@@ -648,13 +648,12 @@ skip_wpa_check: + #endif /* CONFIG_OWE */ + + #ifdef CONFIG_DPP2 +- dpp_pfs_free(sta->dpp_pfs); +- sta->dpp_pfs = NULL; ++ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && ++ hapd->conf->dpp_netaccesskey && sta->wpa_sm && ++ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && ++ elems.owe_dh) { + +- if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && +- hapd->conf->dpp_netaccesskey && sta->wpa_sm && +- wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && +- elems.owe_dh) { ++ if (!sta->dpp_pfs) { + sta->dpp_pfs = dpp_pfs_init( + wpabuf_head(hapd->conf->dpp_netaccesskey), + wpabuf_len(hapd->conf->dpp_netaccesskey)); +@@ -664,19 +663,20 @@ skip_wpa_check: + /* Try to continue without PFS */ + goto pfs_fail; + } ++ } + +- if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, +- elems.owe_dh_len) < 0) { +- dpp_pfs_free(sta->dpp_pfs); +- sta->dpp_pfs = NULL; +- reason = WLAN_REASON_UNSPECIFIED; +- goto fail; +- } ++ if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, ++ elems.owe_dh_len) < 0) { ++ dpp_pfs_free(sta->dpp_pfs); ++ sta->dpp_pfs = NULL; ++ reason = WLAN_REASON_UNSPECIFIED; ++ goto fail; + } ++ } + +- wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? +- sta->dpp_pfs->secret : NULL); +- pfs_fail: ++ wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? ++ sta->dpp_pfs->secret : NULL); ++pfs_fail: + #endif /* CONFIG_DPP2 */ + + if (elems.rrm_enabled && +@@ -1792,8 +1792,9 @@ static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, + wpa_printf(MSG_DEBUG, "OWE: Peer unknown"); + return -1; + } +- if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) { +- wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured"); ++ if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && ++ !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP)) { ++ wpa_printf(MSG_DEBUG, "OWE/DPP: No OWE/DPP AKM configured"); + status = WLAN_STATUS_AKMP_NOT_VALID; + goto err; + } +@@ -1828,9 +1829,21 @@ static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, + } + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); + +- status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, +- elems.rsn_ie_len, elems.owe_dh, +- elems.owe_dh_len); ++#ifdef CONFIG_DPP2 ++ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) { ++ if (hapd->conf->dpp_netaccesskey && elems.owe_dh) ++ status = dpp_process_rsn_ie(hapd, sta, elems.rsn_ie, ++ elems.rsn_ie_len, elems.owe_dh, ++ elems.owe_dh_len); ++ else ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ } else ++#endif /* CONFIG_DPP2 */ ++ { ++ status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, ++ elems.rsn_ie_len, elems.owe_dh, ++ elems.owe_dh_len); ++ } + if (status != WLAN_STATUS_SUCCESS) + ap_free_sta(hapd, sta); + +diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c +index c4f7d00cc..564815381 100644 +--- a/src/ap/ieee802_11.c ++++ b/src/ap/ieee802_11.c +@@ -4348,9 +4348,10 @@ u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, + wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len); + return wpa_res_to_status_code(res); + } +- if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) { ++ if (!(data.key_mgmt & WPA_KEY_MGMT_OWE) && ++ !(data.key_mgmt & WPA_KEY_MGMT_DPP)) { + wpa_printf(MSG_DEBUG, +- "OWE: Unexpected key mgmt 0x%x from " MACSTR, ++ "OWE/DPP: Unexpected key mgmt 0x%x from " MACSTR, + (unsigned int) data.key_mgmt, MAC2STR(peer)); + return WLAN_STATUS_AKMP_NOT_VALID; + } +@@ -4444,6 +4445,71 @@ end: + + #endif /* CONFIG_OWE */ + ++#ifdef CONFIG_DPP2 ++u16 dpp_process_rsn_ie(struct hostapd_data *hapd, ++ struct sta_info *sta, ++ const u8 *rsn_ie, size_t rsn_ie_len, ++ const u8 *owe_dh, size_t owe_dh_len) ++{ ++ u16 status = WLAN_STATUS_SUCCESS; ++ u8 *owe_buf, ie[256 * 2]; ++ size_t ie_len = 0; ++ enum wpa_validate_result res; ++ ++ if (!rsn_ie || rsn_ie_len < 2) { ++ wpa_printf(MSG_DEBUG, "DPP: No RSNE in (Re)AssocReq"); ++ status = WLAN_STATUS_INVALID_IE; ++ goto end; ++ } ++ ++ if (!sta->wpa_sm) ++ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, ++ NULL); ++ if (!sta->wpa_sm) { ++ wpa_printf(MSG_WARNING, ++ "DPP: Failed to initialize WPA state machine"); ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ goto end; ++ } ++ rsn_ie -= 2; ++ rsn_ie_len += 2; ++ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ++ hapd->iface->freq, rsn_ie, rsn_ie_len, ++ NULL, 0, NULL, 0, owe_dh, owe_dh_len); ++ status = wpa_res_to_status_code(res); ++ if (status != WLAN_STATUS_SUCCESS) ++ goto end; ++ ++ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie), ++ NULL, 0); ++ if (!owe_buf) { ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ goto end; ++ } ++ ++ dpp_pfs_free(sta->dpp_pfs); ++ sta->dpp_pfs = NULL; ++ sta->dpp_pfs = dpp_pfs_init( ++ wpabuf_head(hapd->conf->dpp_netaccesskey), ++ wpabuf_len(hapd->conf->dpp_netaccesskey)); ++ ++ if (!sta->dpp_pfs) { ++ wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS"); ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ } else { ++ os_memcpy(owe_buf, wpabuf_head(sta->dpp_pfs->ie), wpabuf_len(sta->dpp_pfs->ie)); ++ ie_len = owe_buf - ie + wpabuf_len(sta->dpp_pfs->ie); ++ } ++end: ++ wpa_printf(MSG_DEBUG, "DPP: Update status %d, ie len %d for peer " ++ MACSTR, status, (unsigned int) ie_len, ++ MAC2STR(sta->addr)); ++ hostapd_drv_update_dh_ie(hapd, sta->addr, status, ++ status == WLAN_STATUS_SUCCESS ? ie : NULL, ++ ie_len); ++ return status; ++} ++#endif /* CONFIG_DPP2 */ + + static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta, + int reassoc) +diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h +index c59ad5e38..3042b6bac 100644 +--- a/src/ap/ieee802_11.h ++++ b/src/ap/ieee802_11.h +@@ -171,6 +171,9 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, + u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *rsn_ie, size_t rsn_ie_len, + const u8 *owe_dh, size_t owe_dh_len); ++u16 dpp_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta, ++ const u8 *rsn_ie, size_t rsn_ie_len, ++ const u8 *owe_dh, size_t owe_dh_len); + u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, + const u8 *rsn_ie, size_t rsn_ie_len, + const u8 *owe_dh, size_t owe_dh_len); +diff --git a/wpa_supplicant/defconfig_base b/wpa_supplicant/defconfig_base +index 59aeae69c..f34011d84 100644 +--- a/wpa_supplicant/defconfig_base ++++ b/wpa_supplicant/defconfig_base +@@ -617,6 +617,7 @@ CONFIG_OWE=y + + # Device Provisioning Protocol (DPP) + CONFIG_DPP=y ++CONFIG_DPP2=y + + # Wired equivalent privacy (WEP) + # WEP is an obsolete cryptographic data confidentiality algorithm that is not +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch new file mode 100644 index 000000000..3928c2cae --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch @@ -0,0 +1,31 @@ +From d449e4402e4981b8c5067aaab1db34cd73e40468 Mon Sep 17 00:00:00 2001 +From: "P Rakshith (CAE 1 A)" +Date: Fri, 20 Oct 2023 08:34:04 +0000 +Subject: [PATCH 58/60] non-upstream: Prevent invalid akm key mgmt when MFP + required is set + +--- + src/ap/ap_config.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c +index 86b6e097c..a7fd85018 100644 +--- a/src/ap/ap_config.c ++++ b/src/ap/ap_config.c +@@ -1432,6 +1432,13 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, + } + #endif /* CONFIG_FILS */ + ++ if (full_config && (bss->ieee80211w == 2) && ++ (bss->wpa_key_mgmt == (WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_PSK))) { ++ wpa_printf(MSG_ERROR, ++ "Cannot set ieee80211w=2 along with with the selected wpa_key_mgmt"); ++ return -1; ++ } ++ + return 0; + } + +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0059-Reset-authentication-and-encryption-parameters-while.digi.patch b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0059-Reset-authentication-and-encryption-parameters-while.digi.patch new file mode 100644 index 000000000..1338294e7 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd/murata/0059-Reset-authentication-and-encryption-parameters-while.digi.patch @@ -0,0 +1,49 @@ +From 10a78d57f331333da8aba9be83f6cafbb7a6f382 Mon Sep 17 00:00:00 2001 +From: Ian Lin +Date: Sun, 22 Oct 2023 21:19:08 -0500 +Subject: [PATCH 59/60] Reset authentication and encryption parameters while + handling roam event + +While supplicant received NL80211_CMD_ROAM event and run EVENT_ASSOC flow, +it will not reset sm->pmk in wpa_supplicant_select_config since old and new SSID are the same. +It causes using wrong pmk when roaming from WPA3 to WPA2. +So add the flow to only reset sm->pmk while handling roam event. + +Signed-off-by: Ian Lin +--- + src/drivers/driver.h | 6 ++++++ + src/drivers/driver_nl80211_event.c | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/src/drivers/driver.h b/src/drivers/driver.h +index d75abbd..9ebb4b0 100644 +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -5546,6 +5546,12 @@ union wpa_event_data { + * fils_pmkid - PMKID used or generated in FILS authentication + */ + const u8 *fils_pmkid; ++ ++ /** ++ * roam_indication - Indicate it's a roam event ++ */ ++ bool roam_indication; ++ + } assoc_info; + + /** +diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c +index d3cb8d8..6ff7479 100644 +--- a/src/drivers/driver_nl80211_event.c ++++ b/src/drivers/driver_nl80211_event.c +@@ -542,6 +542,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, + wpa_ssid_txt(drv->ssid, + drv->ssid_len)); + } ++ event.assoc_info.roam_indication = 1; + } + } + if (resp_ie) { +-- +2.43.0 + diff --git a/meta-digi-dey/recipes-connectivity/hostapd/hostapd_%.bbappend b/meta-digi-dey/recipes-connectivity/hostapd/hostapd_%.bbappend index f3609e60c..fce26a58f 100644 --- a/meta-digi-dey/recipes-connectivity/hostapd/hostapd_%.bbappend +++ b/meta-digi-dey/recipes-connectivity/hostapd/hostapd_%.bbappend @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2023 Digi International. +# Copyright (C) 2016-2024 Digi International Inc. FILESEXTRAPATHS:prepend := "${THISDIR}/${BPN}:" @@ -48,7 +48,17 @@ MURATA_COMMON_PATCHES = " \ file://murata/0041-add-support-to-offload-TWT-setup-request-handling-to.murata.patch \ file://murata/0042-add-support-to-offload-TWT-Teardown-request-handling.murata.patch \ file://murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.murata.patch \ - file://murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch \ + file://murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch \ + file://murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.digi.patch \ + file://murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.digi.patch \ + file://murata/0052-Disable-4-way-handshake-offload-for-DPP.patch \ + file://murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.digi.patch \ + file://murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch \ + file://murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch \ + file://murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch \ + file://murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch \ + file://murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch \ + file://murata/0059-Reset-authentication-and-encryption-parameters-while.digi.patch \ " SRC_URI:append:ccmp1 = " ${MURATA_COMMON_PATCHES}" diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/ccmp1/defconfig b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/ccmp1/defconfig new file mode 100644 index 000000000..aede2dcab --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/ccmp1/defconfig @@ -0,0 +1,655 @@ +# Example wpa_supplicant build time configuration +# +# This file lists the configuration options that are used when building the +# wpa_supplicant binary. All lines starting with # are ignored. Configuration +# option lines must be commented out complete, if they are not to be included, +# i.e., just setting VARIABLE=n is not disabling that variable. +# +# This file is included in Makefile, so variables like CFLAGS and LIBS can also +# be modified from here. In most cases, these lines should use += in order not +# to override previous values of the variables. + + +# Uncomment following two lines and fix the paths if you have installed OpenSSL +# or GnuTLS in non-default location +#CFLAGS += -I/usr/local/openssl/include +#LIBS += -L/usr/local/openssl/lib + +# Some Red Hat versions seem to include kerberos header files from OpenSSL, but +# the kerberos files are not in the default include path. Following line can be +# used to fix build issues on such systems (krb5.h not found). +#CFLAGS += -I/usr/include/kerberos + +# Driver interface for generic Linux wireless extensions +# Note: WEXT is deprecated in the current Linux kernel version and no new +# functionality is added to it. nl80211-based interface is the new +# replacement for WEXT and its use allows wpa_supplicant to properly control +# the driver to improve existing functionality like roaming and to support new +# functionality. +CONFIG_DRIVER_WEXT=y + +# Driver interface for Linux drivers using the nl80211 kernel interface +CONFIG_DRIVER_NL80211=y + +# QCA vendor extensions to nl80211 +#CONFIG_DRIVER_NL80211_QCA=y + +# Support Broadcom driver private wl command +CONFIG_DRIVER_BRCM_WL=y + +# driver_nl80211.c requires libnl. If you are compiling it yourself +# you may need to point hostapd to your version of libnl. +# +#CFLAGS += -I$ +#LIBS += -L$ + +# Use libnl v2.0 (or 3.0) libraries. +#CONFIG_LIBNL20=y + +# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) +CONFIG_LIBNL32=y + + +# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) +#CONFIG_DRIVER_BSD=y +#CFLAGS += -I/usr/local/include +#LIBS += -L/usr/local/lib +#LIBS_p += -L/usr/local/lib +#LIBS_c += -L/usr/local/lib + +# Driver interface for Windows NDIS +#CONFIG_DRIVER_NDIS=y +#CFLAGS += -I/usr/include/w32api/ddk +#LIBS += -L/usr/local/lib +# For native build using mingw +#CONFIG_NATIVE_WINDOWS=y +# Additional directories for cross-compilation on Linux host for mingw target +#CFLAGS += -I/opt/mingw/mingw32/include/ddk +#LIBS += -L/opt/mingw/mingw32/lib +#CC=mingw32-gcc +# By default, driver_ndis uses WinPcap for low-level operations. This can be +# replaced with the following option which replaces WinPcap calls with NDISUIO. +# However, this requires that WZC is disabled (net stop wzcsvc) before starting +# wpa_supplicant. +# CONFIG_USE_NDISUIO=y + +# Driver interface for wired Ethernet drivers +#CONFIG_DRIVER_WIRED=y + +# Driver interface for MACsec capable Qualcomm Atheros drivers +#CONFIG_DRIVER_MACSEC_QCA=y + +# Driver interface for Linux MACsec drivers +#CONFIG_DRIVER_MACSEC_LINUX=y + +# Driver interface for the Broadcom RoboSwitch family +#CONFIG_DRIVER_ROBOSWITCH=y + +# Driver interface for no driver (e.g., WPS ER only) +#CONFIG_DRIVER_NONE=y + +# Solaris libraries +#LIBS += -lsocket -ldlpi -lnsl +#LIBS_c += -lsocket + +# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or +# MACsec is included) +CONFIG_IEEE8021X_EAPOL=y + +# EAP-MD5 +CONFIG_EAP_MD5=y + +# EAP-MSCHAPv2 +CONFIG_EAP_MSCHAPV2=y + +# EAP-TLS +CONFIG_EAP_TLS=y +# Enable EAP-TLSv1.3 support by default (currently disabled unless explicitly +# enabled in network configuration) +CONFIG_EAP_TLSV1_3=y + +# EAL-PEAP +CONFIG_EAP_PEAP=y + +# EAP-TTLS +CONFIG_EAP_TTLS=y + +# EAP-FAST +CONFIG_EAP_FAST=y + +# EAP-TEAP +# Note: The current EAP-TEAP implementation is experimental and should not be +# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number +# of conflicting statements and missing details and the implementation has +# vendor specific workarounds for those and as such, may not interoperate with +# any other implementation. This should not be used for anything else than +# experimentation and interoperability testing until those issues has been +# resolved. +#CONFIG_EAP_TEAP=y + +# EAP-GTC +CONFIG_EAP_GTC=y + +# EAP-OTP +CONFIG_EAP_OTP=y + +# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used) +CONFIG_EAP_SIM=y + +# Enable SIM simulator (Milenage) for EAP-SIM +#CONFIG_SIM_SIMULATOR=y + +# EAP-PSK (experimental; this is _not_ needed for WPA-PSK) +CONFIG_EAP_PSK=y + +# EAP-pwd (secure authentication using only a password) +#CONFIG_EAP_PWD=y + +# EAP-PAX +#CONFIG_EAP_PAX=y + +# LEAP +CONFIG_EAP_LEAP=y + +# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used) +#CONFIG_EAP_AKA=y + +# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). +# This requires CONFIG_EAP_AKA to be enabled, too. +#CONFIG_EAP_AKA_PRIME=y + +# Enable USIM simulator (Milenage) for EAP-AKA +#CONFIG_USIM_SIMULATOR=y + +# EAP-SAKE +#CONFIG_EAP_SAKE=y + +# EAP-GPSK +#CONFIG_EAP_GPSK=y +# Include support for optional SHA256 cipher suite in EAP-GPSK +#CONFIG_EAP_GPSK_SHA256=y + +# EAP-TNC and related Trusted Network Connect support (experimental) +#CONFIG_EAP_TNC=y + +# Wi-Fi Protected Setup (WPS) +CONFIG_WPS=y +# Enable WPS external registrar functionality +#CONFIG_WPS_ER=y +# Disable credentials for an open network by default when acting as a WPS +# registrar. +#CONFIG_WPS_REG_DISABLE_OPEN=y +# Enable WPS support with NFC config method +#CONFIG_WPS_NFC=y + +# EAP-IKEv2 +#CONFIG_EAP_IKEV2=y + +# EAP-EKE +#CONFIG_EAP_EKE=y + +# MACsec +#CONFIG_MACSEC=y + +# PKCS#12 (PFX) support (used to read private key and certificate file from +# a file that usually has extension .p12 or .pfx) +CONFIG_PKCS12=y + +# Smartcard support (i.e., private key on a smartcard), e.g., with openssl +# engine. +CONFIG_SMARTCARD=y + +# PC/SC interface for smartcards (USIM, GSM SIM) +# Enable this if EAP-SIM or EAP-AKA is included +#CONFIG_PCSC=y + +# Support HT overrides (disable HT/HT40, mask MCS rates, etc.) +#CONFIG_HT_OVERRIDES=y + +# Support VHT overrides (disable VHT, mask MCS rates, etc.) +#CONFIG_VHT_OVERRIDES=y + +# Development testing +#CONFIG_EAPOL_TEST=y + +# Select control interface backend for external programs, e.g, wpa_cli: +# unix = UNIX domain sockets (default for Linux/*BSD) +# udp = UDP sockets using localhost (127.0.0.1) +# udp6 = UDP IPv6 sockets using localhost (::1) +# named_pipe = Windows Named Pipe (default for Windows) +# udp-remote = UDP sockets with remote access (only for tests systems/purpose) +# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose) +# y = use default (backwards compatibility) +# If this option is commented out, control interface is not included in the +# build. +CONFIG_CTRL_IFACE=y + +# Include support for GNU Readline and History Libraries in wpa_cli. +# When building a wpa_cli binary for distribution, please note that these +# libraries are licensed under GPL and as such, BSD license may not apply for +# the resulting binary. +#CONFIG_READLINE=y + +# Include internal line edit mode in wpa_cli. This can be used as a replacement +# for GNU Readline to provide limited command line editing and history support. +CONFIG_WPA_CLI_EDIT=y + +# Remove debugging code that is printing out debug message to stdout. +# This can be used to reduce the size of the wpa_supplicant considerably +# if debugging code is not needed. The size reduction can be around 35% +# (e.g., 90 kB). +#CONFIG_NO_STDOUT_DEBUG=y + +# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save +# 35-50 kB in code size. +#CONFIG_NO_WPA=y + +# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support +# This option can be used to reduce code size by removing support for +# converting ASCII passphrases into PSK. If this functionality is removed, the +# PSK can only be configured as the 64-octet hexstring (e.g., from +# wpa_passphrase). This saves about 0.5 kB in code size. +#CONFIG_NO_WPA_PASSPHRASE=y + +# Simultaneous Authentication of Equals (SAE), WPA3-Personal +CONFIG_SAE=y + +# Enable WPA3-Enterprise Suite-B 192 support +CONFIG_SUITEB=y +CONFIG_SUITEB192=y + +# Set SAE Auth status early +CONFIG_WPA3_SAE_AUTH_EARLY_SET=y + +# Disable scan result processing (ap_scan=1) to save code size by about 1 kB. +# This can be used if ap_scan=1 mode is never enabled. +#CONFIG_NO_SCAN_PROCESSING=y + +# Select configuration backend: +# file = text file (e.g., wpa_supplicant.conf; note: the configuration file +# path is given on command line, not here; this option is just used to +# select the backend that allows configuration files to be used) +# winreg = Windows registry (see win_example.reg for an example) +CONFIG_BACKEND=file + +# Remove configuration write functionality (i.e., to allow the configuration +# file to be updated based on runtime configuration changes). The runtime +# configuration can still be changed, the changes are just not going to be +# persistent over restarts. This option can be used to reduce code size by +# about 3.5 kB. +#CONFIG_NO_CONFIG_WRITE=y + +# Remove support for configuration blobs to reduce code size by about 1.5 kB. +#CONFIG_NO_CONFIG_BLOBS=y + +# Select program entry point implementation: +# main = UNIX/POSIX like main() function (default) +# main_winsvc = Windows service (read parameters from registry) +# main_none = Very basic example (development use only) +#CONFIG_MAIN=main + +# Select wrapper for operating system and C library specific functions +# unix = UNIX/POSIX like systems (default) +# win32 = Windows systems +# none = Empty template +#CONFIG_OS=unix + +# Select event loop implementation +# eloop = select() loop (default) +# eloop_win = Windows events and WaitForMultipleObject() loop +#CONFIG_ELOOP=eloop + +# Should we use poll instead of select? Select is used by default. +#CONFIG_ELOOP_POLL=y + +# Should we use epoll instead of select? Select is used by default. +#CONFIG_ELOOP_EPOLL=y + +# Should we use kqueue instead of select? Select is used by default. +#CONFIG_ELOOP_KQUEUE=y + +# Select layer 2 packet implementation +# linux = Linux packet socket (default) +# pcap = libpcap/libdnet/WinPcap +# freebsd = FreeBSD libpcap +# winpcap = WinPcap with receive thread +# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y) +# none = Empty template +#CONFIG_L2_PACKET=linux + +# Disable Linux packet socket workaround applicable for station interface +# in a bridge for EAPOL frames. This should be uncommented only if the kernel +# is known to not have the regression issue in packet socket behavior with +# bridge interfaces (commit 'bridge: respect RFC2863 operational state')'). +#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y + +# Support Operating Channel Validation +#CONFIG_OCV=y + +# Select TLS implementation +# openssl = OpenSSL (default) +# gnutls = GnuTLS +# internal = Internal TLSv1 implementation (experimental) +# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental) +# none = Empty template +#CONFIG_TLS=openssl + +# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1) +# can be enabled to get a stronger construction of messages when block ciphers +# are used. It should be noted that some existing TLS v1.0 -based +# implementation may not be compatible with TLS v1.1 message (ClientHello is +# sent prior to negotiating which version will be used) +#CONFIG_TLSV11=y + +# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2) +# can be enabled to enable use of stronger crypto algorithms. It should be +# noted that some existing TLS v1.0 -based implementation may not be compatible +# with TLS v1.2 message (ClientHello is sent prior to negotiating which version +# will be used) +#CONFIG_TLSV12=y + +# Select which ciphers to use by default with OpenSSL if the user does not +# specify them. +#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW" + +# If CONFIG_TLS=internal is used, additional library and include paths are +# needed for LibTomMath. Alternatively, an integrated, minimal version of +# LibTomMath can be used. See beginning of libtommath.c for details on benefits +# and drawbacks of this option. +#CONFIG_INTERNAL_LIBTOMMATH=y +#ifndef CONFIG_INTERNAL_LIBTOMMATH +#LTM_PATH=/usr/src/libtommath-0.39 +#CFLAGS += -I$(LTM_PATH) +#LIBS += -L$(LTM_PATH) +#LIBS_p += -L$(LTM_PATH) +#endif +# At the cost of about 4 kB of additional binary size, the internal LibTomMath +# can be configured to include faster routines for exptmod, sqr, and div to +# speed up DH and RSA calculation considerably +#CONFIG_INTERNAL_LIBTOMMATH_FAST=y + +# Include NDIS event processing through WMI into wpa_supplicant/wpasvc. +# This is only for Windows builds and requires WMI-related header files and +# WbemUuid.Lib from Platform SDK even when building with MinGW. +#CONFIG_NDIS_EVENTS_INTEGRATED=y +#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" + +# Add support for new DBus control interface +# (fi.w1.wpa_supplicant1) +CONFIG_CTRL_IFACE_DBUS_NEW=y + +# Add introspection support for new DBus control interface +#CONFIG_CTRL_IFACE_DBUS_INTRO=y + +# Add support for loading EAP methods dynamically as shared libraries. +# When this option is enabled, each EAP method can be either included +# statically (CONFIG_EAP_=y) or dynamically (CONFIG_EAP_=dyn). +# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to +# be loaded in the beginning of the wpa_supplicant configuration file +# (see load_dynamic_eap parameter in the example file) before being used in +# the network blocks. +# +# Note that some shared parts of EAP methods are included in the main program +# and in order to be able to use dynamic EAP methods using these parts, the +# main program must have been build with the EAP method enabled (=y or =dyn). +# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries +# unless at least one of them was included in the main build to force inclusion +# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included +# in the main build to be able to load these methods dynamically. +# +# Please also note that using dynamic libraries will increase the total binary +# size. Thus, it may not be the best option for targets that have limited +# amount of memory/flash. +#CONFIG_DYNAMIC_EAP_METHODS=y + +# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode +CONFIG_IEEE80211R=y + +# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) +#CONFIG_DEBUG_FILE=y + +# Send debug messages to syslog instead of stdout +#CONFIG_DEBUG_SYSLOG=y +# Set syslog facility for debug messages +#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON + +# Add support for sending all debug messages (regardless of debug verbosity) +# to the Linux kernel tracing facility. This helps debug the entire stack by +# making it easy to record everything happening from the driver up into the +# same file, e.g., using trace-cmd. +#CONFIG_DEBUG_LINUX_TRACING=y + +# Add support for writing debug log to Android logcat instead of standard +# output +#CONFIG_ANDROID_LOG=y + +# Enable privilege separation (see README 'Privilege separation' for details) +#CONFIG_PRIVSEP=y + +# Enable mitigation against certain attacks against TKIP by delaying Michael +# MIC error reports by a random amount of time between 0 and 60 seconds +#CONFIG_DELAYED_MIC_ERROR_REPORT=y + +# Enable tracing code for developer debugging +# This tracks use of memory allocations and other registrations and reports +# incorrect use with a backtrace of call (or allocation) location. +#CONFIG_WPA_TRACE=y +# For BSD, uncomment these. +#LIBS += -lexecinfo +#LIBS_p += -lexecinfo +#LIBS_c += -lexecinfo + +# Use libbfd to get more details for developer debugging +# This enables use of libbfd to get more detailed symbols for the backtraces +# generated by CONFIG_WPA_TRACE=y. +#CONFIG_WPA_TRACE_BFD=y +# For BSD, uncomment these. +#LIBS += -lbfd -liberty -lz +#LIBS_p += -lbfd -liberty -lz +#LIBS_c += -lbfd -liberty -lz + +# wpa_supplicant depends on strong random number generation being available +# from the operating system. os_get_random() function is used to fetch random +# data when needed, e.g., for key generation. On Linux and BSD systems, this +# works by reading /dev/urandom. It should be noted that the OS entropy pool +# needs to be properly initialized before wpa_supplicant is started. This is +# important especially on embedded devices that do not have a hardware random +# number generator and may by default start up with minimal entropy available +# for random number generation. +# +# As a safety net, wpa_supplicant is by default trying to internally collect +# additional entropy for generating random data to mix in with the data fetched +# from the OS. This by itself is not considered to be very strong, but it may +# help in cases where the system pool is not initialized properly. However, it +# is very strongly recommended that the system pool is initialized with enough +# entropy either by using hardware assisted random number generator or by +# storing state over device reboots. +# +# wpa_supplicant can be configured to maintain its own entropy store over +# restarts to enhance random number generation. This is not perfect, but it is +# much more secure than using the same sequence of random numbers after every +# reboot. This can be enabled with -e command line option. The +# specified file needs to be readable and writable by wpa_supplicant. +# +# If the os_get_random() is known to provide strong random data (e.g., on +# Linux/BSD, the board in question is known to have reliable source of random +# data from /dev/urandom), the internal wpa_supplicant random pool can be +# disabled. This will save some in binary size and CPU use. However, this +# should only be considered for builds that are known to be used on devices +# that meet the requirements described above. +#CONFIG_NO_RANDOM_POOL=y + +# Should we attempt to use the getrandom(2) call that provides more reliable +# yet secure randomness source than /dev/random on Linux 3.17 and newer. +# Requires glibc 2.25 to build, falls back to /dev/random if unavailable. +#CONFIG_GETRANDOM=y + +# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) +CONFIG_IEEE80211AC=y + +# Wireless Network Management (IEEE Std 802.11v-2011) +# Note: This is experimental and not complete implementation. +#CONFIG_WNM=y + +# Interworking (IEEE 802.11u) +# This can be used to enable functionality to improve interworking with +# external networks (GAS/ANQP to learn more about the networks and network +# selection based on available credentials). +#CONFIG_INTERWORKING=y + +# Hotspot 2.0 +CONFIG_HS20=y + +# Enable interface matching in wpa_supplicant +#CONFIG_MATCH_IFACE=y + +# Disable roaming in wpa_supplicant +#CONFIG_NO_ROAMING=y + +# AP mode operations with wpa_supplicant +# This can be used for controlling AP mode operations with wpa_supplicant. It +# should be noted that this is mainly aimed at simple cases like +# WPA2-Personal while more complex configurations like WPA2-Enterprise with an +# external RADIUS server can be supported with hostapd. +CONFIG_AP=y + +# P2P (Wi-Fi Direct) +# This can be used to enable P2P support in wpa_supplicant. See README-P2P for +# more information on P2P operations. +CONFIG_P2P=y + +# Enable TDLS support +#CONFIG_TDLS=y + +# Wi-Fi Display +# This can be used to enable Wi-Fi Display extensions for P2P using an external +# program to control the additional information exchanges in the messages. +#CONFIG_WIFI_DISPLAY=y + +# Autoscan +# This can be used to enable automatic scan support in wpa_supplicant. +# See wpa_supplicant.conf for more information on autoscan usage. +# +# Enabling directly a module will enable autoscan support. +# For exponential module: +#CONFIG_AUTOSCAN_EXPONENTIAL=y +# For periodic module: +#CONFIG_AUTOSCAN_PERIODIC=y + +# Password (and passphrase, etc.) backend for external storage +# These optional mechanisms can be used to add support for storing passwords +# and other secrets in external (to wpa_supplicant) location. This allows, for +# example, operating system specific key storage to be used +# +# External password backend for testing purposes (developer use) +#CONFIG_EXT_PASSWORD_TEST=y +# File-based backend to read passwords from an external file. +#CONFIG_EXT_PASSWORD_FILE=y + +# Enable Fast Session Transfer (FST) +#CONFIG_FST=y + +# Enable CLI commands for FST testing +#CONFIG_FST_TEST=y + +# OS X builds. This is only for building eapol_test. +#CONFIG_OSX=y + +# Automatic Channel Selection +# This will allow wpa_supplicant to pick the channel automatically when channel +# is set to "0". +# +# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative +# to "channel=0". This would enable us to eventually add other ACS algorithms in +# similar way. +# +# Automatic selection is currently only done through initialization, later on +# we hope to do background checks to keep us moving to more ideal channels as +# time goes by. ACS is currently only supported through the nl80211 driver and +# your driver must have survey dump capability that is filled by the driver +# during scanning. +# +# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with +# a newly to create wpa_supplicant.conf variable acs_num_scans. +# +# Supported ACS drivers: +# * ath9k +# * ath5k +# * ath10k +# +# For more details refer to: +# http://wireless.kernel.org/en/users/Documentation/acs +#CONFIG_ACS=y + +# Support Multi Band Operation +#CONFIG_MBO=y + +# Fast Initial Link Setup (FILS) (IEEE 802.11ai) +#CONFIG_FILS=y +# FILS shared key authentication with PFS +#CONFIG_FILS_SK_PFS=y + +# Support RSN on IBSS networks +# This is needed to be able to use mode=1 network profile with proto=RSN and +# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None). +CONFIG_IBSS_RSN=y + +# External PMKSA cache control +# This can be used to enable control interface commands that allow the current +# PMKSA cache entries to be fetched and new entries to be added. +#CONFIG_PMKSA_CACHE_EXTERNAL=y + +# Mesh Networking (IEEE 802.11s) +#CONFIG_MESH=y + +# Background scanning modules +# These can be used to request wpa_supplicant to perform background scanning +# operations for roaming within an ESS (same SSID). See the bgscan parameter in +# the wpa_supplicant.conf file for more details. +# Periodic background scans based on signal strength +CONFIG_BGSCAN_SIMPLE=y +# Learn channels used by the network and try to avoid bgscans on other +# channels (experimental) +#CONFIG_BGSCAN_LEARN=y + +# Opportunistic Wireless Encryption (OWE) +# Experimental implementation of draft-harkins-owe-07.txt +CONFIG_OWE=y + +# Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect) +CONFIG_DPP=y +# DPP version 2 support +CONFIG_DPP2=y +# DPP version 3 support (experimental and still changing; do not enable for +# production use) +#CONFIG_DPP3=y + +# Wired equivalent privacy (WEP) +# WEP is an obsolete cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used for anything anymore. The +# functionality needed to use WEP is available in the current wpa_supplicant +# release under this optional build parameter. This functionality is subject to +# be completely removed in a future release. +#CONFIG_WEP=y + +# Remove all TKIP functionality +# TKIP is an old cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used anymore for anything else than a +# backwards compatibility option as a group cipher when connecting to APs that +# use WPA+WPA2 mixed mode. For now, the default wpa_supplicant build includes +# support for this by default, but that functionality is subject to be removed +# in the future. +#CONFIG_NO_TKIP=y + +# Pre-Association Security Negotiation (PASN) +# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol +# design is still subject to change. As such, this should not yet be enabled in +# production use. +#CONFIG_PASN=y + +# Enable all IFX/Cypress changes +CONFIG_DRIVER_NL80211_IFX=y + +# Offload the TWT Session management to FW +CONFIG_TWT_OFFLOAD_IFX=y + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0001-wpa_supplicant-Support-4-way-handshake-offload-for-F.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0001-wpa_supplicant-Support-4-way-handshake-offload-for-F.patch index 1bd9705e5..7c3f860d8 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0001-wpa_supplicant-Support-4-way-handshake-offload-for-F.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0001-wpa_supplicant-Support-4-way-handshake-offload-for-F.patch @@ -1,7 +1,7 @@ From 6b4bc7fbb9be8eb668985de04eb11618f9dc1781 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 11:32:11 +0800 -Subject: [PATCH 01/49] wpa_supplicant: Support 4-way handshake offload for +Subject: [PATCH 01/60] wpa_supplicant: Support 4-way handshake offload for FT-EAP Add support of 4-way handshake offload for FT-EAP. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0002-wpa_supplicant-Notify-Neighbor-Report-for-driver-tri.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0002-wpa_supplicant-Notify-Neighbor-Report-for-driver-tri.patch index 2b924b185..4a524b937 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0002-wpa_supplicant-Notify-Neighbor-Report-for-driver-tri.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0002-wpa_supplicant-Notify-Neighbor-Report-for-driver-tri.patch @@ -1,7 +1,7 @@ From 4d8eb3c7f31f66085dfb7f7652bf3b333d776896 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 15:22:57 +0800 -Subject: [PATCH 02/49] wpa_supplicant: Notify Neighbor Report for +Subject: [PATCH 02/60] wpa_supplicant: Notify Neighbor Report for driver-triggered request Sending a Neighbor Report request can be triggered by either supplicant diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch index 8de33d112..b203b71df 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0003-nl80211-Report-connection-authorized-in-EVENT_ASSOC.patch @@ -1,7 +1,7 @@ From 21271c00b29db8c178aa704daaf665967e141d47 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 15:55:21 +0800 -Subject: [PATCH 03/49] nl80211: Report connection authorized in EVENT_ASSOC +Subject: [PATCH 03/60] nl80211: Report connection authorized in EVENT_ASSOC When roaming in a network that requires 802.1X authentication, device driver could set the authorized flag if 4-way handshake offload or FT diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0004-wpa_supplicant-Add-PMKSA-cache-for-802.1X-4-way-hand.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0004-wpa_supplicant-Add-PMKSA-cache-for-802.1X-4-way-hand.patch index 0f9876dfc..bd2dacc01 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0004-wpa_supplicant-Add-PMKSA-cache-for-802.1X-4-way-hand.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0004-wpa_supplicant-Add-PMKSA-cache-for-802.1X-4-way-hand.patch @@ -1,7 +1,7 @@ From 578eb72569a03cdd608cf384911d46eb372c583e Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 16:05:49 +0800 -Subject: [PATCH 04/49] wpa_supplicant: Add PMKSA cache for 802.1X 4-way +Subject: [PATCH 04/60] wpa_supplicant: Add PMKSA cache for 802.1X 4-way handshake Add PMKSA cache and set PMK to the driver for 802.1X 4-way handshake diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch index 879bc9ba7..8517fbf02 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0005-OpenSSL-Fix-build-with-OpenSSL-1.0.1.patch @@ -1,7 +1,7 @@ From 78e7373ad2cf51a881a12e55c3db01580932539e Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Fri, 8 Nov 2019 13:23:05 -0600 -Subject: [PATCH 05/49] OpenSSL: Fix build with OpenSSL 1.0.1 +Subject: [PATCH 05/60] OpenSSL: Fix build with OpenSSL 1.0.1 The openssl_debug_dump_certificate_chains() implementation used SSL_CERT_SET_FIRST and SSL_CERT_SET_NEXT, which were added in OpenSSL diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch index 9be859305..297791252 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0006-nl80211-Check-SAE-authentication-offload-support.patch @@ -1,7 +1,7 @@ From f6eed1d9e56502fd8cbab309e94f9787795c3e35 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 17:13:27 +0800 -Subject: [PATCH 06/49] nl80211: Check SAE authentication offload support +Subject: [PATCH 06/60] nl80211: Check SAE authentication offload support Set WPA_DRIVER_FLAGS2_SAE_OFFLOAD flag if driver indicates SAE authentication offload support. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.patch index 4be8a4662..c446cbcff 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0007-SAE-Pass-SAE-password-on-connect-for-SAE-authenticat.patch @@ -1,7 +1,7 @@ From 417097c87d7027ad319d7e8c9931deb666779533 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 29 Oct 2019 17:22:18 +0800 -Subject: [PATCH 07/49] SAE: Pass SAE password on connect for SAE +Subject: [PATCH 07/60] SAE: Pass SAE password on connect for SAE authentication offload support Pass SAE password on connect if driver advertises SAE authentication diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch index 43b4e31f3..2bffa1708 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0008-nl80211-Support-4-way-handshake-offload-for-WPA-WPA2.patch @@ -1,7 +1,7 @@ From 0bdd3f507d5dc92e42c72df7f4b79ffdab514fe1 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:02:39 -0600 -Subject: [PATCH 08/49] nl80211: Support 4-way handshake offload for +Subject: [PATCH 08/60] nl80211: Support 4-way handshake offload for WPA/WPA2-PSK in AP mode If driver advertises support for WPA/WPA2-PSK 4-way handshake offload in diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch index 654fad8e6..442b1a6e7 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0009-AP-Support-4-way-handshake-offload-for-WPA-WPA2-PSK.patch @@ -1,7 +1,7 @@ From 2f8529ec491389bdb41911edcf084bc643d7c9ee Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:03:57 -0600 -Subject: [PATCH 09/49] AP: Support 4-way handshake offload for WPA/WPA2-PSK +Subject: [PATCH 09/60] AP: Support 4-way handshake offload for WPA/WPA2-PSK Add support for WPA/WPA2-PSK 4-way handshake offload in AP mode. In this case, the 4-way handshake is handled by driver instead of user space. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch index 1a3eef521..2d1636e0a 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0010-nl80211-Support-SAE-authentication-offload-in-AP-mod.patch @@ -1,7 +1,7 @@ From 89d2f8b07c948cc5fbe8767948128f487eae2ed5 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:05:16 -0600 -Subject: [PATCH 10/49] nl80211: Support SAE authentication offload in AP mode +Subject: [PATCH 10/60] nl80211: Support SAE authentication offload in AP mode If driver advertises support for SAE authentication offload, pass SAE password in NL80211_CMD_NEW_BEACON command for AP mode. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch index 6667844f7..2ec008ea6 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0011-SAE-Support-SAE-authentication-offload-in-AP-mode.patch @@ -1,7 +1,7 @@ From dfa364f9970f1d88782cc9a9b7292afadbf2358b Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 10 Dec 2019 14:06:20 -0600 -Subject: [PATCH 11/49] SAE: Support SAE authentication offload in AP mode +Subject: [PATCH 11/60] SAE: Support SAE authentication offload in AP mode Add support for SAE authentication offload in AP mode. In this case, the SAE authentication process is handled by driver instead of user space. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0012-DPP-Do-more-condition-test-for-AKM-type-DPP-offload.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0012-DPP-Do-more-condition-test-for-AKM-type-DPP-offload.patch index fd8a89df6..15f91ce7e 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0012-DPP-Do-more-condition-test-for-AKM-type-DPP-offload.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0012-DPP-Do-more-condition-test-for-AKM-type-DPP-offload.patch @@ -1,7 +1,7 @@ From 234dbe729a1041d93efc51b8467ac063b74b2c81 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Mon, 18 May 2020 08:36:59 -0500 -Subject: [PATCH 12/49] DPP: Do more condition test for AKM type DPP offload. +Subject: [PATCH 12/60] DPP: Do more condition test for AKM type DPP offload. If supplicant recieves eapol frame with driver declared WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK, supplicant will check AKM type diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch index dff70c0d3..6e99d6fa9 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0013-non-upstream-defconfig_base-Add-Infineon-default-con.patch @@ -1,7 +1,7 @@ From 69d18183a1df9e72371e33937c91af5b5b79a110 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Mon, 2 Aug 2021 14:15:06 -0500 -Subject: [PATCH 13/49] non-upstream: defconfig_base: Add Infineon default +Subject: [PATCH 13/60] non-upstream: defconfig_base: Add Infineon default configuration Add Infineon default configuration files (defconfig_base). diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch index 1cc5dc822..6be08c05c 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0014-CVE_2019_9501-Fix-to-check-Invalid-GTK-IE-length-in-.patch @@ -1,7 +1,7 @@ From 28c5794ff336f3ec29be79197198071be9add4ac Mon Sep 17 00:00:00 2001 From: Suresh Sanaboina Date: Tue, 1 Feb 2022 13:02:07 +0000 -Subject: [PATCH 14/49] [CVE_2019_9501] Fix to check Invalid GTK IE length in +Subject: [PATCH 14/60] [CVE_2019_9501] Fix to check Invalid GTK IE length in M3 at STA --- diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch index de3a106da..d37745c0d 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0015-Add-CONFIG_WPA3_SAE_AUTH_EARLY_SET-flags-and-codes.murata.patch @@ -1,7 +1,7 @@ From ab61a3dd6d968c62b407c170079a236194357931 Mon Sep 17 00:00:00 2001 From: Danny Chiu Date: Thu, 4 Nov 2021 02:44:17 -0500 -Subject: [PATCH 15/49] Add CONFIG_WPA3_SAE_AUTH_EARLY_SET flags and codes +Subject: [PATCH 15/60] Add CONFIG_WPA3_SAE_AUTH_EARLY_SET flags and codes Enable this flags allow the AP to set authorization to firmware earier as the SAE confirm from is ok. --- diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch index 6843ed4ee..add017ef6 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0016-SAE-Set-the-right-WPA-Versions-for-FT-SAE-key-manage.patch @@ -1,7 +1,7 @@ From 32ee9150ccf3f6c242ba2809aab9b9e115a9d1b5 Mon Sep 17 00:00:00 2001 From: Darren Li Date: Fri, 26 Nov 2021 02:09:03 -0600 -Subject: [PATCH 16/49] SAE: Set the right WPA Versions for FT-SAE key +Subject: [PATCH 16/60] SAE: Set the right WPA Versions for FT-SAE key management Set the right WPA Versions for FT-SAE key management diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.patch index e9a2a0c54..2b8731bc1 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0017-wpa_supplicant-Support-WPA_KEY_MGMT_FT-for-eapol-off.patch @@ -1,7 +1,7 @@ From 6fa06f214ba1cfc4e80dc7413874175146b9c2a5 Mon Sep 17 00:00:00 2001 From: Chien-Chia Chen Date: Tue, 23 Nov 2021 21:29:08 -0600 -Subject: [PATCH 17/49] wpa_supplicant: Support WPA_KEY_MGMT_FT for eapol +Subject: [PATCH 17/60] wpa_supplicant: Support WPA_KEY_MGMT_FT for eapol offloading and driver base roaming Add WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK / WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X / diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.patch index d2045f7df..629df4157 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0018-wpa_supplicant-suppress-deauth-for-PMKSA-caching-dis.patch @@ -1,7 +1,7 @@ From 9af850cef2007cabe1bbffad3ef1d2b13396832d Mon Sep 17 00:00:00 2001 From: Darren Li Date: Tue, 22 Feb 2022 00:34:47 -0600 -Subject: [PATCH 18/49] wpa_supplicant: suppress deauth for PMKSA caching +Subject: [PATCH 18/60] wpa_supplicant: suppress deauth for PMKSA caching disabled wpa_supplicant: Need a command/parameter suppress deauth for PMKSA caching disabled diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch index 7d6f6eea7..53e0f7ec6 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0019-Fix-for-PMK-expiration-issue-through-supplicant.murata.patch @@ -1,7 +1,7 @@ From 5604eb8aaf8382376e6511850e70b66c6e2a22b8 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Sun, 13 Feb 2022 21:34:09 -0600 -Subject: [PATCH 19/49] Fix for PMK expiration issue through supplicant +Subject: [PATCH 19/60] Fix for PMK expiration issue through supplicant Description : Sending Deauth from AP once PMK timeout occurs, So that STA will initiate the Auth process. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0020-SAE-Drop-PMKSA-cache-after-receiving-specific-deauth.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0020-SAE-Drop-PMKSA-cache-after-receiving-specific-deauth.patch index 29d7da831..1f917f89b 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0020-SAE-Drop-PMKSA-cache-after-receiving-specific-deauth.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0020-SAE-Drop-PMKSA-cache-after-receiving-specific-deauth.patch @@ -1,7 +1,7 @@ From ec86cadea38b22595003865c62b5321d55831d9e Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Thu, 24 Feb 2022 03:57:22 -0600 -Subject: [PATCH 20/49] SAE: Drop PMKSA cache after receiving specific deauth +Subject: [PATCH 20/60] SAE: Drop PMKSA cache after receiving specific deauth As a STA mode, when receiving deauth frame with reason code WLAN_REASON_PREV_AUTH_NOT_VALID, it should drop its PMKSA cache. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch index bb1b85bf7..6521a585f 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0021-Avoid-deauthenticating-STA-if-the-reason-for-freeing.patch @@ -1,7 +1,7 @@ From ed487600a81fa99688201a50176072555c90e690 Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 25 Apr 2022 18:35:14 +0530 -Subject: [PATCH 21/49] Avoid deauthenticating STA if the reason for freeing +Subject: [PATCH 21/60] Avoid deauthenticating STA if the reason for freeing PMK entry isn't expiry The PMK cache entry for a STA in the SoftAP managed by wpa_supplicant diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0022-wpa_supplicant-support-bgscan.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0022-wpa_supplicant-support-bgscan.patch index 6899b06f4..0842fe358 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0022-wpa_supplicant-support-bgscan.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0022-wpa_supplicant-support-bgscan.patch @@ -1,7 +1,7 @@ From cfa528ffe320ac638ca72e87751f76444669c48e Mon Sep 17 00:00:00 2001 From: Ian Lin Date: Fri, 20 May 2022 03:00:37 -0500 -Subject: [PATCH 22/49] wpa_supplicant: support bgscan +Subject: [PATCH 22/60] wpa_supplicant: support bgscan Modify defconfig_base to support bgscan feature diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch index ac051fce0..2e52fce06 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0023-non-upstream-wl-cmd-create-interface-to-support-driv.murata.patch @@ -1,7 +1,7 @@ From 1cfe2ac93a1b50a6fd2f6d0022ece6e0f2a91259 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Sun, 10 Apr 2022 22:10:51 -0500 -Subject: [PATCH 23/49] non-upstream: wl-cmd: create interface to support +Subject: [PATCH 23/60] non-upstream: wl-cmd: create interface to support driver priv command 1. Create "wl" command interface to set/get driver information diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch index cdc0e9b2b..acce18fe6 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0024-non-upstream-wl-cmd-create-wl_do_cmd-as-an-entry-doi.patch @@ -1,7 +1,7 @@ From ea5cd91f744dc3c5ebf8e5b8cf1746bec41c1d19 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Tue, 26 Apr 2022 03:02:12 -0500 -Subject: [PATCH 24/49] non-upstream: wl-cmd: create wl_do_cmd as an entry +Subject: [PATCH 24/60] non-upstream: wl-cmd: create wl_do_cmd as an entry doing wl commands Create wl_do_cmd as an entry doing wl commands diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch index c9037f18e..1a6279412 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0025-non-upstream-wl-cmd-create-ops-table-to-do-wl-comman.patch @@ -1,7 +1,7 @@ From 05b1387d4dc2e74a02cf524733d809acc4fd46fb Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Wed, 27 Apr 2022 22:50:25 -0500 -Subject: [PATCH 25/49] non-upstream: wl-cmd: create ops table to do wl +Subject: [PATCH 25/60] non-upstream: wl-cmd: create ops table to do wl commands Creeate wl_cmds to handle wl commands diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.patch index d5220c068..fddb5920f 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0026-non-upstream-wl-cmd-add-more-compile-flag.patch @@ -1,7 +1,7 @@ From a6028c58032672f86c9fe87ba3abbd31c79166e3 Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Wed, 25 May 2022 19:12:47 -0500 -Subject: [PATCH 26/49] non-upstream: wl-cmd: add more compile flag +Subject: [PATCH 26/60] non-upstream: wl-cmd: add more compile flag add more CONFIG_DRIVER_BRCM_WL to separeta this feature diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0027-Fix-dpp-config-parameter-setting.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0027-Fix-dpp-config-parameter-setting.patch index 894a71616..8d66427e5 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0027-Fix-dpp-config-parameter-setting.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0027-Fix-dpp-config-parameter-setting.patch @@ -1,7 +1,7 @@ From e2fb675883cf00992ce51e91a3e2055c898ae3e6 Mon Sep 17 00:00:00 2001 From: "Shankar Amar (CSTIPL CSS ICW SW WFS 1)" Date: Mon, 20 Jun 2022 05:57:46 +0000 -Subject: [PATCH 27/49] Fix dpp config parameter setting +Subject: [PATCH 27/60] Fix dpp config parameter setting --- src/common/dpp.c | 7 ++++--- diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch index 4d8448982..b9bdaf617 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0028-DPP-Resolving-failure-of-dpp-configurator-exchange-f.patch @@ -1,7 +1,7 @@ From b19b6f1165800106ccd941b6042ea804bfa95d5f Mon Sep 17 00:00:00 2001 From: "Shankar Amar (CSTIPL CSS ICW SW WFS 1)" Date: Thu, 30 Jun 2022 08:01:45 +0000 -Subject: [PATCH 28/49] DPP: Resolving failure of dpp configurator exchange for +Subject: [PATCH 28/60] DPP: Resolving failure of dpp configurator exchange for configurator plus initiator in AP role with fmac --- diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch index 49c53d64b..2adecd704 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0029-Enabling-SUITEB192-and-SUITEB-compile-options.patch @@ -1,7 +1,7 @@ From 7d621a129690b061afd61e8bd21d9b816f09d8ac Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Mon, 4 Jul 2022 02:19:48 -0500 -Subject: [PATCH 29/49] Enabling SUITEB192 and SUITEB compile options +Subject: [PATCH 29/60] Enabling SUITEB192 and SUITEB compile options Enabling the compile options for SUITEB and SUITEB-192 related configurations and wpa_cli commands. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch index ea78e16dd..aa98785fa 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0030-DPP-Enabling-CLI_EDIT-option-for-enrollee-plus-respo.patch @@ -1,7 +1,7 @@ From 621de92cbd36719e3febe385411a65ccfa646344 Mon Sep 17 00:00:00 2001 From: "Shankar Amar (CSTIPL CSS ICW SW WFS 1)" Date: Fri, 22 Jul 2022 07:52:30 +0000 -Subject: [PATCH 30/49] DPP: Enabling CLI_EDIT option for enrollee plus +Subject: [PATCH 30/60] DPP: Enabling CLI_EDIT option for enrollee plus responder in STA role with fmac --- diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0031-P2P-Fixes-Scan-trigger-failed-once-GC-invited-by-GO.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0031-P2P-Fixes-Scan-trigger-failed-once-GC-invited-by-GO.patch index 1b94e31b4..516d49a79 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0031-P2P-Fixes-Scan-trigger-failed-once-GC-invited-by-GO.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0031-P2P-Fixes-Scan-trigger-failed-once-GC-invited-by-GO.patch @@ -1,7 +1,7 @@ From a7e23d28ccd14800f0dd3f12bf0d053df6987fe7 Mon Sep 17 00:00:00 2001 From: JasonHuang Date: Tue, 19 Jul 2022 01:44:19 -0500 -Subject: [PATCH 31/49] P2P: Fixes Scan trigger failed, once GC invited by GO +Subject: [PATCH 31/60] P2P: Fixes Scan trigger failed, once GC invited by GO It's regression between 2.9 and 2.10. The 5g frequencys be repeatedly added to the list, then nl80211 driver will return diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch index 3381303ca..d14dfdfcc 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0032-non-upstream-SAE-disconnect-after-PMKSA-cache-expire.patch @@ -1,7 +1,7 @@ From 65ed1eadc11b838a4ba223648bfd3d87bf492319 Mon Sep 17 00:00:00 2001 From: Ian Lin Date: Mon, 18 Jul 2022 00:49:49 -0500 -Subject: [PATCH 32/49] non-upstream: SAE: disconnect after PMKSA cache expire +Subject: [PATCH 32/60] non-upstream: SAE: disconnect after PMKSA cache expire If the dot11RSNAConfigPMKLifetime is set, skip the flow of postponing the expiration in b0f457b6 and run disconnect flow. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0033-Add-support-for-beacon-loss-roaming.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0033-Add-support-for-beacon-loss-roaming.patch index 794236c43..cec9aae8e 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0033-Add-support-for-beacon-loss-roaming.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0033-Add-support-for-beacon-loss-roaming.patch @@ -1,7 +1,7 @@ From b98919427e885679267ac811eb7e02d7209078b4 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 26 Jul 2022 17:24:49 -0400 -Subject: [PATCH 33/49] Add support for beacon loss roaming +Subject: [PATCH 33/60] Add support for beacon loss roaming --- wpa_supplicant/bgscan_learn.c | 19 ++++++++++++++++++- diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch index 743a338bb..bcd9b3132 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0034-wpa_supplicant-Set-PMKSA-to-driver-while-key-mgmt-is.patch @@ -1,7 +1,7 @@ From da53435d4d11db827e3661be372e7b9773eaa842 Mon Sep 17 00:00:00 2001 From: JasonHuang Date: Thu, 8 Sep 2022 03:26:23 -0500 -Subject: [PATCH 34/49] wpa_supplicant: Set PMKSA to driver while key mgmt is +Subject: [PATCH 34/60] wpa_supplicant: Set PMKSA to driver while key mgmt is FT When the fast roaming is determined by the firmware, the diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.patch index d56ee518b..cdc8aadb1 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0035-nl80211-Set-NL80211_SCAN_FLAG_COLOCATED_6GHZ-in-scan.patch @@ -1,7 +1,7 @@ From 2173b4648a59f7ab499b7974189f2ba025b6a25e Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Sun, 24 Apr 2022 12:57:52 +0300 -Subject: [PATCH 35/49] nl80211: Set NL80211_SCAN_FLAG_COLOCATED_6GHZ in scan +Subject: [PATCH 35/60] nl80211: Set NL80211_SCAN_FLAG_COLOCATED_6GHZ in scan Set NL80211_SCAN_FLAG_COLOCATED_6GHZ in the scan parameters to enable scanning for co-located APs discovered based on neighbor reports from diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0036-scan-Add-option-to-disable-6-GHz-collocated-scanning.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0036-scan-Add-option-to-disable-6-GHz-collocated-scanning.patch index 61b690c39..545510758 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0036-scan-Add-option-to-disable-6-GHz-collocated-scanning.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0036-scan-Add-option-to-disable-6-GHz-collocated-scanning.patch @@ -1,7 +1,7 @@ From d2aff0911008db10d28424ca5b8d67f852a5bf89 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 24 Apr 2022 12:57:53 +0300 -Subject: [PATCH 36/49] scan: Add option to disable 6 GHz collocated scanning +Subject: [PATCH 36/60] scan: Add option to disable 6 GHz collocated scanning Add a parameter (non_coloc_6ghz=1) to the manual scan command to disable 6 GHz collocated scanning. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0037-Enabling-OWE-in-wpa_supplicant.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0037-Enabling-OWE-in-wpa_supplicant.patch index 27e02add8..f95ebd8a2 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0037-Enabling-OWE-in-wpa_supplicant.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0037-Enabling-OWE-in-wpa_supplicant.patch @@ -1,7 +1,7 @@ From 4a920e2446cff3f215614d63798e675bb5e25549 Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Wed, 19 Oct 2022 03:29:39 -0500 -Subject: [PATCH 37/49] Enabling OWE in wpa_supplicant +Subject: [PATCH 37/60] Enabling OWE in wpa_supplicant Enabling the compile options for OWE. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0038-Add-link-loss-timer-on-beacon-loss.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0038-Add-link-loss-timer-on-beacon-loss.patch index d9b74486c..5371406e4 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0038-Add-link-loss-timer-on-beacon-loss.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0038-Add-link-loss-timer-on-beacon-loss.patch @@ -1,7 +1,7 @@ From f3695ca19a711fbfcda7233f65af13ac9e8a78f7 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 16 Aug 2022 15:00:14 -0400 -Subject: [PATCH 38/49] Add link loss timer on beacon loss +Subject: [PATCH 38/60] Add link loss timer on beacon loss --- wpa_supplicant/bgscan_learn.c | 19 +++++++++++++++++++ diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0039-FT-Sync-nl80211-ext-feature-index.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0039-FT-Sync-nl80211-ext-feature-index.patch index 91ecd85cf..691ca6e7b 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0039-FT-Sync-nl80211-ext-feature-index.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0039-FT-Sync-nl80211-ext-feature-index.patch @@ -1,7 +1,7 @@ From 7076f7634cc9d7a88f009c448ada307841b42a2a Mon Sep 17 00:00:00 2001 From: JasonHuang Date: Sun, 30 Oct 2022 21:58:34 -0500 -Subject: [PATCH 39/49] FT: Sync nl80211 ext feature index +Subject: [PATCH 39/60] FT: Sync nl80211 ext feature index The backports-5.15.58 has been used. Supplicant should sync the nl80211_ext_feature_index with backports to avoid unexpected fail. diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch index 4aa8a8767..66df83dbc 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0040-nl80211-Introduce-a-vendor-header-for-vendor-NL-ifac.patch @@ -1,7 +1,7 @@ From 62c82984916623e6e00053dcb148de71d24bdaf5 Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:15:25 +0530 -Subject: [PATCH 40/49] nl80211: Introduce a vendor header for vendor NL iface +Subject: [PATCH 40/60] nl80211: Introduce a vendor header for vendor NL iface to DRV with OUI_IFX So far, the proprietary configurations are done either through the private diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.patch index 5a1d7b781..2ce12de54 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0041-add-support-to-offload-TWT-setup-request-handling-to.patch @@ -1,7 +1,7 @@ From 013beb7bc5036bf627fce3707a7a83344ffa05aa Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:16:37 +0530 -Subject: [PATCH 41/49] add support to offload TWT setup request handling to +Subject: [PATCH 41/60] add support to offload TWT setup request handling to the Firmware With "TWT_SETUP" control sock cmd interface currently available in the diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.patch index fda44d72b..03734cdb3 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0042-add-support-to-offload-TWT-Teardown-request-handling.patch @@ -1,7 +1,7 @@ From 9a87c940340e1c665ce7172e7df147d53d1daabe Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:16:50 +0530 -Subject: [PATCH 42/49] add support to offload TWT Teardown request handling to +Subject: [PATCH 42/60] add support to offload TWT Teardown request handling to the Firmware With "TWT_TEARDOWN" control sock cmd interface currently available in the diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.patch index 9ac59f13f..9d170f489 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0043-Add-support-to-configure-TWT-of-a-session-using-offs.patch @@ -1,7 +1,7 @@ From e03937fecb74cf50d70721ea2a0b14fa5e12153a Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Mon, 11 Jul 2022 11:17:04 +0530 -Subject: [PATCH 43/49] Add support to configure TWT of a session using offset +Subject: [PATCH 43/60] Add support to configure TWT of a session using offset in microseconds Introduce a new cmd line argument "twt_offset=" in the existing list diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0044-Establish-a-Default-TWT-session-in-the-STA-after-ass.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0044-Establish-a-Default-TWT-session-in-the-STA-after-ass.patch index 027a59838..9c88182b3 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0044-Establish-a-Default-TWT-session-in-the-STA-after-ass.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0044-Establish-a-Default-TWT-session-in-the-STA-after-ass.patch @@ -1,7 +1,7 @@ From 045ff0dc8aaa1297096c7a941045c74bf1a0e7f3 Mon Sep 17 00:00:00 2001 From: Ramanathan Ramakrishnan Date: Thu, 27 Oct 2022 06:00:28 -0500 -Subject: [PATCH 44/49] Establish a Default TWT session in the STA after +Subject: [PATCH 44/60] Establish a Default TWT session in the STA after associating with the AP Add a new wpa_supplicant conf param "twt_def_algo" to set the Default/Auto diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0045-validate-the-TWT-parameters-exponent-and-mantissa-pa.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0045-validate-the-TWT-parameters-exponent-and-mantissa-pa.patch index 627f15b66..96f864a51 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0045-validate-the-TWT-parameters-exponent-and-mantissa-pa.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0045-validate-the-TWT-parameters-exponent-and-mantissa-pa.patch @@ -1,7 +1,7 @@ From ad935d3fefec7f775188d305a5bf63a64d30a065 Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Fri, 11 Nov 2022 19:40:04 +0530 -Subject: [PATCH 45/49] validate the TWT parameters exponent and mantissa +Subject: [PATCH 45/60] validate the TWT parameters exponent and mantissa passed to wpa_cli The exponent is a 5 bit param and the max value is 31 (0x1F). The mantissa diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0046-Fix-for-station-sending-open-auth-instead-of-SAE-aut.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0046-Fix-for-station-sending-open-auth-instead-of-SAE-aut.patch index 21d23f945..967fcda37 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0046-Fix-for-station-sending-open-auth-instead-of-SAE-aut.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0046-Fix-for-station-sending-open-auth-instead-of-SAE-aut.patch @@ -1,7 +1,7 @@ From ed256e852f6ff9c45974128cba4d2f0fbbdece2f Mon Sep 17 00:00:00 2001 From: Ramesh Rangavittal Date: Mon, 21 Nov 2022 11:21:59 -0600 -Subject: [PATCH 46/49] Fix for station sending open auth instead of SAE auth +Subject: [PATCH 46/60] Fix for station sending open auth instead of SAE auth --- wpa_supplicant/events.c | 2 +- diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0047-Fix-ROAMOFFLOAD-raises-portValid-too-early.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0047-Fix-ROAMOFFLOAD-raises-portValid-too-early.patch deleted file mode 100644 index 5a2f6cdae..000000000 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0047-Fix-ROAMOFFLOAD-raises-portValid-too-early.patch +++ /dev/null @@ -1,54 +0,0 @@ -From a5ae9fcc3baa099a86ecd2739caadf624258a49d Mon Sep 17 00:00:00 2001 -From: Carter Chen -Date: Mon, 28 Nov 2022 21:39:48 -0600 -Subject: [PATCH 47/49] Fix ROAMOFFLOAD raises portValid too early - -1.) while WPA_DRIVER_FLAGS_ROAM_OFFLOAD flag is set, -and if the cipher_mgmt is 8021x related, -the portValid is set while get wpa_supplicant_event_assoc. - -portValid will make the state_machine of SUPP_PAE jumps AUTHENTICATING to AUTHENTICATED. - -2.) while WPA_DRIVER_FLAGS_ROAM_OFFLOAD flag is set, -the PMKCacheLifeTime and pmksa_cache_reauth timer are set while recevied -assoc response. - -3.) if the PMKCacheLifeTime is set to a small value for disable PMK -cache. the pmksa_cache_reauth will expire right away, -for example, while doing 4-way handshake, the timer has expired. - -in case the timer of pmksa_cache_reauth has expired, -if the state of SUPP_PAE is AUTHENTICATED, -eapol_sm_txStart will be called and restart the Radius handshake. - -Solution: ROAM_OFFLOAD and cipher_mgmt is FT related, such as, FT_1X or -FT_PSK. then raise portValid. - -Fixes: SWLINUX-3041 - -Signed-off-by: Carter Chen ---- - wpa_supplicant/events.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c -index 975110b57..b42f758ce 100644 ---- a/wpa_supplicant/events.c -+++ b/wpa_supplicant/events.c -@@ -3425,9 +3425,10 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, - wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); - eapol_sm_notify_portValid(wpa_s->eapol, true); - eapol_sm_notify_eap_success(wpa_s->eapol, true); -- } else if (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) || -- (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS_ROAM_OFFLOAD)) && -- wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { -+ } else if (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) && -+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) || -+ ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS_ROAM_OFFLOAD) && -+ wpa_key_mgmt_ft(wpa_s->key_mgmt))) { - /* - * The driver will take care of RSN 4-way handshake, so we need - * to allow EAPOL supplicant to complete its work without --- -2.17.1 - diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch similarity index 94% rename from meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch rename to meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch index de1124705..150b9c057 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch @@ -1,7 +1,7 @@ -From 897917008b37a16985d0f1ae9d768c6450741574 Mon Sep 17 00:00:00 2001 +From e21ce4eefab80c4d2e8ccf3b6d29cef5af6f955b Mon Sep 17 00:00:00 2001 From: Owen Huang Date: Wed, 30 Nov 2022 01:35:58 -0600 -Subject: [PATCH 48/49] Fix associating failed when PMK lifetime is set to 1 +Subject: [PATCH 47/60] Fix associating failed when PMK lifetime is set to 1 In WPA3 11.1 STAUT server certificate validation test * set dot11RSNAConfigPMKLifetime to 1 diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0049-non-upstream-p2p_add_group-command-unification.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0048-non-upstream-p2p_add_group-command-unification.patch similarity index 95% rename from meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0049-non-upstream-p2p_add_group-command-unification.patch rename to meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0048-non-upstream-p2p_add_group-command-unification.patch index f4e0e02af..b222b47d6 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0049-non-upstream-p2p_add_group-command-unification.patch +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0048-non-upstream-p2p_add_group-command-unification.patch @@ -1,7 +1,7 @@ -From 4624039b5463b1c36fc34cd5ec517a7473981591 Mon Sep 17 00:00:00 2001 +From 34b6fcfddf0004d57c3cdb6a8179339189ff5cf7 Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Thu, 8 Dec 2022 02:37:48 -0600 -Subject: [PATCH 49/49] non-upstream: p2p_add_group command unification +Subject: [PATCH 48/60] non-upstream: p2p_add_group command unification supporting specify operation group of p2p. - wpa_cli p2p_group_add freq=5180/80 diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.patch new file mode 100644 index 000000000..d4000755f --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.patch @@ -0,0 +1,765 @@ +From 67be9ce68d84e2800b481123a0c140e5ad912619 Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Wed, 14 Dec 2022 01:34:23 -0600 +Subject: [PATCH 49/60] non-upstream: MBO: wpa_cli mbo command by IFX vendorID + +Signed-off-by: Carter Chen +Signed-off-by: Shelley Yang +--- + src/common/ifx_vendor.h | 52 ++++++++ + src/drivers/driver.h | 46 +++++++ + src/drivers/driver_nl80211.c | 141 ++++++++++++++++++++++ + src/drivers/driver_nl80211.h | 1 + + src/drivers/driver_nl80211_capa.c | 3 + + wpa_supplicant/ctrl_iface.c | 193 ++++++++++++++++++++++++++++++ + wpa_supplicant/driver_i.h | 8 ++ + wpa_supplicant/mbo.c | 119 ++++++++++++++++++ + wpa_supplicant/wpa_cli.c | 15 +++ + wpa_supplicant/wpa_supplicant_i.h | 9 ++ + 10 files changed, 587 insertions(+) + +diff --git a/src/common/ifx_vendor.h b/src/common/ifx_vendor.h +index aa8e83bc7..6cd3b874c 100644 +--- a/src/common/ifx_vendor.h ++++ b/src/common/ifx_vendor.h +@@ -56,6 +56,8 @@ + * + * @IFX_VENDOR_SCMD_TWT: Vendor subcommand to configure TWT + * Uses attributes defined in enum ifx_vendor_attr_twt. ++ * @IFX_VENDOR_SCMD_MBO: Vendor subcommand to configure MBO ++ * Uses attribute IFX_VENDOR_ATTR_MBO to configure. + * + * @IFX_VENDOR_SCMD_MAX: This acts as a the tail of cmds list. + * Make sure it located at the end of the list. +@@ -74,6 +76,8 @@ enum ifx_nl80211_vendor_subcmds { + IFX_VENDOR_SCMD_LDPC_CAP = 12, + IFX_VENDOR_SCMD_AMSDU = 13, + IFX_VENDOR_SCMD_TWT = 14, ++ /* Reserved 15-17 */ ++ IFX_VENDOR_SCMD_MBO = 18, + IFX_VENDOR_SCMD_MAX + }; + +@@ -96,6 +100,13 @@ enum ifx_vendor_attr { + IFX_VENDOR_ATTR_MAX = 11 + }; + ++enum ifx_vendor_attr_mbo { ++ IFX_VENDOR_ATTR_MBO_UNSPEC, ++ IFX_VENDOR_ATTR_MBO_CMD, ++ IFX_VENDOR_ATTR_MBO_PARAMS, ++ IFX_VENDOR_ATTR_MBO_MAX ++}; ++ + /* + * enum ifx_vendor_attr_twt - Attributes for the TWT vendor command + * +@@ -260,4 +271,45 @@ enum ifx_twt_oper_setup_cmd_type { + IFX_TWT_OPER_SETUP_CMD_TYPE_MAX = 8 + }; + ++enum ifx_mbo_config_cmd_type { ++ IFX_MBO_CONFIG_CMD_TYPE_INVALID = -1, ++ //align internal definition ++ IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF = 1, ++ IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF = 2, ++ IFX_MBO_CONFIG_CMD_LIST_CHAN_PREF = 3, ++ IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP = 4, ++ IFX_MBO_CONFIG_CMD_DUMP_COUNTER = 5, ++ IFX_MBO_CONFIG_CMD_CLEAR_COUNTER = 6, ++ IFX_MBO_CONFIG_CMD_FORCE_ASSOC = 7, ++ IFX_MBO_CONFIG_CMD_BSSTRANS_REJ = 8, ++ IFX_MBO_CONFIG_CMD_SEND_NOTIF = 9, ++ IFX_MBO_CONFIG_CMD_CLR_CHAN_PREF = 10, ++ IFX_MBO_CONFIG_CMD_NBR_INFO_CACHE = 11, ++ IFX_MBO_CONFIG_CMD_ANQPO_SUPPORT = 12, ++ IFX_MBO_CONFIG_CMD_DBG_EVENT_CHECK = 13, ++ IFX_MBO_CONFIG_CMD_EVENT_MASK = 14, ++ IFX_MBO_CONFIG_CMD_ASSOC_DISALLOWED = 15, ++ IFX_MBO_CONFIG_CMD_CELLULAR_DATA_PREF = 16, ++ IFX_MBO_CONFIG_CMD_TYPE_MAX = 17 ++}; ++ ++enum ifx_vendor_attr_mbo_param { ++ IFX_VENDOR_ATTR_MBO_PARAM_UNSPEC, ++ IFX_VENDOR_ATTR_MBO_PARAM_OPCLASS, ++ IFX_VENDOR_ATTR_MBO_PARAM_CHAN, ++ IFX_VENDOR_ATTR_MBO_PARAM_PREFERENCE, ++ IFX_VENDOR_ATTR_MBO_PARAM_REASON_CODE, ++ IFX_VENDOR_ATTR_MBO_PARAM_CELL_DATA_CAP, ++ IFX_VENDOR_ATTR_MBO_PARAM_COUNTERS, ++ IFX_VENDOR_ATTR_MBO_PARAM_ENABLE, ++ IFX_VENDOR_ATTR_MBO_PARAM_SUB_ELEM_TYPE, ++ IFX_VENDOR_ATTR_MBO_PARAM_BTQ_TRIG_START_OFFSET, ++ IFX_VENDOR_ATTR_MBO_PARAM_BTQ_TRIG_RSSI_DELTA, ++ IFX_VENDOR_ATTR_MBO_PARAM_ANQP_CELL_SUPP, ++ IFX_VENDOR_ATTR_MBO_PARAM_BIT_MASK, ++ IFX_VENDOR_ATTR_MBO_PARAM_ASSOC_DISALLOWED, ++ IFX_VENDOR_ATTR_MBO_PARAM_CELLULAR_DATA_PREF, ++ IFX_VENDOR_ATTR_MBO_PARAM_MAX ++}; ++ + #endif /* IFX_VENDOR_H */ +diff --git a/src/drivers/driver.h b/src/drivers/driver.h +index 23f599bef..996614ee5 100644 +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -2553,6 +2553,51 @@ struct drv_teardown_twt_params { + u8 teardown_all_twt; + }; + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ ++struct drv_config_mbo_params { ++ u8 cmd; ++ union { ++ struct { ++ u8 op_class; ++ u8 chan; ++ u8 pref_val; ++ u8 reason; ++ } add_chan_pref; ++ struct { ++ u8 op_class; ++ u8 chan; ++ } del_chan_pref; ++ struct { ++ u8 cap; ++ } cell_data_cap; ++ struct { ++ u8 enable; ++ } force_assoc; ++ struct { ++ u8 enable; ++ u8 reason; ++ } bsstrans_reject; ++ struct { ++ u8 type; ++ } send_notif; ++ struct { ++ u8 enable; ++ u8 t_offset; ++ u8 trig_delta; ++ } nbr_info_cache; ++ struct { ++ u8 enable; ++ u8 value; ++ } anqpo_support; ++ struct { ++ u8 disallow; ++ u8 reason; ++ } assoc_disallow; ++ struct { ++ u8 pref_value; ++ } cellular_pref; ++ } u; ++}; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + struct wpa_bss_trans_info { +@@ -4681,6 +4726,7 @@ struct wpa_driver_ops { + */ + int (*teardown_twt)(void *priv, struct drv_teardown_twt_params *params); + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ int (*config_mbo)(void *priv, struct drv_config_mbo_params *params); + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + }; +diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c +index 3d98e5943..506b1e406 100644 +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -12473,6 +12473,146 @@ fail: + return ret; + } + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ ++static int wpa_driver_nl80211_config_mbo(void *priv, struct drv_config_mbo_params *params) ++{ ++ struct i802_bss *bss = priv; ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ struct nl_msg *msg = NULL; ++ struct nlattr *data, *mbo_param_attrs; ++ int ret = -1; ++ ++ if (!drv->ifx_mbo_offload) ++ goto fail; ++ ++ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_IFX) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, IFX_VENDOR_SCMD_MBO)) ++ goto fail; ++ ++ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); ++ if (!data) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_CMD, params->cmd)) ++ goto fail; ++ ++ switch (params->cmd) { ++ case IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_OPCLASS, ++ params->u.add_chan_pref.op_class) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_CHAN, ++ params->u.add_chan_pref.chan) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_PREFERENCE, ++ params->u.add_chan_pref.pref_val) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_REASON_CODE, ++ params->u.add_chan_pref.reason)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_OPCLASS, ++ params->u.del_chan_pref.op_class) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_CHAN, ++ params->u.del_chan_pref.chan)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_CELL_DATA_CAP, ++ params->u.cell_data_cap.cap)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_FORCE_ASSOC: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_ENABLE, ++ params->u.force_assoc.enable)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_FORCE_ASSOC msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_BSSTRANS_REJ: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_ENABLE, ++ params->u.bsstrans_reject.enable) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_REASON_CODE, ++ params->u.bsstrans_reject.reason)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_SEND_NOTIF: ++ mbo_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_MBO_PARAMS); ++ if (!mbo_param_attrs) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_MBO_PARAM_SUB_ELEM_TYPE, ++ params->u.send_notif.type)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: build IFX_MBO_CONFIG_CMD_FORCE_ASSOC msg failed"); ++ goto fail; ++ } ++ nla_nest_end(msg, mbo_param_attrs); ++ break; ++ case IFX_MBO_CONFIG_CMD_LIST_CHAN_PREF: ++ case IFX_MBO_CONFIG_CMD_DUMP_COUNTER: ++ case IFX_MBO_CONFIG_CMD_CLEAR_COUNTER: ++ wpa_printf(MSG_DEBUG, ++ "MBO config: cmd %d doesn't need extra attribute", ++ params->cmd); ++ break; ++ default: ++ break; ++ } ++ ++ nla_nest_end(msg, data); ++ ++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); ++ if (ret) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: MBO config: Failed to invoke driver " ++ "MBO config function: %s", ++ strerror(-ret)); ++ } ++ ++ return ret; ++fail: ++ nl80211_nlmsg_clear(msg); ++ nlmsg_free(msg); ++ return ret; ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { +@@ -12624,5 +12764,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { + .setup_twt = wpa_driver_nl80211_setup_twt, + .teardown_twt = wpa_driver_nl80211_teardown_twt, + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ .config_mbo = wpa_driver_nl80211_config_mbo, + #endif /* CONFIG_DRIVER_NL80211_IFX */ + }; +diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h +index f681afb41..6d2c09477 100644 +--- a/src/drivers/driver_nl80211.h ++++ b/src/drivers/driver_nl80211.h +@@ -182,6 +182,7 @@ struct wpa_driver_nl80211_data { + unsigned int brcm_do_acs:1; + #ifdef CONFIG_DRIVER_NL80211_IFX + unsigned int ifx_twt_offload:1; ++ unsigned int ifx_mbo_offload:1; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + u64 vendor_scan_cookie; +diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c +index 19d1569bf..b0807a7fc 100644 +--- a/src/drivers/driver_nl80211_capa.c ++++ b/src/drivers/driver_nl80211_capa.c +@@ -1059,6 +1059,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) + case IFX_VENDOR_SCMD_TWT: + drv->ifx_twt_offload = 1; + break; ++ case IFX_VENDOR_SCMD_MBO: ++ drv->ifx_mbo_offload = 1; ++ break; + } + #endif /* CONFIG_DRIVER_NL80211_IFX */ + } +diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c +index 90cc4861c..9f0149a20 100644 +--- a/wpa_supplicant/ctrl_iface.c ++++ b/wpa_supplicant/ctrl_iface.c +@@ -10150,6 +10150,194 @@ static int wpas_ctrl_iface_send_twt_teardown(struct wpa_supplicant *wpa_s, + } + + ++#ifdef CONFIG_DRIVER_NL80211_IFX ++int wpas_config_offload_send_mbo_config(struct wpa_supplicant *wpa_s, u8 cmd_id, ++ u8 oper_class, u8 chan, u8 pref_val, ++ u8 reason_code, u8 enable, u8 notif_type, ++ u8 time_offset, u8 rssi_trig_delta, ++ bool enable_anqpo, bool enable_cell_pref, ++ u8 cell_pref_val, u8 cell_cap) ++{ ++ struct drv_config_mbo_params params; ++ int ret = 0; ++ ++ memset(¶ms, 0, sizeof(struct drv_config_mbo_params)); ++ ++ switch (cmd_id) { ++ case IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF: ++ if (!oper_class || !chan || ++ (pref_val != 0 && pref_val != 1 && pref_val != 255) || ++ reason_code > 3) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for add_chan_pref oper_class: %d " ++ "chan:%d pref_val:%d reason_code:%d", ++ oper_class, chan, pref_val, reason_code); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.add_chan_pref.op_class = oper_class; ++ params.u.add_chan_pref.chan = chan; ++ params.u.add_chan_pref.pref_val = pref_val; ++ params.u.add_chan_pref.reason = reason_code; ++ break; ++ case IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF: ++ if (!oper_class || !chan) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for del_chan_pref " ++ "oper_class: %d chan:%d", ++ oper_class, chan); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.del_chan_pref.op_class = oper_class; ++ params.u.del_chan_pref.chan = chan; ++ break; ++ case IFX_MBO_CONFIG_CMD_LIST_CHAN_PREF: ++ case IFX_MBO_CONFIG_CMD_DUMP_COUNTER: ++ case IFX_MBO_CONFIG_CMD_CLEAR_COUNTER: ++ params.cmd = cmd_id; ++ break; ++ case IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP: ++ if (!cell_cap || cell_cap > 3) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for cellular_data_cap:%d", ++ cell_cap); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.cell_data_cap.cap = cell_cap; ++ break; ++ case IFX_MBO_CONFIG_CMD_FORCE_ASSOC: ++ if (enable > 1) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for force_assoc:%d", ++ enable); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.force_assoc.enable = enable; ++ break; ++ case IFX_MBO_CONFIG_CMD_BSSTRANS_REJ: ++ if (enable > 1 || reason_code > 6) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for bsstrans reject, enable:%d, reason:%d", ++ enable, reason_code); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.bsstrans_reject.enable = enable; ++ params.u.bsstrans_reject.reason = reason_code; ++ break; ++ case IFX_MBO_CONFIG_CMD_SEND_NOTIF: ++ if (notif_type != 2 && notif_type != 3) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for send notifty:%d", ++ notif_type); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.send_notif.type = notif_type; ++ break; ++ case IFX_MBO_CONFIG_CMD_NBR_INFO_CACHE: ++ case IFX_MBO_CONFIG_CMD_ANQPO_SUPPORT: ++ case IFX_MBO_CONFIG_CMD_CELLULAR_DATA_PREF: ++ default: ++ wpa_printf(MSG_DEBUG, "MBO: Unsupported cmd_id %d", ++ cmd_id); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ ++ ret = wpa_drv_config_mbo(wpa_s, ¶ms); ++ ++fail: ++ return ret; ++} ++ ++static int wpas_ctrl_iface_send_mbo_config(struct wpa_supplicant *wpa_s, ++ const char *cmd) ++{ ++ u8 oper_class = 0; ++ u8 chan = 0; ++ u8 pref_val = 0; ++ u8 reason_code = 0; ++ u8 cmd_id = 0; ++ u8 enable = 0; ++ u8 notif_type = 0; ++ u8 time_offset = 0; ++ u8 rssi_trig_delta = 0; ++ bool enable_anqpo = false; ++ bool enable_cell_pref = false; ++ u8 cell_pref_val = 0; ++ u8 cell_cap = 0; ++ const char *tok_s; ++ ++ tok_s = os_strstr(cmd, " cmd_id="); ++ if (tok_s) ++ cmd_id = strtol(tok_s + os_strlen(" cmd_id="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " oper_class="); ++ if (tok_s) ++ oper_class = strtol(tok_s + os_strlen(" oper_class="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " pref_val="); ++ if (tok_s) ++ pref_val = strtol(tok_s + os_strlen(" pref_val="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " reason_code="); ++ if (tok_s) ++ reason_code = strtol(tok_s + os_strlen(" reason_code="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " chan="); ++ if (tok_s) ++ chan = strtol(tok_s + os_strlen(" chan="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " cell_cap="); ++ if (tok_s) ++ cell_cap = strtol(tok_s + os_strlen(" cell_cap="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " enable="); ++ if (tok_s) ++ enable = strtol(tok_s + os_strlen(" enable="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " notif_type="); ++ if (tok_s) ++ notif_type = strtol(tok_s + os_strlen(" notif_type="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " time_offset="); ++ if (tok_s) ++ time_offset = strtol(tok_s + os_strlen(" time_offset="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " rssi_trig_delta="); ++ if (tok_s) ++ rssi_trig_delta = strtol(tok_s + os_strlen(" rssi_trig_delta="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " enable_anqpo="); ++ if (tok_s) ++ enable_anqpo = strtol(tok_s + os_strlen(" enable_anqpo="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " enable_cell_pref="); ++ if (tok_s) ++ enable_cell_pref = strtol(tok_s + os_strlen(" enable_cell_pref="), NULL, 10); ++ ++ tok_s = os_strstr(cmd, " cell_pref_val="); ++ if (tok_s) ++ cell_pref_val = strtol(tok_s + os_strlen(" cell_pref_val="), NULL, 10); ++ ++ return wpas_config_offload_send_mbo_config(wpa_s, cmd_id, oper_class, ++ chan, pref_val, reason_code, ++ enable, notif_type, time_offset, ++ rssi_trig_delta, enable_anqpo, ++ enable_cell_pref, cell_pref_val, ++ cell_cap); ++} ++#endif /* CONFIG_DRIVER_NL80211_IFX */ + + static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) + { +@@ -12271,6 +12459,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, + } else if (os_strcmp(buf, "TWT_SETUP") == 0) { + if (wpas_ctrl_iface_send_twt_setup(wpa_s, "")) + reply_len = -1; ++#ifdef CONFIG_DRIVER_NL80211_IFX ++ } else if (os_strncmp(buf, "MBO ", 4) == 0) { ++ if (wpas_ctrl_iface_send_mbo_config(wpa_s, buf + 3)) ++ reply_len = -1; ++#endif /* CONFIG_DRIVER_NL80211_IFX */ + } else if (os_strncmp(buf, "TWT_TEARDOWN ", 13) == 0) { + if (wpas_ctrl_iface_send_twt_teardown(wpa_s, buf + 12)) + reply_len = -1; +diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h +index 9a7975a6a..2fcfa44a6 100644 +--- a/wpa_supplicant/driver_i.h ++++ b/wpa_supplicant/driver_i.h +@@ -1145,6 +1145,14 @@ static inline int wpa_drv_teardown_twt(struct wpa_supplicant *wpa_s, + return wpa_s->driver->teardown_twt(wpa_s->drv_priv, params); + } + #endif /* CONFIG_TWT_OFFLOAD_IFX */ ++ ++static inline int wpa_drv_config_mbo(struct wpa_supplicant *wpa_s, ++ struct drv_config_mbo_params *params) ++{ ++ if (!wpa_s->driver->config_mbo) ++ return -1; ++ return wpa_s->driver->config_mbo(wpa_s->drv_priv, params); ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + #endif /* DRIVER_I_H */ +diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c +index 3df86ef07..714f9ef6f 100644 +--- a/wpa_supplicant/mbo.c ++++ b/wpa_supplicant/mbo.c +@@ -663,3 +663,122 @@ void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, + break; + } + } ++ ++#ifdef CONFIG_DRIVER_NL80211_IFX ++int wpas_config_offload_send_mbo_config(struct wpa_supplicant *wpa_s, u8 cmd_id, ++ u8 oper_class, u8 chan, u8 pref_val, ++ u8 reason_code, u8 enable, u8 notif_type, ++ u8 time_offset, u8 rssi_trig_delta, ++ bool enable_anqpo, bool enable_cell_pref, ++ u8 cell_pref_val, u8 cell_cap) ++{ ++ struct drv_config_mbo_params params; ++ int ret = 0; ++ ++ memset(¶ms, 0, sizeof(struct drv_config_mbo_params)); ++ ++ switch (cmd_id) { ++ case IFX_MBO_CONFIG_CMD_ADD_CHAN_PREF: ++ if (!oper_class || !chan || ++ (pref_val != 0 && pref_val != 1 && pref_val != 255) || ++ reason_code > 3) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for add_chan_pref oper_class: %d " ++ "chan:%d pref_val:%d reason_code:%d", ++ oper_class, chan, pref_val, reason_code); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.add_chan_pref.op_class = oper_class; ++ params.u.add_chan_pref.chan = chan; ++ params.u.add_chan_pref.pref_val = pref_val; ++ params.u.add_chan_pref.reason = reason; ++ break; ++ case IFX_MBO_CONFIG_CMD_DEL_CHAN_PREF: ++ if (!oper_class || !chan) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for del_chan_pref " ++ "oper_class: %d chan:%d", ++ oper_class, chan); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.del_chan_pref.op_class = oper_class; ++ params.u.del_chan_pref.chan = chan; ++ break; ++ case IFX_MBO_CONFIG_CMD_LIST_CHAN_PREF: ++ params.cmd = cmd_id; ++ break; ++ case IFX_MBO_CONFIG_CMD_CELLULAR_DATA_CAP: ++ if (!cell_cap || cell_cap > 3) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for cellular_data_cap:%d", ++ cell_cap); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.cell_data_cap.cap = cell_cap; ++ break; ++ case IFX_MBO_CONFIG_CMD_DUMP_COUNTER: ++ params.cmd = cmd_id; ++ break; ++ case IFX_MBO_CONFIG_CMD_CLEAR_COUNTER: ++ params.cmd = cmd_id; ++ break; ++ case IFX_MBO_CONFIG_CMD_FORCE_ASSOC: ++ if (enable > 1) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for force_assoc:%d", ++ enable); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.force_assoc.enable = enable; ++ break; ++ case IFX_MBO_CONFIG_CMD_BSSTRANS_REJ: ++ if (enable > 1 || reason_code > 6) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for bsstrans reject, enable:%d, reason:%d", ++ enable, reason_code); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.bsstrans_reject.enable = enable; ++ params.u.bsstrans_reject.reason = reason_code; ++ break; ++ case IFX_MBO_CONFIG_CMD_SEND_NOTIF: ++ if (notif_type != 2 && notif_type != 3) { ++ wpa_printf(MSG_ERROR, ++ "MBO: incorrect parameter for send notifty:%d", ++ notif_type); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ params.cmd = cmd_id; ++ params.u.send_notif.type = notif_type; ++ break; ++ case IFX_MBO_CONFIG_CMD_NBR_INFO_CACHE: ++ break; ++ case IFX_MBO_CONFIG_CMD_ANQPO_SUPPORT: ++ break; ++ case IFX_MBO_CONFIG_CMD_CELLULAR_DATA_PREF: ++ break; ++ default: ++ wpa_printf(MSG_DEBUG, "MBO: Unsupported cmd_id %d", ++ cmd_id); ++ ret = -EOPNOTSUPP; ++ goto fail; ++ } ++ ++ ret = wpa_drv_config_mbo(wpa_s, params); ++ ++fail: ++ return ret; ++} ++#endif /* CONFIG_DRIVER_NL80211_IFX */ ++ +diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c +index 07160b5da..3055417fe 100644 +--- a/wpa_supplicant/wpa_cli.c ++++ b/wpa_supplicant/wpa_cli.c +@@ -2957,6 +2957,15 @@ static int wpa_cli_cmd_twt_teardown(struct wpa_ctrl *ctrl, int argc, + } + + ++#ifdef CONFIG_DRIVER_NL80211_IFX ++static int wpa_cli_cmd_mbo_config(struct wpa_ctrl *ctrl, int argc, ++ char *argv[]) ++{ ++ return wpa_cli_cmd(ctrl, "MBO", 0, argc, argv); ++} ++#endif /* CONFIG_DRIVER_NL80211_IFX */ ++ ++ + static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) + { + return wpa_ctrl_command(ctrl, "ERP_FLUSH"); +@@ -3880,8 +3889,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { + }, + { "twt_teardown", + wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none, ++ "[cmd_id=] [oper_class=0|1|255] [pref_val=0|1|255] [reason_code=] [chan=] [cell_cap=1|2] [enable=0|1] [notif_type=2|3] = Send MBO Setup frame" ++ }, ++#ifdef CONFIG_DRIVER_NL80211_IFX ++ { "mbo", ++ wpa_cli_cmd_mbo_config, NULL, cli_cmd_flag_none, + "[flags=] = Send TWT Teardown frame" + }, ++#endif/* CONFIG_DRIVER_NL80211_IFX */ + { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none, + "= flush ERP keys" }, + { "mac_rand_scan", +diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h +index 28eff55ed..553d27d2c 100644 +--- a/wpa_supplicant/wpa_supplicant_i.h ++++ b/wpa_supplicant/wpa_supplicant_i.h +@@ -1712,6 +1712,15 @@ void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, + const u8 *data, size_t slen); + void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s); + ++#ifdef CONFIG_DRIVER_NL80211_IFX ++int wpas_config_offload_send_mbo_config(struct wpa_supplicant *wpa_s, u8 cmd_id, ++ u8 oper_class, u8 chan, u8 pref_val, ++ u8 reason_code, u8 enable, u8 notif_type, ++ u8 time_offset, u8 rssi_trig_delta, ++ bool enable_anqpo, bool enable_cell_pref, ++ u8 cell_pref_val, u8 cell_cap); ++#endif /* CONFIG_DRIVER_NL80211_IFX */ ++ + /* op_classes.c */ + enum chan_allowed { + NOT_ALLOWED, NO_IR, RADAR, ALLOWED +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.patch new file mode 100644 index 000000000..c315cf322 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.patch @@ -0,0 +1,94 @@ +From cfaf2f6273ddd9ac618c61bc2294fb60297100a7 Mon Sep 17 00:00:00 2001 +From: Jouni Malinen +Date: Wed, 6 Apr 2022 16:13:22 +0300 +Subject: [PATCH 50/60] EAP-TLS: Allow TLSv1.3 support to be enabled with build + config + +The default behavior in wpa_supplicant is to disable use of TLSv1.3 in +EAP-TLS unless explicitly enabled in network configuration. The new +CONFIG_EAP_TLSV1_3=y build parameter can be used to change this to +enable TLSv1.3 by default (if supported by the TLS library). + +Signed-off-by: Jouni Malinen +--- + src/eap_peer/eap_tls_common.c | 12 +++++++----- + wpa_supplicant/Android.mk | 3 +++ + wpa_supplicant/Makefile | 3 +++ + wpa_supplicant/defconfig | 3 +++ + 4 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c +index c1837db06..5fb894501 100644 +--- a/src/eap_peer/eap_tls_common.c ++++ b/src/eap_peer/eap_tls_common.c +@@ -192,18 +192,20 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, + * TLS v1.3 changes, so disable this by default for now. */ + params->flags |= TLS_CONN_DISABLE_TLSv1_3; + } ++#ifndef EAP_TLSV1_3 + if (data->eap_type == EAP_TYPE_TLS || + data->eap_type == EAP_UNAUTH_TLS_TYPE || + data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) { + /* While the current EAP-TLS implementation is more or less +- * complete for TLS v1.3, there has been no interoperability +- * testing with other implementations, so disable for by default +- * for now until there has been chance to confirm that no +- * significant interoperability issues show up with TLS version +- * update. ++ * complete for TLS v1.3, there has been only minimal ++ * interoperability testing with other implementations, so ++ * disable it by default for now until there has been chance to ++ * confirm that no significant interoperability issues show up ++ * with TLS version update. + */ + params->flags |= TLS_CONN_DISABLE_TLSv1_3; + } ++#endif /* EAP_TLSV1_3 */ + if (phase2 && sm->use_machine_cred) { + wpa_printf(MSG_DEBUG, "TLS: using machine config options"); + eap_tls_params_from_conf2m(params, config); +diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk +index 892cb7507..a54517eea 100644 +--- a/wpa_supplicant/Android.mk ++++ b/wpa_supplicant/Android.mk +@@ -482,6 +482,9 @@ OBJS += src/eap_peer/eap_tls.c + endif + TLS_FUNCS=y + CONFIG_IEEE8021X_EAPOL=y ++ifdef CONFIG_EAP_TLSV1_3 ++L_CFLAGS += -DEAP_TLSV1_3 ++endif + endif + + ifdef CONFIG_EAP_UNAUTH_TLS +diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile +index 16e484ce6..8978546c8 100644 +--- a/wpa_supplicant/Makefile ++++ b/wpa_supplicant/Makefile +@@ -484,6 +484,9 @@ OBJS += ../src/eap_peer/eap_tls.o + endif + TLS_FUNCS=y + CONFIG_IEEE8021X_EAPOL=y ++ifdef CONFIG_EAP_TLSV1_3 ++CFLAGS += -DEAP_TLSV1_3 ++endif + endif + + ifdef CONFIG_EAP_UNAUTH_TLS +diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig +index a4719dbb5..ab3fba322 100644 +--- a/wpa_supplicant/defconfig ++++ b/wpa_supplicant/defconfig +@@ -101,6 +101,9 @@ CONFIG_EAP_MSCHAPV2=y + + # EAP-TLS + CONFIG_EAP_TLS=y ++# Enable EAP-TLSv1.3 support by default (currently disabled unless explicitly ++# enabled in network configuration) ++#CONFIG_EAP_TLSV1_3=y + + # EAL-PEAP + CONFIG_EAP_PEAP=y +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0051-Enabling-TLS-v1.3-by-default.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0051-Enabling-TLS-v1.3-by-default.patch new file mode 100644 index 000000000..65e270a6d --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0051-Enabling-TLS-v1.3-by-default.patch @@ -0,0 +1,27 @@ +From 39e1c0d43c57f3f76ac02813caa75b7a3dfb5d69 Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Fri, 24 Mar 2023 01:45:06 -0500 +Subject: [PATCH 51/60] Enabling TLS v1.3 by default + +Fixes: SWLINUX-3331 +--- + wpa_supplicant/defconfig_base | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/wpa_supplicant/defconfig_base b/wpa_supplicant/defconfig_base +index bfaed5d91..59aeae69c 100644 +--- a/wpa_supplicant/defconfig_base ++++ b/wpa_supplicant/defconfig_base +@@ -103,6 +103,9 @@ CONFIG_EAP_MSCHAPV2=y + + # EAP-TLS + CONFIG_EAP_TLS=y ++# Enable EAP-TLSv1.3 support by default (currently disabled unless explicitly ++# enabled in network configuration) ++CONFIG_EAP_TLSV1_3=y + + # EAL-PEAP + CONFIG_EAP_PEAP=y +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch new file mode 100644 index 000000000..14df86fa1 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0052-Disable-4-way-handshake-offload-for-DPP.patch @@ -0,0 +1,31 @@ +From e533a201ebe00eb208509117b3b69b3e58f34633 Mon Sep 17 00:00:00 2001 +From: avishad verma +Date: Tue, 7 Mar 2023 04:44:25 -0600 +Subject: [PATCH 52/60] Disable 4-way handshake offload for DPP + +H1 combo is using internal supplicant and 4-way handshake is offloaded +to firmware for softap mode. +For DPP Softap role external supplicant will be used. + +Signed-off-by: avishad verma +--- + src/ap/wpa_auth_glue.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c +index c8dee2aef..7e3b8384f 100644 +--- a/src/ap/wpa_auth_glue.c ++++ b/src/ap/wpa_auth_glue.c +@@ -1529,6 +1529,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) + !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG); + + if (!hapd->conf->p2p && ++#ifdef CONFIG_DPP ++ (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP)) && ++#endif /* CONFIG_DPP */ + (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) + _conf.psk_4way_hs_offload = 1; + +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.patch new file mode 100644 index 000000000..62fb1ea47 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.patch @@ -0,0 +1,382 @@ +From 54929427eb8af4affaf8017bc8d127cc7c629581 Mon Sep 17 00:00:00 2001 +From: Shelley Yang +Date: Wed, 29 Mar 2023 03:28:59 -0500 +Subject: [PATCH 53/60] non-upstream: WNM: wpa_cli wnm_maxilde command by IFX + vendorID + +1. set +before: wl wnm_maxidle 10 1 +after: wpa_cli wnm_maxidle period=10 option=1 +2. get +before: wl wnm_maxidle +after: wpa_cli wnm_maxidle + +Fixes: SWWLAN-145213 + +Signed-off-by: Shelley Yang +--- + src/common/ifx_vendor.h | 55 ++++++++++++++++++ + src/drivers/driver.h | 7 +++ + src/drivers/driver_nl80211.c | 92 +++++++++++++++++++++++++++++++ + src/drivers/driver_nl80211.h | 1 + + src/drivers/driver_nl80211_capa.c | 3 + + wpa_supplicant/ctrl_iface.c | 56 +++++++++++++++++++ + wpa_supplicant/driver_i.h | 8 +++ + wpa_supplicant/wpa_cli.c | 10 ++++ + 8 files changed, 232 insertions(+) + +diff --git a/src/common/ifx_vendor.h b/src/common/ifx_vendor.h +index 6cd3b874c..2fed69ca6 100644 +--- a/src/common/ifx_vendor.h ++++ b/src/common/ifx_vendor.h +@@ -78,6 +78,7 @@ enum ifx_nl80211_vendor_subcmds { + IFX_VENDOR_SCMD_TWT = 14, + /* Reserved 15-17 */ + IFX_VENDOR_SCMD_MBO = 18, ++ IFX_VENDOR_SCMD_WNM = 25, + IFX_VENDOR_SCMD_MAX + }; + +@@ -312,4 +313,58 @@ enum ifx_vendor_attr_mbo_param { + IFX_VENDOR_ATTR_MBO_PARAM_MAX + }; + ++enum ifx_vendor_attr_wnm { ++ IFX_VENDOR_ATTR_WNM_UNSPEC, ++ IFX_VENDOR_ATTR_WNM_CMD, ++ IFX_VENDOR_ATTR_WNM_PARAMS, ++ IFX_VENDOR_ATTR_WNM_MAX ++}; ++ ++enum ifx_wnm_config_cmd_type { ++ IFX_WNM_CONFIG_CMD_TYPE_INVALID = -1, ++ //align internal definition ++ IFX_WNM_CONFIG_CMD_IOV_WNM = 1, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_MAXIDLE = 2, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TIMBC_OFFSET = 3, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_URL = 4, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_REQ = 5, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_TCLASTYPE = 6, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_PARP_DISCARD = 7, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_PARP_ALLNODE = 8, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TIMBC_SET = 9, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TIMBC_STATUS = 10, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_SET = 11, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_TERM = 12, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_SERVICE_TERM = 13, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_SLEEP_INTV = 14, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_SLEEP_MODE = 15, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_QUERY = 16, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_RESP = 17, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TCLAS_ADD = 18, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TCLAS_DEL = 19, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TCLAS_LIST = 20, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_STATUS = 21, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_KEEPALIVES_MAX_IDLE = 22, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_PM_IGNORE_BCMC = 23, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_DMS_DEPENDENCY = 24, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_ROAMTHROTTLE = 25, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_SET = 26, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_TERM = 27, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_TFS_STATUS = 28, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BTQ_NBR_ADD = 29, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BTQ_NBR_DEL = 30, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BTQ_NBR_LIST = 31, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_BSSTRANS_RSSI_RATE_MAP = 32, ++ IFX_WNM_CONFIG_CMD_IOV_WNM_KEEPALIVE_PKT_TYPE = 33, ++ IFX_WNM_CONFIG_CMD_TYPE_MAX ++}; ++ ++enum ifx_vendor_attr_wnm_maxidle_param { ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_UNSPEC, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_GET_INFO, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_MAX ++}; ++ + #endif /* IFX_VENDOR_H */ +diff --git a/src/drivers/driver.h b/src/drivers/driver.h +index 996614ee5..d75abbd5e 100644 +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -2598,6 +2598,12 @@ struct drv_config_mbo_params { + } cellular_pref; + } u; + }; ++ ++struct drv_maxidle_wnm_params { ++ u8 get_info; ++ int period; ++ int protect; ++}; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + struct wpa_bss_trans_info { +@@ -4727,6 +4733,7 @@ struct wpa_driver_ops { + int (*teardown_twt)(void *priv, struct drv_teardown_twt_params *params); + #endif /* CONFIG_TWT_OFFLOAD_IFX */ + int (*config_mbo)(void *priv, struct drv_config_mbo_params *params); ++ int (*maxidle_wnm)(void *priv, struct drv_maxidle_wnm_params *params); + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + }; +diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c +index 506b1e406..ed7c969c1 100644 +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -12613,6 +12613,97 @@ fail: + nlmsg_free(msg); + return ret; + } ++ ++static int wpa_driver_nl80211_maxidle_wnm_reply_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ char *buf = arg; ++ char *data; ++ int len; ++ ++ wpa_printf(MSG_INFO, "nl80211: maxidle_wnm command reply handler"); ++ ++ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ if (tb_msg[NL80211_ATTR_VENDOR_DATA]) { ++ data = (char *)((char *)tb_msg[NL80211_ATTR_VENDOR_DATA] + GENL_HDRLEN); ++ len = nla_len(tb_msg[NL80211_ATTR_VENDOR_DATA]); ++ os_memcpy(buf, data, len); ++ } ++ return NL_SKIP; ++} ++ ++static int wpa_driver_nl80211_config_maxidle_wnm(void *priv, struct drv_maxidle_wnm_params *params) ++{ ++ struct i802_bss *bss = priv; ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ struct nl_msg *msg = NULL; ++ struct nlattr *data, *wnm_param_attrs; ++ int ret = -1, get_period = 0; ++ ++ if (!drv->ifx_wnm_offload) ++ goto fail; ++ ++ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_IFX) || ++ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, IFX_VENDOR_SCMD_WNM)) ++ goto fail; ++ ++ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); ++ if (!data) ++ goto fail; ++ ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_CMD, IFX_WNM_CONFIG_CMD_IOV_WNM_MAXIDLE)) ++ goto fail; ++ ++ wnm_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_WNM_PARAMS); ++ if (!wnm_param_attrs) ++ goto fail; ++ ++ if (params->get_info) { ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_GET_INFO, ++ params->get_info)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: WNM config: build msg ATTR:%d failed", ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_GET_INFO); ++ goto fail; ++ } ++ } else { ++ if (nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD, ++ params->period) || ++ nla_put_u8(msg, IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT, ++ params->protect)) { ++ wpa_printf(MSG_ERROR, ++ "nl80211: WNM config: build ATTR:%d %d failed", ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD, ++ IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT); ++ goto fail; ++ } ++ } ++ nla_nest_end(msg, wnm_param_attrs); ++ nla_nest_end(msg, data); ++ ++ if (params->get_info) ++ ret = send_and_recv_msgs(drv, msg, wpa_driver_nl80211_maxidle_wnm_reply_handler, ++ &get_period, NULL, NULL); ++ else ++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); ++ ++ if (ret) ++ wpa_printf(MSG_ERROR, "nl80211: WNM maxidle: Failed to invoke driver %s", ++ strerror(-ret)); ++ else ++ if (params->get_info) ++ params->period = get_period; ++ ++ return ret; ++fail: ++ nl80211_nlmsg_clear(msg); ++ nlmsg_free(msg); ++ return ret; ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { +@@ -12765,5 +12856,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { + .teardown_twt = wpa_driver_nl80211_teardown_twt, + #endif /* CONFIG_TWT_OFFLOAD_IFX */ + .config_mbo = wpa_driver_nl80211_config_mbo, ++ .maxidle_wnm = wpa_driver_nl80211_config_maxidle_wnm, + #endif /* CONFIG_DRIVER_NL80211_IFX */ + }; +diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h +index 6d2c09477..6d9945c88 100644 +--- a/src/drivers/driver_nl80211.h ++++ b/src/drivers/driver_nl80211.h +@@ -183,6 +183,7 @@ struct wpa_driver_nl80211_data { + #ifdef CONFIG_DRIVER_NL80211_IFX + unsigned int ifx_twt_offload:1; + unsigned int ifx_mbo_offload:1; ++ unsigned int ifx_wnm_offload:1; + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + u64 vendor_scan_cookie; +diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c +index b0807a7fc..21b9c03ff 100644 +--- a/src/drivers/driver_nl80211_capa.c ++++ b/src/drivers/driver_nl80211_capa.c +@@ -1062,6 +1062,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) + case IFX_VENDOR_SCMD_MBO: + drv->ifx_mbo_offload = 1; + break; ++ case IFX_VENDOR_SCMD_WNM: ++ drv->ifx_wnm_offload = 1; ++ break; + } + #endif /* CONFIG_DRIVER_NL80211_IFX */ + } +diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c +index 9f0149a20..d07fdb0a9 100644 +--- a/wpa_supplicant/ctrl_iface.c ++++ b/wpa_supplicant/ctrl_iface.c +@@ -10337,6 +10337,58 @@ static int wpas_ctrl_iface_send_mbo_config(struct wpa_supplicant *wpa_s, + enable_cell_pref, cell_pref_val, + cell_cap); + } ++ ++static int wpas_ctrl_iface_send_wnm_maxidle(struct wpa_supplicant *wpa_s, ++ const char *cmd, char *reply, int reply_size) ++{ ++ u8 params_check = 0; ++ int period = 0, option = 0, ret = 0; ++ const char *tok_s; ++ struct drv_maxidle_wnm_params params; ++ char *pos, *end; ++ ++ pos = reply; ++ end = pos + reply_size; ++ os_memset(¶ms, 0, sizeof(struct drv_maxidle_wnm_params)); ++ ++ if (cmd) { ++ tok_s = os_strstr(cmd, " period="); ++ if (tok_s) { ++ period = atoi(tok_s + os_strlen(" period=")); ++ params_check |= BIT(IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD); ++ } ++ ++ tok_s = os_strstr(cmd, " option="); ++ if (tok_s) { ++ option = atoi(tok_s + os_strlen(" option=")); ++ params_check |= BIT(IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT); ++ } ++ ++ if (params_check & BIT(IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_IDLE_PERIOD) && ++ params_check & BIT(IFX_VENDOR_ATTR_WNM_MAXIDLE_PARAM_PROTECTION_OPT)) { ++ params.period = period; ++ params.protect = option; ++ params.get_info = false; ++ } else { ++ wpa_printf(MSG_ERROR, "set wnm_maxidle parameters not full(%02x).\n", ++ params_check); ++ ret = -EINVAL; ++ goto fail; ++ } ++ } else { ++ params.get_info = true; ++ wpa_printf(MSG_DEBUG, "get wnm_maxidle parameters\n"); ++ } ++ ret = wpa_drv_maxidle_wnm(wpa_s, ¶ms); ++ if (cmd == NULL && !ret) { ++ ret = os_snprintf(pos, end - pos, "BSS Max Idle Period: %d\n", params.period); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - reply; ++ } ++ ++fail: ++ return ret; ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) +@@ -12463,6 +12515,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, + } else if (os_strncmp(buf, "MBO ", 4) == 0) { + if (wpas_ctrl_iface_send_mbo_config(wpa_s, buf + 3)) + reply_len = -1; ++ } else if (os_strncmp(buf, "WNM_MAXIDLE ", 12) == 0) { ++ reply_len = wpas_ctrl_iface_send_wnm_maxidle(wpa_s, buf + 11, reply, reply_size); ++ } else if (os_strcmp(buf, "WNM_MAXIDLE") == 0) { ++ reply_len = wpas_ctrl_iface_send_wnm_maxidle(wpa_s, NULL, reply, reply_size); + #endif /* CONFIG_DRIVER_NL80211_IFX */ + } else if (os_strncmp(buf, "TWT_TEARDOWN ", 13) == 0) { + if (wpas_ctrl_iface_send_twt_teardown(wpa_s, buf + 12)) +diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h +index 2fcfa44a6..fa11f72aa 100644 +--- a/wpa_supplicant/driver_i.h ++++ b/wpa_supplicant/driver_i.h +@@ -1153,6 +1153,14 @@ static inline int wpa_drv_config_mbo(struct wpa_supplicant *wpa_s, + return -1; + return wpa_s->driver->config_mbo(wpa_s->drv_priv, params); + } ++ ++static inline int wpa_drv_maxidle_wnm(struct wpa_supplicant *wpa_s, ++ struct drv_maxidle_wnm_params *params) ++{ ++ if (!wpa_s->driver->maxidle_wnm) ++ return -1; ++ return wpa_s->driver->maxidle_wnm(wpa_s->drv_priv, params); ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + #endif /* DRIVER_I_H */ +diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c +index 3055417fe..8119d0865 100644 +--- a/wpa_supplicant/wpa_cli.c ++++ b/wpa_supplicant/wpa_cli.c +@@ -2963,6 +2963,12 @@ static int wpa_cli_cmd_mbo_config(struct wpa_ctrl *ctrl, int argc, + { + return wpa_cli_cmd(ctrl, "MBO", 0, argc, argv); + } ++ ++static int wpa_cli_cmd_wnm_maxidle(struct wpa_ctrl *ctrl, int argc, ++ char *argv[]) ++{ ++ return wpa_cli_cmd(ctrl, "WNM_MAXIDLE", 0, argc, argv); ++} + #endif /* CONFIG_DRIVER_NL80211_IFX */ + + +@@ -3896,6 +3902,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { + wpa_cli_cmd_mbo_config, NULL, cli_cmd_flag_none, + "[flags=] = Send TWT Teardown frame" + }, ++ { "wnm_maxidle", ++ wpa_cli_cmd_wnm_maxidle, NULL, cli_cmd_flag_none, ++ "[period=] [option=]" ++ }, + #endif/* CONFIG_DRIVER_NL80211_IFX */ + { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none, + "= flush ERP keys" }, +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch new file mode 100644 index 000000000..0e0400b14 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch @@ -0,0 +1,170 @@ +From b3165e0a92a3090a99ef396e77fa90b7e61d6558 Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Wed, 3 May 2023 21:13:26 -0500 +Subject: [PATCH 54/60] brcmfmac: sync content of nl80211_copy.h for BSS_COLOR + attributes + +sync the nl80211.h as of 0d2ab3aea in brcm80211 + +Signed-off-by: Carter Chen +--- + src/drivers/driver_nl80211_event.c | 5 +++ + src/drivers/nl80211_copy.h | 56 ++++++++++++++++++++++++++++-- + 2 files changed, 59 insertions(+), 2 deletions(-) + +diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c +index fe91fff90..d3cb8d882 100644 +--- a/src/drivers/driver_nl80211_event.c ++++ b/src/drivers/driver_nl80211_event.c +@@ -172,6 +172,11 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) + C2S(NL80211_CMD_UNPROT_BEACON) + C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS) + C2S(NL80211_CMD_SET_SAR_SPECS) ++ C2S(NL80211_CMD_OBSS_COLOR_COLLISION) ++ C2S(NL80211_CMD_COLOR_CHANGE_REQUEST) ++ C2S(NL80211_CMD_COLOR_CHANGE_STARTED) ++ C2S(NL80211_CMD_COLOR_CHANGE_ABORTED) ++ C2S(NL80211_CMD_COLOR_CHANGE_COMPLETED) + C2S(__NL80211_CMD_AFTER_LAST) + } + #undef C2S +diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h +index db5b1503d..ee80ae025 100644 +--- a/src/drivers/nl80211_copy.h ++++ b/src/drivers/nl80211_copy.h +@@ -11,7 +11,7 @@ + * Copyright 2008 Jouni Malinen + * Copyright 2008 Colin McCabe + * Copyright 2015-2017 Intel Deutschland GmbH +- * Copyright (C) 2018-2020 Intel Corporation ++ * Copyright (C) 2018-2021 Intel Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -1185,6 +1185,21 @@ + * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to + * specify the wiphy index to be applied to. + * ++ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever ++ * mac80211/drv detects a bss color collision. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that ++ * userspace wants to change the BSS color. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has ++ * started ++ * ++ * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has ++ * been aborted ++ * ++ * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change ++ * has completed ++ * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +@@ -1417,6 +1432,14 @@ enum nl80211_commands { + + NL80211_CMD_SET_SAR_SPECS, + ++ NL80211_CMD_OBSS_COLOR_COLLISION, ++ ++ NL80211_CMD_COLOR_CHANGE_REQUEST, ++ ++ NL80211_CMD_COLOR_CHANGE_STARTED, ++ NL80211_CMD_COLOR_CHANGE_ABORTED, ++ NL80211_CMD_COLOR_CHANGE_COMPLETED, ++ + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ +@@ -2403,7 +2426,10 @@ enum nl80211_commands { + * in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it + * wants to use the supported offload of the 4-way handshake. + * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT. +- * @NL80211_ATTR_PORT_AUTHORIZED: (reserved) ++ * @NL80211_ATTR_PORT_AUTHORIZED: flag attribute used in %NL80211_CMD_ROAMED ++ * notification indicating that that 802.1X authentication was done by ++ * the driver or is not needed (because roaming used the Fast Transition ++ * protocol). + * + * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external + * authentication operation (u32 attribute with an +@@ -2560,6 +2586,16 @@ enum nl80211_commands { + * disassoc events to indicate that an immediate reconnect to the AP + * is desired. + * ++ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the ++ * %NL80211_CMD_OBSS_COLOR_COLLISION event. ++ * ++ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's ++ * until the color switch event. ++ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are ++ * switching to ++ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE ++ * information for the time while performing a color switch. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3057,6 +3093,12 @@ enum nl80211_attrs { + + NL80211_ATTR_DISABLE_HE, + ++ NL80211_ATTR_OBSS_COLOR_BITMAP, ++ ++ NL80211_ATTR_COLOR_CHANGE_COUNT, ++ NL80211_ATTR_COLOR_CHANGE_COLOR, ++ NL80211_ATTR_COLOR_CHANGE_ELEMS, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -3654,6 +3696,8 @@ enum nl80211_mpath_info { + * defined + * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16), + * given for all 6 GHz band channels ++ * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are ++ * advertised on this band/for this iftype (binary) + * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use + */ + enum nl80211_band_iftype_attr { +@@ -3665,6 +3709,7 @@ enum nl80211_band_iftype_attr { + NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, + NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, ++ NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, + + /* keep last */ + __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, +@@ -5950,6 +5995,9 @@ enum nl80211_feature_flags { + * frame protection for all management frames exchanged during the + * negotiation and range measurement procedure. + * ++ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision ++ * detection and change announcemnts. ++ * + * @NUM_NL80211_EXT_FEATURES: number of extended features. + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. + */ +@@ -6914,6 +6962,9 @@ enum nl80211_peer_measurement_ftm_capa { + * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only + * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set. ++ * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the ++ * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED ++ * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set. + * + * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal + * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number +@@ -6933,6 +6984,7 @@ enum nl80211_peer_measurement_ftm_req { + NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, ++ NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, + + /* keep last */ + NUM_NL80211_PMSR_FTM_REQ_ATTR, +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch new file mode 100644 index 000000000..90ac1dd4f --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch @@ -0,0 +1,37 @@ +From 2d7ff191ddcea8740b6fb48094b87de12150c88f Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Wed, 3 May 2023 20:43:09 -0500 +Subject: [PATCH 55/60] WPA3-SAE: enable nl_connect socket while + WPA_DRIVER_FLAGS_BSS_SELECTION + +The driver-base roaming uses WPA_DRIVER_FLAGS_BSS_SELECTION flag. + +As the SAE is handled by wpa_supplicant, +the driver will report send_req of auth req frame. + +WPA3-CERT 5.8.3 connects to PSK AP first, then roaming to SAE AP. +the nl_connect needs to keep opening to listen the event for process +auth frames. + +Fixes: SWLINUX-3420 + +Signed-off-by: Carter Chen +--- + src/drivers/driver_nl80211.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c +index ed7c969c1..55b4d07dc 100644 +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -557,6 +557,7 @@ send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv, + struct nl_sock * get_connect_handle(struct i802_bss *bss) + { + if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) || ++ (bss->drv->capa.flags & WPA_DRIVER_FLAGS_BSS_SELECTION) || + bss->use_nl_connect) + return bss->nl_connect; + +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch new file mode 100644 index 000000000..b7e0c451f --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch @@ -0,0 +1,31 @@ +From 8a905fcddca5936ba8873c7f0dacab7188dc6eac Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Mon, 17 Jul 2023 22:31:46 -0500 +Subject: [PATCH 56/60] OWE AP: enable OWE compile option for hostapd executing + OWE + +Enabling OWE compile option + +Fixes: SWLINUX-3620 + +Signed-off-by: Carter Chen +--- + hostapd/defconfig_base | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hostapd/defconfig_base b/hostapd/defconfig_base +index 16e8c645a..571ab6eda 100644 +--- a/hostapd/defconfig_base ++++ b/hostapd/defconfig_base +@@ -374,7 +374,7 @@ CONFIG_WPA_CLI_EDIT=y + + # Opportunistic Wireless Encryption (OWE) + # Experimental implementation of draft-harkins-owe-07.txt +-#CONFIG_OWE=y ++CONFIG_OWE=y + + # Airtime policy support + #CONFIG_AIRTIME_POLICY=y +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch new file mode 100644 index 000000000..dc1d7eecf --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch @@ -0,0 +1,232 @@ +From 8a6154044994dbeac362d76bbe5822612af64067 Mon Sep 17 00:00:00 2001 +From: "Lin Ian (IFTW CSS ICW SW WFS 1)" +Date: Mon, 16 Oct 2023 09:18:19 +0000 +Subject: [PATCH 57/60] DPP2.0: support DPP2.0 and add pfs init flow on + EVENT_UPDATE_DH + +--- + hostapd/defconfig_base | 1 + + src/ap/drv_callbacks.c | 55 ++++++++++++++++----------- + src/ap/ieee802_11.c | 70 ++++++++++++++++++++++++++++++++++- + src/ap/ieee802_11.h | 3 ++ + wpa_supplicant/defconfig_base | 1 + + 5 files changed, 107 insertions(+), 23 deletions(-) + +diff --git a/hostapd/defconfig_base b/hostapd/defconfig_base +index 571ab6eda..eae36af0b 100644 +--- a/hostapd/defconfig_base ++++ b/hostapd/defconfig_base +@@ -406,3 +406,4 @@ CONFIG_WPA3_SAE_AUTH_EARLY_SET=y + + # Device Provisioning Protocol (DPP) + CONFIG_DPP=y ++CONFIG_DPP2=y +diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c +index a50e6f2af..989ba735d 100644 +--- a/src/ap/drv_callbacks.c ++++ b/src/ap/drv_callbacks.c +@@ -648,13 +648,12 @@ skip_wpa_check: + #endif /* CONFIG_OWE */ + + #ifdef CONFIG_DPP2 +- dpp_pfs_free(sta->dpp_pfs); +- sta->dpp_pfs = NULL; ++ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && ++ hapd->conf->dpp_netaccesskey && sta->wpa_sm && ++ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && ++ elems.owe_dh) { + +- if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && +- hapd->conf->dpp_netaccesskey && sta->wpa_sm && +- wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && +- elems.owe_dh) { ++ if (!sta->dpp_pfs) { + sta->dpp_pfs = dpp_pfs_init( + wpabuf_head(hapd->conf->dpp_netaccesskey), + wpabuf_len(hapd->conf->dpp_netaccesskey)); +@@ -664,19 +663,20 @@ skip_wpa_check: + /* Try to continue without PFS */ + goto pfs_fail; + } ++ } + +- if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, +- elems.owe_dh_len) < 0) { +- dpp_pfs_free(sta->dpp_pfs); +- sta->dpp_pfs = NULL; +- reason = WLAN_REASON_UNSPECIFIED; +- goto fail; +- } ++ if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, ++ elems.owe_dh_len) < 0) { ++ dpp_pfs_free(sta->dpp_pfs); ++ sta->dpp_pfs = NULL; ++ reason = WLAN_REASON_UNSPECIFIED; ++ goto fail; + } ++ } + +- wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? +- sta->dpp_pfs->secret : NULL); +- pfs_fail: ++ wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? ++ sta->dpp_pfs->secret : NULL); ++pfs_fail: + #endif /* CONFIG_DPP2 */ + + if (elems.rrm_enabled && +@@ -1792,8 +1792,9 @@ static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, + wpa_printf(MSG_DEBUG, "OWE: Peer unknown"); + return -1; + } +- if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) { +- wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured"); ++ if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && ++ !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP)) { ++ wpa_printf(MSG_DEBUG, "OWE/DPP: No OWE/DPP AKM configured"); + status = WLAN_STATUS_AKMP_NOT_VALID; + goto err; + } +@@ -1828,9 +1829,21 @@ static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, + } + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); + +- status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, +- elems.rsn_ie_len, elems.owe_dh, +- elems.owe_dh_len); ++#ifdef CONFIG_DPP2 ++ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) { ++ if (hapd->conf->dpp_netaccesskey && elems.owe_dh) ++ status = dpp_process_rsn_ie(hapd, sta, elems.rsn_ie, ++ elems.rsn_ie_len, elems.owe_dh, ++ elems.owe_dh_len); ++ else ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ } else ++#endif /* CONFIG_DPP2 */ ++ { ++ status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, ++ elems.rsn_ie_len, elems.owe_dh, ++ elems.owe_dh_len); ++ } + if (status != WLAN_STATUS_SUCCESS) + ap_free_sta(hapd, sta); + +diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c +index c4f7d00cc..564815381 100644 +--- a/src/ap/ieee802_11.c ++++ b/src/ap/ieee802_11.c +@@ -4348,9 +4348,10 @@ u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, + wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len); + return wpa_res_to_status_code(res); + } +- if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) { ++ if (!(data.key_mgmt & WPA_KEY_MGMT_OWE) && ++ !(data.key_mgmt & WPA_KEY_MGMT_DPP)) { + wpa_printf(MSG_DEBUG, +- "OWE: Unexpected key mgmt 0x%x from " MACSTR, ++ "OWE/DPP: Unexpected key mgmt 0x%x from " MACSTR, + (unsigned int) data.key_mgmt, MAC2STR(peer)); + return WLAN_STATUS_AKMP_NOT_VALID; + } +@@ -4444,6 +4445,71 @@ end: + + #endif /* CONFIG_OWE */ + ++#ifdef CONFIG_DPP2 ++u16 dpp_process_rsn_ie(struct hostapd_data *hapd, ++ struct sta_info *sta, ++ const u8 *rsn_ie, size_t rsn_ie_len, ++ const u8 *owe_dh, size_t owe_dh_len) ++{ ++ u16 status = WLAN_STATUS_SUCCESS; ++ u8 *owe_buf, ie[256 * 2]; ++ size_t ie_len = 0; ++ enum wpa_validate_result res; ++ ++ if (!rsn_ie || rsn_ie_len < 2) { ++ wpa_printf(MSG_DEBUG, "DPP: No RSNE in (Re)AssocReq"); ++ status = WLAN_STATUS_INVALID_IE; ++ goto end; ++ } ++ ++ if (!sta->wpa_sm) ++ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, ++ NULL); ++ if (!sta->wpa_sm) { ++ wpa_printf(MSG_WARNING, ++ "DPP: Failed to initialize WPA state machine"); ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ goto end; ++ } ++ rsn_ie -= 2; ++ rsn_ie_len += 2; ++ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ++ hapd->iface->freq, rsn_ie, rsn_ie_len, ++ NULL, 0, NULL, 0, owe_dh, owe_dh_len); ++ status = wpa_res_to_status_code(res); ++ if (status != WLAN_STATUS_SUCCESS) ++ goto end; ++ ++ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie), ++ NULL, 0); ++ if (!owe_buf) { ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ goto end; ++ } ++ ++ dpp_pfs_free(sta->dpp_pfs); ++ sta->dpp_pfs = NULL; ++ sta->dpp_pfs = dpp_pfs_init( ++ wpabuf_head(hapd->conf->dpp_netaccesskey), ++ wpabuf_len(hapd->conf->dpp_netaccesskey)); ++ ++ if (!sta->dpp_pfs) { ++ wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS"); ++ status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ } else { ++ os_memcpy(owe_buf, wpabuf_head(sta->dpp_pfs->ie), wpabuf_len(sta->dpp_pfs->ie)); ++ ie_len = owe_buf - ie + wpabuf_len(sta->dpp_pfs->ie); ++ } ++end: ++ wpa_printf(MSG_DEBUG, "DPP: Update status %d, ie len %d for peer " ++ MACSTR, status, (unsigned int) ie_len, ++ MAC2STR(sta->addr)); ++ hostapd_drv_update_dh_ie(hapd, sta->addr, status, ++ status == WLAN_STATUS_SUCCESS ? ie : NULL, ++ ie_len); ++ return status; ++} ++#endif /* CONFIG_DPP2 */ + + static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta, + int reassoc) +diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h +index c59ad5e38..3042b6bac 100644 +--- a/src/ap/ieee802_11.h ++++ b/src/ap/ieee802_11.h +@@ -171,6 +171,9 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, + u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *rsn_ie, size_t rsn_ie_len, + const u8 *owe_dh, size_t owe_dh_len); ++u16 dpp_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta, ++ const u8 *rsn_ie, size_t rsn_ie_len, ++ const u8 *owe_dh, size_t owe_dh_len); + u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, + const u8 *rsn_ie, size_t rsn_ie_len, + const u8 *owe_dh, size_t owe_dh_len); +diff --git a/wpa_supplicant/defconfig_base b/wpa_supplicant/defconfig_base +index 59aeae69c..f34011d84 100644 +--- a/wpa_supplicant/defconfig_base ++++ b/wpa_supplicant/defconfig_base +@@ -617,6 +617,7 @@ CONFIG_OWE=y + + # Device Provisioning Protocol (DPP) + CONFIG_DPP=y ++CONFIG_DPP2=y + + # Wired equivalent privacy (WEP) + # WEP is an obsolete cryptographic data confidentiality algorithm that is not +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch new file mode 100644 index 000000000..3928c2cae --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch @@ -0,0 +1,31 @@ +From d449e4402e4981b8c5067aaab1db34cd73e40468 Mon Sep 17 00:00:00 2001 +From: "P Rakshith (CAE 1 A)" +Date: Fri, 20 Oct 2023 08:34:04 +0000 +Subject: [PATCH 58/60] non-upstream: Prevent invalid akm key mgmt when MFP + required is set + +--- + src/ap/ap_config.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c +index 86b6e097c..a7fd85018 100644 +--- a/src/ap/ap_config.c ++++ b/src/ap/ap_config.c +@@ -1432,6 +1432,13 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, + } + #endif /* CONFIG_FILS */ + ++ if (full_config && (bss->ieee80211w == 2) && ++ (bss->wpa_key_mgmt == (WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_PSK))) { ++ wpa_printf(MSG_ERROR, ++ "Cannot set ieee80211w=2 along with with the selected wpa_key_mgmt"); ++ return -1; ++ } ++ + return 0; + } + +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0059-Reset-authentication-and-encryption-parameters-while.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0059-Reset-authentication-and-encryption-parameters-while.patch new file mode 100644 index 000000000..88dbf9807 --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0059-Reset-authentication-and-encryption-parameters-while.patch @@ -0,0 +1,70 @@ +From 10a78d57f331333da8aba9be83f6cafbb7a6f382 Mon Sep 17 00:00:00 2001 +From: Ian Lin +Date: Sun, 22 Oct 2023 21:19:08 -0500 +Subject: [PATCH 59/60] Reset authentication and encryption parameters while + handling roam event + +While supplicant received NL80211_CMD_ROAM event and run EVENT_ASSOC flow, +it will not reset sm->pmk in wpa_supplicant_select_config since old and new SSID are the same. +It causes using wrong pmk when roaming from WPA3 to WPA2. +So add the flow to only reset sm->pmk while handling roam event. + +Signed-off-by: Ian Lin +--- + src/drivers/driver.h | 6 ++++++ + src/drivers/driver_nl80211_event.c | 1 + + wpa_supplicant/events.c | 9 +++++++++ + 3 files changed, 16 insertions(+) + +diff --git a/src/drivers/driver.h b/src/drivers/driver.h +index d75abbd5e..9ebb4b07f 100644 +--- a/src/drivers/driver.h ++++ b/src/drivers/driver.h +@@ -5546,6 +5546,12 @@ union wpa_event_data { + * fils_pmkid - PMKID used or generated in FILS authentication + */ + const u8 *fils_pmkid; ++ ++ /** ++ * roam_indication - Indicate it's a roam event ++ */ ++ bool roam_indication; ++ + } assoc_info; + + /** +diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c +index d3cb8d882..6ff74794c 100644 +--- a/src/drivers/driver_nl80211_event.c ++++ b/src/drivers/driver_nl80211_event.c +@@ -542,6 +542,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, + wpa_ssid_txt(drv->ssid, + drv->ssid_len)); + } ++ event.assoc_info.roam_indication = 1; + } + } + if (resp_ie) { +diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c +index 975110b57..9abd197e7 100644 +--- a/wpa_supplicant/events.c ++++ b/wpa_supplicant/events.c +@@ -3326,6 +3326,15 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + return; + } ++ ++ if (data && data->assoc_info.roam_indication) { ++ if (wpa_s->current_ssid->psk_set) { ++ wpa_hexdump_key(MSG_MSGDUMP, "reset PMK from config", ++ wpa_s->current_ssid->psk, PMK_LEN); ++ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->current_ssid->psk, PMK_LEN, NULL, ++ NULL); ++ } ++ } + } + + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0060-brcmfmac-add-a-configurable-link_loss-parameter-for-.patch b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0060-brcmfmac-add-a-configurable-link_loss-parameter-for-.patch new file mode 100644 index 000000000..8db13a7fa --- /dev/null +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant/murata/0060-brcmfmac-add-a-configurable-link_loss-parameter-for-.patch @@ -0,0 +1,117 @@ +From 326cd433b6c98a757188ea84e383f58cd8be23f1 Mon Sep 17 00:00:00 2001 +From: Carter Chen +Date: Wed, 15 Nov 2023 21:09:55 -0600 +Subject: [PATCH 60/60] brcmfmac: add a configurable link_loss parameter for + bgscan modules + +add a parameter for make the 600 seconds hard coding link_loss threshold +become configurable. + +--- + wpa_supplicant/bgscan_learn.c | 16 +++++++++++++--- + wpa_supplicant/bgscan_simple.c | 16 +++++++++++++--- + 2 files changed, 26 insertions(+), 6 deletions(-) + +diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c +index c872d8d35..8e35b6ae4 100644 +--- a/wpa_supplicant/bgscan_learn.c ++++ b/wpa_supplicant/bgscan_learn.c +@@ -42,6 +42,7 @@ struct bgscan_learn_data { + struct dl_list bss; + int *supp_freqs; + int probe_idx; ++ int link_loss_thresh_secs; + }; + + +@@ -350,6 +351,12 @@ static int bgscan_learn_get_params(struct bgscan_learn_data *data, + } + pos++; + data->long_interval = atoi(pos); ++ pos = os_strchr(pos, ':'); ++ if (pos) { ++ pos++; ++ data->link_loss_thresh_secs = atoi(pos); ++ } ++ + pos = os_strchr(pos, ':'); + if (pos) { + pos++; +@@ -420,10 +427,13 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s, + return NULL; + } + ++ if (data->link_loss_thresh_secs <= 0 || data->link_loss_thresh_secs >= 600) ++ data->link_loss_thresh_secs = 600; ++ + wpa_printf(MSG_DEBUG, "bgscan learn: Signal strength threshold %d " +- "Short bgscan interval %d Long bgscan interval %d", ++ "Short bgscan interval %d Long bgscan interval %d Link Lost threshold secs %d", + data->signal_threshold, data->short_interval, +- data->long_interval); ++ data->long_interval, data->link_loss_thresh_secs); + + if (data->signal_threshold && + wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) { +@@ -571,7 +581,7 @@ static void bgscan_learn_notify_beacon_loss(void *priv) + wpa_printf(MSG_DEBUG, "bgscan learn: beacon loss"); + + wpa_printf(MSG_DEBUG, "bgscan learn: Start Link Loss timer"); +- eloop_register_timeout(BGSCAN_LEARN_LINK_LOSS_THRESH_SECS, ++ eloop_register_timeout(data->link_loss_thresh_secs, + 0, bgscan_learn_link_loss_timeout, data, NULL); + + wpa_printf(MSG_DEBUG, "bgscan learn: Flush all prev bss entries"); +diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c +index bf9184e43..24e9f8658 100644 +--- a/wpa_supplicant/bgscan_simple.c ++++ b/wpa_supplicant/bgscan_simple.c +@@ -30,6 +30,7 @@ struct bgscan_simple_data { + int short_interval; /* use if signal < threshold */ + int long_interval; /* use if signal > threshold */ + struct os_reltime last_bgscan; ++ int link_loss_thresh_secs; + }; + + +@@ -111,6 +112,12 @@ static int bgscan_simple_get_params(struct bgscan_simple_data *data, + pos++; + data->long_interval = atoi(pos); + ++ pos = os_strchr(pos, ':'); ++ if (pos) { ++ pos++; ++ data->link_loss_thresh_secs = atoi(pos); ++ } ++ + return 0; + } + +@@ -135,10 +142,13 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s, + if (data->long_interval <= 0) + data->long_interval = 30; + ++ if (data->link_loss_thresh_secs <= 0 || data->link_loss_thresh_secs >= 600) ++ data->link_loss_thresh_secs = 600; ++ + wpa_printf(MSG_DEBUG, "bgscan simple: Signal strength threshold %d " +- "Short bgscan interval %d Long bgscan interval %d", ++ "Short bgscan interval %d Long bgscan interval %d Link Lost threshold secs %d", + data->signal_threshold, data->short_interval, +- data->long_interval); ++ data->long_interval, data->link_loss_thresh_secs); + + if (data->signal_threshold && + wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) { +@@ -212,7 +222,7 @@ static void bgscan_simple_notify_beacon_loss(void *priv) + wpa_printf(MSG_DEBUG, "bgscan simple: beacon loss"); + + wpa_printf(MSG_DEBUG, "bgscan simple: Start Link Loss timer"); +- eloop_register_timeout(BGSCAN_SIMPLE_LINK_LOSS_THRESH_SECS, ++ eloop_register_timeout(data->link_loss_thresh_secs, + 0, bgscan_simple_link_loss_timeout, data, NULL); + + wpa_printf(MSG_DEBUG, "bgscan simple: Flush all prev bss entries"); +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant_%.bbappend b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant_%.bbappend index 038bc5ab9..8a4f12433 100644 --- a/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant_%.bbappend +++ b/meta-digi-dey/recipes-connectivity/wpa-supplicant/wpa-supplicant_%.bbappend @@ -1,4 +1,4 @@ -# Copyright (C) 2013-2023 Digi International. +# Copyright (C) 2013-2024 Digi International Inc. FILESEXTRAPATHS:prepend := "${THISDIR}/${BPN}:" @@ -58,9 +58,20 @@ MURATA_COMMON_PATCHES = " \ file://murata/0044-Establish-a-Default-TWT-session-in-the-STA-after-ass.patch \ file://murata/0045-validate-the-TWT-parameters-exponent-and-mantissa-pa.patch \ file://murata/0046-Fix-for-station-sending-open-auth-instead-of-SAE-aut.patch \ - file://murata/0047-Fix-ROAMOFFLOAD-raises-portValid-too-early.patch \ - file://murata/0048-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch \ - file://murata/0049-non-upstream-p2p_add_group-command-unification.patch \ + file://murata/0047-Fix-associating-failed-when-PMK-lifetime-is-set-to-1.patch \ + file://murata/0048-non-upstream-p2p_add_group-command-unification.patch \ + file://murata/0049-non-upstream-MBO-wpa_cli-mbo-command-by-IFX-vendorID.patch \ + file://murata/0050-EAP-TLS-Allow-TLSv1.3-support-to-be-enabled-with-bui.patch \ + file://murata/0051-Enabling-TLS-v1.3-by-default.patch \ + file://murata/0052-Disable-4-way-handshake-offload-for-DPP.patch \ + file://murata/0053-non-upstream-WNM-wpa_cli-wnm_maxilde-command-by-IFX-.patch \ + file://murata/0054-brcmfmac-sync-content-of-nl80211_copy.h-for-BSS_COLO.patch \ + file://murata/0055-WPA3-SAE-enable-nl_connect-socket-while-WPA_DRIVER_F.patch \ + file://murata/0056-OWE-AP-enable-OWE-compile-option-for-hostapd-executi.patch \ + file://murata/0057-DPP2.0-support-DPP2.0-and-add-pfs-init-flow-on-EVENT.patch \ + file://murata/0058-non-upstream-Prevent-invalid-akm-key-mgmt-when-MFP-r.patch \ + file://murata/0059-Reset-authentication-and-encryption-parameters-while.patch \ + file://murata/0060-brcmfmac-add-a-configurable-link_loss-parameter-for-.patch \ " SRC_URI:append:ccimx6sbc = " file://wpa_supplicant_p2p.conf_atheros" From 72675e510c92707977332df78503e2e06f05be60 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Fri, 15 Mar 2024 10:28:28 +0100 Subject: [PATCH 48/91] ccmp1: decouple FIT functionality from signed FIT functionality We rely on FIT support to implement boot artifact authentication on ccmp1 platforms, but our implementation made it impossible to enable FIT support outside of the context of Trustfence/secure boot. Change this so that it's possible to enable FIT support without having to sign the FIT artifacts. Also, modify the linux-dey 5.15 recipe so that the U-Boot DTBs with signatures get copied only when FIT signing is enabled. https://onedigi.atlassian.net/browse/DEL-8946 Signed-off-by: Gabriel Valcazar --- meta-digi-arm/conf/machine/ccmp13-dvk.conf | 4 ++-- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 4 ++-- meta-digi-arm/conf/machine/include/ccmp1.inc | 2 +- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb | 4 ++-- meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb | 2 +- meta-digi-dey/classes/trustfence.bbclass | 2 -- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/meta-digi-arm/conf/machine/ccmp13-dvk.conf b/meta-digi-arm/conf/machine/ccmp13-dvk.conf index a4df2b433..b70b081d7 100644 --- a/meta-digi-arm/conf/machine/ccmp13-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp13-dvk.conf @@ -46,7 +46,7 @@ STM32MP_KERNEL_DEVICETREE:ccmp13-dvk += " \ _ov_som_wifi_ccmp13.dtbo \ " # Set DTB load address to U-Boot fdt_addr_r -UBOOT_DTB_LOADADDRESS = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', '0xc4000000', '', d)}" +UBOOT_DTB_LOADADDRESS = "0xc4000000" # List of U-Boot device tree to use UBOOT_DEVICETREE = "${STM32MP_DEVICETREE}" @@ -112,7 +112,7 @@ OPTEE_CONF = "${STM32MP_DEVICETREE}" # Kernel # ========================================================================= KERNEL_IMAGETYPE = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', 'fitImage', 'zImage', d)}" -KERNEL_CLASSES = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', 'kernel-fitimage', 'kernel-uimage', d)}" +KERNEL_CLASSES = "kernel-fitimage" KERNEL_ALT_IMAGETYPE = "Image vmlinux" KERNEL_DEFCONFIG ?= "arch/arm/configs/ccmp1_defconfig" diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index cdcf53aad..2784a040e 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -53,7 +53,7 @@ STM32MP_KERNEL_DEVICETREE:ccmp15-dvk += " \ _ov_som_wifi_ccmp15.dtbo \ " # Set DTB load address to U-Boot fdt_addr_r -UBOOT_DTB_LOADADDRESS = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', '0xc4000000', '', d)}" +UBOOT_DTB_LOADADDRESS = "0xc4000000" # List of U-Boot device tree to use UBOOT_DEVICETREE = "${STM32MP_DEVICETREE}" @@ -123,7 +123,7 @@ OPTEE_CONF = "${STM32MP_DEVICETREE}" # Kernel # ========================================================================= KERNEL_IMAGETYPE = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', 'fitImage', 'zImage', d)}" -KERNEL_CLASSES = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', 'kernel-fitimage', 'kernel-uimage', d)}" +KERNEL_CLASSES = "kernel-fitimage" KERNEL_ALT_IMAGETYPE = "Image vmlinux" KERNEL_DEFCONFIG ?= "arch/arm/configs/ccmp1_defconfig" diff --git a/meta-digi-arm/conf/machine/include/ccmp1.inc b/meta-digi-arm/conf/machine/include/ccmp1.inc index e298e91f6..e6d31378b 100644 --- a/meta-digi-arm/conf/machine/include/ccmp1.inc +++ b/meta-digi-arm/conf/machine/include/ccmp1.inc @@ -78,7 +78,7 @@ TRUSTFENCE_CONSOLE_DISABLE ?= "0" do_create_flashlayout_config[noexec] = "1" # Include boot script into the FIT image -UBOOT_ENV = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', 'boot', '', d)}" +UBOOT_ENV = "boot" # Partitions to blacklist for swupdate: # fsbl1, fsbl2, metadata1, metadata2, fip-a, fip-b diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb index 1d0e04099..84cd41898 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb @@ -15,7 +15,7 @@ UBOOT_FIT_CFG_FRAGMENTS = " \ " SRC_URI += " \ - ${@oe.utils.conditional('TRUSTFENCE_SIGN', '1', '${UBOOT_FIT_CFG_FRAGMENTS}', '', d)} \ + ${@oe.utils.conditional('TRUSTFENCE_FIT_IMG', '1', '${UBOOT_FIT_CFG_FRAGMENTS}', '', d)} \ " install_helper_files() { @@ -41,7 +41,7 @@ install_helper_files() { do_install:append() { # Copy additional files, so kernel can use it when creating the FIT image - if [ "${TRUSTFENCE_FIT_IMG}" = "1" ]; then + if [ "${KERNEL_IMAGETYPE}" = "fitImage" ]; then install_helper_files fi } diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb index e219c7709..3d078e899 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb @@ -41,7 +41,7 @@ do_assemble_fitimage:append:ccmp1() { } kernel_do_deploy:append:ccmp1() { - if [ "${UBOOT_SIGN_ENABLE}" = "1" -o "${UBOOT_FITIMAGE_ENABLE}" = "1" ] && \ + if [ "${UBOOT_SIGN_ENABLE}" = "1" ] && \ [ -n "${UBOOT_DTB_BINARY}" ] ; then # Install device tree files with signature if [ -n "${UBOOT_DEVICETREE}" ]; then diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index 6d10ec992..d1f356a90 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -57,8 +57,6 @@ IMAGE_FEATURES += "dey-trustfence" # Usage of FIT Image signed # --------------------------------- -# Enable FIT image build when Trustfence is enabled -MACHINE_FEATURES += "${@oe.utils.conditional('TRUSTFENCE_FIT_IMG', '1', 'fit', '', d)}" # key to sign FIT config nodes TRUSTFENCE_FIT_CFG_SIGN_KEYNAME ?= "fitcfg" # key to sign FIT image nodes From 9ac912d28959340d7ec01a2f44c3292347712cc0 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Mon, 18 Mar 2024 12:01:02 +0100 Subject: [PATCH 49/91] ccmp1: remove linux/u-boot functions related to FIT image bootscript copying This logic was fixed in commit e915a14b4b1e457620b2aad8aa821d4b06b7da4a, so we no longer have to manually copy the bootscript to generate FIT images. https://onedigi.atlassian.net/browse/DEL-8946 Signed-off-by: Gabriel Valcazar --- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb | 9 --------- meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb | 6 ------ 2 files changed, 15 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb index 84cd41898..3c21e4595 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb @@ -19,15 +19,6 @@ SRC_URI += " \ " install_helper_files() { - # Install UBOOT_ENV_BINARY to datadir, so that kernel can use it - # to include it into the FIT image. - if [ -f "${D}/boot/${UBOOT_ENV_BINARY}" ]; then - install -Dm 0644 ${D}/boot/${UBOOT_ENV_BINARY} ${D}${datadir}/${UBOOT_ENV_IMAGE} - ln -sf ${UBOOT_ENV_IMAGE} ${D}${datadir}/${UBOOT_ENV_BINARY} - else - bbwarn "${D}/boot/${UBOOT_ENV_BINARY} not found" - fi - # Install dtbs from UBOOT_DEVICETREE to datadir, so that kernel # can use it for signing, and kernel will deploy after signs it. if [ -n "${UBOOT_DEVICETREE}" ]; then diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb index 3d078e899..cc65d7536 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb @@ -7,12 +7,6 @@ SRCBRANCH:stm32mpcommon = "v5.15.118/stm/master" SRCREV = "${AUTOREV}" SRCREV:stm32mpcommon = "${AUTOREV}" -do_assemble_fitimage:prepend:ccmp1() { - # Deploy u-boot script to be included into the FIT image - install -d ${STAGING_DIR_HOST}/boot - install -m 0644 ${RECIPE_SYSROOT}/${datadir}/${UBOOT_ENV_BINARY} ${STAGING_DIR_HOST}/boot/ -} - do_assemble_fitimage:append:ccmp1() { # # Step 9: Add public keys to the different U-Boot dtb files From aabf4cb72df54138126472c7efe56e8c432d2f6e Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Mon, 18 Mar 2024 12:03:04 +0100 Subject: [PATCH 50/91] ccmp1: u-boot-dey: merge FIT signature config fragments into a single file Unless we have a use case in which we need to apply these fragments separately, we can merge them both into a single fragment. https://onedigi.atlassian.net/browse/DEL-8946 Signed-off-by: Gabriel Valcazar --- .../recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_legacy.cfg | 1 - .../recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg | 1 + meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb | 7 +------ 3 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_legacy.cfg diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_legacy.cfg b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_legacy.cfg deleted file mode 100644 index 27c702af0..000000000 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_legacy.cfg +++ /dev/null @@ -1 +0,0 @@ -# CONFIG_LEGACY_IMAGE_FORMAT is not set diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg index 362903338..826c740cb 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/fit_signature.cfg @@ -1,3 +1,4 @@ +# CONFIG_LEGACY_IMAGE_FORMAT is not set CONFIG_FIT_SIGNATURE=y CONFIG_RSA=y CONFIG_ECDSA=y diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb index 3c21e4595..5e921be4c 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb @@ -9,13 +9,8 @@ DEPENDS += "python3-setuptools-native" SRCBRANCH = "v2021.10/master" SRCREV = "${AUTOREV}" -UBOOT_FIT_CFG_FRAGMENTS = " \ - file://fit_legacy.cfg \ - file://fit_signature.cfg \ -" - SRC_URI += " \ - ${@oe.utils.conditional('TRUSTFENCE_FIT_IMG', '1', '${UBOOT_FIT_CFG_FRAGMENTS}', '', d)} \ + ${@oe.utils.conditional('TRUSTFENCE_FIT_IMG', '1', 'file://fit_signature.cfg', '', d)} \ " install_helper_files() { From 3fc0a301150febecff39806993e8c75674818d97 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Tue, 19 Mar 2024 13:20:30 +0100 Subject: [PATCH 51/91] trustfence: rename variables related to FIT image signing Different mechanisms are used to sign FIT images on the ccmp1 platforms and the ccimx93, and we manage each mechanism via a different variable. The variable names don't really reflect which platform they affect, which makes maintenance harder. Rename the variables so that it's easier to identify the platforms/vendors they affect: * Replace TRUSTFENCE_FIT_IMG with TRUSTFENCE_SIGN_FIT_STM * Replace TRUSTFENCE_SIGN_FIT_ARTIFACT with TRUSTFENCE_SIGN_FIT_NXP Don't rename TRUSTFENCE_FIT_IMG_SIGN_KEYNAME Signed-off-by: Gabriel Valcazar --- meta-digi-arm/classes/image_types_digi.bbclass | 2 +- meta-digi-arm/conf/machine/ccmp13-dvk.conf | 2 +- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 2 +- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc | 2 +- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb | 2 +- .../recipes-kernel/linux/linux-trustfence.inc | 2 +- meta-digi-dey/classes/trustfence.bbclass | 10 +++++----- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/meta-digi-arm/classes/image_types_digi.bbclass b/meta-digi-arm/classes/image_types_digi.bbclass index d5fded013..236164dc1 100644 --- a/meta-digi-arm/classes/image_types_digi.bbclass +++ b/meta-digi-arm/classes/image_types_digi.bbclass @@ -221,7 +221,7 @@ trustence_sign_cpio() { # Image generation code for image type 'cpio.gz.u-boot.tf' # (signed/encrypted ramdisk) # - if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ] && [ "${TRUSTFENCE_SIGN_FIT_ARTIFACT}" = "0" ]; then + if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ] && [ "${TRUSTFENCE_SIGN_FIT_NXP}" = "0" ]; then # Set environment variables for trustfence configuration export CONFIG_SIGN_KEYS_PATH="${TRUSTFENCE_SIGN_KEYS_PATH}" [ -n "${TRUSTFENCE_KEY_INDEX}" ] && export CONFIG_KEY_INDEX="${TRUSTFENCE_KEY_INDEX}" diff --git a/meta-digi-arm/conf/machine/ccmp13-dvk.conf b/meta-digi-arm/conf/machine/ccmp13-dvk.conf index b70b081d7..7564a34d4 100644 --- a/meta-digi-arm/conf/machine/ccmp13-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp13-dvk.conf @@ -111,7 +111,7 @@ OPTEE_CONF = "${STM32MP_DEVICETREE}" # ========================================================================= # Kernel # ========================================================================= -KERNEL_IMAGETYPE = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', 'fitImage', 'zImage', d)}" +KERNEL_IMAGETYPE = "${@bb.utils.contains('TRUSTFENCE_SIGN_FIT_STM', '1', 'fitImage', 'zImage', d)}" KERNEL_CLASSES = "kernel-fitimage" KERNEL_ALT_IMAGETYPE = "Image vmlinux" KERNEL_DEFCONFIG ?= "arch/arm/configs/ccmp1_defconfig" diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index 2784a040e..9d4e5fd72 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -122,7 +122,7 @@ OPTEE_CONF = "${STM32MP_DEVICETREE}" # ========================================================================= # Kernel # ========================================================================= -KERNEL_IMAGETYPE = "${@bb.utils.contains('TRUSTFENCE_FIT_IMG', '1', 'fitImage', 'zImage', d)}" +KERNEL_IMAGETYPE = "${@bb.utils.contains('TRUSTFENCE_SIGN_FIT_STM', '1', 'fitImage', 'zImage', d)}" KERNEL_CLASSES = "kernel-fitimage" KERNEL_ALT_IMAGETYPE = "Image vmlinux" KERNEL_DEFCONFIG ?= "arch/arm/configs/ccmp1_defconfig" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 30b6c55b3..637b0033d 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -118,7 +118,7 @@ build_uboot_scripts() { rm -f ${TMP_BOOTSCR} # Sign the boot script if not contained in a FIT image - if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ] && [ "${TRUSTFENCE_SIGN_FIT_ARTIFACT}" = "0" ]; then + if [ "${TRUSTFENCE_SIGN_ARTIFACTS}" = "1" ] && [ "${TRUSTFENCE_SIGN_FIT_NXP}" = "0" ]; then export CONFIG_SIGN_KEYS_PATH="${TRUSTFENCE_SIGN_KEYS_PATH}" [ -n "${TRUSTFENCE_KEY_INDEX}" ] && export CONFIG_KEY_INDEX="${TRUSTFENCE_KEY_INDEX}" [ -n "${TRUSTFENCE_SRK_REVOKE_MASK}" ] && export SRK_REVOKE_MASK="${TRUSTFENCE_SRK_REVOKE_MASK}" diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb index 5e921be4c..8550e699c 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey_2021.10.bb @@ -10,7 +10,7 @@ SRCBRANCH = "v2021.10/master" SRCREV = "${AUTOREV}" SRC_URI += " \ - ${@oe.utils.conditional('TRUSTFENCE_FIT_IMG', '1', 'file://fit_signature.cfg', '', d)} \ + ${@oe.utils.conditional('TRUSTFENCE_SIGN_FIT_STM', '1', 'file://fit_signature.cfg', '', d)} \ " install_helper_files() { diff --git a/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc b/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc index 4fca51f2c..1a65fc204 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc +++ b/meta-digi-arm/recipes-kernel/linux/linux-trustfence.inc @@ -32,7 +32,7 @@ trustfence_sign() { done # For FIT images there is no need to sign the rest of artifacts - [ "${TRUSTFENCE_SIGN_FIT_ARTIFACT}" = "1" ] && return 0 + [ "${TRUSTFENCE_SIGN_FIT_NXP}" = "1" ] && return 0 # Sign/encrypt the device tree blobs for DTB in ${KERNEL_DEVICETREE}; do diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index d1f356a90..af122e8b5 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -32,7 +32,7 @@ TRUSTFENCE_SRK_REVOKE_MASK ?= "0x0" TRUSTFENCE_KEY_INDEX ?= "0" TRUSTFENCE_SIGN_ARTIFACTS = "1" TRUSTFENCE_SIGN_ARTIFACTS:ccmp1 = "0" -TRUSTFENCE_FIT_IMG:ccmp1 ?= "1" +TRUSTFENCE_SIGN_FIT_STM:ccmp1 ?= "1" # Partition encryption configuration TRUSTFENCE_ENCRYPT_PARTITIONS ?= "1" @@ -48,8 +48,8 @@ TRUSTFENCE_READ_ONLY_ROOTFS ?= "${@bb.utils.contains("IMAGE_FEATURES", "read-onl # # NXP-based sign a FIT-format boot artifact -TRUSTFENCE_SIGN_FIT_ARTIFACT = "0" -TRUSTFENCE_SIGN_FIT_ARTIFACT:ccimx93 = "${TRUSTFENCE_SIGN_ARTIFACTS}" +TRUSTFENCE_SIGN_FIT_NXP = "0" +TRUSTFENCE_SIGN_FIT_NXP:ccimx93 = "${TRUSTFENCE_SIGN_ARTIFACTS}" IMAGE_FEATURES += "dey-trustfence" @@ -183,7 +183,7 @@ python () { d.appendVar("UBOOT_TF_CONF", "CONFIG_SIGN_IMAGE=y ") if (d.getVar("TRUSTFENCE_SIGN_ARTIFACTS") == "1"): d.appendVar("UBOOT_TF_CONF", "CONFIG_AUTH_ARTIFACTS=y ") - if (d.getVar("TRUSTFENCE_SIGN_FIT_ARTIFACT") == "1"): + if (d.getVar("TRUSTFENCE_SIGN_FIT_NXP") == "1"): d.appendVar("UBOOT_TF_CONF", '"# CONFIG_CMD_BOOTI is not set" ') d.appendVar("UBOOT_TF_CONF", '"# CONFIG_LEGACY_IMAGE_FORMAT is not set" ') if (d.getVar("TRUSTFENCE_READ_ONLY_ROOTFS") == "1"): @@ -201,7 +201,7 @@ python () { d.appendVar("UBOOT_TF_CONF", 'CONFIG_SIGN_MODE="%s" ' % d.getVar("TRUSTFENCE_SIGN_MODE")) - if (d.getVar("TRUSTFENCE_FIT_IMG") == "1"): + if (d.getVar("TRUSTFENCE_SIGN_FIT_STM") == "1"): # FIT-related variables # Create keys if not defined d.setVar("FIT_GENERATE_KEYS", "1") From 22429e62cb58db52f770f555f8d55bd5fcd24cc1 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Tue, 19 Mar 2024 18:18:26 +0100 Subject: [PATCH 52/91] meta-digi-arm: add support for Worldwide regulatory domains - For Qualcomm QCA65x4 platforms: Add support to create the 'World' board data file for the QCA65x4 Wi-Fi chip to operate on World regulatory domain. Kernel wireless driver already supports selecting the correct file based on the configured Regulatory Domain via Kernel command line argument 'wlan.regdmn', which allows the following parameters: * "US", for U.S.A. (default) * "World", for worldwide - For Murata type2AE platforms: Add World CLM blob file for the wireless interface and JRL hcd file for the Bluetooth interface. Also add the autocountry ininitialization script and systemd service. World CLM blob file: - cyfmac4373-sdio_World.clm_blob (1abe7f3fa86d4123b0586cbbf0ec91ac) Kernel wireless and bluetooth drivers already support selecting the correct files based on the configured Regulatory Domain via Kernel command line arguments 'brcmfmac.regdmn' and 'btbcm.regdmn' respectively, which allow the following parameters: 'brcmfmac.regdmn': * "US", for U.S.A. (default) * "World", for worldwide 'btbcm.regdmn': * "FCC.CE", for U.S.A., Europe and the rest of the world (default) * "JRL", for Japan https://onedigi.atlassian.net/browse/DEL-8905 Co-authored-by: Gonzalo Ruiz Signed-off-by: Arturo Buzarra --- meta-digi-arm/conf/machine/ccmp13-dvk.conf | 2 +- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 2 +- .../firmware-murata-infineon.bb | 40 +++++++++++++++++- .../cyfmac4373-sdio_World.clm_blob | Bin 0 -> 2020 bytes .../cyw4373-autocountry | 38 +++++++++++++++++ .../cyw4373-autocountry.service | 10 +++++ .../firmware-qualcomm/firmware-qualcomm.bb | 4 ++ 7 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyfmac4373-sdio_World.clm_blob create mode 100644 meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyw4373-autocountry create mode 100644 meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyw4373-autocountry.service diff --git a/meta-digi-arm/conf/machine/ccmp13-dvk.conf b/meta-digi-arm/conf/machine/ccmp13-dvk.conf index 7564a34d4..d448cba91 100644 --- a/meta-digi-arm/conf/machine/ccmp13-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp13-dvk.conf @@ -59,7 +59,7 @@ MACHINE_FEATURES += "wifi" # ========================================================================= # Firmware # ========================================================================= -MACHINE_FIRMWARE:append = " firmware-murata-infineon firmware-murata-infineon-mfgtest" +MACHINE_FIRMWARE:append = " firmware-murata-infineon" MACHINE_EXTRA_RRECOMMENDS += " \ ${MACHINE_FIRMWARE} \ diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index 9d4e5fd72..56f0a57ee 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -67,7 +67,7 @@ MACHINE_FEATURES += "gpu" # ========================================================================= # Firmware # ========================================================================= -MACHINE_FIRMWARE:append = " firmware-murata-infineon firmware-murata-infineon-mfgtest" +MACHINE_FIRMWARE:append = " firmware-murata-infineon" MACHINE_EXTRA_RRECOMMENDS += " \ ${MACHINE_FIRMWARE} \ diff --git a/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb index 4377c33f2..ac9f11d92 100644 --- a/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb +++ b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon.bb @@ -1,4 +1,4 @@ -# Copyright (C) 2022,2024 Digi International Inc. +# Copyright (C) 2022-2024 Digi International Inc. SUMMARY = "Murata Infineon firmware binaries" SECTION = "base" @@ -12,6 +12,9 @@ SRC_URI = " \ git://github.com/murata-wireless/cyw-fmac-utils-imx32;protocol=http;branch=master;destsuffix=cyw-fmac-utils-imx32;name=cyw-fmac-utils-imx32 \ git://github.com/murata-wireless/cyw-fmac-utils-imx64;protocol=http;branch=master;destsuffix=cyw-fmac-utils-imx64;name=cyw-fmac-utils-imx64 \ file://cyfmac4373-sdio_US.clm_blob \ + file://cyfmac4373-sdio_World.clm_blob \ + file://cyw4373-autocountry \ + file://cyw4373-autocountry.service \ " SRCREV_cyw-fmac-fw="db8deb03b8d24e5069ac4581d1c35b767012e926" @@ -35,11 +38,13 @@ do_install () { # Install Bluetooth patch *.HCD file # For Murata 2AE (LBEE5PK2AE-564) install -m 444 ${S}/cyw-bt-patch/BCM4373A0_001.001.025.0103.0155.FCC.CE.2AE.hcd ${D}${base_libdir}/firmware/brcm/BCM4373A0_FCC.CE.hcd + install -m 444 ${S}/cyw-bt-patch/BCM4373A0_001.001.025.0103.0156.JRL.2AE.hcd ${D}${base_libdir}/firmware/brcm/BCM4373A0_JRL.hcd # Install WLAN firmware file (*.bin) and Regulatory binary file (*.clm_blob) # For Murata 2AE (LBEE5PK2AE-564) install -m 444 ${S}/cyw-fmac-fw/cyfmac4373-sdio.2AE.bin ${D}${base_libdir}/firmware/cypress/cyfmac4373-sdio.bin install -m 444 cyfmac4373-sdio_US.clm_blob ${D}${base_libdir}/firmware/cypress/cyfmac4373-sdio_US.clm_blob + install -m 444 cyfmac4373-sdio_World.clm_blob ${D}${base_libdir}/firmware/cypress/cyfmac4373-sdio_World.clm_blob # Install NVRAM files (*.txt) # For Murata 2AE (LBEE5PK2AE-564) @@ -51,9 +56,31 @@ do_install () { else install -m 755 ${S}/cyw-fmac-utils-imx32/wl ${D}${sbindir} fi + + if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then + # Install systemd unit files + install -d ${D}${systemd_unitdir}/system/ + install -m 0644 ${WORKDIR}/cyw4373-autocountry.service ${D}${systemd_unitdir}/system/cyw4373-autocountry.service + fi + + install -d ${D}${sysconfdir}/init.d/ + install -m 0755 ${WORKDIR}/cyw4373-autocountry ${D}${sysconfdir}/cyw4373-autocountry + ln -sf /etc/cyw4373-autocountry ${D}${sysconfdir}/init.d/cyw4373-autocountry } -PACKAGES =+ "${PN}-mfgtest" +inherit update-rc.d systemd + +INITSCRIPT_PACKAGES += "${PN}-autocountry" +INITSCRIPT_NAME:${PN}-autocountry = "cyw4373-autocountry" +INITSCRIPT_PARAMS:${PN}-autocountry = "start 19 2 3 4 5 . stop 21 0 1 6 ." + +SYSTEMD_PACKAGES = "${PN}-autocountry" +SYSTEMD_SERVICE:${PN}-autocountry = "cyw4373-autocountry.service" + +PACKAGES =+ " \ + ${PN}-mfgtest \ + ${PN}-autocountry \ +" FILES:${PN} = " \ ${base_libdir}/firmware \ @@ -63,6 +90,15 @@ FILES:${PN}-mfgtest = " \ ${sbindir} \ " +FILES:${PN}-autocountry = " \ + ${sysconfdir}/cyw4373-autocountry \ + ${sysconfdir}/init.d/cyw4373-autocountry \ + ${systemd_unitdir}/system/cyw4373-autocountry.service \ +" + +RDEPENDS:${PN}:append = " ${PN}-autocountry" +RDEPENDS:${PN}-autocountry:append = " ${PN}-mfgtest" + INSANE_SKIP:${PN} += "build-deps" INSANE_SKIP:${PN} += "file-rdeps" diff --git a/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyfmac4373-sdio_World.clm_blob b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyfmac4373-sdio_World.clm_blob new file mode 100644 index 0000000000000000000000000000000000000000..4aef50d59ca8692cbba8f332a019ddf7bb15b012 GIT binary patch literal 2020 zcma)6O=x3P6h8O9pS&h%nx^eEooQo|K0^sMlVmba4Z|Zp?d!BAozk?!Ojj;K?UZR9 zw200^5K1XElq@V2Dip!2Mwo?LSFT*nN)%iSxD^C9x)9=b-@8exj5vqfeD9p|o$sA@ z-o39-cFLX74f zyz?MatJ@j^V;~T~>o-j^YnIGCvt_o;&P;aZR-shb zE3`_bX0y51Y&F|kds~P5hx@Jl_I{_;YPZ{+lP^y?olZWRFU)51v-w;+d$X8(vzWIi zolbA3AE%GfXXz)!;`a9T(c`0|GuRVv@BN^7_!E#*mzmgUmV)*VzPl5i6b7Az3 zipH_M86%x*8e=+F;c%boMhCoH5FT>q2)`Gcu}iWlPK(ml#yDsijj%!Hem{Q2b-Ebd zJ_?^b2_x4t(d!||H-MjFnI*N^R!=(OoAL-Nssll4Vm;T0J_q+NTnBOe8Ze9e8z9eM zy^ZJWu6&~10}9&$J_ASChgd(0reMEG{1&+uIEJW)P8jP)=)R174_+MnXFvn^1$4G# zVHSF$Sl*jeSyvqo#KvP&rpeWcpIIZ!nqo4 zWW_jhl1yh^1@+O8$rVvODoPdJS0BzQPAh9x~aGyU)JHT*dglk@LMQB0?p1CSFwdlkjy+ zgsc&=rYLEWPc3q?46;I$940@v7$pOwV>aXrlRZY(6>_eUGf7sQoFw`5jQd^4_{k1Z zCPa1^Re45vKk1kPS);D3B4h`oCU-U6Y=o93$fs10^^qMQzfvKxbSfJESB`mJYU$bw z`Wfu?!}2QW7%)}Bq8}&Wwq&65qAG5N<}Hsr/dev/null 2>/dev/null; then + systemd-cat -p "${1}" -t "${SCRIPTNAME}" printf "%s" "${2}" + else + logger -p "${1}" -t "${SCRIPTNAME}" "${2}" + fi +} + +# Only for Wireless variants +if [ -d "/proc/device-tree/wireless" ]; then + # Check if WorldWide regulatory domain is available + if wl country list | grep -qs ^XZ; then + # Select WorldWide Country Code as driver operational region + wl country XZ/0 agg + # Select WorldWide Country Code for use with Auto Contry Discovery + wl autocountry_default XZ + # Enable 802.11d + wl autocountry 1 + log info "Set WorldWide regulatory domain" + fi +fi diff --git a/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyw4373-autocountry.service b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyw4373-autocountry.service new file mode 100644 index 000000000..eeda03d77 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/firmware-murata-infineon/firmware-murata-infineon/cyw4373-autocountry.service @@ -0,0 +1,10 @@ +[Unit] +Description=CYW4373 autocountry (802.11d) +After=network.target suspend.target + +[Service] +Type=oneshot +ExecStart=/etc/cyw4373-autocountry + +[Install] +WantedBy=multi-user.target suspend.target diff --git a/meta-digi-arm/recipes-bsp/firmware-qualcomm/firmware-qualcomm.bb b/meta-digi-arm/recipes-bsp/firmware-qualcomm/firmware-qualcomm.bb index fc3437f36..2737a910c 100644 --- a/meta-digi-arm/recipes-bsp/firmware-qualcomm/firmware-qualcomm.bb +++ b/meta-digi-arm/recipes-bsp/firmware-qualcomm/firmware-qualcomm.bb @@ -132,6 +132,10 @@ do_install() { length="$(expr $(stat -L -c %s ${D}${base_libdir}/firmware/qca/nvm_tlv_3.2.bin) - 4)" /bin/echo -ne "\x$(printf '%02x' $(expr $length % 256))" | dd of=${D}${base_libdir}/firmware/qca/nvm_tlv_3.2.bin bs=1 seek=1 count=1 conv=notrunc,fsync /bin/echo -ne "\x$(printf '%02x' $(expr $length / 256))" | dd of=${D}${base_libdir}/firmware/qca/nvm_tlv_3.2.bin bs=1 seek=2 count=1 conv=notrunc,fsync + + # Create World BDF file + cp ${D}${WIFI_FW_PATH}/bdwlan30_US.bin ${D}${WIFI_FW_PATH}/bdwlan30_World.bin + /bin/echo -ne "\x60\x00" | dd of="${D}${WIFI_FW_PATH}/bdwlan30_World.bin" bs=1 seek=12 count=2 conv=notrunc,fsync } QCA_MODEL ?= "qca6564" From 259221650185051e89b98b30d77ed41b45611618 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Fri, 22 Mar 2024 09:24:37 +0100 Subject: [PATCH 53/91] README: remove 802.11r known issue for CCMP1 platform It is fixed with the new wireless firmware v5.15.58-2023_1128 integrated in Yocto. https://onedigi.atlassian.net/browse/DEL-8667 Signed-off-by: Arturo Buzarra --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 26501324b..c0bb79b55 100644 --- a/README.md +++ b/README.md @@ -292,8 +292,6 @@ updated list can be found on the online documentation. * Wireless * P2P on the ConnectCore MP1 doesn't currently work in concurrency with other modes (station or SoftAP). - * Connecting to a 802.11r network throws an unexpected error with the latest - CYW4373E wireless firmware. ## ConnectCore 6UL From b9d9a0104bd7649b73712b5ff5f87097ef615c43 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Tue, 26 Mar 2024 12:37:06 +0100 Subject: [PATCH 54/91] trustfence: stm: fix PKI tree check for ccmp13 platform This commit fixes a race condition where, if you have an existing PKI tree with the new format (one key_pass file for each key), the script detects that the PKI tree is incomplete because it is always trying to find the key_pass.txt file with the old format. This commit adds an additional validation step to verify the new keys format. Signed-off-by: Arturo Buzarra --- .../trustfence-sign-tools/trustfence-gen-pki-stm.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-gen-pki-stm.sh b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-gen-pki-stm.sh index cba7b6627..0fcb54aa5 100755 --- a/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-gen-pki-stm.sh +++ b/meta-digi-arm/recipes-digi/trustfence/trustfence-sign-tools/trustfence-gen-pki-stm.sh @@ -74,7 +74,10 @@ if [ "${PLATFORM}" = "ccmp15" ]; then chmod 400 "${KEY_PASS_FILE}" fi elif [ "${PLATFORM}" = "ccmp13" ]; then - if [ "${N_PUBK}" = "8" ] && [ "${N_PRVK}" = "8" ] && [ "${N_PASS}" != "8" ] && [ -f "${KEY_PASS_FILE}" ]; then + if [ "${N_PUBK}" = "8" ] && [ "${N_PRVK}" = "8" ] && [ "${N_PASS}" = "8" ]; then + # PKI tree already exists. + echo "Using existing PKI tree" + elif [ "${N_PUBK}" = "8" ] && [ "${N_PRVK}" = "8" ] && [ "${N_PASS}" != "8" ] && [ -f "${KEY_PASS_FILE}" ]; then # Backwards compatibility: if a single key_pass.txt file exists, # split into 8 files with one password each for i in $(seq 0 7); do From 2c4e1f85fdbaada330a7f9d3b7cf38dd3341c4ed Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Tue, 26 Mar 2024 13:06:51 +0100 Subject: [PATCH 55/91] trustfence: stm: fix TRUSTFENCE_PASSWORD_FILE initialization for ccmp13 platform Trustfence class was setting the TRUSTFENCE_PASSWORD_FILE variable using the old keys format where a unique key_pass.txt file contains all the key passwords. However, in the new format there are one key_pass file for each key, so using a PKI tree with the new format throws an unexpected error in the FIP generation due to it is not able to find the required key password. This commit sets the TRUSTFENCE_PASSWORD_FILE variable for the ccmp1 platforms on different way. Signed-off-by: Arturo Buzarra --- meta-digi-dey/classes/trustfence.bbclass | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index af122e8b5..7b59b474f 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -176,9 +176,10 @@ python () { d.setVar("FIP_SIGN_KEY_EXTERNAL", "1") if (d.getVar("DIGI_SOM") == "ccmp15" ): d.setVar("FIP_SIGN_KEY", d.getVar("TRUSTFENCE_SIGN_KEYS_PATH") + "/keys/privateKey.pem"); + d.setVar("TRUSTFENCE_PASSWORD_FILE", d.getVar("TRUSTFENCE_SIGN_KEYS_PATH") + "/keys/key_pass.txt") elif (d.getVar("DIGI_SOM") == "ccmp13" ): d.setVar("FIP_SIGN_KEY", d.getVar("TRUSTFENCE_SIGN_KEYS_PATH") + "/keys/privateKey0%s.pem" % d.getVar("TRUSTFENCE_KEY_INDEX")); - d.setVar("TRUSTFENCE_PASSWORD_FILE", d.getVar("TRUSTFENCE_SIGN_KEYS_PATH") + "/keys/key_pass.txt") + d.setVar("TRUSTFENCE_PASSWORD_FILE", d.getVar("TRUSTFENCE_SIGN_KEYS_PATH") + "/keys/key_pass0%s.txt" % d.getVar("TRUSTFENCE_KEY_INDEX")) d.appendVar("UBOOT_TF_CONF", "CONFIG_SIGN_IMAGE=y ") if (d.getVar("TRUSTFENCE_SIGN_ARTIFACTS") == "1"): From 4b4d4b5a6b63985714dfcd2e9ce90d3d0ef8b461 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Thu, 1 Feb 2024 16:27:39 +0100 Subject: [PATCH 56/91] u-boot-dey: add install uboot on redundant partition This commit adds instructions to update the redundant u-boot partition. https://onedigi.atlassian.net/browse/DEL-8848 Signed-off-by: Mike Engel --- .../ccimx93/install_linux_fw_sd.txt | 20 ++++++++++++++++++- .../ccimx93/install_linux_fw_usb.txt | 20 ++++++++++++++++++- .../ccimx93/install_linux_fw_uuu.sh | 13 ++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt index 31f7bd298..b973c36b6 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_sd.txt @@ -76,7 +76,10 @@ echo " on the partitions of the eMMC." echo "" echo " PARTITION FILENAME" echo " --------- --------" -echo " bootloader ${INSTALL_UBOOT_FILENAME}" +echo " bootloader1 ${INSTALL_UBOOT_FILENAME}" +if test "${install_redundant_bootloader}" = "yes"; then + echo " bootloader2 ${INSTALL_UBOOT_FILENAME}" +fi if test "${dualboot}" = "yes"; then echo " linux_a ${INSTALL_LINUX_FILENAME}" if test "${install_dualboot}" = "yes"; then @@ -129,6 +132,21 @@ if test $? -eq 1; then fi fi +if test "${install_redundant_bootloader}" = yes; then + echo ""; + echo ""; + echo ">> Installing U-Boot boot loader image ${INSTALL_UBOOT_FILENAME} on redundant partition"; + echo ""; + echo ""; + update uboot-redundant mmc ${INSTALL_MMCDEV} ${INSTALL_UBOOT_FILENAME}; + if test $? -eq 1; then + echo "[ERROR] Failed to update redundant U-Boot boot loader!"; + echo ""; + echo "Aborted."; + exit; + fi; +fi; + # Set 'bootcmd' to the second part of the script that will # - Reset environment to defaults # - Restore 'dualboot' if previously set diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt index d1a80f0d7..e20b94544 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_usb.txt @@ -76,7 +76,10 @@ echo " on the partitions of the eMMC." echo "" echo " PARTITION FILENAME" echo " --------- --------" -echo " bootloader ${INSTALL_UBOOT_FILENAME}" +echo " bootloader1 ${INSTALL_UBOOT_FILENAME}" +if test "${install_redundant_bootloader}" = "yes"; then + echo " bootloader2 ${INSTALL_UBOOT_FILENAME}" +fi if test "${dualboot}" = "yes"; then echo " linux_a ${INSTALL_LINUX_FILENAME}" if test "${install_dualboot}" = "yes"; then @@ -129,6 +132,21 @@ if test $? -eq 1; then fi fi +if test "${install_redundant_bootloader}" = yes; then + echo ""; + echo ""; + echo ">> Installing U-Boot boot loader image ${INSTALL_UBOOT_FILENAME} on redundant partition"; + echo ""; + echo ""; + update uboot-redundant usb ${INSTALL_USBDEV} ${INSTALL_UBOOT_FILENAME}; + if test $? -eq 1; then + echo "[ERROR] Failed to update redundant U-Boot boot loader!"; + echo ""; + echo "Aborted."; + exit; + fi; +fi; + # Set 'bootcmd' to the second part of the script that will # - Reset environment to defaults # - Restore 'dualboot' if previously set diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh index fd1336cbd..c6213dff3 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh @@ -42,6 +42,8 @@ show_usage() echo " -n No wait. Skips 10 seconds delay to stop script." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." + echo " -U Update redundant bootloader partition." + exit 2 } @@ -57,7 +59,7 @@ part_update() echo "=====================================================================================" echo "\033[0m" - if [ "${1}" = "bootloader" ]; then + if [ "${1}" = "bootloader" ] || [ "${1}" = "bootloader_redundant" ]; then uuu fb: flash "${1}" "${2}" else uuu fb: flash -raw2sparse "${1}" "${2}" @@ -73,7 +75,7 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:nu:' c +while getopts 'bdhi:nu:U' c do case $c in b) BOOTCOUNT=true ;; @@ -82,6 +84,7 @@ do i) IMAGE_NAME=${OPTARG} ;; n) NOWAIT=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; + U) INSTALL_REDUNDANT_UBOOT=true ;; esac done @@ -191,6 +194,9 @@ if [ "${NOWAIT}" != true ]; then printf " PARTITION\tFILENAME\n" printf " ---------\t--------\n" printf " bootloader\t${INSTALL_UBOOT_FILENAME}\n" + if [ "${INSTALL_REDUNDANT_UBOOT}" = true ]; then + printf " bootloader_redundant\t${INSTALL_UBOOT_FILENAME}\n" + fi if [ "${DUALBOOT}" = true ]; then printf " ${LINUX_NAME}_a\t${INSTALL_LINUX_FILENAME}\n" if [ "${INSTALL_DUALBOOT}" = true ]; then @@ -225,6 +231,9 @@ uuu fb: ucmd setenv forced_update 1 # Update U-Boot part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" +if [ "${INSTALL_REDUNDANT_UBOOT}" = true ]; then + part_update bootloader_redundant "${INSTALL_UBOOT_FILENAME}" +fi # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 From 4b98b3f49ec4b95d38dc61dcd2e11a60cfaebc3e Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Tue, 2 Apr 2024 17:53:37 +0200 Subject: [PATCH 57/91] tf-a-stm32mp: fix set_fip_sign_key() to obtain the key password This commit fixes the set_fip_sign_key() function to match the new keys format where there is a key_pass file for each key, no longer needing to search with the key index. Signed-off-by: Arturo Buzarra --- .../recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend index 0241faded..b8dfb74c1 100644 --- a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend @@ -44,12 +44,9 @@ python set_fip_sign_key() { passfile = d.getVar('TRUSTFENCE_PASSWORD_FILE') if (os.path.isfile(passfile)): with open(passfile, "r") as file: - p = file.read().split() - i = int(d.getVar('TRUSTFENCE_KEY_INDEX')) - if (i > 7): - i = 0 + p = file.read().strip() if (p): - d.setVar('FIP_SIGN_KEY_PASS', p[i]) + d.setVar('FIP_SIGN_KEY_PASS', p) } do_deploy:append() { From b00e341495405c276598332f429b75ec7e8ffecf Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Mon, 8 Apr 2024 11:28:51 +0200 Subject: [PATCH 58/91] meta-digi: remove python3-scipy This recipe is not supported anymore. If you need to add that package for aarch64, a solution is include pip3 in your image and install it using the pip3 install manager. Signed-off-by: Isaac Hermida --- .../python3-scipy/python3-scipy_1.7.0.bb | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 meta-digi-dey/recipes-devtools/python3-scipy/python3-scipy_1.7.0.bb diff --git a/meta-digi-dey/recipes-devtools/python3-scipy/python3-scipy_1.7.0.bb b/meta-digi-dey/recipes-devtools/python3-scipy/python3-scipy_1.7.0.bb deleted file mode 100644 index baa69a763..000000000 --- a/meta-digi-dey/recipes-devtools/python3-scipy/python3-scipy_1.7.0.bb +++ /dev/null @@ -1,48 +0,0 @@ -DESCRIPTION = "Open-source software for mathematics, science, and engineering. It includes modules for statistics, optimization, integration, linear algebra, Fourier transforms, signal and image processing, ODE solvers, and more." -SECTION = "devel/python" -HOMEPAGE = "https://www.scipy.org" -LICENSE = "BSD-3-Clause" -LIC_FILES_CHKSUM = "file://${S}/scipy-1.7.0.dist-info/LICENSE.txt;md5=caecddab96f03de0092b62333ea77f91" - -PYTHON_PACKAGE = "scipy-1.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" - -SRC_URI = "https://files.pythonhosted.org/packages/d0/8d/3dbb59d78218b6a76f1ddb55db60ea5459fa7968655acb21252a59a10bc3/${PYTHON_PACKAGE};subdir=${BP}" -SRC_URI[md5sum] = "e2e369078c6b7ca29c952cb9971bc154" -SRC_URI[sha256sum] = "bd4399d4388ca0239a4825e312b3e61b60f743dd6daf49e5870837716502a92a" - -DEPENDS = "python3 python3-pip-native python3-wheel-native" - -RDEPENDS:${PN} = "${PYTHON_PN} \ - ${PYTHON_PN}-numpy \ -" -RPROVIDES:${PN} += "\ - libgfortran-daac5196.so.5.0.0(GFORTRAN_8)(64bit) \ -" - -inherit python3native - -do_unpack[depends] += "unzip-native:do_populate_sysroot" - -do_unpack_extra(){ - [ -d ${S} ] || mkdir -p ${S} - cd ${S} - unzip -q -o ${S}/${PYTHON_PACKAGE} -d ${S} -} -addtask unpack_extra after do_unpack before do_patch - -do_install() { - # Install pip package - install -d ${D}/${PYTHON_SITEPACKAGES_DIR} - ${STAGING_BINDIR_NATIVE}/pip3 install --disable-pip-version-check -v \ - -t ${D}/${PYTHON_SITEPACKAGES_DIR} --no-cache-dir --no-deps \ - ${WORKDIR}/${BP}/scipy-*.whl -} - -FILES:${PN} += "\ - ${libdir}/${PYTHON_DIR}/site-packages/* \ -" - -INSANE_SKIP:${PN} += "already-stripped" - -COMPATIBLE_MACHINE = "(-)" -COMPATIBLE_MACHINE:aarch64 = "(.*)" From b84de064c07bffcac1fe4de0128ce988b488ad26 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Wed, 3 Apr 2024 12:16:14 +0200 Subject: [PATCH 59/91] ccimx93: tensorflow-lite-ethosu-delegate: fix hang issue with multiple tflite context This patch fixes the hang issue with EiQ demos using multiple tflite files, for instance the gesture_detection demo. https://onedigi.atlassian.net/browse/DEL-8949 Signed-off-by: Isaac Hermida --- ...g-issue-with-multiple-tflite-context.patch | 102 ++++++++++++++++++ ...rflow-lite-ethosu-delegate_2.12.1.bbappend | 3 + 2 files changed, 105 insertions(+) create mode 100644 meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate/0001-Fix-hang-issue-with-multiple-tflite-context.patch create mode 100644 meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate_2.12.1.bbappend diff --git a/meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate/0001-Fix-hang-issue-with-multiple-tflite-context.patch b/meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate/0001-Fix-hang-issue-with-multiple-tflite-context.patch new file mode 100644 index 000000000..6d1db0fe2 --- /dev/null +++ b/meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate/0001-Fix-hang-issue-with-multiple-tflite-context.patch @@ -0,0 +1,102 @@ +From: nxf77310 +Date: Tue, 26 Mar 2024 12:38:26 +0530 +Subject: [PATCH] Fix hang issue with multiple tflite context + +--- + ethosu_delegate.cc | 34 ++++++++++++++++++++++------------ + simple_delegate.cc | 2 +- + simple_delegate.h | 2 +- + 3 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/ethosu_delegate.cc b/ethosu_delegate.cc +index b45ba26..b975b31 100644 +--- a/ethosu_delegate.cc ++++ b/ethosu_delegate.cc +@@ -456,19 +456,21 @@ class EthosuDelegate : public SimpleDelegateInterface { + + TfLiteStatus Initialize(TfLiteContext* context) override { + try { +- ethosu_context.device = +- EthosU::Device::GetSingleton(options_.device_name.c_str()); ++ TfLiteEthosuContext *ethosu_context = new TfLiteEthosuContext; ++ ethosu_context->device = ++ EthosU::Device::GetSingleton(options_.device_name.c_str()); + + if (options_.enable_profiling && options_.profiling_buffer_size != 0){ + size_t size = sizeof(EthosuQreadEvent) * options_.profiling_buffer_size; +- ethosu_context.qread_buffer = +- make_shared(*ethosu_context.device, size); +- ethosu_context.qread_buffer->resize(0); +- } else { +- ethosu_context.qread_buffer = nullptr; ++ ethosu_context->qread_buffer = ++ make_shared(*ethosu_context->device, size); ++ ethosu_context->qread_buffer->resize(0); ++ } else { ++ ethosu_context->qread_buffer = nullptr; + } +- ethosu_context.arena_buffer = nullptr; +- ethosu_context.flash_buffer = nullptr; ++ ethosu_context->arena_buffer = nullptr; ++ ethosu_context->flash_buffer = nullptr; ++ context_map_[context] = ethosu_context; + } catch (exception &e) { + TF_LITE_KERNEL_LOG(context, "Failed to create ethos_u driver.\n"); + return kTfLiteDelegateError; +@@ -477,8 +479,9 @@ class EthosuDelegate : public SimpleDelegateInterface { + return kTfLiteOk; + } + +- void *GetDelegateContext() const{ +- return (void*) ðosu_context; ++ void *GetDelegateContext(TfLiteContext* context) const{ ++ return context_map_.at(context); ++ + } + + const char* Name() const override { +@@ -496,9 +499,16 @@ class EthosuDelegate : public SimpleDelegateInterface { + return SimpleDelegateInterface::Options(); + } + ++ ~EthosuDelegate() { ++ std::map::iterator itr; ++ for (itr = context_map_.begin(); itr != context_map_.end(); ++itr) { ++ delete (TfLiteEthosuContext*)itr->second; ++ } ++ } ++ + private: + const EthosuDelegateOptions options_; +- TfLiteEthosuContext ethosu_context; ++ std::map context_map_; + }; + + } // namespace ethosu +diff --git a/simple_delegate.cc b/simple_delegate.cc +index 51bd5b7..f65b475 100644 +--- a/simple_delegate.cc ++++ b/simple_delegate.cc +@@ -48,7 +48,7 @@ TfLiteRegistration GetDelegateKernelRegistration( + } + auto* delegate = + reinterpret_cast(params->delegate->data_); +- void* delegate_context = delegate->GetDelegateContext(); ++ void* delegate_context = delegate->GetDelegateContext(context); + std::unique_ptr delegate_kernel( + delegate->CreateDelegateKernelInterface()); + if (delegate_kernel->Init(context, params, delegate_context) != kTfLiteOk) { +diff --git a/simple_delegate.h b/simple_delegate.h +index 9bd891d..6509374 100644 +--- a/simple_delegate.h ++++ b/simple_delegate.h +@@ -115,7 +115,7 @@ class SimpleDelegateInterface { + virtual SimpleDelegateInterface::Options DelegateOptions() const = 0; + + // Get the SimpleDelegate global context data +- virtual void *GetDelegateContext() const = 0; ++ virtual void *GetDelegateContext(TfLiteContext* context) const = 0; + }; + + // Factory class that provides static methods to deal with SimpleDelegate + diff --git a/meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate_2.12.1.bbappend b/meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate_2.12.1.bbappend new file mode 100644 index 000000000..994126454 --- /dev/null +++ b/meta-digi-dey/dynamic-layers/meta-ml/recipes-libraries/tensorflow-lite/tensorflow-lite-ethosu-delegate_2.12.1.bbappend @@ -0,0 +1,3 @@ +# Copyright (C) 2024 Digi International Inc. + +SRC_URI += "file://0001-Fix-hang-issue-with-multiple-tflite-context.patch" From cfd40ca02f08fcdd244c60ed57f26b5d1386844a Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Wed, 27 Mar 2024 10:51:35 +0100 Subject: [PATCH 60/91] trustfence-stm-signtools: include external libraries in the package itself The signing tools have a dependency of libQt5Core.so.5, which implies that this library must to be installed on the native PC. This commit includes all the required shared libraries for the signing tools inside the own package to avoid external dependencies. With this change there is not needed any more the qtbase dependency at build time. Package version has been bumped to 1.2. Signed-off-by: Arturo Buzarra --- .../nativesdk-trustfence-stm-signtools_1.1.bb | 9 --------- .../nativesdk-trustfence-stm-signtools_1.2.bb | 4 ++++ ...ive_1.1.bb => trustfence-stm-signtools-native_1.2.bb} | 0 .../trustfence-stm-signtools.inc | 8 ++++---- 4 files changed, 8 insertions(+), 13 deletions(-) delete mode 100644 meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.1.bb create mode 100644 meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.2.bb rename meta-digi-arm/recipes-bsp/trustfence-stm-signtools/{trustfence-stm-signtools-native_1.1.bb => trustfence-stm-signtools-native_1.2.bb} (100%) diff --git a/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.1.bb b/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.1.bb deleted file mode 100644 index f4614cc4e..000000000 --- a/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.1.bb +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) 2023 Digi International. - -require trustfence-stm-signtools.inc -inherit nativesdk - -# STM signing tools binaries depend on libQt5Core.so.5 -RDEPENDS:${PN} += " \ - nativesdk-qtbase \ -" diff --git a/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.2.bb b/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.2.bb new file mode 100644 index 000000000..65ab80168 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/nativesdk-trustfence-stm-signtools_1.2.bb @@ -0,0 +1,4 @@ +# Copyright (C) 2023,2024 Digi International. + +require trustfence-stm-signtools.inc +inherit nativesdk diff --git a/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools-native_1.1.bb b/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools-native_1.2.bb similarity index 100% rename from meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools-native_1.1.bb rename to meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools-native_1.2.bb diff --git a/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools.inc b/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools.inc index 54540ab00..c3db046ea 100644 --- a/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools.inc +++ b/meta-digi-arm/recipes-bsp/trustfence-stm-signtools/trustfence-stm-signtools.inc @@ -1,17 +1,17 @@ -# Copyright (C) 2023 Digi International. +# Copyright (C) 2023,2024 Digi International. SUMMARY = "STM key generation and signing tools" SECTION = "console/tools" LICENSE = "Proprietary" -LIC_FILES_CHKSUM = "file://en.SLA0048.txt;md5=108361d167deef887d204830aba9cf94" +LIC_FILES_CHKSUM = "file://licenses/en.SLA0048.txt;md5=108361d167deef887d204830aba9cf94" PKGNAME = "trustfence-stm-signtools" # tarball SRC_URI = "${DIGI_PKG_SRC}/${PKGNAME}-${PV}.tar.gz" -SRC_URI[md5sum] = "38ce0cd682350b15e773e725ee842da4" -SRC_URI[sha256sum] = "cc349bdcaa764d5af25b12ee9e0c143f93dc80d531f42f8a57a735e170cd378b" +SRC_URI[md5sum] = "995b612c1da7e3d9b9b402ede578f41d" +SRC_URI[sha256sum] = "b3c975c12f71acda356e086c1440398ca95256e104fd4813ef6a720237f6dd72" inherit bin_package From cc728825848946ad621efdd6d0d10c11a05c9179 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Mon, 8 Apr 2024 18:41:35 +0200 Subject: [PATCH 61/91] ccmp15: add DT overlay for the SV4E MIPI analyzer https://onedigi.atlassian.net/browse/DEL-8978 Signed-off-by: Arturo Buzarra --- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index 56f0a57ee..ce7cb5ec3 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -45,6 +45,7 @@ STM32MP_KERNEL_DEVICETREE:ccmp15-dvk += " \ _ov_board_mikroe-accel2-click_ccmp15-dvk.dtbo \ _ov_board_mikroe-gyro-click_ccmp15-dvk.dtbo \ _ov_board_mikroe-i2c-to-spi-click_ccmp15-dvk.dtbo \ + _ov_board_sv4e-mipi-analyzer_ccmp15-dvk.dtbo \ _ov_board_v1_ccmp15-dvk.dtbo \ _ov_board_v2_ccmp15-dvk.dtbo \ _ov_som_bt_ccmp15.dtbo \ From 3c26ef78e0cf5d1729d4aa43669ca4f7fc3ab7c9 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Thu, 11 Apr 2024 18:18:13 +0200 Subject: [PATCH 62/91] meta-digi: enable boot artifacts encryption support on ccimx93 Add a check on the existence of the "temp-fitimg-loaded" environment variable before setting it. It is needed, as with encrypted FIT images, we need to decrypt them before accessing the boot script. In such cases, u-boot sets that variable to "no" so the boot script does not override it, and the FIT image is loaded again before the final boot to the OS. https://onedigi.atlassian.net/browse/DEL-8945 Signed-off-by: Javier Viguera --- .../recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt | 2 +- meta-digi-dey/classes/trustfence.bbclass | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt index 0dc69b973..173b3b84d 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93-dvk/boot.txt @@ -84,7 +84,7 @@ if test "${module_has_npu}" = "1" && test -z "${disable_npu}"; then setenv overlays _ov_som_npu_ccimx93.dtbo,${overlays} fi -if test "${dboot_kernel_var}" = "fitimage"; then +if test "${dboot_kernel_var}" = "fitimage" && test -z "${temp-fitimg-loaded}"; then # Set temp var to avoid re-loading fitimage setenv temp-fitimg-loaded yes fi diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index 7b59b474f..d8db03b7d 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -24,7 +24,6 @@ TRUSTFENCE_CONSOLE_DISABLE ?= "0" TRUSTFENCE_SIGN ?= "1" TRUSTFENCE_SIGN_KEYS_PATH ?= "default" TRUSTFENCE_DEK_PATH ?= "default" -TRUSTFENCE_DEK_PATH:ccimx93 ?= "0" TRUSTFENCE_DEK_PATH:ccmp1 ?= "0" TRUSTFENCE_ENCRYPT_ENVIRONMENT ?= "1" TRUSTFENCE_ENCRYPT_ENVIRONMENT:ccimx93 ?= "0" From e8860f7bbfbdb8150326c49b470f8c93de6cfcaa Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Wed, 17 Apr 2024 17:55:16 +0200 Subject: [PATCH 63/91] optee-client: fix package installation in the rootfs Several things were wrong after the latest update to version 4.0: the tee-supplicant path, some settings in the systemd unit, etc. This commit fixes the installation so the optee test suite completes again. https://onedigi.atlassian.net/browse/DEL-8989 Signed-off-by: Javier Viguera --- .../optee-imx/optee-client_4.0.0.imx.bb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-client_4.0.0.imx.bb b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-client_4.0.0.imx.bb index 32d91245c..427bdf1a8 100644 --- a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-client_4.0.0.imx.bb +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-client_4.0.0.imx.bb @@ -8,6 +8,14 @@ require recipes-security/optee-imx/optee-client_3.19.0.imx.bb SRCBRANCH = "lf-6.1.55_2.2.0" SRCREV = "acb0885c117e73cb6c5c9b1dd9054cb3f93507ee" -EXTRA_OEMAKE += "PKG_CONFIG=pkg-config" +EXTRA_OEMAKE += "PKG_CONFIG=pkg-config CFG_TEE_FS_PARENT_PATH='${localstatedir}/lib/tee'" + +do_install() { + oe_runmake DESTDIR=${D} install + install -D -p -m0644 ${WORKDIR}/tee-supplicant.service ${D}${systemd_system_unitdir}/tee-supplicant.service + sed -i -e s:@sysconfdir@:${sysconfdir}:g \ + -e s:@sbindir@:${sbindir}:g \ + ${D}${systemd_system_unitdir}/tee-supplicant.service +} COMPATIBLE_MACHINE = "(ccimx93)" From afde974a174d89d88be3ca7b1f950fae4bfc5691 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Wed, 17 Apr 2024 17:58:11 +0200 Subject: [PATCH 64/91] packagegroup-imx-ml: ccimx93: only install tensorflow-lite Rework commit c5c9838e54847624886198d4c6665566a4f3e979 to only limit ML packages for our ccimx93 and not for other imx93-based devices. Signed-off-by: Javier Viguera --- .../recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend b/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend index e187c97cb..ef6cbd501 100644 --- a/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend +++ b/meta-digi-dey/dynamic-layers/meta-ml/recipes-fsl/packagegroup/packagegroup-imx-ml.bbappend @@ -2,8 +2,12 @@ ML_NNSTREAMER_PKGS_LIST:remove = "nnstreamer-deepview-rt" -# Only install tensorflow-lite to save space -ML_PKGS:mx9-nxp-bsp:mx93-nxp-bsp = "tensorflow-lite" +ML_PKGS:mx9-nxp-bsp:remove = "deepview-rt-examples" + +# For the ccimx93 install only tensorflow-lite engine, as it is +# the only one supported in the NPU. This reduces significantly +# the rootfs image size. +ML_PKGS:ccimx93 = "tensorflow-lite" # ARM ethos-u package ETHOS_U_PKGS:append:mx93-nxp-bsp = " \ From 8e63e5243597799eb4a07613840427d5a424324f Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Thu, 18 Apr 2024 11:26:48 +0200 Subject: [PATCH 65/91] stm32mp: optee: add optee-client support by default Optee-client provides the TEE Client API as defined by the GlobalPlatform TEE standard. It is required to communicate with a Trusted Application (TA) running in a Trusted OS. https://onedigi.atlassian.net/browse/DEL-8970 Signed-off-by: Arturo Buzarra --- meta-digi-arm/conf/machine/include/ccmp1.inc | 3 ++ .../optee/optee-client/tee-supplicant.service | 10 ++++++ .../optee/optee-client_3.16.bb | 33 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client/tee-supplicant.service create mode 100755 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client_3.16.bb diff --git a/meta-digi-arm/conf/machine/include/ccmp1.inc b/meta-digi-arm/conf/machine/include/ccmp1.inc index e6d31378b..93a33dd36 100644 --- a/meta-digi-arm/conf/machine/include/ccmp1.inc +++ b/meta-digi-arm/conf/machine/include/ccmp1.inc @@ -42,6 +42,9 @@ UBOOT_ENV_SIZE ?= "0x20000" # available space in the environment partition) UBOOT_ENV_RANGE ?= "" +# OPTEE runtime packages to install +OPTEE_PKGS ??= "optee-client" + MACHINE_EXTRA_RDEPENDS += " \ mtd-utils-ubifs \ " diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client/tee-supplicant.service b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client/tee-supplicant.service new file mode 100644 index 000000000..ffb54d390 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client/tee-supplicant.service @@ -0,0 +1,10 @@ +[Unit] +Description=TEE Supplicant + +[Service] +User=root +EnvironmentFile=-/etc/default/tee-supplicant +ExecStart=/usr/sbin/tee-supplicant $OPTARGS + +[Install] +WantedBy=basic.target diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client_3.16.bb b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client_3.16.bb new file mode 100755 index 000000000..4a3164499 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-security/optee/optee-client_3.16.bb @@ -0,0 +1,33 @@ +SUMMARY = "OPTEE Client" +HOMEPAGE = "https://github.com/OP-TEE/optee_client" + +LICENSE = "BSD-2-Clause" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=69663ab153298557a59c67a60a743e5b" + +inherit python3native systemd cmake + +SRC_URI = "git://github.com/OP-TEE/optee_client.git;protocol=https;branch=master \ + file://tee-supplicant.service \ + " + +SRCREV = "06db73b3f3fdb8d23eceaedbc46c49c0b45fd1e2" + +PV = "3.16.0+git${SRCPV}" + +S = "${WORKDIR}/git" + +SYSTEMD_SERVICE:${PN} = "tee-supplicant.service" + +EXTRA_OECMAKE = " \ + -DCFG_TEE_FS_PARENT_PATH='${localstatedir}/lib/tee' \ + -DCFG_WERROR=OFF \ + -DCFG_TEE_CLIENT_LOG_LEVEL=2 \ + -DBUILD_SHARED_LIBS=ON \ + " + +do_install:append() { + if ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then + install -D -p -m0644 ${WORKDIR}/tee-supplicant.service ${D}${systemd_system_unitdir}/tee-supplicant.service + fi +} +FILES:${PN} += "${systemd_system_unitdir}" From 041ca93cd9185e7d3bcdafddf9f2719fcc6b2a53 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Mon, 22 Apr 2024 15:47:01 +0200 Subject: [PATCH 66/91] ccimx8x: fix u-boot Trustfence naming for installation script This commit fixes u-boot Trustfence naming for signed and encrypted images used in the installation script removing the a duplicated dash in the u-boot name. https://onedigi.atlassian.net/browse/DEL-8271 Signed-off-by: Mike Engel --- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index 637b0033d..aa0f7e391 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -89,9 +89,9 @@ build_uboot_scripts() { if [ "${TRUSTFENCE_SIGN}" = "1" ]; then if [ "${DEY_SOC_VENDOR}" = "NXP" ]; then if [ "${TRUSTFENCE_DEK_PATH}" != "0" ]; then - sed -i -e 's,##SIGNED##,-encrypted,g' ${TMP_INSTALL_SCR} + sed -i -e 's,##SIGNED##,encrypted,g' ${TMP_INSTALL_SCR} else - sed -i -e 's,##SIGNED##,-signed,g' ${TMP_INSTALL_SCR} + sed -i -e 's,##SIGNED##,signed,g' ${TMP_INSTALL_SCR} fi else sed -i -e 's,##SIGNED##,_Signed,g' ${TMP_INSTALL_SCR} From 55b313e7d2bf5fa066ae3d23c428f235ce9c1f2d Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Tue, 23 Apr 2024 12:14:51 +0200 Subject: [PATCH 67/91] trustfence: create symbolic links for all SOC revisions of the CCiMX8X This commit creates symbolic links for all SOC revisions of the CCiMX8X platform. Signed-off-by: Mike Engel --- .../recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend index dc26c104f..c83f09161 100644 --- a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend @@ -201,10 +201,12 @@ trustfence_sign_imxboot:ccimx8x() { done # Generate symlinks for trustfence artifacts. - ln -sf ${UBOOT_PREFIX}-signed-${MACHINE}-${rev}.bin-${IMAGE_IMXBOOT_TARGET} ${DEPLOYDIR}/${UBOOT_PREFIX}-signed-${MACHINE}.bin - if [ -n "${TRUSTFENCE_DEK_PATH}" ] && [ "${TRUSTFENCE_DEK_PATH}" != "0" ]; then - ln -sf ${UBOOT_PREFIX}-encrypted-${MACHINE}-${rev}.bin-${IMAGE_IMXBOOT_TARGET} ${DEPLOYDIR}/${UBOOT_PREFIX}-encrypted-${MACHINE}.bin - fi + for rev in ${SOC_REVISIONS}; do + ln -sf ${UBOOT_PREFIX}-signed-${MACHINE}-${rev}.bin-${IMAGE_IMXBOOT_TARGET} ${DEPLOYDIR}/${UBOOT_PREFIX}-signed-${MACHINE}-${rev}.bin + if [ -n "${TRUSTFENCE_DEK_PATH}" ] && [ "${TRUSTFENCE_DEK_PATH}" != "0" ]; then + ln -sf ${UBOOT_PREFIX}-encrypted-${MACHINE}-${rev}.bin-${IMAGE_IMXBOOT_TARGET} ${DEPLOYDIR}/${UBOOT_PREFIX}-encrypted-${MACHINE}-${rev}.bin + fi + done } trustfence_sign_imxboot[dirs] = "${DEPLOYDIR}" From e2caf16da4cd7287fca304bbd6c80d8c57f2e839 Mon Sep 17 00:00:00 2001 From: Isaac Hermida Date: Fri, 26 Apr 2024 14:10:14 +0200 Subject: [PATCH 68/91] mount: use the ubi class to check for attached devices Use the generic sys class to check if a mtd device is attached. The virtual node may not be present in some kernel versions. Signed-off-by: Isaac Hermida --- .../recipes-core/udev/udev-extraconf/mount_digiparts.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meta-digi-arm/recipes-core/udev/udev-extraconf/mount_digiparts.sh b/meta-digi-arm/recipes-core/udev/udev-extraconf/mount_digiparts.sh index e13cf8593..f632924ae 100644 --- a/meta-digi-arm/recipes-core/udev/udev-extraconf/mount_digiparts.sh +++ b/meta-digi-arm/recipes-core/udev/udev-extraconf/mount_digiparts.sh @@ -146,8 +146,8 @@ if [ "${SUBSYSTEM}" = "block" ]; then elif [ "${SUBSYSTEM}" = "mtd" ]; then # Before attaching, find out if partition already attached MTD_NUM="$(echo ${MTDN} | sed -ne 's,.*mtd\([0-9]\+\),\1,g;T;p')" - for ubidev in /sys/devices/virtual/ubi/*; do - echo "${ubidev}" | grep -qs '/sys/devices/virtual/ubi/\*' && continue + for ubidev in /sys/class/ubi/*; do + echo "${ubidev}" | grep -qs '/sys/class/ubi/\*' && continue mtd_att="$(cat ${ubidev}/mtd_num)" if [ "${mtd_att}" = "${MTD_NUM}" ]; then dev_number="$(echo ${ubidev} | sed -ne 's,.*ubi\([0-9]\+\),\1,g;T;p')" From 2eb37cf30b9a17b39cd7e28230ca1e7b6ae146e4 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Fri, 9 Feb 2024 12:05:07 +0100 Subject: [PATCH 69/91] linux-dey-6.1: add RT functionality to CCiMX93 This commit adds RT functionality to the CCiMX93 platform. The patches have been extracted from the NXP real time edge BSP and include the maineline RT patches and the NXP RT driver patches and RT Kernel defconfig changes. https://onedigi.atlassian.net/browse/DEL-8881 Signed-off-by: Mike Engel --- .../0001-arch-arm-add-NXP-RT-support.patch | 4297 +++ .../ccimx93/0002-RT-add-RT-localversion.patch | 21 + .../0003-arch-arm64-add-NXP-RT-support.patch | 5862 +++++ ...004-Documentation-add-NXP-RT-support.patch | 581 + .../0005-include-add-NXP-RT-support.patch | 1392 + .../0006-kernel-add-NXP-RT-support.patch | 2435 ++ .../0007-drivers-add-NXP-RT-support.patch | 21976 ++++++++++++++++ .../ccimx93/0008-net-add-RT-NXP-support.patch | 1486 ++ .../0009-init-add-NXP-RT-support.patch | 28 + .../linux/linux-dey/ccimx93/nxp_rt_conf.cfg | 31 + .../recipes-kernel/linux/linux-dey_6.1.bb | 21 +- 11 files changed, 38129 insertions(+), 1 deletion(-) create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0001-arch-arm-add-NXP-RT-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0002-RT-add-RT-localversion.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0003-arch-arm64-add-NXP-RT-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0004-Documentation-add-NXP-RT-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0005-include-add-NXP-RT-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0006-kernel-add-NXP-RT-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0007-drivers-add-NXP-RT-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0008-net-add-RT-NXP-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0009-init-add-NXP-RT-support.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/nxp_rt_conf.cfg diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0001-arch-arm-add-NXP-RT-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0001-arch-arm-add-NXP-RT-support.patch new file mode 100644 index 000000000..1affe022b --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0001-arch-arm-add-NXP-RT-support.patch @@ -0,0 +1,4297 @@ +From f30b008a0e7277dea1c5bc16d87dfa3e868d245a Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Fri, 23 Feb 2024 08:39:38 +0100 +Subject: [PATCH 01/10] arch:arm: add NXP RT support + +Signed-off-by: Mike Engel +--- + arch/arm/Kconfig | 5 +- + arch/arm/boot/dts/Makefile | 8 +- + arch/arm/boot/dts/imx6ul-14x14-evk-ecat.dts | 11 + + .../boot/dts/imx6ull-14x14-evk-avb-mcr.dts | 59 + + arch/arm/boot/dts/imx6ull-14x14-evk-avb.dts | 29 + + arch/arm/boot/dts/imx6ull-14x14-evk-ecat.dts | 11 + + .../arm/boot/dts/imx6ull-14x14-evk-lpuart.dts | 25 + + arch/arm/boot/dts/ls1021a-iot-bm.dts | 259 ++ + arch/arm/boot/dts/ls1021a-iot.dts | 47 + + arch/arm/boot/dts/ls1021a.dtsi | 4 +- + arch/arm/configs/imx6ullevk-plc.config | 3333 +++++++++++++++++ + arch/arm/configs/imx_avb.config | 8 + + arch/arm/configs/imx_up.config | 2 + + arch/arm/configs/imx_v6_v7_defconfig | 3 +- + arch/arm/configs/imx_v7_defconfig | 9 +- + arch/arm/configs/lsdk.config | 20 + + arch/arm/configs/multi_v7_defconfig | 2 + + arch/arm/include/asm/thread_info.h | 6 +- + arch/arm/kernel/asm-offsets.c | 5 +- + arch/arm/kernel/entry-armv.S | 19 +- + arch/arm/kernel/signal.c | 3 +- + arch/arm/kernel/smp.c | 22 + + arch/arm/mach-imx/Kconfig | 10 + + arch/arm/mm/fault.c | 6 + + 24 files changed, 3891 insertions(+), 15 deletions(-) + create mode 100644 arch/arm/boot/dts/imx6ul-14x14-evk-ecat.dts + create mode 100644 arch/arm/boot/dts/imx6ull-14x14-evk-avb-mcr.dts + create mode 100644 arch/arm/boot/dts/imx6ull-14x14-evk-avb.dts + create mode 100644 arch/arm/boot/dts/imx6ull-14x14-evk-ecat.dts + create mode 100644 arch/arm/boot/dts/imx6ull-14x14-evk-lpuart.dts + create mode 100644 arch/arm/boot/dts/ls1021a-iot-bm.dts + create mode 100644 arch/arm/configs/imx6ullevk-plc.config + create mode 100644 arch/arm/configs/imx_avb.config + create mode 100644 arch/arm/configs/imx_up.config + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index edc39ef9d6c0..6432868439a7 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -33,6 +33,7 @@ config ARM + select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7 + select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE ++ select ARCH_SUPPORTS_RT if HAVE_POSIX_CPU_TIMERS_TASK_WORK + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_USE_MEMTEST +@@ -71,7 +72,7 @@ config ARM + select HARDIRQS_SW_RESEND + select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT + select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 +- select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU ++ select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU && !PREEMPT_RT + select HAVE_ARCH_KFENCE if MMU && !XIP_KERNEL + select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU + select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL +@@ -115,6 +116,8 @@ config ARM + select HAVE_PERF_EVENTS + select HAVE_PERF_REGS + select HAVE_PERF_USER_STACK_DUMP ++ select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM ++ select HAVE_PREEMPT_LAZY + select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE + select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RSEQ +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 92f31aa19dbc..21e6828fcea0 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -761,6 +761,7 @@ dtb-$(CONFIG_SOC_IMX6SX) += \ + imx6sx-udoo-neo-full.dtb + dtb-$(CONFIG_SOC_IMX6UL) += \ + imx6ul-14x14-evk.dtb \ ++ imx6ul-14x14-evk-ecat.dtb \ + imx6ul-14x14-evk-csi.dtb \ + imx6ul-14x14-evk-emmc.dtb \ + imx6ul-14x14-evk-btwifi.dtb \ +@@ -803,6 +804,10 @@ dtb-$(CONFIG_SOC_IMX6UL) += \ + imx6ul-ccimx6ulstarter-wb.dtb \ + imx6ul-ccimx6ulstarter-wb-mfg.dtb \ + imx6ull-14x14-evk.dtb \ ++ imx6ull-14x14-evk-ecat.dtb \ ++ imx6ull-14x14-evk-lpuart.dtb \ ++ imx6ull-14x14-evk-avb.dtb \ ++ imx6ull-14x14-evk-avb-mcr.dtb \ + imx6ull-14x14-evk-emmc.dtb \ + imx6ull-14x14-evk-btwifi.dtb \ + imx6ull-14x14-evk-gpmi-weim.dtb \ +@@ -941,7 +946,8 @@ dtb-$(CONFIG_SOC_LS1021A) += \ + ls1021a-moxa-uc-8410a.dtb \ + ls1021a-qds.dtb \ + ls1021a-tsn.dtb \ +- ls1021a-twr.dtb ++ ls1021a-twr.dtb \ ++ ls1021a-iot.dtb + dtb-$(CONFIG_SOC_VF610) += \ + vf500-colibri-eval-v3.dtb \ + vf610-bk4.dtb \ +diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk-ecat.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-ecat.dts +new file mode 100644 +index 000000000000..2a99ab3960f1 +--- /dev/null ++++ b/arch/arm/boot/dts/imx6ul-14x14-evk-ecat.dts +@@ -0,0 +1,11 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx6ul-14x14-evk.dts" ++ ++ ++&fec1 { ++ compatible = "fsl,imx6ul-fec-ecat", "fsl,imx6q-fec-ecat"; ++}; +diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-avb-mcr.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-avb-mcr.dts +new file mode 100644 +index 000000000000..e06167bd96bc +--- /dev/null ++++ b/arch/arm/boot/dts/imx6ull-14x14-evk-avb-mcr.dts +@@ -0,0 +1,59 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++// ++// Copyright 2022 NXP ++ ++#include "imx6ull-14x14-evk-avb.dts" ++ ++/****************************************************************************************** ++* This dts adds the media clock recovery capability for AVB to the imx6ull-14x14-evk board. ++* A hardware rework is necessary for this feature: ++* -connect SD1_DATA2 and GPIO1_IO05 pads (can be done by connecting R1728 and TP2120) ++* -connect JTAG_MOD and JTAG_TMS (SAI2_MCLK) pads (can be done by connecting R1023 and ++* JTAG pin number 7) ++* ++* Warning: this will prevent using SD1 Slot. ++*******************************************************************************************/ ++ ++&iomuxc { ++ pinctrl_avb: avbgrp { ++ fsl,pins = < ++ MX6UL_PAD_SD1_DATA2__GPT2_CAPTURE1 0x110b0 ++ MX6UL_PAD_GPIO1_IO05__ENET2_1588_EVENT0_OUT 0x88 ++ MX6UL_PAD_JTAG_MOD__GPT2_CLK 0x1f0b0 ++ >; ++ }; ++}; ++ ++/* AVB MCR timer */ ++&gpt2 { ++ compatible = "fsl,avb-gpt"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_avb>; ++ prescale = <1>; ++ ++ rec-channel = <1 0 0>; /* capture channel, eth port, ENET TC id */ ++ domain = <0>; ++ ++ clocks = <&clks IMX6UL_CLK_GPT2_BUS>, <&clks IMX6UL_CLK_GPT2_SERIAL>, ++ <&clks IMX6UL_CLK_SAI2>, <&clks IMX6UL_CLK_PLL4>; ++ clock-names = "ipg", "per", "clk_in", "audio_pll"; ++ ++ status = "okay"; ++}; ++ ++/* Pin conflict on GPIO1_IO05 */ ++&usdhc1 { ++ status = "disabled"; ++}; ++ ++/* Set PERCLK parent to IPG to make sure that GPT_CLK set above is lower ++ * than 1/4 of frequency of the peripheral clock ++ * (Keep previsouly set, from included dts files, clocks in the node) ++ */ ++&clks { ++ assigned-clocks = <&clks IMX6UL_CLK_PERCLK_SEL>, ++ <&clks IMX6UL_CLK_PLL3_PFD2>, ++ <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>; ++ assigned-clock-parents = <&clks IMX6UL_CLK_IPG>; ++ assigned-clock-rates = <0>, <320000000>, <786432000>; ++}; +diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-avb.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-avb.dts +new file mode 100644 +index 000000000000..09af5531b3e0 +--- /dev/null ++++ b/arch/arm/boot/dts/imx6ull-14x14-evk-avb.dts +@@ -0,0 +1,29 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++// ++// Copyright 2018 NXP ++ ++#include "imx6ull-14x14-evk.dts" ++ ++/* AVB HW timer*/ ++&epit1 { ++ compatible = "fsl,avb-epit"; ++ clocks = <&clks IMX6UL_CLK_EPIT1>; ++ clock-names = "epit1"; ++ ++ status = "okay"; ++}; ++ ++&fec1 { ++ fsl,rx-phy-delay-100-ns = <670>; ++ fsl,tx-phy-delay-100-ns = <670>; ++ fsl,rx-phy-delay-1000-ns = <0>; ++ fsl,tx-phy-delay-1000-ns = <0>; ++}; ++ ++&fec2 { ++ fsl,rx-phy-delay-100-ns = <670>; ++ fsl,tx-phy-delay-100-ns = <670>; ++ fsl,rx-phy-delay-1000-ns = <0>; ++ fsl,tx-phy-delay-1000-ns = <0>; ++}; ++ +diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-ecat.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-ecat.dts +new file mode 100644 +index 000000000000..67df18babf56 +--- /dev/null ++++ b/arch/arm/boot/dts/imx6ull-14x14-evk-ecat.dts +@@ -0,0 +1,11 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx6ull-14x14-evk.dts" ++ ++ ++&fec1 { ++ compatible = "fsl,imx6ul-fec-ecat", "fsl,imx6q-fec-ecat"; ++}; +diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk-lpuart.dts b/arch/arm/boot/dts/imx6ull-14x14-evk-lpuart.dts +new file mode 100644 +index 000000000000..d7a378c5349c +--- /dev/null ++++ b/arch/arm/boot/dts/imx6ull-14x14-evk-lpuart.dts +@@ -0,0 +1,25 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx6ull-14x14-evk.dts" ++ ++/* Unbind lpuart2 from Bluetooth, use it for lpuart test. */ ++&uart2 { ++ /delete-node/ bluetooth; ++}; ++ ++/* ++ * uart test port1. Note: don't use Bluetooth at the sametime. ++ * J1703: Pin1--RX Pin2--TX ++ */ ++&pinctrl_uart2 { ++ fsl,pins = < ++ MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1 ++ MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1 ++ MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1 ++ MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1 ++ >; ++}; ++ +diff --git a/arch/arm/boot/dts/ls1021a-iot-bm.dts b/arch/arm/boot/dts/ls1021a-iot-bm.dts +new file mode 100644 +index 000000000000..3a23b97f0081 +--- /dev/null ++++ b/arch/arm/boot/dts/ls1021a-iot-bm.dts +@@ -0,0 +1,259 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape baremetal ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Author: Changming Huang ++ * ++ */ ++ ++/dts-v1/; ++#include "ls1021a.dtsi" ++ ++/ { ++ model = "LS1021A IOT Board"; ++ ++ sys_mclk: clock-mclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24576000>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_3p3v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_2p5v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "2P5V"; ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-always-on; ++ }; ++ }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,format = "i2s"; ++ simple-audio-card,widgets = ++ "Microphone", "Microphone Jack", ++ "Headphone", "Headphone Jack", ++ "Speaker", "Speaker Ext", ++ "Line", "Line In Jack"; ++ simple-audio-card,routing = ++ "MIC_IN", "Microphone Jack", ++ "Microphone Jack", "Mic Bias", ++ "LINE_IN", "Line In Jack", ++ "Headphone Jack", "HP_OUT", ++ "Speaker Ext", "LINE_OUT"; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&sai2>; ++ frame-master; ++ bitclock-master; ++ }; ++ ++ simple-audio-card,codec { ++ sound-dai = <&codec>; ++ frame-master; ++ bitclock-master; ++ }; ++ }; ++ ++ firmware { ++ optee { ++ compatible = "linaro,optee-tz"; ++ method = "smc"; ++ }; ++ }; ++}; ++ ++&enet0 { ++ tbi-handle = <&tbi1>; ++ phy-handle = <&phy1>; ++ phy-connection-type = "sgmii"; ++ status = "okay"; ++}; ++ ++&enet1 { ++ tbi-handle = <&tbi1>; ++ phy-handle = <&phy3>; ++ phy-connection-type = "sgmii"; ++ status = "okay"; ++}; ++ ++&enet2 { ++ fixed-link = <0 1 1000 0 0>; ++ phy-connection-type = "rgmii-id"; ++ status = "okay"; ++}; ++ ++&can0{ ++ status = "disabled"; ++}; ++ ++&can1{ ++ status = "disabled"; ++}; ++ ++&can2{ ++ status = "disabled"; ++}; ++ ++&can3{ ++ status = "okay"; ++}; ++ ++&esdhc{ ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ max1239@35 { ++ compatible = "maxim,max1239"; ++ reg = <0x35>; ++ #io-channel-cells = <1>; ++ }; ++ ++ codec: sgtl5000@2a { ++ #sound-dai-cells=<0x0>; ++ compatible = "fsl,sgtl5000"; ++ reg = <0x2a>; ++ VDDA-supply = <®_3p3v>; ++ VDDIO-supply = <®_2p5v>; ++ clocks = <&sys_mclk 1>; ++ }; ++ ++ pca9555: pca9555@23 { ++ compatible = "nxp,pca9555"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x23>; ++ }; ++ ++ ina220@44 { ++ compatible = "ti,ina220"; ++ reg = <0x44>; ++ shunt-resistor = <1000>; ++ }; ++ ++ ina220@45 { ++ compatible = "ti,ina220"; ++ reg = <0x45>; ++ shunt-resistor = <1000>; ++ }; ++ ++ lm75b@48 { ++ compatible = "nxp,lm75a"; ++ reg = <0x48>; ++ }; ++ ++ adt7461a@4c { ++ compatible = "adt7461a"; ++ reg = <0x4c>; ++ }; ++ ++ hdmi: sii9022a@39 { ++ compatible = "fsl,sii902x"; ++ reg = <0x39>; ++ interrupts = ; ++ }; ++}; ++ ++&i2c1 { ++ status = "disabled"; ++}; ++ ++&ifc { ++ status = "disabled"; ++}; ++ ++&lpuart0 { ++ status = "okay"; ++}; ++ ++&mdio0 { ++ phy0: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ }; ++ phy2: ethernet-phy@2 { ++ reg = <0x2>; ++ }; ++ phy3: ethernet-phy@3 { ++ reg = <0x3>; ++ }; ++ tbi1: tbi-phy@1f { ++ reg = <0x1f>; ++ device_type = "tbi-phy"; ++ }; ++}; ++ ++&sai2 { ++ status = "okay"; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&dcu { ++ display = <&display>; ++ status = "okay"; ++ ++ display: display@0 { ++ bits-per-pixel = <24>; ++ ++ display-timings { ++ native-mode = <&timing0>; ++ ++ timing0: mode0 { ++ clock-frequency = <25000000>; ++ hactive = <640>; ++ vactive = <480>; ++ hback-porch = <80>; ++ hfront-porch = <80>; ++ vback-porch = <16>; ++ vfront-porch = <16>; ++ hsync-len = <12>; ++ vsync-len = <2>; ++ hsync-active = <1>; ++ vsync-active = <1>; ++ }; ++ }; ++ }; ++}; ++ ++&usb3 { ++ status = "disabled"; ++}; ++ ++&pcie1 { ++ status = "okay"; ++}; ++ ++&pcie2 { ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/ls1021a-iot.dts b/arch/arm/boot/dts/ls1021a-iot.dts +index ce8e26d7791f..fa65c467cfd0 100644 +--- a/arch/arm/boot/dts/ls1021a-iot.dts ++++ b/arch/arm/boot/dts/ls1021a-iot.dts +@@ -129,6 +129,26 @@ &esdhc{ + status = "okay"; + }; + ++&can0{ ++ status = "disabled"; ++}; ++ ++&can1{ ++ status = "disabled"; ++}; ++ ++&can2{ ++ status = "disabled"; ++}; ++ ++&can3{ ++ status = "okay"; ++}; ++ ++&esdhc{ ++ status = "okay"; ++}; ++ + &i2c0 { + status = "okay"; + +@@ -225,3 +245,30 @@ &uart0 { + &uart1 { + status = "okay"; + }; ++ ++&dcu { ++ display = <&display>; ++ status = "okay"; ++ ++ display: display@0 { ++ bits-per-pixel = <24>; ++ ++ display-timings { ++ native-mode = <&timing0>; ++ ++ timing0: mode0 { ++ clock-frequency = <25000000>; ++ hactive = <640>; ++ vactive = <480>; ++ hback-porch = <80>; ++ hfront-porch = <80>; ++ vback-porch = <16>; ++ vfront-porch = <16>; ++ hsync-len = <12>; ++ vsync-len = <2>; ++ hsync-active = <1>; ++ vsync-active = <1>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi +index db945475918d..541abf48b90d 100644 +--- a/arch/arm/boot/dts/ls1021a.dtsi ++++ b/arch/arm/boot/dts/ls1021a.dtsi +@@ -815,7 +815,7 @@ usb3: usb@3100000 { + snps,host-vbus-glitches; + }; + +- pcie@3400000 { ++ pcie1: pcie@3400000 { + compatible = "fsl,ls1021a-pcie"; + reg = <0x00 0x03400000 0x0 0x00010000>, /* controller registers */ + <0x40 0x00000000 0x0 0x00002000>; /* configuration space */ +@@ -841,7 +841,7 @@ pcie@3400000 { + status = "disabled"; + }; + +- pcie@3500000 { ++ pcie2: pcie@3500000 { + compatible = "fsl,ls1021a-pcie"; + reg = <0x00 0x03500000 0x0 0x00010000>, /* controller registers */ + <0x48 0x00000000 0x0 0x00002000>; /* configuration space */ +diff --git a/arch/arm/configs/imx6ullevk-plc.config b/arch/arm/configs/imx6ullevk-plc.config +new file mode 100644 +index 000000000000..7a309a93b547 +--- /dev/null ++++ b/arch/arm/configs/imx6ullevk-plc.config +@@ -0,0 +1,3333 @@ ++# ++# General setup ++# ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++# CONFIG_COMPILE_TEST is not set ++# CONFIG_WERROR is not set ++CONFIG_LOCALVERSION="" ++CONFIG_LOCALVERSION_AUTO=y ++CONFIG_BUILD_SALT="" ++CONFIG_HAVE_KERNEL_GZIP=y ++CONFIG_HAVE_KERNEL_LZMA=y ++CONFIG_HAVE_KERNEL_XZ=y ++CONFIG_HAVE_KERNEL_LZO=y ++CONFIG_HAVE_KERNEL_LZ4=y ++# CONFIG_KERNEL_GZIP is not set ++# CONFIG_KERNEL_LZMA is not set ++# CONFIG_KERNEL_XZ is not set ++CONFIG_KERNEL_LZO=y ++# CONFIG_KERNEL_LZ4 is not set ++CONFIG_DEFAULT_INIT="" ++CONFIG_DEFAULT_HOSTNAME="(none)" ++# CONFIG_SWAP is not set ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_POSIX_MQUEUE_SYSCTL=y ++# CONFIG_WATCH_QUEUE is not set ++CONFIG_CROSS_MEMORY_ATTACH=y ++# CONFIG_USELIB is not set ++# CONFIG_AUDIT is not set ++CONFIG_HAVE_ARCH_AUDITSYSCALL=y ++ ++# ++# IRQ subsystem ++# ++CONFIG_GENERIC_IRQ_PROBE=y ++CONFIG_GENERIC_IRQ_SHOW=y ++CONFIG_GENERIC_IRQ_SHOW_LEVEL=y ++CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y ++CONFIG_HARDIRQS_SW_RESEND=y ++CONFIG_GENERIC_IRQ_CHIP=y ++CONFIG_IRQ_DOMAIN=y ++CONFIG_IRQ_DOMAIN_HIERARCHY=y ++CONFIG_HANDLE_DOMAIN_IRQ=y ++CONFIG_IRQ_FORCED_THREADING=y ++CONFIG_SPARSE_IRQ=y ++# end of IRQ subsystem ++ ++CONFIG_GENERIC_IRQ_MULTI_HANDLER=y ++CONFIG_GENERIC_TIME_VSYSCALL=y ++CONFIG_GENERIC_CLOCKEVENTS=y ++CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y ++CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y ++ ++# ++# Timers subsystem ++# ++CONFIG_TICK_ONESHOT=y ++CONFIG_NO_HZ_COMMON=y ++# CONFIG_HZ_PERIODIC is not set ++CONFIG_NO_HZ_IDLE=y ++# CONFIG_NO_HZ is not set ++CONFIG_HIGH_RES_TIMERS=y ++# end of Timers subsystem ++ ++CONFIG_BPF=y ++CONFIG_HAVE_EBPF_JIT=y ++ ++# ++# BPF subsystem ++# ++# CONFIG_BPF_SYSCALL is not set ++# CONFIG_BPF_JIT is not set ++# end of BPF subsystem ++ ++CONFIG_HAVE_PREEMPT_LAZY=y ++CONFIG_PREEMPT_LAZY=y ++# CONFIG_PREEMPT_NONE is not set ++# CONFIG_PREEMPT_VOLUNTARY is not set ++# CONFIG_PREEMPT is not set ++CONFIG_PREEMPT_RT=y ++CONFIG_PREEMPT_COUNT=y ++CONFIG_PREEMPTION=y ++ ++# ++# CPU/Task time and stats accounting ++# ++CONFIG_TICK_CPU_ACCOUNTING=y ++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set ++# CONFIG_IRQ_TIME_ACCOUNTING is not set ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_TASKSTATS is not set ++# CONFIG_PSI is not set ++# end of CPU/Task time and stats accounting ++ ++# ++# RCU Subsystem ++# ++CONFIG_TREE_RCU=y ++CONFIG_PREEMPT_RCU=y ++# CONFIG_RCU_EXPERT is not set ++CONFIG_SRCU=y ++CONFIG_TREE_SRCU=y ++CONFIG_TASKS_RCU_GENERIC=y ++CONFIG_TASKS_RCU=y ++CONFIG_RCU_STALL_COMMON=y ++CONFIG_RCU_NEED_SEGCBLIST=y ++CONFIG_RCU_BOOST=y ++CONFIG_RCU_BOOST_DELAY=500 ++# end of RCU Subsystem ++ ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++# CONFIG_IKHEADERS is not set ++CONFIG_LOG_BUF_SHIFT=18 ++CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 ++CONFIG_GENERIC_SCHED_CLOCK=y ++ ++# ++# Scheduler features ++# ++# end of Scheduler features ++ ++# CONFIG_CGROUPS is not set ++CONFIG_NAMESPACES=y ++# CONFIG_UTS_NS is not set ++# CONFIG_IPC_NS is not set ++# CONFIG_USER_NS is not set ++# CONFIG_PID_NS is not set ++# CONFIG_NET_NS is not set ++# CONFIG_CHECKPOINT_RESTORE is not set ++# CONFIG_SCHED_AUTOGROUP is not set ++# CONFIG_SYSFS_DEPRECATED is not set ++CONFIG_RELAY=y ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_BOOT_CONFIG is not set ++CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y ++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set ++CONFIG_LD_ORPHAN_WARN=y ++CONFIG_SYSCTL=y ++CONFIG_HAVE_UID16=y ++CONFIG_EXPERT=y ++CONFIG_UID16=y ++CONFIG_MULTIUSER=y ++# CONFIG_SGETMASK_SYSCALL is not set ++CONFIG_SYSFS_SYSCALL=y ++CONFIG_FHANDLE=y ++CONFIG_POSIX_TIMERS=y ++CONFIG_PRINTK=y ++CONFIG_BUG=y ++CONFIG_ELF_CORE=y ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_FUTEX_PI=y ++CONFIG_HAVE_FUTEX_CMPXCHG=y ++CONFIG_EPOLL=y ++CONFIG_SIGNALFD=y ++CONFIG_TIMERFD=y ++CONFIG_EVENTFD=y ++CONFIG_SHMEM=y ++CONFIG_AIO=y ++CONFIG_IO_URING=y ++CONFIG_ADVISE_SYSCALLS=y ++CONFIG_MEMBARRIER=y ++CONFIG_KALLSYMS=y ++# CONFIG_KALLSYMS_ALL is not set ++CONFIG_KALLSYMS_BASE_RELATIVE=y ++# CONFIG_USERFAULTFD is not set ++CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y ++CONFIG_KCMP=y ++CONFIG_RSEQ=y ++# CONFIG_DEBUG_RSEQ is not set ++CONFIG_EMBEDDED=y ++CONFIG_HAVE_PERF_EVENTS=y ++CONFIG_PERF_USE_VMALLOC=y ++# CONFIG_PC104 is not set ++ ++# ++# Kernel Performance Events And Counters ++# ++# CONFIG_PERF_EVENTS is not set ++# end of Kernel Performance Events And Counters ++ ++# CONFIG_VM_EVENT_COUNTERS is not set ++# CONFIG_SLUB_DEBUG is not set ++# CONFIG_COMPAT_BRK is not set ++CONFIG_SLUB=y ++# CONFIG_SLAB_MERGE_DEFAULT is not set ++# CONFIG_SLAB_FREELIST_RANDOM is not set ++# CONFIG_SLAB_FREELIST_HARDENED is not set ++# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set ++# CONFIG_PROFILING is not set ++# end of General setup ++ ++CONFIG_ARM=y ++CONFIG_ARM_HAS_SG_CHAIN=y ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_HAVE_PROC_CPU=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_FIX_EARLYCON_MEM=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_ARCH_SUPPORTS_UPROBES=y ++CONFIG_ARM_PATCH_PHYS_VIRT=y ++CONFIG_GENERIC_BUG=y ++CONFIG_PGTABLE_LEVELS=2 ++ ++# ++# System Type ++# ++CONFIG_MMU=y ++CONFIG_ARCH_MMAP_RND_BITS_MIN=8 ++CONFIG_ARCH_MMAP_RND_BITS_MAX=15 ++CONFIG_ARCH_MULTIPLATFORM=y ++# CONFIG_ARCH_EP93XX is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_IOP32X is not set ++# CONFIG_ARCH_IXP4XX is not set ++# CONFIG_ARCH_DOVE is not set ++# CONFIG_ARCH_PXA is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_S3C24XX is not set ++# CONFIG_ARCH_OMAP1 is not set ++ ++# ++# Multiple platform selection ++# ++ ++# ++# CPU Core family selection ++# ++# CONFIG_ARCH_MULTI_V6 is not set ++CONFIG_ARCH_MULTI_V7=y ++CONFIG_ARCH_MULTI_V6_V7=y ++# end of Multiple platform selection ++ ++# CONFIG_ARCH_VIRT is not set ++# CONFIG_ARCH_ACTIONS is not set ++# CONFIG_ARCH_ALPINE is not set ++# CONFIG_ARCH_ARTPEC is not set ++# CONFIG_ARCH_ASPEED is not set ++# CONFIG_ARCH_AT91 is not set ++# CONFIG_ARCH_BCM is not set ++# CONFIG_ARCH_BERLIN is not set ++# CONFIG_ARCH_DIGICOLOR is not set ++# CONFIG_ARCH_EXYNOS is not set ++# CONFIG_ARCH_HIGHBANK is not set ++# CONFIG_ARCH_HISI is not set ++CONFIG_ARCH_MXC=y ++CONFIG_HAVE_IMX_ANATOP=y ++CONFIG_HAVE_IMX_GPC=y ++CONFIG_HAVE_IMX_GPCV2=y ++CONFIG_HAVE_IMX_MMDC=y ++CONFIG_HAVE_IMX_AMP=y ++CONFIG_HAVE_IMX_DDRC=y ++CONFIG_HAVE_IMX_BUSFREQ=y ++CONFIG_HAVE_IMX_MU=y ++CONFIG_HAVE_IMX_RPMSG=y ++CONFIG_HAVE_IMX_SRC=y ++ ++# ++# Cortex-A platforms ++# ++# CONFIG_SOC_IMX50 is not set ++# CONFIG_SOC_IMX51 is not set ++# CONFIG_SOC_IMX53 is not set ++CONFIG_SOC_IMX6=y ++CONFIG_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++CONFIG_SOC_IMX6SLL=y ++CONFIG_SOC_IMX6SX=y ++CONFIG_SOC_IMX6UL=y ++# CONFIG_SOC_LS1021A is not set ++# CONFIG_SOC_IMX6Q_BAREMETAL is not set ++ ++# ++# Cortex-A/Cortex-M asymmetric multiprocessing platforms ++# ++CONFIG_SOC_IMX7D_CA7=y ++CONFIG_SOC_IMX7D=y ++# CONFIG_SOC_IMX7ULP is not set ++# CONFIG_SOC_VF610 is not set ++# CONFIG_ARCH_KEYSTONE is not set ++# CONFIG_ARCH_MEDIATEK is not set ++# CONFIG_ARCH_MESON is not set ++# CONFIG_ARCH_MILBEAUT is not set ++# CONFIG_ARCH_MMP is not set ++# CONFIG_ARCH_MSTARV7 is not set ++# CONFIG_ARCH_MVEBU is not set ++# CONFIG_ARCH_NPCM is not set ++ ++# ++# TI OMAP/AM/DM/DRA Family ++# ++# CONFIG_ARCH_OMAP3 is not set ++# CONFIG_ARCH_OMAP4 is not set ++# CONFIG_SOC_OMAP5 is not set ++# CONFIG_SOC_AM33XX is not set ++# CONFIG_SOC_AM43XX is not set ++# CONFIG_SOC_DRA7XX is not set ++# end of TI OMAP/AM/DM/DRA Family ++ ++# CONFIG_ARCH_QCOM is not set ++# CONFIG_ARCH_RDA is not set ++# CONFIG_ARCH_REALTEK is not set ++# CONFIG_ARCH_REALVIEW is not set ++# CONFIG_ARCH_ROCKCHIP is not set ++# CONFIG_ARCH_S5PV210 is not set ++# CONFIG_ARCH_RENESAS is not set ++# CONFIG_ARCH_INTEL_SOCFPGA is not set ++# CONFIG_PLAT_SPEAR is not set ++# CONFIG_ARCH_STI is not set ++# CONFIG_ARCH_STM32 is not set ++# CONFIG_ARCH_SUNXI is not set ++# CONFIG_ARCH_TEGRA is not set ++# CONFIG_ARCH_UNIPHIER is not set ++# CONFIG_ARCH_U8500 is not set ++# CONFIG_ARCH_VEXPRESS is not set ++# CONFIG_ARCH_WM8850 is not set ++# CONFIG_ARCH_ZYNQ is not set ++ ++# ++# Processor Type ++# ++CONFIG_CPU_V7=y ++CONFIG_CPU_THUMB_CAPABLE=y ++CONFIG_CPU_32v6K=y ++CONFIG_CPU_32v7=y ++CONFIG_CPU_ABRT_EV7=y ++CONFIG_CPU_PABRT_V7=y ++CONFIG_CPU_CACHE_V7=y ++CONFIG_CPU_CACHE_VIPT=y ++CONFIG_CPU_COPY_V6=y ++CONFIG_CPU_TLB_V7=y ++CONFIG_CPU_HAS_ASID=y ++CONFIG_CPU_CP15=y ++CONFIG_CPU_CP15_MMU=y ++ ++# ++# Processor Features ++# ++# CONFIG_ARM_LPAE is not set ++CONFIG_ARM_THUMB=y ++# CONFIG_ARM_THUMBEE is not set ++CONFIG_ARM_VIRT_EXT=y ++# CONFIG_SWP_EMULATE is not set ++# CONFIG_CPU_BIG_ENDIAN is not set ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++# CONFIG_CPU_BPREDICT_DISABLE is not set ++CONFIG_CPU_SPECTRE=y ++CONFIG_HARDEN_BRANCH_PREDICTOR=y ++CONFIG_HARDEN_BRANCH_HISTORY=y ++CONFIG_KUSER_HELPERS=y ++CONFIG_VDSO=y ++CONFIG_OUTER_CACHE=y ++CONFIG_OUTER_CACHE_SYNC=y ++CONFIG_MIGHT_HAVE_CACHE_L2X0=y ++CONFIG_CACHE_L2X0=y ++# CONFIG_PL310_ERRATA_588369 is not set ++# CONFIG_PL310_ERRATA_727915 is not set ++# CONFIG_PL310_ERRATA_753970 is not set ++CONFIG_PL310_ERRATA_769419=y ++CONFIG_ARM_L1_CACHE_SHIFT_6=y ++CONFIG_ARM_L1_CACHE_SHIFT=6 ++CONFIG_ARM_DMA_MEM_BUFFERABLE=y ++CONFIG_ARM_HEAVY_MB=y ++CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y ++# CONFIG_DEBUG_ALIGN_RODATA is not set ++# CONFIG_ARM_ERRATA_430973 is not set ++# CONFIG_ARM_ERRATA_720789 is not set ++CONFIG_ARM_ERRATA_754322=y ++CONFIG_ARM_ERRATA_775420=y ++# CONFIG_ARM_ERRATA_773022 is not set ++# CONFIG_ARM_ERRATA_818325_852422 is not set ++# CONFIG_ARM_ERRATA_821420 is not set ++# CONFIG_ARM_ERRATA_825619 is not set ++# CONFIG_ARM_ERRATA_857271 is not set ++# CONFIG_ARM_ERRATA_852421 is not set ++# CONFIG_ARM_ERRATA_852423 is not set ++# CONFIG_ARM_ERRATA_857272 is not set ++# end of System Type ++ ++# ++# Bus support ++# ++CONFIG_ARM_ERRATA_814220=y ++# end of Bus support ++ ++# ++# Kernel Features ++# ++CONFIG_HAVE_SMP=y ++# CONFIG_SMP is not set ++CONFIG_HAVE_ARM_ARCH_TIMER=y ++CONFIG_HAVE_ARM_TWD=y ++# CONFIG_VMSPLIT_3G is not set ++# CONFIG_VMSPLIT_3G_OPT is not set ++CONFIG_VMSPLIT_2G=y ++# CONFIG_VMSPLIT_1G is not set ++CONFIG_PAGE_OFFSET=0x80000000 ++CONFIG_ARM_PSCI=y ++CONFIG_ARCH_NR_GPIO=0 ++CONFIG_HZ_FIXED=0 ++CONFIG_HZ_100=y ++# CONFIG_HZ_200 is not set ++# CONFIG_HZ_250 is not set ++# CONFIG_HZ_300 is not set ++# CONFIG_HZ_500 is not set ++# CONFIG_HZ_1000 is not set ++CONFIG_HZ=100 ++CONFIG_SCHED_HRTICK=y ++# CONFIG_THUMB2_KERNEL is not set ++CONFIG_ARM_PATCH_IDIV=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_ARCH_SELECT_MEMORY_MODEL=y ++CONFIG_ARCH_FLATMEM_ENABLE=y ++CONFIG_ARCH_SPARSEMEM_ENABLE=y ++# CONFIG_HIGHMEM is not set ++# CONFIG_CPU_SW_DOMAIN_PAN is not set ++CONFIG_ARCH_WANT_GENERAL_HUGETLB=y ++CONFIG_ARM_MODULE_PLTS=y ++CONFIG_FORCE_MAX_ZONEORDER=14 ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_UACCESS_WITH_MEMCPY is not set ++# CONFIG_PARAVIRT is not set ++# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set ++# CONFIG_XEN is not set ++# end of Kernel Features ++ ++# ++# Boot options ++# ++CONFIG_USE_OF=y ++CONFIG_ATAGS=y ++# CONFIG_DEPRECATED_PARAM_STRUCT is not set ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++# CONFIG_ARM_APPENDED_DTB is not set ++CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CMDLINE_FROM_BOOTLOADER=y ++# CONFIG_CMDLINE_EXTEND is not set ++# CONFIG_CMDLINE_FORCE is not set ++# CONFIG_KEXEC is not set ++# CONFIG_CRASH_DUMP is not set ++CONFIG_AUTO_ZRELADDR=y ++# CONFIG_EFI is not set ++# end of Boot options ++ ++# ++# CPU Power Management ++# ++ ++# ++# CPU Frequency scaling ++# ++CONFIG_CPU_FREQ=y ++# CONFIG_CPU_FREQ_STAT is not set ++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set ++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set ++# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set ++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set ++ ++# ++# CPU frequency scaling drivers ++# ++# CONFIG_CPUFREQ_DT is not set ++CONFIG_ARM_IMX6Q_CPUFREQ=y ++# end of CPU Frequency scaling ++ ++# ++# CPU Idle ++# ++# CONFIG_CPU_IDLE is not set ++# end of CPU Idle ++# end of CPU Power Management ++ ++# ++# Floating point emulation ++# ++ ++# ++# At least one emulation must be selected ++# ++CONFIG_VFP=y ++CONFIG_VFPv3=y ++CONFIG_NEON=y ++CONFIG_KERNEL_MODE_NEON=y ++# end of Floating point emulation ++ ++# ++# Power management options ++# ++# CONFIG_SUSPEND is not set ++# CONFIG_PM is not set ++# CONFIG_APM_EMULATION is not set ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_ARM_CPU_SUSPEND=y ++CONFIG_ARCH_HIBERNATION_POSSIBLE=y ++# end of Power management options ++ ++CONFIG_ARM_CRYPTO=y ++CONFIG_CRYPTO_SHA1_ARM=y ++# CONFIG_CRYPTO_SHA1_ARM_NEON is not set ++# CONFIG_CRYPTO_SHA1_ARM_CE is not set ++# CONFIG_CRYPTO_SHA2_ARM_CE is not set ++CONFIG_CRYPTO_SHA256_ARM=y ++CONFIG_CRYPTO_SHA512_ARM=y ++CONFIG_CRYPTO_BLAKE2S_ARM=y ++# CONFIG_CRYPTO_BLAKE2B_NEON is not set ++CONFIG_CRYPTO_AES_ARM=y ++# CONFIG_CRYPTO_AES_ARM_BS is not set ++# CONFIG_CRYPTO_AES_ARM_CE is not set ++# CONFIG_CRYPTO_GHASH_ARM_CE is not set ++# CONFIG_CRYPTO_CRCT10DIF_ARM_CE is not set ++# CONFIG_CRYPTO_CRC32_ARM_CE is not set ++CONFIG_CRYPTO_CHACHA20_NEON=y ++CONFIG_CRYPTO_POLY1305_ARM=y ++# CONFIG_CRYPTO_NHPOLY1305_NEON is not set ++# CONFIG_CRYPTO_CURVE25519_NEON is not set ++CONFIG_AS_VFP_VMRS_FPINST=y ++ ++# ++# General architecture-dependent options ++# ++CONFIG_SET_FS=y ++# CONFIG_KPROBES is not set ++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y ++CONFIG_ARCH_USE_BUILTIN_BSWAP=y ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++CONFIG_HAVE_OPTPROBES=y ++CONFIG_HAVE_NMI=y ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++CONFIG_HAVE_ARCH_TRACEHOOK=y ++CONFIG_HAVE_DMA_CONTIGUOUS=y ++CONFIG_GENERIC_SMP_IDLE_THREAD=y ++CONFIG_GENERIC_IDLE_POLL_SETUP=y ++CONFIG_ARCH_HAS_FORTIFY_SOURCE=y ++CONFIG_ARCH_HAS_KEEPINITRD=y ++CONFIG_ARCH_HAS_SET_MEMORY=y ++CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y ++CONFIG_ARCH_32BIT_OFF_T=y ++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y ++CONFIG_HAVE_RSEQ=y ++CONFIG_HAVE_PERF_REGS=y ++CONFIG_HAVE_PERF_USER_STACK_DUMP=y ++CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y ++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y ++CONFIG_HAVE_ARCH_SECCOMP=y ++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y ++CONFIG_SECCOMP=y ++CONFIG_SECCOMP_FILTER=y ++# CONFIG_SECCOMP_CACHE_DEBUG is not set ++CONFIG_HAVE_STACKPROTECTOR=y ++CONFIG_STACKPROTECTOR=y ++# CONFIG_STACKPROTECTOR_STRONG is not set ++CONFIG_LTO_NONE=y ++CONFIG_HAVE_CONTEXT_TRACKING=y ++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y ++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y ++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y ++CONFIG_MODULES_USE_ELF_REL=y ++CONFIG_ARCH_HAS_ELF_RANDOMIZE=y ++CONFIG_HAVE_ARCH_MMAP_RND_BITS=y ++CONFIG_HAVE_EXIT_THREAD=y ++CONFIG_ARCH_MMAP_RND_BITS=8 ++CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y ++CONFIG_CLONE_BACKWARDS=y ++CONFIG_OLD_SIGSUSPEND3=y ++CONFIG_OLD_SIGACTION=y ++CONFIG_COMPAT_32BIT_TIME=y ++CONFIG_ARCH_SUPPORTS_RT=y ++CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y ++CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y ++CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y ++CONFIG_STRICT_KERNEL_RWX=y ++CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y ++# CONFIG_STRICT_MODULE_RWX is not set ++CONFIG_ARCH_HAS_PHYS_TO_DMA=y ++CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y ++CONFIG_HAVE_ARCH_PFN_VALID=y ++ ++# ++# GCOV-based kernel profiling ++# ++CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y ++# end of GCOV-based kernel profiling ++ ++CONFIG_HAVE_GCC_PLUGINS=y ++# CONFIG_GCC_PLUGINS is not set ++# end of General architecture-dependent options ++ ++CONFIG_RT_MUTEXES=y ++CONFIG_BASE_SMALL=0 ++CONFIG_MODULES=y ++# CONFIG_MODULE_FORCE_LOAD is not set ++# CONFIG_MODULE_UNLOAD is not set ++# CONFIG_MODVERSIONS is not set ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++# CONFIG_MODULE_SIG is not set ++CONFIG_MODULE_COMPRESS_NONE=y ++# CONFIG_MODULE_COMPRESS_GZIP is not set ++# CONFIG_MODULE_COMPRESS_XZ is not set ++# CONFIG_MODULE_COMPRESS_ZSTD is not set ++# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set ++CONFIG_MODPROBE_PATH="/sbin/modprobe" ++# CONFIG_TRIM_UNUSED_KSYMS is not set ++CONFIG_BLOCK=y ++# CONFIG_BLK_DEV_BSGLIB is not set ++# CONFIG_BLK_DEV_INTEGRITY is not set ++# CONFIG_BLK_DEV_ZONED is not set ++# CONFIG_BLK_WBT is not set ++# CONFIG_BLK_SED_OPAL is not set ++# CONFIG_BLK_INLINE_ENCRYPTION is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++CONFIG_EFI_PARTITION=y ++# end of Partition Types ++ ++CONFIG_BLK_MQ_VIRTIO=y ++ ++# ++# IO Schedulers ++# ++CONFIG_MQ_IOSCHED_DEADLINE=y ++# CONFIG_MQ_IOSCHED_KYBER is not set ++# CONFIG_IOSCHED_BFQ is not set ++# end of IO Schedulers ++ ++CONFIG_ASN1=y ++CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y ++CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y ++ ++# ++# Executable file formats ++# ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_ELF_FDPIC is not set ++CONFIG_ELFCORE=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_BINFMT_SCRIPT=y ++CONFIG_ARCH_HAS_BINFMT_FLAT=y ++# CONFIG_BINFMT_FLAT is not set ++CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y ++# CONFIG_BINFMT_MISC is not set ++CONFIG_COREDUMP=y ++# end of Executable file formats ++ ++# ++# Memory Management options ++# ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++# CONFIG_SPARSEMEM_MANUAL is not set ++CONFIG_FLATMEM=y ++CONFIG_ARCH_KEEP_MEMBLOCK=y ++CONFIG_MEMORY_ISOLATION=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_COMPACTION is not set ++# CONFIG_PAGE_REPORTING is not set ++CONFIG_MIGRATION=y ++CONFIG_CONTIG_ALLOC=y ++# CONFIG_KSM is not set ++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 ++CONFIG_NEED_PER_CPU_KM=y ++# CONFIG_CLEANCACHE is not set ++CONFIG_CMA=y ++# CONFIG_CMA_DEBUG is not set ++# CONFIG_CMA_SYSFS is not set ++CONFIG_CMA_AREAS=7 ++# CONFIG_ZPOOL is not set ++# CONFIG_ZSMALLOC is not set ++CONFIG_GENERIC_EARLY_IOREMAP=y ++# CONFIG_IDLE_PAGE_TRACKING is not set ++# CONFIG_PERCPU_STATS is not set ++ ++# ++# GUP_TEST needs to have DEBUG_FS enabled ++# ++ ++# ++# Data Access Monitoring ++# ++# CONFIG_DAMON is not set ++# end of Data Access Monitoring ++# end of Memory Management options ++ ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_DIAG is not set ++CONFIG_UNIX=y ++CONFIG_UNIX_SCM=y ++CONFIG_AF_UNIX_OOB=y ++# CONFIG_UNIX_DIAG is not set ++CONFIG_TLS=y ++CONFIG_TLS_DEVICE=y ++# CONFIG_TLS_TOE is not set ++# CONFIG_XFRM_USER is not set ++# CONFIG_NET_KEY is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++# CONFIG_IP_PNP_BOOTP is not set ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE_DEMUX is not set ++# CONFIG_IP_MROUTE is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_NET_IPVTI is not set ++# CONFIG_NET_FOU is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++CONFIG_INET_DIAG=y ++CONFIG_INET_TCP_DIAG=y ++# CONFIG_INET_UDP_DIAG is not set ++# CONFIG_INET_RAW_DIAG is not set ++# CONFIG_INET_DIAG_DESTROY is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++# CONFIG_IPV6 is not set ++# CONFIG_MPTCP is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_BPFILTER is not set ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_RDS is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_L2TP is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_NET_DSA is not set ++CONFIG_VLAN_8021Q=y ++# CONFIG_VLAN_8021Q_GVRP is not set ++# CONFIG_VLAN_8021Q_MVRP is not set ++# CONFIG_DECNET is not set ++CONFIG_LLC=y ++CONFIG_LLC2=y ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_PHONET is not set ++# CONFIG_IEEE802154 is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++# CONFIG_BATMAN_ADV is not set ++# CONFIG_OPENVSWITCH is not set ++# CONFIG_VSOCKETS is not set ++# CONFIG_NETLINK_DIAG is not set ++# CONFIG_MPLS is not set ++# CONFIG_NET_NSH is not set ++# CONFIG_HSR is not set ++# CONFIG_NET_SWITCHDEV is not set ++# CONFIG_NET_L3_MASTER_DEV is not set ++# CONFIG_QRTR is not set ++# CONFIG_NET_NCSI is not set ++CONFIG_SOCK_RX_QUEUE_MAPPING=y ++CONFIG_BQL=y ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# end of Network testing ++# end of Networking options ++ ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++# CONFIG_AF_KCM is not set ++CONFIG_STREAM_PARSER=y ++# CONFIG_MCTP is not set ++# CONFIG_WIRELESS is not set ++# CONFIG_RFKILL is not set ++# CONFIG_NET_9P is not set ++# CONFIG_CAIF is not set ++# CONFIG_CEPH_LIB is not set ++# CONFIG_NFC is not set ++# CONFIG_PSAMPLE is not set ++# CONFIG_NET_IFE is not set ++# CONFIG_LWTUNNEL is not set ++CONFIG_SOCK_VALIDATE_XMIT=y ++CONFIG_NET_SELFTESTS=y ++CONFIG_NET_SOCK_MSG=y ++# CONFIG_FAILOVER is not set ++CONFIG_ETHTOOL_NETLINK=y ++ ++# ++# Device Drivers ++# ++CONFIG_HAVE_PCI=y ++# CONFIG_PCI is not set ++# CONFIG_PCCARD is not set ++ ++# ++# Generic Driver Options ++# ++# CONFIG_UEVENT_HELPER is not set ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_PREVENT_FIRMWARE_BUILD=y ++ ++# ++# Firmware loader ++# ++CONFIG_FW_LOADER=y ++CONFIG_FW_LOADER_PAGED_BUF=y ++CONFIG_EXTRA_FIRMWARE="" ++CONFIG_FW_LOADER_USER_HELPER=y ++CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y ++# CONFIG_FW_LOADER_COMPRESS is not set ++# end of Firmware loader ++ ++CONFIG_ALLOW_DEV_COREDUMP=y ++# CONFIG_DEBUG_DRIVER is not set ++# CONFIG_DEBUG_DEVRES is not set ++# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set ++# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set ++CONFIG_GENERIC_CPU_AUTOPROBE=y ++CONFIG_GENERIC_CPU_VULNERABILITIES=y ++CONFIG_SOC_BUS=y ++CONFIG_REGMAP=y ++CONFIG_REGMAP_I2C=y ++CONFIG_REGMAP_MMIO=y ++CONFIG_REGMAP_IRQ=y ++CONFIG_DMA_SHARED_BUFFER=y ++# CONFIG_DMA_FENCE_TRACE is not set ++# end of Generic Driver Options ++ ++# ++# Bus devices ++# ++# CONFIG_BRCMSTB_GISB_ARB is not set ++CONFIG_IMX_WEIM=y ++# CONFIG_VEXPRESS_CONFIG is not set ++# CONFIG_FSL_MC_BUS is not set ++# CONFIG_MHI_BUS is not set ++# end of Bus devices ++ ++# CONFIG_CONNECTOR is not set ++ ++# ++# Firmware Drivers ++# ++ ++# ++# ARM System Control and Management Interface Protocol ++# ++# CONFIG_ARM_SCMI_PROTOCOL is not set ++# end of ARM System Control and Management Interface Protocol ++ ++# CONFIG_ARM_SCPI_PROTOCOL is not set ++# CONFIG_FIRMWARE_MEMMAP is not set ++# CONFIG_FW_CFG_SYSFS is not set ++# CONFIG_TRUSTED_FOUNDATIONS is not set ++# CONFIG_GOOGLE_FIRMWARE is not set ++# CONFIG_IMX_DSP is not set ++# CONFIG_IMX_SCU is not set ++# CONFIG_IMX_SECO_MU is not set ++# CONFIG_IMX_EL_ENCLAVE is not set ++CONFIG_ARM_PSCI_FW=y ++CONFIG_HAVE_ARM_SMCCC=y ++CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y ++CONFIG_ARM_SMCCC_SOC_ID=y ++ ++# ++# Tegra firmware driver ++# ++# end of Tegra firmware driver ++# end of Firmware Drivers ++ ++# CONFIG_GNSS is not set ++# CONFIG_MTD is not set ++CONFIG_DTC=y ++CONFIG_OF=y ++# CONFIG_OF_UNITTEST is not set ++CONFIG_OF_FLATTREE=y ++CONFIG_OF_EARLY_FLATTREE=y ++CONFIG_OF_KOBJ=y ++CONFIG_OF_DYNAMIC=y ++CONFIG_OF_ADDRESS=y ++CONFIG_OF_IRQ=y ++CONFIG_OF_RESERVED_MEM=y ++CONFIG_OF_RESOLVE=y ++CONFIG_OF_OVERLAY=y ++CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_NULL_BLK is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_DRBD is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_VIRTIO_BLK is not set ++# CONFIG_BLK_DEV_RBD is not set ++ ++# ++# NVME Support ++# ++# CONFIG_NVME_FC is not set ++# CONFIG_NVME_TCP is not set ++# CONFIG_NVME_TARGET is not set ++# end of NVME Support ++ ++# ++# Misc devices ++# ++# CONFIG_AD525X_DPOT is not set ++# CONFIG_DUMMY_IRQ is not set ++# CONFIG_ICS932S401 is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_APDS9802ALS is not set ++# CONFIG_ISL29003 is not set ++# CONFIG_ISL29020 is not set ++# CONFIG_SENSORS_TSL2550 is not set ++# CONFIG_SENSORS_BH1770 is not set ++# CONFIG_SENSORS_APDS990X is not set ++# CONFIG_HMC6352 is not set ++# CONFIG_DS1682 is not set ++CONFIG_SRAM=y ++CONFIG_SRAM_EXEC=y ++# CONFIG_XILINX_SDFEC is not set ++# CONFIG_C2PORT is not set ++ ++# ++# EEPROM support ++# ++CONFIG_EEPROM_AT24=y ++# CONFIG_EEPROM_LEGACY is not set ++# CONFIG_EEPROM_MAX6875 is not set ++# CONFIG_EEPROM_93CX6 is not set ++# CONFIG_EEPROM_IDT_89HPESX is not set ++# CONFIG_EEPROM_EE1004 is not set ++# end of EEPROM support ++ ++# ++# Texas Instruments shared transport line discipline ++# ++# CONFIG_TI_ST is not set ++# end of Texas Instruments shared transport line discipline ++ ++# CONFIG_SENSORS_LIS3_I2C is not set ++# CONFIG_ALTERA_STAPL is not set ++# CONFIG_ECHO is not set ++# CONFIG_PVPANIC is not set ++# end of Misc devices ++ ++# ++# SCSI device support ++# ++CONFIG_SCSI_MOD=y ++# CONFIG_RAID_ATTRS is not set ++# CONFIG_SCSI is not set ++# end of SCSI device support ++ ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++# CONFIG_TARGET_CORE is not set ++CONFIG_NETDEVICES=y ++CONFIG_NET_CORE=y ++# CONFIG_BONDING is not set ++# CONFIG_DUMMY is not set ++# CONFIG_WIREGUARD is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_NET_TEAM is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_IPVLAN is not set ++# CONFIG_VXLAN is not set ++# CONFIG_GENEVE is not set ++# CONFIG_BAREUDP is not set ++# CONFIG_GTP is not set ++# CONFIG_MACSEC is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_TUN is not set ++# CONFIG_TUN_VNET_CROSS_LE is not set ++# CONFIG_VETH is not set ++# CONFIG_VIRTIO_NET is not set ++# CONFIG_NLMON is not set ++CONFIG_ETHERNET=y ++# CONFIG_NET_VENDOR_ALACRITECH is not set ++# CONFIG_ALTERA_TSE is not set ++# CONFIG_NET_VENDOR_AMAZON is not set ++# CONFIG_NET_VENDOR_AQUANTIA is not set ++# CONFIG_NET_VENDOR_ARC is not set ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CADENCE is not set ++# CONFIG_NET_VENDOR_CAVIUM is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++# CONFIG_NET_VENDOR_CORTINA is not set ++# CONFIG_DM9000 is not set ++# CONFIG_DNET is not set ++# CONFIG_NET_VENDOR_EZCHIP is not set ++# CONFIG_NET_VENDOR_FARADAY is not set ++CONFIG_NET_VENDOR_FREESCALE=y ++CONFIG_FEC=y ++CONFIG_FEC_ECAT=y ++# CONFIG_FEC_UIO is not set ++# CONFIG_AVB_SUPPORT is not set ++# CONFIG_FSL_PQ_MDIO is not set ++# CONFIG_FSL_XGMAC_MDIO is not set ++# CONFIG_GIANFAR is not set ++ ++# ++# Frame Manager support ++# ++# end of Frame Manager support ++ ++# CONFIG_FSL_ENETC_IERB is not set ++# CONFIG_NET_VENDOR_GOOGLE is not set ++# CONFIG_NET_VENDOR_HISILICON is not set ++# CONFIG_NET_VENDOR_HUAWEI is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_LITEX is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MELLANOX is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_MICROSEMI is not set ++# CONFIG_NET_VENDOR_MICROSOFT is not set ++# CONFIG_NET_VENDOR_NI is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_NETRONOME is not set ++# CONFIG_ETHOC is not set ++# CONFIG_NET_VENDOR_PENSANDO is not set ++# CONFIG_NET_VENDOR_QUALCOMM is not set ++# CONFIG_NET_VENDOR_RENESAS is not set ++# CONFIG_NET_VENDOR_ROCKER is not set ++# CONFIG_NET_VENDOR_SAMSUNG is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SOLARFLARE is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_SOCIONEXT is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++# CONFIG_NET_VENDOR_SYNOPSYS is not set ++# CONFIG_NET_VENDOR_VIA is not set ++# CONFIG_NET_VENDOR_WIZNET is not set ++# CONFIG_NET_VENDOR_XILINX is not set ++CONFIG_PHYLIB=y ++CONFIG_SWPHY=y ++CONFIG_FIXED_PHY=y ++ ++# ++# MII PHY device drivers ++# ++# CONFIG_AMD_PHY is not set ++# CONFIG_ADIN_PHY is not set ++# CONFIG_AQUANTIA_PHY is not set ++CONFIG_AX88796B_PHY=y ++# CONFIG_BROADCOM_PHY is not set ++# CONFIG_BCM54140_PHY is not set ++# CONFIG_BCM7XXX_PHY is not set ++# CONFIG_BCM84881_PHY is not set ++# CONFIG_BCM87XX_PHY is not set ++# CONFIG_CICADA_PHY is not set ++# CONFIG_CORTINA_PHY is not set ++# CONFIG_DAVICOM_PHY is not set ++# CONFIG_ICPLUS_PHY is not set ++# CONFIG_LXT_PHY is not set ++# CONFIG_INPHI_PHY is not set ++# CONFIG_INTEL_XWAY_PHY is not set ++# CONFIG_LSI_ET1011C_PHY is not set ++# CONFIG_MARVELL_PHY is not set ++# CONFIG_MARVELL_10G_PHY is not set ++# CONFIG_MARVELL_88X2222_PHY is not set ++# CONFIG_MAXLINEAR_GPHY is not set ++# CONFIG_MEDIATEK_GE_PHY is not set ++CONFIG_MICREL_PHY=y ++CONFIG_MICROCHIP_PHY=y ++# CONFIG_MICROCHIP_T1_PHY is not set ++# CONFIG_MICROSEMI_PHY is not set ++# CONFIG_MOTORCOMM_PHY is not set ++# CONFIG_NATIONAL_PHY is not set ++# CONFIG_NXP_C45_TJA11XX_PHY is not set ++# CONFIG_NXP_TJA11XX_PHY is not set ++CONFIG_AT803X_PHY=y ++# CONFIG_QSEMI_PHY is not set ++# CONFIG_REALTEK_PHY is not set ++# CONFIG_RENESAS_PHY is not set ++# CONFIG_ROCKCHIP_PHY is not set ++CONFIG_SMSC_PHY=y ++# CONFIG_STE10XP is not set ++# CONFIG_TERANETICS_PHY is not set ++# CONFIG_DP83822_PHY is not set ++# CONFIG_DP83TC811_PHY is not set ++# CONFIG_DP83848_PHY is not set ++# CONFIG_DP83867_PHY is not set ++# CONFIG_DP83869_PHY is not set ++# CONFIG_VITESSE_PHY is not set ++# CONFIG_XILINX_GMII2RGMII is not set ++CONFIG_MDIO_DEVICE=y ++CONFIG_MDIO_BUS=y ++CONFIG_FWNODE_MDIO=y ++CONFIG_OF_MDIO=y ++CONFIG_MDIO_DEVRES=y ++# CONFIG_MDIO_BITBANG is not set ++# CONFIG_MDIO_BCM_UNIMAC is not set ++# CONFIG_MDIO_HISI_FEMAC is not set ++# CONFIG_MDIO_MSCC_MIIM is not set ++# CONFIG_MDIO_IPQ4019 is not set ++# CONFIG_MDIO_IPQ8064 is not set ++ ++# ++# MDIO Multiplexers ++# ++# CONFIG_MDIO_BUS_MUX_GPIO is not set ++# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set ++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set ++ ++# ++# PCS device drivers ++# ++# CONFIG_PCS_XPCS is not set ++# end of PCS device drivers ++ ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++ ++# ++# Host-side USB support is needed for USB Network Adapter support ++# ++# CONFIG_WLAN is not set ++# CONFIG_WAN is not set ++ ++# ++# Wireless WAN ++# ++# CONFIG_WWAN is not set ++# end of Wireless WAN ++ ++# CONFIG_NET_FAILOVER is not set ++# CONFIG_IMX_SHMEM_NET is not set ++# CONFIG_ISDN is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_SPARSEKMAP is not set ++# CONFIG_INPUT_MATRIXKMAP is not set ++ ++# ++# Userland interfaces ++# ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++# CONFIG_INPUT_EVBUG is not set ++ ++# ++# Input Device Drivers ++# ++# CONFIG_INPUT_KEYBOARD is not set ++CONFIG_KEYBOARD_SNVS_PWRKEY=y ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++# CONFIG_INPUT_TOUCHSCREEN is not set ++# CONFIG_TOUCHSCREEN_FTS is not set ++# CONFIG_INPUT_MISC is not set ++# CONFIG_RMI4_CORE is not set ++ ++# ++# Hardware I/O ports ++# ++# CONFIG_SERIO is not set ++# CONFIG_GAMEPORT is not set ++# end of Hardware I/O ports ++# end of Input device support ++ ++# ++# Character devices ++# ++CONFIG_TTY=y ++CONFIG_VT=y ++CONFIG_CONSOLE_TRANSLATIONS=y ++CONFIG_VT_CONSOLE=y ++CONFIG_HW_CONSOLE=y ++CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_UNIX98_PTYS=y ++# CONFIG_LEGACY_PTYS is not set ++CONFIG_LDISC_AUTOLOAD=y ++ ++# ++# Serial drivers ++# ++CONFIG_SERIAL_EARLYCON=y ++# CONFIG_SERIAL_8250 is not set ++ ++# ++# Non-8250 serial port support ++# ++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set ++CONFIG_SERIAL_IMX=y ++CONFIG_SERIAL_IMX_CONSOLE=y ++CONFIG_SERIAL_IMX_EARLYCON=y ++# CONFIG_SERIAL_UARTLITE is not set ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++# CONFIG_SERIAL_SIFIVE is not set ++# CONFIG_SERIAL_SCCNXP is not set ++# CONFIG_SERIAL_SC16IS7XX is not set ++# CONFIG_SERIAL_BCM63XX is not set ++# CONFIG_SERIAL_ALTERA_JTAGUART is not set ++# CONFIG_SERIAL_ALTERA_UART is not set ++# CONFIG_SERIAL_XILINX_PS_UART is not set ++# CONFIG_SERIAL_ARC is not set ++CONFIG_SERIAL_FSL_LPUART=y ++CONFIG_SERIAL_FSL_LPUART_CONSOLE=y ++# CONFIG_SERIAL_FSL_LINFLEXUART is not set ++# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set ++# CONFIG_SERIAL_ST_ASC is not set ++# CONFIG_SERIAL_SPRD is not set ++# end of Serial drivers ++ ++CONFIG_SERIAL_MCTRL_GPIO=y ++# CONFIG_SERIAL_NONSTANDARD is not set ++# CONFIG_N_GSM is not set ++# CONFIG_NULL_TTY is not set ++# CONFIG_HVC_DCC is not set ++# CONFIG_RPMSG_TTY is not set ++CONFIG_SERIAL_DEV_BUS=y ++CONFIG_SERIAL_DEV_CTRL_TTYPORT=y ++# CONFIG_TTY_PRINTK is not set ++# CONFIG_VIRTIO_CONSOLE is not set ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_IPMB_DEVICE_INTERFACE is not set ++CONFIG_HW_RANDOM=y ++# CONFIG_HW_RANDOM_TIMERIOMEM is not set ++# CONFIG_HW_RANDOM_BA431 is not set ++# CONFIG_HW_RANDOM_VIRTIO is not set ++CONFIG_HW_RANDOM_IMX_RNGC=y ++CONFIG_HW_RANDOM_OPTEE=y ++# CONFIG_HW_RANDOM_CCTRNG is not set ++# CONFIG_HW_RANDOM_XIPHERA is not set ++CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=y ++# CONFIG_DEVMEM is not set ++# CONFIG_TCG_TPM is not set ++# CONFIG_XILLYBUS is not set ++CONFIG_IMX_SEMA4=y ++CONFIG_RANDOM_TRUST_BOOTLOADER=y ++# end of Character devices ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++CONFIG_I2C_BOARDINFO=y ++# CONFIG_I2C_COMPAT is not set ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_MUX=y ++ ++# ++# Multiplexer I2C Chip support ++# ++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set ++CONFIG_I2C_MUX_GPIO=y ++# CONFIG_I2C_MUX_GPMUX is not set ++# CONFIG_I2C_MUX_LTC4306 is not set ++# CONFIG_I2C_MUX_PCA9541 is not set ++# CONFIG_I2C_MUX_PCA954x is not set ++# CONFIG_I2C_MUX_PINCTRL is not set ++# CONFIG_I2C_MUX_REG is not set ++# CONFIG_I2C_DEMUX_PINCTRL is not set ++# CONFIG_I2C_MUX_MLXCPLD is not set ++# end of Multiplexer I2C Chip support ++ ++# CONFIG_I2C_HELPER_AUTO is not set ++# CONFIG_I2C_SMBUS is not set ++ ++# ++# I2C Algorithms ++# ++CONFIG_I2C_ALGOBIT=y ++CONFIG_I2C_ALGOPCF=y ++CONFIG_I2C_ALGOPCA=y ++# end of I2C Algorithms ++ ++# ++# I2C Hardware Bus support ++# ++ ++# ++# I2C system bus drivers (mostly embedded / system-on-chip) ++# ++# CONFIG_I2C_CBUS_GPIO is not set ++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set ++# CONFIG_I2C_EMEV2 is not set ++CONFIG_I2C_GPIO=y ++# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set ++CONFIG_I2C_IMX=y ++CONFIG_I2C_IMX_LPI2C=y ++CONFIG_I2C_IMX_FLEXIO=y ++# CONFIG_I2C_OCORES is not set ++# CONFIG_I2C_PCA_PLATFORM is not set ++# CONFIG_I2C_RK3X is not set ++# CONFIG_I2C_RPBUS is not set ++# CONFIG_I2C_SIMTEC is not set ++# CONFIG_I2C_XILINX is not set ++ ++# ++# External I2C/SMBus adapter drivers ++# ++# CONFIG_I2C_TAOS_EVM is not set ++ ++# ++# Other I2C/SMBus bus drivers ++# ++# CONFIG_I2C_VIRTIO is not set ++# end of I2C Hardware Bus support ++ ++# CONFIG_I2C_STUB is not set ++CONFIG_I2C_SLAVE=y ++# CONFIG_I2C_SLAVE_EEPROM is not set ++# CONFIG_I2C_SLAVE_TESTUNIT is not set ++# CONFIG_I2C_DEBUG_CORE is not set ++# CONFIG_I2C_DEBUG_ALGO is not set ++# CONFIG_I2C_DEBUG_BUS is not set ++# end of I2C support ++ ++# CONFIG_I3C is not set ++# CONFIG_SPI is not set ++# CONFIG_SPMI is not set ++# CONFIG_HSI is not set ++CONFIG_PPS=y ++# CONFIG_PPS_DEBUG is not set ++ ++# ++# PPS clients support ++# ++# CONFIG_PPS_CLIENT_KTIMER is not set ++# CONFIG_PPS_CLIENT_LDISC is not set ++# CONFIG_PPS_CLIENT_GPIO is not set ++ ++# ++# PPS generators support ++# ++ ++# ++# PTP clock support ++# ++# CONFIG_PTP_1588_CLOCK is not set ++CONFIG_PTP_1588_CLOCK_OPTIONAL=y ++ ++# ++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. ++# ++# end of PTP clock support ++ ++CONFIG_PINCTRL=y ++CONFIG_GENERIC_PINCTRL_GROUPS=y ++CONFIG_PINMUX=y ++CONFIG_GENERIC_PINMUX_FUNCTIONS=y ++CONFIG_PINCONF=y ++CONFIG_GENERIC_PINCONF=y ++# CONFIG_DEBUG_PINCTRL is not set ++# CONFIG_PINCTRL_DA9062 is not set ++# CONFIG_PINCTRL_MCP23S08 is not set ++# CONFIG_PINCTRL_SINGLE is not set ++# CONFIG_PINCTRL_SX150X is not set ++# CONFIG_PINCTRL_STMFX is not set ++# CONFIG_PINCTRL_OCELOT is not set ++# CONFIG_PINCTRL_MICROCHIP_SGPIO is not set ++CONFIG_PINCTRL_IMX=y ++CONFIG_PINCTRL_IMX6Q=y ++CONFIG_PINCTRL_IMX6SL=y ++CONFIG_PINCTRL_IMX6SLL=y ++CONFIG_PINCTRL_IMX6SX=y ++CONFIG_PINCTRL_IMX6UL=y ++CONFIG_PINCTRL_IMX7D=y ++# CONFIG_PINCTRL_IMX8MM is not set ++# CONFIG_PINCTRL_IMX8MN is not set ++# CONFIG_PINCTRL_IMX8MP is not set ++# CONFIG_PINCTRL_IMX8MQ is not set ++# CONFIG_PINCTRL_IMX8ULP is not set ++# CONFIG_PINCTRL_IMX93 is not set ++# CONFIG_PINCTRL_S32V_CORE is not set ++ ++# ++# Renesas pinctrl drivers ++# ++# end of Renesas pinctrl drivers ++ ++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y ++CONFIG_GPIOLIB=y ++CONFIG_GPIOLIB_FASTPATH_LIMIT=512 ++CONFIG_OF_GPIO=y ++CONFIG_GPIOLIB_IRQCHIP=y ++# CONFIG_DEBUG_GPIO is not set ++# CONFIG_GPIO_SYSFS is not set ++CONFIG_GPIO_CDEV=y ++CONFIG_GPIO_CDEV_V1=y ++CONFIG_GPIO_GENERIC=y ++ ++# ++# Memory mapped GPIO drivers ++# ++# CONFIG_GPIO_74XX_MMIO is not set ++# CONFIG_GPIO_ALTERA is not set ++# CONFIG_GPIO_CADENCE is not set ++# CONFIG_GPIO_DWAPB is not set ++# CONFIG_GPIO_FTGPIO010 is not set ++# CONFIG_GPIO_GENERIC_PLATFORM is not set ++# CONFIG_GPIO_GRGPIO is not set ++# CONFIG_GPIO_HLWD is not set ++# CONFIG_GPIO_LOGICVC is not set ++# CONFIG_GPIO_MB86S7X is not set ++# CONFIG_GPIO_MPC8XXX is not set ++CONFIG_GPIO_MXC=y ++# CONFIG_GPIO_SAMA5D2_PIOBU is not set ++# CONFIG_GPIO_SIFIVE is not set ++# CONFIG_GPIO_SYSCON is not set ++CONFIG_GPIO_VF610=y ++CONFIG_GPIO_IMX_RPMSG=y ++# CONFIG_GPIO_XILINX is not set ++# CONFIG_GPIO_ZEVIO is not set ++# CONFIG_GPIO_AMD_FCH is not set ++# end of Memory mapped GPIO drivers ++ ++# ++# I2C GPIO expanders ++# ++# CONFIG_GPIO_ADP5588 is not set ++# CONFIG_GPIO_ADNP is not set ++# CONFIG_GPIO_GW_PLD is not set ++# CONFIG_GPIO_MAX7300 is not set ++CONFIG_GPIO_MAX732X=y ++# CONFIG_GPIO_MAX732X_IRQ is not set ++CONFIG_GPIO_PCA953X=y ++# CONFIG_GPIO_PCA953X_IRQ is not set ++# CONFIG_GPIO_PCA9570 is not set ++CONFIG_GPIO_PCF857X=y ++# CONFIG_GPIO_TPIC2810 is not set ++# CONFIG_GPIO_TS4900 is not set ++# end of I2C GPIO expanders ++ ++# ++# MFD GPIO expanders ++# ++# CONFIG_GPIO_DA9052 is not set ++# CONFIG_HTC_EGPIO is not set ++# CONFIG_GPIO_WM8994 is not set ++# end of MFD GPIO expanders ++ ++# ++# Virtual GPIO drivers ++# ++# CONFIG_GPIO_AGGREGATOR is not set ++# CONFIG_GPIO_MOCKUP is not set ++# CONFIG_GPIO_VIRTIO is not set ++# end of Virtual GPIO drivers ++ ++# CONFIG_W1 is not set ++CONFIG_POWER_RESET=y ++# CONFIG_POWER_RESET_BRCMKONA is not set ++# CONFIG_POWER_RESET_BRCMSTB is not set ++# CONFIG_POWER_RESET_GPIO is not set ++# CONFIG_POWER_RESET_GPIO_RESTART is not set ++# CONFIG_POWER_RESET_LTC2952 is not set ++# CONFIG_POWER_RESET_REGULATOR is not set ++# CONFIG_POWER_RESET_RESTART is not set ++# CONFIG_POWER_RESET_VERSATILE is not set ++CONFIG_POWER_RESET_SYSCON=y ++CONFIG_POWER_RESET_SYSCON_POWEROFF=y ++# CONFIG_SYSCON_REBOOT_MODE is not set ++# CONFIG_NVMEM_REBOOT_MODE is not set ++CONFIG_POWER_SUPPLY=y ++# CONFIG_POWER_SUPPLY_DEBUG is not set ++# CONFIG_POWER_SUPPLY_HWMON is not set ++# CONFIG_PDA_POWER is not set ++# CONFIG_TEST_POWER is not set ++# CONFIG_CHARGER_ADP5061 is not set ++# CONFIG_BATTERY_CW2015 is not set ++# CONFIG_BATTERY_DS2780 is not set ++# CONFIG_BATTERY_DS2781 is not set ++# CONFIG_BATTERY_DS2782 is not set ++# CONFIG_BATTERY_SBS is not set ++# CONFIG_CHARGER_SBS is not set ++# CONFIG_MANAGER_SBS is not set ++# CONFIG_BATTERY_BQ27XXX is not set ++# CONFIG_BATTERY_DA9052 is not set ++# CONFIG_BATTERY_MAX17040 is not set ++# CONFIG_BATTERY_MAX17042 is not set ++# CONFIG_CHARGER_MAX8903 is not set ++# CONFIG_CHARGER_LP8727 is not set ++# CONFIG_CHARGER_GPIO is not set ++# CONFIG_CHARGER_MANAGER is not set ++# CONFIG_CHARGER_LT3651 is not set ++# CONFIG_CHARGER_LTC4162L is not set ++# CONFIG_CHARGER_DETECTOR_MAX14656 is not set ++# CONFIG_CHARGER_BQ2415X is not set ++# CONFIG_CHARGER_BQ24190 is not set ++# CONFIG_CHARGER_BQ24257 is not set ++# CONFIG_CHARGER_BQ24735 is not set ++# CONFIG_CHARGER_BQ2515X is not set ++# CONFIG_CHARGER_BQ25890 is not set ++# CONFIG_CHARGER_BQ25980 is not set ++# CONFIG_CHARGER_BQ256XX is not set ++# CONFIG_CHARGER_SMB347 is not set ++# CONFIG_BATTERY_GAUGE_LTC2941 is not set ++# CONFIG_BATTERY_GOLDFISH is not set ++# CONFIG_BATTERY_RT5033 is not set ++# CONFIG_CHARGER_RT9455 is not set ++# CONFIG_CHARGER_UCS1002 is not set ++# CONFIG_CHARGER_BD99954 is not set ++CONFIG_HWMON=y ++# CONFIG_HWMON_DEBUG_CHIP is not set ++ ++# ++# Native drivers ++# ++# CONFIG_SENSORS_AD7414 is not set ++# CONFIG_SENSORS_AD7418 is not set ++# CONFIG_SENSORS_ADM1021 is not set ++# CONFIG_SENSORS_ADM1025 is not set ++# CONFIG_SENSORS_ADM1026 is not set ++# CONFIG_SENSORS_ADM1029 is not set ++# CONFIG_SENSORS_ADM1031 is not set ++# CONFIG_SENSORS_ADM1177 is not set ++# CONFIG_SENSORS_ADM9240 is not set ++# CONFIG_SENSORS_ADT7410 is not set ++# CONFIG_SENSORS_ADT7411 is not set ++# CONFIG_SENSORS_ADT7462 is not set ++# CONFIG_SENSORS_ADT7470 is not set ++# CONFIG_SENSORS_ADT7475 is not set ++# CONFIG_SENSORS_AHT10 is not set ++# CONFIG_SENSORS_AS370 is not set ++# CONFIG_SENSORS_ASC7621 is not set ++# CONFIG_SENSORS_AXI_FAN_CONTROL is not set ++# CONFIG_SENSORS_ASPEED is not set ++# CONFIG_SENSORS_ATXP1 is not set ++# CONFIG_SENSORS_CORSAIR_CPRO is not set ++# CONFIG_SENSORS_CORSAIR_PSU is not set ++# CONFIG_SENSORS_DS620 is not set ++# CONFIG_SENSORS_DS1621 is not set ++# CONFIG_SENSORS_DA9052_ADC is not set ++# CONFIG_SENSORS_F71805F is not set ++# CONFIG_SENSORS_F71882FG is not set ++# CONFIG_SENSORS_F75375S is not set ++CONFIG_SENSORS_MC13783_ADC=y ++# CONFIG_SENSORS_FTSTEUTATES is not set ++# CONFIG_SENSORS_GL518SM is not set ++# CONFIG_SENSORS_GL520SM is not set ++# CONFIG_SENSORS_G760A is not set ++# CONFIG_SENSORS_G762 is not set ++CONFIG_SENSORS_GPIO_FAN=y ++# CONFIG_SENSORS_HIH6130 is not set ++# CONFIG_SENSORS_IT87 is not set ++# CONFIG_SENSORS_JC42 is not set ++# CONFIG_SENSORS_POWR1220 is not set ++# CONFIG_SENSORS_LINEAGE is not set ++# CONFIG_SENSORS_LTC2945 is not set ++# CONFIG_SENSORS_LTC2947_I2C is not set ++# CONFIG_SENSORS_LTC2990 is not set ++# CONFIG_SENSORS_LTC2992 is not set ++# CONFIG_SENSORS_LTC4151 is not set ++# CONFIG_SENSORS_LTC4215 is not set ++# CONFIG_SENSORS_LTC4222 is not set ++# CONFIG_SENSORS_LTC4245 is not set ++# CONFIG_SENSORS_LTC4260 is not set ++# CONFIG_SENSORS_LTC4261 is not set ++# CONFIG_SENSORS_MAX127 is not set ++# CONFIG_SENSORS_MAX16065 is not set ++# CONFIG_SENSORS_MAX1619 is not set ++# CONFIG_SENSORS_MAX1668 is not set ++CONFIG_SENSORS_MAX17135=y ++# CONFIG_SENSORS_MAX197 is not set ++# CONFIG_SENSORS_MAX31730 is not set ++# CONFIG_SENSORS_MAX6621 is not set ++# CONFIG_SENSORS_MAX6639 is not set ++# CONFIG_SENSORS_MAX6642 is not set ++# CONFIG_SENSORS_MAX6650 is not set ++# CONFIG_SENSORS_MAX6697 is not set ++# CONFIG_SENSORS_MAX31790 is not set ++# CONFIG_SENSORS_MCP3021 is not set ++# CONFIG_SENSORS_TC654 is not set ++# CONFIG_SENSORS_TPS23861 is not set ++# CONFIG_SENSORS_MR75203 is not set ++# CONFIG_SENSORS_LM63 is not set ++# CONFIG_SENSORS_LM73 is not set ++# CONFIG_SENSORS_LM75 is not set ++# CONFIG_SENSORS_LM77 is not set ++# CONFIG_SENSORS_LM78 is not set ++# CONFIG_SENSORS_LM80 is not set ++# CONFIG_SENSORS_LM83 is not set ++# CONFIG_SENSORS_LM85 is not set ++# CONFIG_SENSORS_LM87 is not set ++# CONFIG_SENSORS_LM90 is not set ++# CONFIG_SENSORS_LM92 is not set ++# CONFIG_SENSORS_LM93 is not set ++# CONFIG_SENSORS_LM95234 is not set ++# CONFIG_SENSORS_LM95241 is not set ++# CONFIG_SENSORS_LM95245 is not set ++# CONFIG_SENSORS_PC87360 is not set ++# CONFIG_SENSORS_PC87427 is not set ++# CONFIG_SENSORS_NTC_THERMISTOR is not set ++# CONFIG_SENSORS_NCT6683 is not set ++# CONFIG_SENSORS_NCT6775 is not set ++# CONFIG_SENSORS_NCT7802 is not set ++# CONFIG_SENSORS_NCT7904 is not set ++# CONFIG_SENSORS_NPCM7XX is not set ++# CONFIG_SENSORS_OCC_P8_I2C is not set ++# CONFIG_SENSORS_PCF8591 is not set ++# CONFIG_PMBUS is not set ++# CONFIG_SENSORS_SBTSI is not set ++# CONFIG_SENSORS_SBRMI is not set ++# CONFIG_SENSORS_SHT15 is not set ++# CONFIG_SENSORS_SHT21 is not set ++# CONFIG_SENSORS_SHT3x is not set ++# CONFIG_SENSORS_SHT4x is not set ++# CONFIG_SENSORS_SHTC1 is not set ++# CONFIG_SENSORS_DME1737 is not set ++# CONFIG_SENSORS_EMC1403 is not set ++# CONFIG_SENSORS_EMC2103 is not set ++# CONFIG_SENSORS_EMC6W201 is not set ++# CONFIG_SENSORS_SMSC47M1 is not set ++# CONFIG_SENSORS_SMSC47M192 is not set ++# CONFIG_SENSORS_SMSC47B397 is not set ++# CONFIG_SENSORS_SCH5627 is not set ++# CONFIG_SENSORS_SCH5636 is not set ++# CONFIG_SENSORS_STTS751 is not set ++# CONFIG_SENSORS_SMM665 is not set ++# CONFIG_SENSORS_ADC128D818 is not set ++# CONFIG_SENSORS_ADS7828 is not set ++# CONFIG_SENSORS_AMC6821 is not set ++# CONFIG_SENSORS_INA209 is not set ++# CONFIG_SENSORS_INA2XX is not set ++# CONFIG_SENSORS_INA3221 is not set ++# CONFIG_SENSORS_TC74 is not set ++# CONFIG_SENSORS_THMC50 is not set ++# CONFIG_SENSORS_TMP102 is not set ++# CONFIG_SENSORS_TMP103 is not set ++# CONFIG_SENSORS_TMP108 is not set ++# CONFIG_SENSORS_TMP401 is not set ++# CONFIG_SENSORS_TMP421 is not set ++# CONFIG_SENSORS_TMP513 is not set ++# CONFIG_SENSORS_VT1211 is not set ++# CONFIG_SENSORS_W83773G is not set ++# CONFIG_SENSORS_W83781D is not set ++# CONFIG_SENSORS_W83791D is not set ++# CONFIG_SENSORS_W83792D is not set ++# CONFIG_SENSORS_W83793 is not set ++# CONFIG_SENSORS_W83795 is not set ++# CONFIG_SENSORS_W83L785TS is not set ++# CONFIG_SENSORS_W83L786NG is not set ++# CONFIG_SENSORS_W83627HF is not set ++# CONFIG_SENSORS_W83627EHF is not set ++CONFIG_THERMAL=y ++# CONFIG_THERMAL_NETLINK is not set ++CONFIG_THERMAL_STATISTICS=y ++CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 ++CONFIG_THERMAL_HWMON=y ++CONFIG_THERMAL_OF=y ++CONFIG_THERMAL_WRITABLE_TRIPS=y ++CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y ++# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set ++# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set ++# CONFIG_THERMAL_GOV_FAIR_SHARE is not set ++CONFIG_THERMAL_GOV_STEP_WISE=y ++# CONFIG_THERMAL_GOV_BANG_BANG is not set ++# CONFIG_THERMAL_GOV_USER_SPACE is not set ++CONFIG_CPU_THERMAL=y ++CONFIG_CPU_FREQ_THERMAL=y ++# CONFIG_THERMAL_EMULATION is not set ++# CONFIG_THERMAL_MMIO is not set ++CONFIG_IMX_THERMAL=y ++# CONFIG_IMX8MM_THERMAL is not set ++CONFIG_DEVICE_THERMAL=y ++# CONFIG_DA9062_THERMAL is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y ++CONFIG_WATCHDOG_OPEN_TIMEOUT=0 ++# CONFIG_WATCHDOG_SYSFS is not set ++# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set ++ ++# ++# Watchdog Pretimeout Governors ++# ++# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set ++ ++# ++# Watchdog Device Drivers ++# ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_DA9052_WATCHDOG is not set ++CONFIG_DA9063_WATCHDOG=y ++CONFIG_DA9062_WATCHDOG=y ++# CONFIG_GPIO_WATCHDOG is not set ++# CONFIG_XILINX_WATCHDOG is not set ++# CONFIG_ZIIRAVE_WATCHDOG is not set ++# CONFIG_CADENCE_WATCHDOG is not set ++# CONFIG_FTWDT010_WATCHDOG is not set ++# CONFIG_DW_WATCHDOG is not set ++CONFIG_RN5T618_WATCHDOG=y ++# CONFIG_MAX63XX_WATCHDOG is not set ++CONFIG_IMX2_WDT=y ++CONFIG_IMX7ULP_WDT=y ++# CONFIG_ARM_SMC_WATCHDOG is not set ++# CONFIG_MEN_A21_WDT is not set ++CONFIG_SSB_POSSIBLE=y ++# CONFIG_SSB is not set ++CONFIG_BCMA_POSSIBLE=y ++# CONFIG_BCMA is not set ++ ++# ++# Multifunction device drivers ++# ++CONFIG_MFD_CORE=y ++# CONFIG_MFD_ADP5585 is not set ++# CONFIG_MFD_ACT8945A is not set ++# CONFIG_MFD_AS3711 is not set ++# CONFIG_MFD_AS3722 is not set ++# CONFIG_PMIC_ADP5520 is not set ++# CONFIG_MFD_AAT2870_CORE is not set ++# CONFIG_MFD_ATMEL_FLEXCOM is not set ++# CONFIG_MFD_ATMEL_HLCDC is not set ++# CONFIG_MFD_BCM590XX is not set ++# CONFIG_MFD_BD9571MWV is not set ++# CONFIG_MFD_AXP20X_I2C is not set ++# CONFIG_MFD_MADERA is not set ++# CONFIG_MFD_ASIC3 is not set ++# CONFIG_PMIC_DA903X is not set ++CONFIG_PMIC_DA9052=y ++CONFIG_MFD_DA9052_I2C=y ++# CONFIG_MFD_DA9055 is not set ++CONFIG_MFD_DA9062=y ++CONFIG_MFD_DA9063=y ++# CONFIG_MFD_DA9150 is not set ++# CONFIG_MFD_GATEWORKS_GSC is not set ++CONFIG_MFD_MC13XXX=y ++CONFIG_MFD_MC13XXX_I2C=y ++# CONFIG_MFD_MP2629 is not set ++# CONFIG_MFD_IMX_MIX is not set ++CONFIG_MFD_MXC_HDMI=y ++# CONFIG_MFD_HI6421_PMIC is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_HTC_I2CPLD is not set ++# CONFIG_MFD_IQS62X is not set ++# CONFIG_MFD_KEMPLD is not set ++# CONFIG_MFD_88PM800 is not set ++# CONFIG_MFD_88PM805 is not set ++# CONFIG_MFD_88PM860X is not set ++# CONFIG_MFD_MAX14577 is not set ++CONFIG_MFD_MAX17135=y ++# CONFIG_MFD_FP9931 is not set ++# CONFIG_MFD_MAX77620 is not set ++# CONFIG_MFD_MAX77650 is not set ++# CONFIG_MFD_MAX77686 is not set ++# CONFIG_MFD_MAX77693 is not set ++# CONFIG_MFD_MAX77843 is not set ++# CONFIG_MFD_MAX8907 is not set ++# CONFIG_MFD_MAX8925 is not set ++# CONFIG_MFD_MAX8997 is not set ++# CONFIG_MFD_MAX8998 is not set ++# CONFIG_MFD_MT6360 is not set ++# CONFIG_MFD_MT6397 is not set ++# CONFIG_MFD_MENF21BMC is not set ++# CONFIG_MFD_NTXEC is not set ++# CONFIG_MFD_RETU is not set ++# CONFIG_MFD_PCF50633 is not set ++# CONFIG_MFD_PM8XXX is not set ++# CONFIG_MFD_RT4831 is not set ++# CONFIG_MFD_RT5033 is not set ++# CONFIG_MFD_RC5T583 is not set ++# CONFIG_MFD_RK808 is not set ++CONFIG_MFD_RN5T618=y ++# CONFIG_MFD_SEC_CORE is not set ++CONFIG_MFD_SI476X_CORE=y ++# CONFIG_MFD_SM501 is not set ++# CONFIG_MFD_SKY81452 is not set ++# CONFIG_MFD_STMPE is not set ++CONFIG_MFD_SYSCON=y ++# CONFIG_MFD_TI_AM335X_TSCADC is not set ++# CONFIG_MFD_LP3943 is not set ++# CONFIG_MFD_LP8788 is not set ++# CONFIG_MFD_TI_LMU is not set ++# CONFIG_MFD_PALMAS is not set ++# CONFIG_TPS6105X is not set ++# CONFIG_TPS65010 is not set ++# CONFIG_TPS6507X is not set ++# CONFIG_MFD_TPS65086 is not set ++# CONFIG_MFD_TPS65090 is not set ++# CONFIG_MFD_TPS65217 is not set ++# CONFIG_MFD_TI_LP873X is not set ++# CONFIG_MFD_TI_LP87565 is not set ++# CONFIG_MFD_TPS65218 is not set ++# CONFIG_MFD_TPS6586X is not set ++# CONFIG_MFD_TPS65910 is not set ++# CONFIG_MFD_TPS65912_I2C is not set ++# CONFIG_MFD_TPS80031 is not set ++# CONFIG_TWL4030_CORE is not set ++# CONFIG_TWL6040_CORE is not set ++# CONFIG_MFD_WL1273_CORE is not set ++# CONFIG_MFD_LM3533 is not set ++# CONFIG_MFD_TC3589X is not set ++# CONFIG_MFD_T7L66XB is not set ++# CONFIG_MFD_TC6387XB is not set ++# CONFIG_MFD_TC6393XB is not set ++# CONFIG_MFD_TQMX86 is not set ++# CONFIG_MFD_LOCHNAGAR is not set ++# CONFIG_MFD_ARIZONA_I2C is not set ++# CONFIG_MFD_WM8400 is not set ++# CONFIG_MFD_WM831X_I2C is not set ++# CONFIG_MFD_WM8350_I2C is not set ++CONFIG_MFD_WM8994=y ++# CONFIG_MFD_ROHM_BD718XX is not set ++# CONFIG_MFD_ROHM_BD70528 is not set ++# CONFIG_MFD_ROHM_BD71828 is not set ++# CONFIG_MFD_ROHM_BD957XMUF is not set ++# CONFIG_MFD_STPMIC1 is not set ++# CONFIG_MFD_STMFX is not set ++# CONFIG_MFD_ATC260X_I2C is not set ++# CONFIG_MFD_QCOM_PM8008 is not set ++# CONFIG_RAVE_SP_CORE is not set ++# CONFIG_MFD_RSMU_I2C is not set ++# end of Multifunction device drivers ++ ++CONFIG_REGULATOR=y ++# CONFIG_REGULATOR_DEBUG is not set ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set ++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set ++# CONFIG_REGULATOR_88PG86X is not set ++# CONFIG_REGULATOR_ACT8865 is not set ++# CONFIG_REGULATOR_AD5398 is not set ++CONFIG_REGULATOR_ANATOP=y ++CONFIG_REGULATOR_DA9052=y ++CONFIG_REGULATOR_DA9062=y ++CONFIG_REGULATOR_DA9063=y ++# CONFIG_REGULATOR_DA9121 is not set ++# CONFIG_REGULATOR_DA9210 is not set ++# CONFIG_REGULATOR_DA9211 is not set ++# CONFIG_REGULATOR_FAN53555 is not set ++# CONFIG_REGULATOR_FAN53880 is not set ++CONFIG_REGULATOR_GPIO=y ++# CONFIG_REGULATOR_ISL9305 is not set ++# CONFIG_REGULATOR_ISL6271A is not set ++# CONFIG_REGULATOR_LP3971 is not set ++# CONFIG_REGULATOR_LP3972 is not set ++# CONFIG_REGULATOR_LP872X is not set ++# CONFIG_REGULATOR_LP8755 is not set ++# CONFIG_REGULATOR_LTC3589 is not set ++CONFIG_REGULATOR_LTC3676=y ++# CONFIG_REGULATOR_MAX1586 is not set ++CONFIG_REGULATOR_MAX17135=y ++# CONFIG_REGULATOR_MAX8649 is not set ++# CONFIG_REGULATOR_MAX8660 is not set ++# CONFIG_REGULATOR_MAX8893 is not set ++# CONFIG_REGULATOR_MAX8952 is not set ++# CONFIG_REGULATOR_MAX8973 is not set ++# CONFIG_REGULATOR_MAX77826 is not set ++CONFIG_REGULATOR_MC13XXX_CORE=y ++CONFIG_REGULATOR_MC13783=y ++CONFIG_REGULATOR_MC13892=y ++# CONFIG_REGULATOR_MCP16502 is not set ++# CONFIG_REGULATOR_MP5416 is not set ++# CONFIG_REGULATOR_MP8859 is not set ++# CONFIG_REGULATOR_MP886X is not set ++# CONFIG_REGULATOR_MPQ7920 is not set ++# CONFIG_REGULATOR_MT6311 is not set ++# CONFIG_REGULATOR_PCA9450 is not set ++# CONFIG_REGULATOR_PF8X00 is not set ++# CONFIG_REGULATOR_PF1550_RPMSG is not set ++CONFIG_REGULATOR_PFUZE100=y ++# CONFIG_REGULATOR_PV88060 is not set ++# CONFIG_REGULATOR_PV88080 is not set ++# CONFIG_REGULATOR_PV88090 is not set ++# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set ++CONFIG_REGULATOR_RN5T618=y ++# CONFIG_REGULATOR_RT4801 is not set ++# CONFIG_REGULATOR_RT6160 is not set ++# CONFIG_REGULATOR_RT6245 is not set ++# CONFIG_REGULATOR_RTQ2134 is not set ++# CONFIG_REGULATOR_RTMV20 is not set ++# CONFIG_REGULATOR_RTQ6752 is not set ++# CONFIG_REGULATOR_SLG51000 is not set ++# CONFIG_REGULATOR_SY8106A is not set ++# CONFIG_REGULATOR_SY8824X is not set ++# CONFIG_REGULATOR_SY8827N is not set ++# CONFIG_REGULATOR_TPS51632 is not set ++# CONFIG_REGULATOR_TPS62360 is not set ++# CONFIG_REGULATOR_TPS65023 is not set ++# CONFIG_REGULATOR_TPS6507X is not set ++# CONFIG_REGULATOR_TPS65132 is not set ++# CONFIG_REGULATOR_VCTRL is not set ++# CONFIG_REGULATOR_WM8994 is not set ++# CONFIG_RC_CORE is not set ++# CONFIG_MEDIA_CEC_SUPPORT is not set ++# CONFIG_MEDIA_SUPPORT is not set ++ ++# ++# Graphics support ++# ++# CONFIG_IMX_IPUV3_CORE is not set ++# CONFIG_IMX_DPU_CORE is not set ++# CONFIG_IMX_LCDIF_CORE is not set ++# CONFIG_IMX_LCDIFV3_CORE is not set ++CONFIG_DRM=y ++# CONFIG_DRM_DP_AUX_CHARDEV is not set ++# CONFIG_DRM_DEBUG_MM is not set ++# CONFIG_DRM_DEBUG_SELFTEST is not set ++CONFIG_DRM_KMS_HELPER=y ++# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set ++# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set ++# CONFIG_DRM_DP_CEC is not set ++ ++# ++# I2C encoder or helper chips ++# ++# CONFIG_DRM_I2C_CH7006 is not set ++# CONFIG_DRM_I2C_SIL164 is not set ++# CONFIG_DRM_I2C_NXP_TDA998X is not set ++# CONFIG_DRM_I2C_NXP_TDA9950 is not set ++# end of I2C encoder or helper chips ++ ++# ++# ARM devices ++# ++# CONFIG_DRM_HDLCD is not set ++# CONFIG_DRM_MALI_DISPLAY is not set ++# CONFIG_DRM_KOMEDA is not set ++# end of ARM devices ++ ++# CONFIG_DRM_VGEM is not set ++# CONFIG_DRM_VKMS is not set ++# CONFIG_DRM_EXYNOS is not set ++# CONFIG_DRM_ARMADA is not set ++# CONFIG_DRM_RCAR_DW_HDMI is not set ++# CONFIG_DRM_RCAR_LVDS is not set ++# CONFIG_DRM_OMAP is not set ++# CONFIG_DRM_TILCDC is not set ++# CONFIG_DRM_FSL_DCU is not set ++# CONFIG_DRM_STM is not set ++CONFIG_DRM_PANEL=y ++ ++# ++# Display Panels ++# ++# CONFIG_DRM_PANEL_ARM_VERSATILE is not set ++CONFIG_DRM_PANEL_LVDS=y ++# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set ++# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set ++# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set ++# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set ++CONFIG_DRM_PANEL_SEIKO_43WVF1G=y ++# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set ++# CONFIG_DRM_PANEL_WKS_101WX001 is not set ++# end of Display Panels ++ ++CONFIG_DRM_BRIDGE=y ++CONFIG_DRM_PANEL_BRIDGE=y ++ ++# ++# Display Interface Bridges ++# ++# CONFIG_DRM_CDNS_DSI is not set ++# CONFIG_DRM_CHIPONE_ICN6211 is not set ++# CONFIG_DRM_CHRONTEL_CH7033 is not set ++# CONFIG_DRM_DISPLAY_CONNECTOR is not set ++# CONFIG_DRM_LONTIUM_LT8912B is not set ++# CONFIG_DRM_LONTIUM_LT9611 is not set ++# CONFIG_DRM_LONTIUM_LT9611UXC is not set ++# CONFIG_DRM_ITE_IT66121 is not set ++# CONFIG_DRM_FSL_IMX_LVDS_BRIDGE is not set ++# CONFIG_DRM_LVDS_CODEC is not set ++# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set ++# CONFIG_DRM_NWL_MIPI_DSI is not set ++# CONFIG_DRM_SEC_MIPI_DSIM is not set ++# CONFIG_DRM_NXP_SEIKO_43WVFIG is not set ++# CONFIG_DRM_NXP_PTN3460 is not set ++# CONFIG_DRM_PARADE_PS8622 is not set ++# CONFIG_DRM_PARADE_PS8640 is not set ++# CONFIG_DRM_SIL_SII8620 is not set ++# CONFIG_DRM_SII902X is not set ++# CONFIG_DRM_SII9234 is not set ++# CONFIG_DRM_SIMPLE_BRIDGE is not set ++# CONFIG_DRM_THINE_THC63LVD1024 is not set ++# CONFIG_DRM_TOSHIBA_TC358762 is not set ++# CONFIG_DRM_TOSHIBA_TC358764 is not set ++# CONFIG_DRM_TOSHIBA_TC358767 is not set ++# CONFIG_DRM_TOSHIBA_TC358768 is not set ++# CONFIG_DRM_TOSHIBA_TC358775 is not set ++CONFIG_DRM_TI_TFP410=y ++# CONFIG_DRM_TI_SN65DSI83 is not set ++# CONFIG_DRM_TI_SN65DSI86 is not set ++# CONFIG_DRM_TI_TPD12S015 is not set ++# CONFIG_DRM_ANALOGIX_ANX6345 is not set ++# CONFIG_DRM_ANALOGIX_ANX78XX is not set ++# CONFIG_DRM_ANALOGIX_ANX7625 is not set ++# CONFIG_DRM_I2C_ADV7511 is not set ++# CONFIG_DRM_CDNS_MHDP8546 is not set ++# CONFIG_DRM_CDNS_MHDP is not set ++# CONFIG_DRM_CDNS_HDMI_CEC is not set ++# CONFIG_DRM_ITE_IT6263 is not set ++# CONFIG_DRM_ITE_IT6161 is not set ++# end of Display Interface Bridges ++ ++# CONFIG_DRM_STI is not set ++# CONFIG_IMX8MP_HDMI_PAVI is not set ++# CONFIG_DRM_IMX_DCNANO is not set ++# CONFIG_DRM_ETNAVIV is not set ++# CONFIG_DRM_MXSFB is not set ++# CONFIG_DRM_ARCPGU is not set ++# CONFIG_DRM_SIMPLEDRM is not set ++# CONFIG_DRM_PL111 is not set ++# CONFIG_DRM_TVE200 is not set ++# CONFIG_DRM_LIMA is not set ++# CONFIG_DRM_PANFROST is not set ++# CONFIG_DRM_MCDE is not set ++# CONFIG_DRM_TIDSS is not set ++# CONFIG_DRM_LEGACY is not set ++CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y ++ ++# ++# Frame buffer Devices ++# ++CONFIG_FB_CMDLINE=y ++# CONFIG_FB is not set ++# CONFIG_FB_MXC_DISP_FRAMEWORK is not set ++# end of Frame buffer Devices ++ ++# ++# Backlight & LCD device support ++# ++CONFIG_LCD_CLASS_DEVICE=y ++CONFIG_LCD_PLATFORM=y ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++# CONFIG_BACKLIGHT_KTD253 is not set ++# CONFIG_BACKLIGHT_DA9052 is not set ++# CONFIG_BACKLIGHT_QCOM_WLED is not set ++# CONFIG_BACKLIGHT_ADP8860 is not set ++# CONFIG_BACKLIGHT_ADP8870 is not set ++# CONFIG_BACKLIGHT_LM3639 is not set ++CONFIG_BACKLIGHT_GPIO=y ++# CONFIG_BACKLIGHT_LV5207LP is not set ++# CONFIG_BACKLIGHT_BD6107 is not set ++# CONFIG_BACKLIGHT_ARCXCNN is not set ++# end of Backlight & LCD device support ++ ++CONFIG_VIDEOMODE_HELPERS=y ++CONFIG_HDMI=y ++ ++# ++# Console display driver support ++# ++CONFIG_DUMMY_CONSOLE=y ++# end of Console display driver support ++# end of Graphics support ++ ++# CONFIG_SOUND is not set ++ ++# ++# HID support ++# ++CONFIG_HID=y ++# CONFIG_HID_BATTERY_STRENGTH is not set ++# CONFIG_HIDRAW is not set ++# CONFIG_UHID is not set ++CONFIG_HID_GENERIC=y ++ ++# ++# Special HID drivers ++# ++# CONFIG_HID_A4TECH is not set ++# CONFIG_HID_ACRUX is not set ++# CONFIG_HID_APPLE is not set ++# CONFIG_HID_AUREAL is not set ++# CONFIG_HID_BELKIN is not set ++# CONFIG_HID_CHERRY is not set ++# CONFIG_HID_COUGAR is not set ++# CONFIG_HID_MACALLY is not set ++# CONFIG_HID_CMEDIA is not set ++# CONFIG_HID_CYPRESS is not set ++# CONFIG_HID_DRAGONRISE is not set ++# CONFIG_HID_EMS_FF is not set ++# CONFIG_HID_ELECOM is not set ++# CONFIG_HID_EZKEY is not set ++# CONFIG_HID_GEMBIRD is not set ++# CONFIG_HID_GFRM is not set ++# CONFIG_HID_GLORIOUS is not set ++# CONFIG_HID_VIVALDI is not set ++# CONFIG_HID_KEYTOUCH is not set ++# CONFIG_HID_KYE is not set ++# CONFIG_HID_WALTOP is not set ++# CONFIG_HID_VIEWSONIC is not set ++# CONFIG_HID_GYRATION is not set ++# CONFIG_HID_ICADE is not set ++# CONFIG_HID_ITE is not set ++# CONFIG_HID_JABRA is not set ++# CONFIG_HID_TWINHAN is not set ++# CONFIG_HID_KENSINGTON is not set ++# CONFIG_HID_LCPOWER is not set ++# CONFIG_HID_LENOVO is not set ++# CONFIG_HID_MAGICMOUSE is not set ++# CONFIG_HID_MALTRON is not set ++# CONFIG_HID_MAYFLASH is not set ++# CONFIG_HID_REDRAGON is not set ++# CONFIG_HID_MICROSOFT is not set ++# CONFIG_HID_MONTEREY is not set ++CONFIG_HID_MULTITOUCH=y ++# CONFIG_HID_NTI is not set ++# CONFIG_HID_ORTEK is not set ++# CONFIG_HID_PANTHERLORD is not set ++# CONFIG_HID_PETALYNX is not set ++# CONFIG_HID_PICOLCD is not set ++# CONFIG_HID_PLANTRONICS is not set ++# CONFIG_HID_PLAYSTATION is not set ++# CONFIG_HID_PRIMAX is not set ++# CONFIG_HID_SAITEK is not set ++# CONFIG_HID_SEMITEK is not set ++# CONFIG_HID_SPEEDLINK is not set ++# CONFIG_HID_STEAM is not set ++# CONFIG_HID_STEELSERIES is not set ++# CONFIG_HID_SUNPLUS is not set ++# CONFIG_HID_RMI is not set ++# CONFIG_HID_GREENASIA is not set ++# CONFIG_HID_SMARTJOYPLUS is not set ++# CONFIG_HID_TIVO is not set ++# CONFIG_HID_TOPSEED is not set ++# CONFIG_HID_UDRAW_PS3 is not set ++# CONFIG_HID_XINMO is not set ++# CONFIG_HID_ZEROPLUS is not set ++# CONFIG_HID_ZYDACRON is not set ++# CONFIG_HID_SENSOR_HUB is not set ++# CONFIG_HID_ALPS is not set ++# end of Special HID drivers ++ ++# ++# I2C HID support ++# ++# CONFIG_I2C_HID_OF is not set ++# CONFIG_I2C_HID_OF_GOODIX is not set ++# end of I2C HID support ++# end of HID support ++ ++CONFIG_USB_OHCI_LITTLE_ENDIAN=y ++# CONFIG_USB_SUPPORT is not set ++CONFIG_MMC=y ++CONFIG_PWRSEQ_EMMC=y ++CONFIG_PWRSEQ_SIMPLE=y ++CONFIG_MMC_BLOCK=y ++CONFIG_MMC_BLOCK_MINORS=8 ++# CONFIG_SDIO_UART is not set ++# CONFIG_MMC_TEST is not set ++ ++# ++# MMC/SD/SDIO Host Controller Drivers ++# ++# CONFIG_MMC_DEBUG is not set ++CONFIG_MMC_SDHCI=y ++CONFIG_MMC_SDHCI_IO_ACCESSORS=y ++CONFIG_MMC_SDHCI_PLTFM=y ++# CONFIG_MMC_SDHCI_OF_ARASAN is not set ++# CONFIG_MMC_SDHCI_OF_ASPEED is not set ++# CONFIG_MMC_SDHCI_OF_AT91 is not set ++# CONFIG_MMC_SDHCI_OF_ESDHC is not set ++# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set ++# CONFIG_MMC_SDHCI_CADENCE is not set ++CONFIG_MMC_SDHCI_ESDHC_IMX=y ++# CONFIG_MMC_SDHCI_F_SDH30 is not set ++# CONFIG_MMC_SDHCI_MILBEAUT is not set ++# CONFIG_MMC_MXC is not set ++# CONFIG_MMC_DW is not set ++# CONFIG_MMC_USDHI6ROL0 is not set ++CONFIG_MMC_CQHCI=y ++# CONFIG_MMC_HSQ is not set ++# CONFIG_MMC_MTK is not set ++# CONFIG_MMC_SDHCI_XENON is not set ++# CONFIG_MMC_SDHCI_OMAP is not set ++# CONFIG_MMC_SDHCI_AM654 is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++# CONFIG_INFINIBAND is not set ++CONFIG_EDAC_ATOMIC_SCRUB=y ++CONFIG_EDAC_SUPPORT=y ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_HCTOSYS=y ++CONFIG_RTC_HCTOSYS_DEVICE="rtc0" ++CONFIG_RTC_SYSTOHC=y ++CONFIG_RTC_SYSTOHC_DEVICE="rtc0" ++# CONFIG_RTC_DEBUG is not set ++CONFIG_RTC_NVMEM=y ++ ++# ++# RTC interfaces ++# ++CONFIG_RTC_INTF_SYSFS=y ++CONFIG_RTC_INTF_PROC=y ++CONFIG_RTC_INTF_DEV=y ++CONFIG_RTC_INTF_DEV_UIE_EMUL=y ++# CONFIG_RTC_DRV_TEST is not set ++ ++# ++# I2C RTC drivers ++# ++# CONFIG_RTC_DRV_ABB5ZES3 is not set ++# CONFIG_RTC_DRV_ABEOZ9 is not set ++# CONFIG_RTC_DRV_ABX80X is not set ++CONFIG_RTC_DRV_DS1307=y ++# CONFIG_RTC_DRV_DS1307_CENTURY is not set ++# CONFIG_RTC_DRV_DS1374 is not set ++# CONFIG_RTC_DRV_DS1672 is not set ++# CONFIG_RTC_DRV_HYM8563 is not set ++# CONFIG_RTC_DRV_MAX6900 is not set ++# CONFIG_RTC_DRV_RS5C372 is not set ++CONFIG_RTC_DRV_ISL1208=y ++# CONFIG_RTC_DRV_ISL12022 is not set ++# CONFIG_RTC_DRV_ISL12026 is not set ++# CONFIG_RTC_DRV_X1205 is not set ++CONFIG_RTC_DRV_PCF8523=y ++# CONFIG_RTC_DRV_PCF85063 is not set ++# CONFIG_RTC_DRV_PCF85363 is not set ++CONFIG_RTC_DRV_PCF8563=y ++# CONFIG_RTC_DRV_PCF8583 is not set ++CONFIG_RTC_DRV_M41T80=y ++# CONFIG_RTC_DRV_M41T80_WDT is not set ++# CONFIG_RTC_DRV_BQ32K is not set ++CONFIG_RTC_DRV_RC5T619=y ++# CONFIG_RTC_DRV_S35390A is not set ++# CONFIG_RTC_DRV_FM3130 is not set ++# CONFIG_RTC_DRV_RX8010 is not set ++# CONFIG_RTC_DRV_RX8581 is not set ++# CONFIG_RTC_DRV_RX8025 is not set ++# CONFIG_RTC_DRV_EM3027 is not set ++# CONFIG_RTC_DRV_RV3028 is not set ++# CONFIG_RTC_DRV_RV3032 is not set ++# CONFIG_RTC_DRV_RV8803 is not set ++# CONFIG_RTC_DRV_SD3078 is not set ++ ++# ++# SPI RTC drivers ++# ++CONFIG_RTC_I2C_AND_SPI=y ++ ++# ++# SPI and I2C RTC drivers ++# ++# CONFIG_RTC_DRV_DS3232 is not set ++# CONFIG_RTC_DRV_PCF2127 is not set ++# CONFIG_RTC_DRV_RV3029C2 is not set ++# CONFIG_RTC_DRV_RX6110 is not set ++ ++# ++# Platform RTC drivers ++# ++# CONFIG_RTC_DRV_CMOS is not set ++# CONFIG_RTC_DRV_DS1286 is not set ++# CONFIG_RTC_DRV_DS1511 is not set ++# CONFIG_RTC_DRV_DS1553 is not set ++# CONFIG_RTC_DRV_DS1685_FAMILY is not set ++# CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_DS2404 is not set ++# CONFIG_RTC_DRV_DA9052 is not set ++CONFIG_RTC_DRV_DA9063=y ++# CONFIG_RTC_DRV_STK17TA8 is not set ++# CONFIG_RTC_DRV_M48T86 is not set ++# CONFIG_RTC_DRV_M48T35 is not set ++# CONFIG_RTC_DRV_M48T59 is not set ++# CONFIG_RTC_DRV_MSM6242 is not set ++# CONFIG_RTC_DRV_BQ4802 is not set ++# CONFIG_RTC_DRV_RP5C01 is not set ++# CONFIG_RTC_DRV_V3020 is not set ++# CONFIG_RTC_DRV_ZYNQMP is not set ++ ++# ++# on-CPU RTC drivers ++# ++# CONFIG_RTC_DRV_IMXDI is not set ++# CONFIG_RTC_DRV_CADENCE is not set ++# CONFIG_RTC_DRV_FTRTC010 is not set ++CONFIG_RTC_DRV_MC13XXX=y ++CONFIG_RTC_DRV_MXC=y ++CONFIG_RTC_DRV_MXC_V2=y ++CONFIG_RTC_DRV_SNVS=y ++# CONFIG_RTC_DRV_BBNSM is not set ++CONFIG_RTC_DRV_IMX_RPMSG=y ++# CONFIG_RTC_DRV_R7301 is not set ++ ++# ++# HID Sensor RTC drivers ++# ++# CONFIG_RTC_DRV_GOLDFISH is not set ++CONFIG_DMADEVICES=y ++# CONFIG_DMADEVICES_DEBUG is not set ++ ++# ++# DMA Devices ++# ++CONFIG_DMA_ENGINE=y ++CONFIG_DMA_VIRTUAL_CHANNELS=y ++CONFIG_DMA_OF=y ++# CONFIG_ALTERA_MSGDMA is not set ++# CONFIG_CRYPTO_DEV_FSL_CAAM_DMA is not set ++# CONFIG_DW_AXI_DMAC is not set ++CONFIG_FSL_EDMA=y ++# CONFIG_FSL_QDMA is not set ++# CONFIG_FSL_EDMA_V3 is not set ++# CONFIG_IMX_DMA is not set ++CONFIG_IMX_SDMA=y ++# CONFIG_INTEL_IDMA64 is not set ++CONFIG_MXS_DMA=y ++# CONFIG_MXC_PXP_V2 is not set ++# CONFIG_MXC_PXP_V3 is not set ++# CONFIG_MX3_IPU is not set ++# CONFIG_NBPFAXI_DMA is not set ++# CONFIG_XILINX_ZYNQMP_DPDMA is not set ++# CONFIG_QCOM_HIDMA_MGMT is not set ++# CONFIG_QCOM_HIDMA is not set ++# CONFIG_DW_DMAC is not set ++# CONFIG_SF_PDMA is not set ++ ++# ++# DMA Clients ++# ++# CONFIG_ASYNC_TX_DMA is not set ++# CONFIG_DMATEST is not set ++ ++# ++# DMABUF options ++# ++CONFIG_SYNC_FILE=y ++# CONFIG_UDMABUF is not set ++# CONFIG_DMABUF_MOVE_NOTIFY is not set ++# CONFIG_DMABUF_DEBUG is not set ++# CONFIG_DMABUF_SELFTESTS is not set ++# CONFIG_DMABUF_HEAPS is not set ++# CONFIG_DMABUF_SYSFS_STATS is not set ++# end of DMABUF options ++ ++# CONFIG_AUXDISPLAY is not set ++# CONFIG_UIO is not set ++# CONFIG_VFIO is not set ++# CONFIG_VIRT_DRIVERS is not set ++CONFIG_VIRTIO=y ++# CONFIG_VIRTIO_MENU is not set ++# CONFIG_VDPA is not set ++# CONFIG_VHOST_MENU is not set ++ ++# ++# Microsoft Hyper-V guest support ++# ++# end of Microsoft Hyper-V guest support ++ ++# CONFIG_GREYBUS is not set ++# CONFIG_COMEDI is not set ++# CONFIG_STAGING is not set ++# CONFIG_GOLDFISH is not set ++# CONFIG_CHROME_PLATFORMS is not set ++# CONFIG_MELLANOX_PLATFORM is not set ++CONFIG_HAVE_CLK=y ++CONFIG_HAVE_CLK_PREPARE=y ++CONFIG_COMMON_CLK=y ++ ++# ++# Clock driver for ARM Reference designs ++# ++# CONFIG_ICST is not set ++# CONFIG_CLK_SP810 is not set ++# end of Clock driver for ARM Reference designs ++ ++# CONFIG_COMMON_CLK_MAX9485 is not set ++# CONFIG_COMMON_CLK_SI5341 is not set ++# CONFIG_COMMON_CLK_SI5351 is not set ++# CONFIG_COMMON_CLK_SI514 is not set ++# CONFIG_COMMON_CLK_SI544 is not set ++# CONFIG_COMMON_CLK_SI570 is not set ++# CONFIG_COMMON_CLK_CDCE706 is not set ++# CONFIG_COMMON_CLK_CDCE925 is not set ++# CONFIG_COMMON_CLK_CS2000_CP is not set ++# CONFIG_COMMON_CLK_AXI_CLKGEN is not set ++# CONFIG_COMMON_CLK_VC5 is not set ++# CONFIG_COMMON_CLK_FIXED_MMIO is not set ++CONFIG_MXC_CLK=y ++CONFIG_CLK_IMX6Q=y ++CONFIG_CLK_IMX6SL=y ++CONFIG_CLK_IMX6SLL=y ++CONFIG_CLK_IMX6SX=y ++CONFIG_CLK_IMX6UL=y ++CONFIG_CLK_IMX7D=y ++# CONFIG_CLK_IMX8MM is not set ++# CONFIG_CLK_IMX8MN is not set ++# CONFIG_CLK_IMX8MP is not set ++# CONFIG_CLK_IMX8MQ is not set ++# CONFIG_CLK_IMX8ULP is not set ++# CONFIG_CLK_IMX93 is not set ++# CONFIG_ARCH_S32_CLK is not set ++# CONFIG_XILINX_VCU is not set ++# CONFIG_HWSPINLOCK is not set ++ ++# ++# Clock Source drivers ++# ++CONFIG_TIMER_OF=y ++CONFIG_TIMER_PROBE=y ++CONFIG_CLKSRC_MMIO=y ++CONFIG_ARM_ARCH_TIMER=y ++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y ++CONFIG_CLKSRC_IMX_GPT=y ++# CONFIG_MICROCHIP_PIT64B is not set ++# end of Clock Source drivers ++ ++CONFIG_MAILBOX=y ++CONFIG_IMX_MBOX=y ++# CONFIG_PLATFORM_MHU is not set ++# CONFIG_ALTERA_MBOX is not set ++# CONFIG_MAILBOX_TEST is not set ++CONFIG_IOMMU_SUPPORT=y ++ ++# ++# Generic IOMMU Pagetable Support ++# ++# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set ++# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set ++# end of Generic IOMMU Pagetable Support ++ ++# CONFIG_ARM_SMMU is not set ++ ++# ++# Remoteproc drivers ++# ++# CONFIG_REMOTEPROC is not set ++# end of Remoteproc drivers ++ ++# ++# Rpmsg drivers ++# ++CONFIG_RPMSG=y ++# CONFIG_RPMSG_CHAR is not set ++# CONFIG_RPMSG_CTRL is not set ++CONFIG_RPMSG_NS=y ++# CONFIG_RPMSG_QCOM_GLINK_RPM is not set ++CONFIG_RPMSG_VIRTIO=y ++# CONFIG_IMX_RPMSG_PINGPONG is not set ++# CONFIG_IMX_RPMSG_TTY is not set ++# end of Rpmsg drivers ++ ++# CONFIG_SOUNDWIRE is not set ++ ++# ++# SOC (System On Chip) specific Drivers ++# ++ ++# ++# Amlogic SoC drivers ++# ++# end of Amlogic SoC drivers ++ ++# ++# Broadcom SoC drivers ++# ++# CONFIG_SOC_BRCMSTB is not set ++# end of Broadcom SoC drivers ++ ++# ++# NXP/Freescale QorIQ SoC drivers ++# ++# CONFIG_QUICC_ENGINE is not set ++# CONFIG_FSL_QIXIS is not set ++# end of NXP/Freescale QorIQ SoC drivers ++ ++# ++# i.MX SoC drivers ++# ++# CONFIG_SOC_IMX_MU is not set ++# CONFIG_SOC_IMX9 is not set ++# CONFIG_SOC_IMX8M is not set ++# CONFIG_RPMSG_LIFE_CYCLE is not set ++# CONFIG_IMX8ULP_LPM_CTRL is not set ++# end of i.MX SoC drivers ++ ++# ++# Enable LiteX SoC Builder specific drivers ++# ++# CONFIG_LITEX_SOC_CONTROLLER is not set ++# end of Enable LiteX SoC Builder specific drivers ++ ++# ++# Qualcomm SoC drivers ++# ++# end of Qualcomm SoC drivers ++ ++# CONFIG_SOC_TI is not set ++ ++# ++# Xilinx SoC drivers ++# ++# end of Xilinx SoC drivers ++# end of SOC (System On Chip) specific Drivers ++ ++# CONFIG_PM_DEVFREQ is not set ++CONFIG_EXTCON=y ++ ++# ++# Extcon Device Drivers ++# ++# CONFIG_EXTCON_FSA9480 is not set ++# CONFIG_EXTCON_GPIO is not set ++# CONFIG_EXTCON_MAX3355 is not set ++# CONFIG_EXTCON_PTN5150 is not set ++# CONFIG_EXTCON_RT8973A is not set ++# CONFIG_EXTCON_SM5502 is not set ++CONFIG_EXTCON_USB_GPIO=y ++# CONFIG_EXTCON_USBC_TUSB320 is not set ++# CONFIG_MEMORY is not set ++# CONFIG_IIO is not set ++# CONFIG_PWM is not set ++ ++# ++# IRQ chip support ++# ++CONFIG_IRQCHIP=y ++CONFIG_ARM_GIC=y ++CONFIG_ARM_GIC_MAX_NR=1 ++# CONFIG_AL_FIC is not set ++CONFIG_IMX_GPCV2=y ++# CONFIG_IMX_IRQSTEER is not set ++CONFIG_IMX_INTMUX=y ++# end of IRQ chip support ++ ++# CONFIG_IPACK_BUS is not set ++CONFIG_ARCH_HAS_RESET_CONTROLLER=y ++CONFIG_RESET_CONTROLLER=y ++CONFIG_RESET_DISPMIX=y ++CONFIG_RESET_IMX7=y ++# CONFIG_RESET_IMX8ULP_SIM is not set ++CONFIG_RESET_GPIO=y ++# CONFIG_RESET_TI_SYSCON is not set ++ ++# ++# PHY Subsystem ++# ++CONFIG_GENERIC_PHY=y ++# CONFIG_PHY_CAN_TRANSCEIVER is not set ++# CONFIG_PHY_MIXEL_LVDS is not set ++# CONFIG_PHY_MIXEL_LVDS_COMBO is not set ++# CONFIG_BCM_KONA_USB2_PHY is not set ++# CONFIG_PHY_CADENCE_TORRENT is not set ++# CONFIG_PHY_CADENCE_DPHY is not set ++# CONFIG_PHY_CADENCE_SIERRA is not set ++# CONFIG_PHY_CADENCE_SALVO is not set ++# CONFIG_PHY_FSL_IMX8MP_LVDS is not set ++# CONFIG_PHY_FSL_IMX8MQ_USB is not set ++# CONFIG_PHY_FSL_IMX93_MIPI_DPHY is not set ++# CONFIG_PHY_MIXEL_MIPI_DPHY is not set ++# CONFIG_PHY_SAMSUNG_HDMI_PHY is not set ++CONFIG_PHY_FSL_IMX_PCIE=y ++# CONFIG_PHY_FSL_LYNX_28G is not set ++# CONFIG_PHY_PXA_28NM_HSIC is not set ++# CONFIG_PHY_PXA_28NM_USB2 is not set ++# CONFIG_PHY_OCELOT_SERDES is not set ++# end of PHY Subsystem ++ ++# CONFIG_POWERCAP is not set ++# CONFIG_MCB is not set ++# CONFIG_RAS is not set ++ ++# ++# Android ++# ++# CONFIG_ANDROID is not set ++# end of Android ++ ++# CONFIG_DAX is not set ++CONFIG_NVMEM=y ++CONFIG_NVMEM_SYSFS=y ++# CONFIG_NVMEM_IMX_IIM is not set ++CONFIG_NVMEM_IMX_OCOTP=y ++CONFIG_NVMEM_SNVS_LPGPR=y ++# CONFIG_NVMEM_RMEM is not set ++ ++# ++# HW tracing support ++# ++# CONFIG_STM is not set ++# CONFIG_INTEL_TH is not set ++# end of HW tracing support ++ ++# CONFIG_FPGA is not set ++# CONFIG_FSI is not set ++CONFIG_TEE=y ++ ++# ++# TEE drivers ++# ++CONFIG_OPTEE=y ++CONFIG_OPTEE_SHM_NUM_PRIV_PAGES=1 ++# end of TEE drivers ++ ++CONFIG_PM_OPP=y ++# CONFIG_SIOX is not set ++# CONFIG_SLIMBUS is not set ++# CONFIG_INTERCONNECT is not set ++# CONFIG_COUNTER is not set ++# CONFIG_MOST is not set ++ ++# ++# MXC support drivers ++# ++# CONFIG_MXC_SIM is not set ++# CONFIG_MXC_IPU is not set ++ ++# ++# MXC Vivante GPU support ++# ++# CONFIG_MXC_GPU_VIV is not set ++# end of MXC Vivante GPU support ++ ++# ++# MXC SIM Support ++# ++# end of MXC SIM Support ++ ++# ++# MXC Media Local Bus Driver ++# ++CONFIG_MXC_MLB=y ++CONFIG_MXC_MLB150=y ++# end of MXC Media Local Bus Driver ++ ++# ++# MXC HDMI CEC (Consumer Electronics Control) support ++# ++# end of MXC HDMI CEC (Consumer Electronics Control) support ++ ++# ++# MXC MIPI Support ++# ++CONFIG_MXC_MIPI_CSI2=y ++# end of MXC MIPI Support ++ ++# ++# MXC VPU(Video Processing Unit) support ++# ++CONFIG_MXC_VPU=y ++# CONFIG_MXC_VPU_DEBUG is not set ++# CONFIG_MX6_VPU_352M is not set ++# end of MXC VPU(Video Processing Unit) support ++# end of MXC support drivers ++# end of Device Drivers ++ ++# ++# File systems ++# ++CONFIG_DCACHE_WORD_ACCESS=y ++# CONFIG_VALIDATE_FS_PARSER is not set ++CONFIG_FS_IOMAP=y ++CONFIG_EXT2_FS=y ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT3_FS is not set ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_POSIX_ACL=y ++CONFIG_EXT4_FS_SECURITY=y ++# CONFIG_EXT4_DEBUG is not set ++CONFIG_JBD2=y ++# CONFIG_JBD2_DEBUG is not set ++CONFIG_FS_MBCACHE=y ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_GFS2_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++# CONFIG_NILFS2_FS is not set ++# CONFIG_F2FS_FS is not set ++CONFIG_FS_POSIX_ACL=y ++CONFIG_EXPORTFS=y ++# CONFIG_EXPORTFS_BLOCK_OPS is not set ++CONFIG_FILE_LOCKING=y ++# CONFIG_FS_ENCRYPTION is not set ++# CONFIG_FS_VERITY is not set ++# CONFIG_DNOTIFY is not set ++# CONFIG_INOTIFY_USER is not set ++# CONFIG_FANOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_FUSE_FS is not set ++# CONFIG_OVERLAY_FS is not set ++ ++# ++# Caches ++# ++# CONFIG_FSCACHE is not set ++# end of Caches ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++# end of CD-ROM/DVD Filesystems ++ ++# ++# DOS/FAT/EXFAT/NT Filesystems ++# ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++# CONFIG_FAT_DEFAULT_UTF8 is not set ++# CONFIG_EXFAT_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS3_FS is not set ++# end of DOS/FAT/EXFAT/NT Filesystems ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++CONFIG_PROC_SYSCTL=y ++CONFIG_PROC_PAGE_MONITOR=y ++CONFIG_PROC_CHILDREN=y ++CONFIG_KERNFS=y ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_TMPFS_XATTR=y ++CONFIG_MEMFD_CREATE=y ++CONFIG_CONFIGFS_FS=y ++# end of Pseudo filesystems ++ ++# CONFIG_MISC_FILESYSTEMS is not set ++# CONFIG_NETWORK_FILESYSTEMS is not set ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++CONFIG_NLS_ISO8859_15=y ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_MAC_ROMAN is not set ++# CONFIG_NLS_MAC_CELTIC is not set ++# CONFIG_NLS_MAC_CENTEURO is not set ++# CONFIG_NLS_MAC_CROATIAN is not set ++# CONFIG_NLS_MAC_CYRILLIC is not set ++# CONFIG_NLS_MAC_GAELIC is not set ++# CONFIG_NLS_MAC_GREEK is not set ++# CONFIG_NLS_MAC_ICELAND is not set ++# CONFIG_NLS_MAC_INUIT is not set ++# CONFIG_NLS_MAC_ROMANIAN is not set ++# CONFIG_NLS_MAC_TURKISH is not set ++CONFIG_NLS_UTF8=y ++# CONFIG_DLM is not set ++# CONFIG_UNICODE is not set ++CONFIG_IO_WQ=y ++# end of File systems ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY_DMESG_RESTRICT is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y ++# CONFIG_HARDENED_USERCOPY is not set ++# CONFIG_FORTIFY_SOURCE is not set ++# CONFIG_STATIC_USERMODEHELPER is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,bpf" ++ ++# ++# Kernel hardening options ++# ++ ++# ++# Memory initialization ++# ++CONFIG_INIT_STACK_NONE=y ++# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set ++# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set ++CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y ++# CONFIG_ZERO_CALL_USED_REGS is not set ++# end of Memory initialization ++# end of Kernel hardening options ++# end of Security options ++ ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++CONFIG_CRYPTO_ALGAPI=y ++CONFIG_CRYPTO_ALGAPI2=y ++CONFIG_CRYPTO_AEAD=y ++CONFIG_CRYPTO_AEAD2=y ++CONFIG_CRYPTO_SKCIPHER=y ++CONFIG_CRYPTO_SKCIPHER2=y ++CONFIG_CRYPTO_HASH=y ++CONFIG_CRYPTO_HASH2=y ++CONFIG_CRYPTO_RNG=y ++CONFIG_CRYPTO_RNG2=y ++CONFIG_CRYPTO_RNG_DEFAULT=y ++CONFIG_CRYPTO_AKCIPHER2=y ++CONFIG_CRYPTO_AKCIPHER=y ++CONFIG_CRYPTO_KPP2=y ++CONFIG_CRYPTO_KPP=y ++CONFIG_CRYPTO_ACOMP2=y ++CONFIG_CRYPTO_MANAGER=y ++CONFIG_CRYPTO_MANAGER2=y ++CONFIG_CRYPTO_USER=y ++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y ++CONFIG_CRYPTO_GF128MUL=y ++CONFIG_CRYPTO_NULL=y ++CONFIG_CRYPTO_NULL2=y ++# CONFIG_CRYPTO_CRYPTD is not set ++CONFIG_CRYPTO_AUTHENC=y ++# CONFIG_CRYPTO_TEST is not set ++CONFIG_CRYPTO_ENGINE=y ++ ++# ++# Public-key cryptography ++# ++CONFIG_CRYPTO_RSA=y ++# CONFIG_CRYPTO_DH is not set ++CONFIG_CRYPTO_ECC=y ++CONFIG_CRYPTO_ECDH=y ++# CONFIG_CRYPTO_ECDSA is not set ++# CONFIG_CRYPTO_ECRDSA is not set ++# CONFIG_CRYPTO_SM2 is not set ++# CONFIG_CRYPTO_CURVE25519 is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++CONFIG_CRYPTO_CCM=y ++CONFIG_CRYPTO_GCM=y ++# CONFIG_CRYPTO_CHACHA20POLY1305 is not set ++# CONFIG_CRYPTO_AEGIS128 is not set ++# CONFIG_CRYPTO_SEQIV is not set ++CONFIG_CRYPTO_ECHAINIV=y ++CONFIG_CRYPTO_TLS=y ++ ++# ++# Block modes ++# ++CONFIG_CRYPTO_CBC=y ++CONFIG_CRYPTO_CFB=y ++CONFIG_CRYPTO_CTR=y ++CONFIG_CRYPTO_CTS=y ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_LRW=y ++CONFIG_CRYPTO_OFB=y ++CONFIG_CRYPTO_PCBC=y ++CONFIG_CRYPTO_XTS=y ++# CONFIG_CRYPTO_KEYWRAP is not set ++# CONFIG_CRYPTO_ADIANTUM is not set ++CONFIG_CRYPTO_ESSIV=y ++ ++# ++# Hash modes ++# ++CONFIG_CRYPTO_CMAC=y ++CONFIG_CRYPTO_HMAC=y ++CONFIG_CRYPTO_XCBC=y ++CONFIG_CRYPTO_VMAC=y ++ ++# ++# Digest ++# ++CONFIG_CRYPTO_CRC32C=y ++# CONFIG_CRYPTO_CRC32 is not set ++CONFIG_CRYPTO_XXHASH=y ++CONFIG_CRYPTO_BLAKE2B=y ++CONFIG_CRYPTO_BLAKE2S=y ++CONFIG_CRYPTO_CRCT10DIF=y ++CONFIG_CRYPTO_GHASH=y ++# CONFIG_CRYPTO_POLY1305 is not set ++CONFIG_CRYPTO_MD4=y ++CONFIG_CRYPTO_MD5=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_RMD160=y ++CONFIG_CRYPTO_SHA1=y ++CONFIG_CRYPTO_SHA256=y ++CONFIG_CRYPTO_SHA512=y ++CONFIG_CRYPTO_SHA3=y ++CONFIG_CRYPTO_SM3=y ++CONFIG_CRYPTO_STREEBOG=y ++CONFIG_CRYPTO_WP512=y ++ ++# ++# Ciphers ++# ++CONFIG_CRYPTO_AES=y ++# CONFIG_CRYPTO_AES_TI is not set ++CONFIG_CRYPTO_ANUBIS=y ++CONFIG_CRYPTO_ARC4=y ++CONFIG_CRYPTO_BLOWFISH=y ++CONFIG_CRYPTO_BLOWFISH_COMMON=y ++CONFIG_CRYPTO_CAMELLIA=y ++CONFIG_CRYPTO_CAST_COMMON=y ++CONFIG_CRYPTO_CAST5=y ++CONFIG_CRYPTO_CAST6=y ++CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_FCRYPT=y ++CONFIG_CRYPTO_KHAZAD=y ++# CONFIG_CRYPTO_CHACHA20 is not set ++CONFIG_CRYPTO_SEED=y ++CONFIG_CRYPTO_SERPENT=y ++CONFIG_CRYPTO_SM4=y ++CONFIG_CRYPTO_TEA=y ++CONFIG_CRYPTO_TWOFISH=y ++CONFIG_CRYPTO_TWOFISH_COMMON=y ++ ++# ++# Compression ++# ++CONFIG_CRYPTO_DEFLATE=y ++CONFIG_CRYPTO_LZO=y ++# CONFIG_CRYPTO_842 is not set ++# CONFIG_CRYPTO_LZ4 is not set ++# CONFIG_CRYPTO_LZ4HC is not set ++CONFIG_CRYPTO_ZSTD=y ++ ++# ++# Random Number Generation ++# ++CONFIG_CRYPTO_ANSI_CPRNG=y ++CONFIG_CRYPTO_DRBG_MENU=y ++CONFIG_CRYPTO_DRBG_HMAC=y ++# CONFIG_CRYPTO_DRBG_HASH is not set ++# CONFIG_CRYPTO_DRBG_CTR is not set ++CONFIG_CRYPTO_DRBG=y ++CONFIG_CRYPTO_JITTERENTROPY=y ++CONFIG_CRYPTO_USER_API=y ++CONFIG_CRYPTO_USER_API_HASH=y ++CONFIG_CRYPTO_USER_API_SKCIPHER=y ++CONFIG_CRYPTO_USER_API_RNG=y ++# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set ++CONFIG_CRYPTO_USER_API_AEAD=y ++CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y ++# CONFIG_CRYPTO_STATS is not set ++CONFIG_CRYPTO_HW=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y ++CONFIG_CRYPTO_DEV_FSL_CAAM=y ++# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM_JR=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 ++# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API=y ++# CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API_TEST is not set ++# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE=7 ++# CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST is not set ++CONFIG_CRYPTO_DEV_SAHARA=y ++# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set ++# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set ++CONFIG_CRYPTO_DEV_MXS_DCP=y ++# CONFIG_CRYPTO_DEV_VIRTIO is not set ++# CONFIG_CRYPTO_DEV_SAFEXCEL is not set ++# CONFIG_CRYPTO_DEV_CCREE is not set ++# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set ++ ++# ++# Certificates for signature checking ++# ++# end of Certificates for signature checking ++ ++# ++# Library routines ++# ++CONFIG_LINEAR_RANGES=y ++# CONFIG_PACKING is not set ++CONFIG_BITREVERSE=y ++CONFIG_HAVE_ARCH_BITREVERSE=y ++CONFIG_GENERIC_STRNCPY_FROM_USER=y ++CONFIG_GENERIC_STRNLEN_USER=y ++CONFIG_GENERIC_NET_UTILS=y ++# CONFIG_CORDIC is not set ++# CONFIG_PRIME_NUMBERS is not set ++CONFIG_RATIONAL=y ++CONFIG_GENERIC_PCI_IOMAP=y ++CONFIG_STMP_DEVICE=y ++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y ++ ++# ++# Crypto library routines ++# ++CONFIG_CRYPTO_LIB_AES=y ++CONFIG_CRYPTO_LIB_ARC4=y ++CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y ++CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y ++CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=y ++# CONFIG_CRYPTO_LIB_CHACHA is not set ++# CONFIG_CRYPTO_LIB_CURVE25519 is not set ++CONFIG_CRYPTO_LIB_DES=y ++CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 ++CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=y ++# CONFIG_CRYPTO_LIB_POLY1305 is not set ++# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set ++CONFIG_CRYPTO_LIB_SHA256=y ++CONFIG_CRYPTO_LIB_SM4=y ++# end of Crypto library routines ++ ++CONFIG_LIB_MEMNEQ=y ++CONFIG_CRC_CCITT=y ++CONFIG_CRC16=y ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC_ITU_T=y ++CONFIG_CRC32=y ++# CONFIG_CRC32_SELFTEST is not set ++CONFIG_CRC32_SLICEBY8=y ++# CONFIG_CRC32_SLICEBY4 is not set ++# CONFIG_CRC32_SARWATE is not set ++# CONFIG_CRC32_BIT is not set ++# CONFIG_CRC64 is not set ++# CONFIG_CRC4 is not set ++CONFIG_CRC7=y ++CONFIG_LIBCRC32C=y ++# CONFIG_CRC8 is not set ++CONFIG_XXHASH=y ++# CONFIG_RANDOM32_SELFTEST is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++CONFIG_LZO_COMPRESS=y ++CONFIG_LZO_DECOMPRESS=y ++CONFIG_ZSTD_COMPRESS=y ++CONFIG_ZSTD_DECOMPRESS=y ++CONFIG_XZ_DEC=y ++CONFIG_XZ_DEC_X86=y ++CONFIG_XZ_DEC_POWERPC=y ++CONFIG_XZ_DEC_IA64=y ++CONFIG_XZ_DEC_ARM=y ++CONFIG_XZ_DEC_ARMTHUMB=y ++CONFIG_XZ_DEC_SPARC=y ++CONFIG_XZ_DEC_BCJ=y ++# CONFIG_XZ_DEC_TEST is not set ++CONFIG_GENERIC_ALLOCATOR=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_IOPORT_MAP=y ++CONFIG_HAS_DMA=y ++CONFIG_DMA_OPS=y ++CONFIG_NEED_DMA_MAP_STATE=y ++CONFIG_DMA_DECLARE_COHERENT=y ++CONFIG_ARCH_HAS_SETUP_DMA_OPS=y ++CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y ++CONFIG_DMA_NONCOHERENT_MMAP=y ++CONFIG_DMA_REMAP=y ++CONFIG_DMA_CMA=y ++# CONFIG_DMA_PERNUMA_CMA is not set ++ ++# ++# Default contiguous memory area size: ++# ++CONFIG_CMA_SIZE_MBYTES=16 ++CONFIG_CMA_SIZE_SEL_MBYTES=y ++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set ++# CONFIG_CMA_SIZE_SEL_MIN is not set ++# CONFIG_CMA_SIZE_SEL_MAX is not set ++CONFIG_CMA_ALIGNMENT=8 ++# CONFIG_DMA_API_DEBUG is not set ++CONFIG_SGL_ALLOC=y ++CONFIG_DQL=y ++CONFIG_GLOB=y ++# CONFIG_GLOB_SELFTEST is not set ++CONFIG_NLATTR=y ++CONFIG_CLZ_TAB=y ++# CONFIG_IRQ_POLL is not set ++CONFIG_MPILIB=y ++CONFIG_LIBFDT=y ++CONFIG_HAVE_GENERIC_VDSO=y ++CONFIG_GENERIC_GETTIMEOFDAY=y ++CONFIG_GENERIC_VDSO_32=y ++CONFIG_SBITMAP=y ++# end of Library routines ++ ++CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y ++ ++# ++# Kernel hacking ++# ++ ++# ++# printk and dmesg options ++# ++# CONFIG_PRINTK_TIME is not set ++# CONFIG_PRINTK_CALLER is not set ++# CONFIG_STACKTRACE_BUILD_ID is not set ++CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 ++CONFIG_CONSOLE_LOGLEVEL_QUIET=4 ++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 ++# CONFIG_BOOT_PRINTK_DELAY is not set ++# CONFIG_DYNAMIC_DEBUG is not set ++# CONFIG_DYNAMIC_DEBUG_CORE is not set ++# CONFIG_SYMBOLIC_ERRNAME is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++# end of printk and dmesg options ++ ++# ++# Compile-time checks and compiler options ++# ++# CONFIG_DEBUG_INFO is not set ++CONFIG_FRAME_WARN=1024 ++# CONFIG_STRIP_ASM_SYMS is not set ++# CONFIG_READABLE_ASM is not set ++# CONFIG_HEADERS_INSTALL is not set ++# CONFIG_DEBUG_SECTION_MISMATCH is not set ++# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set ++# CONFIG_VMLINUX_MAP is not set ++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set ++# end of Compile-time checks and compiler options ++ ++# ++# Generic Kernel Debugging Instruments ++# ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 ++CONFIG_MAGIC_SYSRQ_SERIAL=y ++CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" ++# CONFIG_DEBUG_FS is not set ++CONFIG_HAVE_ARCH_KGDB=y ++# CONFIG_KGDB is not set ++# CONFIG_UBSAN is not set ++CONFIG_HAVE_KCSAN_COMPILER=y ++# end of Generic Kernel Debugging Instruments ++ ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_MISC=y ++ ++# ++# Memory Debugging ++# ++# CONFIG_PAGE_EXTENSION is not set ++# CONFIG_DEBUG_PAGEALLOC is not set ++# CONFIG_PAGE_OWNER is not set ++# CONFIG_PAGE_POISONING is not set ++# CONFIG_DEBUG_RODATA_TEST is not set ++# CONFIG_DEBUG_WX is not set ++# CONFIG_DEBUG_OBJECTS is not set ++# CONFIG_SLUB_STATS is not set ++CONFIG_HAVE_DEBUG_KMEMLEAK=y ++# CONFIG_DEBUG_KMEMLEAK is not set ++# CONFIG_DEBUG_STACK_USAGE is not set ++# CONFIG_SCHED_STACK_END_CHECK is not set ++# CONFIG_DEBUG_VM is not set ++CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y ++# CONFIG_DEBUG_VIRTUAL is not set ++# CONFIG_DEBUG_MEMORY_INIT is not set ++CONFIG_HAVE_ARCH_KASAN=y ++CONFIG_CC_HAS_KASAN_GENERIC=y ++CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y ++# CONFIG_KASAN is not set ++# end of Memory Debugging ++ ++# CONFIG_DEBUG_SHIRQ is not set ++ ++# ++# Debug Oops, Lockups and Hangs ++# ++# CONFIG_PANIC_ON_OOPS is not set ++CONFIG_PANIC_ON_OOPS_VALUE=0 ++CONFIG_PANIC_TIMEOUT=0 ++# CONFIG_SOFTLOCKUP_DETECTOR is not set ++# CONFIG_DETECT_HUNG_TASK is not set ++# CONFIG_WQ_WATCHDOG is not set ++# CONFIG_TEST_LOCKUP is not set ++# end of Debug Oops, Lockups and Hangs ++ ++# ++# Scheduler Debugging ++# ++CONFIG_SCHED_DEBUG=y ++# CONFIG_SCHEDSTATS is not set ++# end of Scheduler Debugging ++ ++# CONFIG_DEBUG_TIMEKEEPING is not set ++CONFIG_DEBUG_PREEMPT=y ++ ++# ++# Lock Debugging (spinlocks, mutexes, etc...) ++# ++CONFIG_LOCK_DEBUGGING_SUPPORT=y ++# CONFIG_PROVE_LOCKING is not set ++# CONFIG_LOCK_STAT is not set ++# CONFIG_DEBUG_RT_MUTEXES is not set ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set ++# CONFIG_DEBUG_RWSEMS is not set ++# CONFIG_DEBUG_LOCK_ALLOC is not set ++# CONFIG_DEBUG_ATOMIC_SLEEP is not set ++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set ++# CONFIG_LOCK_TORTURE_TEST is not set ++# CONFIG_WW_MUTEX_SELFTEST is not set ++# CONFIG_SCF_TORTURE_TEST is not set ++# end of Lock Debugging (spinlocks, mutexes, etc...) ++ ++# CONFIG_DEBUG_IRQFLAGS is not set ++# CONFIG_STACKTRACE is not set ++# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set ++# CONFIG_DEBUG_KOBJECT is not set ++ ++# ++# Debug kernel data structures ++# ++# CONFIG_DEBUG_LIST is not set ++# CONFIG_DEBUG_PLIST is not set ++# CONFIG_DEBUG_SG is not set ++# CONFIG_DEBUG_NOTIFIERS is not set ++# CONFIG_BUG_ON_DATA_CORRUPTION is not set ++# end of Debug kernel data structures ++ ++# CONFIG_DEBUG_CREDENTIALS is not set ++ ++# ++# RCU Debugging ++# ++# CONFIG_RCU_SCALE_TEST is not set ++# CONFIG_RCU_TORTURE_TEST is not set ++# CONFIG_RCU_REF_SCALE_TEST is not set ++CONFIG_RCU_CPU_STALL_TIMEOUT=21 ++CONFIG_RCU_TRACE=y ++# CONFIG_RCU_EQS_DEBUG is not set ++# end of RCU Debugging ++ ++# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set ++# CONFIG_LATENCYTOP is not set ++CONFIG_HAVE_FUNCTION_TRACER=y ++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y ++CONFIG_HAVE_DYNAMIC_FTRACE=y ++CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y ++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y ++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y ++CONFIG_HAVE_C_RECORDMCOUNT=y ++CONFIG_TRACE_CLOCK=y ++CONFIG_TRACING_SUPPORT=y ++# CONFIG_FTRACE is not set ++# CONFIG_SAMPLES is not set ++ ++# ++# arm Debugging ++# ++# CONFIG_ARM_PTDUMP_DEBUGFS is not set ++# CONFIG_UNWINDER_FRAME_POINTER is not set ++CONFIG_UNWINDER_ARM=y ++CONFIG_ARM_UNWIND=y ++# CONFIG_DEBUG_USER is not set ++# CONFIG_DEBUG_LL is not set ++CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" ++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" ++# CONFIG_PID_IN_CONTEXTIDR is not set ++# CONFIG_CORESIGHT is not set ++# end of arm Debugging ++ ++# ++# Kernel Testing and Coverage ++# ++# CONFIG_KUNIT is not set ++# CONFIG_NOTIFIER_ERROR_INJECTION is not set ++# CONFIG_FAULT_INJECTION is not set ++CONFIG_ARCH_HAS_KCOV=y ++CONFIG_CC_HAS_SANCOV_TRACE_PC=y ++# CONFIG_KCOV is not set ++# CONFIG_RUNTIME_TESTING_MENU is not set ++CONFIG_ARCH_USE_MEMTEST=y ++# CONFIG_MEMTEST is not set ++# end of Kernel Testing and Coverage ++# end of Kernel hacking +diff --git a/arch/arm/configs/imx_avb.config b/arch/arm/configs/imx_avb.config +new file mode 100644 +index 000000000000..49b8d258c306 +--- /dev/null ++++ b/arch/arm/configs/imx_avb.config +@@ -0,0 +1,8 @@ ++CONFIG_EXPERT=y ++CONFIG_PREEMPT_RT=y ++CONFIG_AVB_SUPPORT=y ++CONFIG_NET_SWITCHDEV=y ++CONFIG_DEBUG_INFO=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y +diff --git a/arch/arm/configs/imx_up.config b/arch/arm/configs/imx_up.config +new file mode 100644 +index 000000000000..18b877a41fa7 +--- /dev/null ++++ b/arch/arm/configs/imx_up.config +@@ -0,0 +1,2 @@ ++CONFIG_SMP=n ++CONFIG_HIGHMEM=n +diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig +index 591aaaeffc04..b9dc12e991e2 100644 +--- a/arch/arm/configs/imx_v6_v7_defconfig ++++ b/arch/arm/configs/imx_v6_v7_defconfig +@@ -49,7 +49,8 @@ CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" + CONFIG_KEXEC=y + CONFIG_CPU_FREQ=y + CONFIG_CPU_FREQ_STAT=y +-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_STAT_DETAILS=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y + CONFIG_CPU_FREQ_GOV_POWERSAVE=y + CONFIG_CPU_FREQ_GOV_USERSPACE=y + CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig +index 87c777f33baa..bd5ee5bf5ec9 100644 +--- a/arch/arm/configs/imx_v7_defconfig ++++ b/arch/arm/configs/imx_v7_defconfig +@@ -25,7 +25,7 @@ CONFIG_SOC_IMX6SLL=y + CONFIG_SOC_IMX6SX=y + CONFIG_SOC_IMX6UL=y + CONFIG_SOC_IMX7D=y +-CONFIG_SOC_IMX7ULP=y ++# CONFIG_SOC_IMX7ULP is not set + CONFIG_SMP=y + CONFIG_VMSPLIT_2G=y + CONFIG_ARM_PSCI=y +@@ -35,7 +35,8 @@ CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" + CONFIG_KEXEC=y + CONFIG_CPU_FREQ=y + CONFIG_CPU_FREQ_STAT=y +-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_STAT_DETAILS=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y + CONFIG_CPU_FREQ_GOV_POWERSAVE=y + CONFIG_CPU_FREQ_GOV_USERSPACE=y + CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +@@ -287,7 +288,7 @@ CONFIG_REGULATOR_LTC3676=y + CONFIG_REGULATOR_MAX17135=y + CONFIG_REGULATOR_MC13783=y + CONFIG_REGULATOR_MC13892=y +-CONFIG_REGULATOR_PF1550_RPMSG=y ++# CONFIG_REGULATOR_PF1550_RPMSG is not set + CONFIG_REGULATOR_PFUZE100=y + CONFIG_REGULATOR_RN5T618=y + CONFIG_RC_CORE=y +@@ -594,3 +595,5 @@ CONFIG_CRYPTO_SM3_GENERIC=m + CONFIG_CRYPTO_SM4_GENERIC=m + CONFIG_CRYPTO_ARIA=m + CONFIG_CRYPTO_POLYVAL_ARM64_CE=m ++ ++CONFIG_PREEMPT_RT=y +diff --git a/arch/arm/configs/lsdk.config b/arch/arm/configs/lsdk.config +index d10724fbff81..1fcf47b5c19d 100644 +--- a/arch/arm/configs/lsdk.config ++++ b/arch/arm/configs/lsdk.config +@@ -64,6 +64,26 @@ CONFIG_IP6_NF_NAT=y + CONFIG_IP6_NF_FILTER=y + CONFIG_NETFILTER_XT_MATCH_COMMENT=y + ++# can ++CONFIG_CAN_FLEXCAN=y ++# dspi ++CONFIG_SPI_BITBANG=y ++CONFIG_SPI_FSL_DSPI=y ++# watchdog ++CONFIG_IMX2_WDT=y ++# sound ++CONFIG_SND_MIXER_OSS=y ++CONFIG_SND_PCM_OSS=y ++CONFIG_SND_SOC_FSL_SAI=y ++CONFIG_SND_SOC_SGTL5000=y ++CONFIG_SND_SIMPLE_CARD=y ++# Video ++CONFIG_FB=y ++CONFIG_FB_FSL_DCU=y ++CONFIG_FB_FSL_SII902X=y ++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y ++CONFIG_LOGO=y ++CONFIG_SOC_VF610=n + # filesystems + CONFIG_EXT4_FS_POSIX_ACL=y + CONFIG_EXT4_FS_SECURITY=y +diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig +index a20a26c864fe..f6710d000cf4 100644 +--- a/arch/arm/configs/multi_v7_defconfig ++++ b/arch/arm/configs/multi_v7_defconfig +@@ -1276,3 +1276,5 @@ CONFIG_CMA_SIZE_MBYTES=64 + CONFIG_PRINTK_TIME=y + CONFIG_MAGIC_SYSRQ=y + CONFIG_DEBUG_FS=y ++# PREEMPT RT ++CONFIG_PREEMPT_RT=y +\ No newline at end of file +diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h +index 2799dc6a8a81..d10630ddf491 100644 +--- a/arch/arm/include/asm/thread_info.h ++++ b/arch/arm/include/asm/thread_info.h +@@ -64,6 +64,7 @@ struct cpu_context_save { + struct thread_info { + unsigned long flags; /* low level flags */ + int preempt_count; /* 0 => preemptable, <0 => bug */ ++ int preempt_lazy_count; /* 0 => preemptable, <0 => bug */ + mm_segment_t addr_limit; /* address limit */ + __u32 cpu; /* cpu */ + __u32 cpu_domain; /* cpu domain */ +@@ -133,6 +134,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, + #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ + #define TIF_UPROBE 3 /* breakpointed or singlestepping */ + #define TIF_NOTIFY_SIGNAL 4 /* signal notifications exist */ ++#define TIF_NEED_RESCHED_LAZY 5 + + #define TIF_USING_IWMMXT 17 + #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ +@@ -152,6 +154,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, + #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) + #define _TIF_SECCOMP (1 << TIF_SECCOMP) + #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) ++#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) + #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) + + /* Checks for any syscall work in entry-common.S */ +@@ -161,7 +164,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, + /* + * Change these and you break ASM code in entry-common.S + */ +-#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ ++#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \ ++ _TIF_SIGPENDING | \ + _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ + _TIF_NOTIFY_SIGNAL) + +diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c +index 69eab049ea09..1e91df6537d9 100644 +--- a/arch/arm/kernel/asm-offsets.c ++++ b/arch/arm/kernel/asm-offsets.c +@@ -2,7 +2,7 @@ + /* + * Copyright (C) 1995-2003 Russell King + * 2001-2002 Keith Owens +- * ++ * + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed to extract + * and format the required data. +@@ -43,6 +43,7 @@ int main(void) + BLANK(); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); ++ DEFINE(TI_PREEMPT_LAZY, offsetof(struct thread_info, preempt_lazy_count)); + DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain)); +@@ -171,5 +172,5 @@ int main(void) + DEFINE(KEXEC_INDIR_PAGE, offsetof(struct kexec_relocate_data, kexec_indirection_page)); + DEFINE(KEXEC_MACH_TYPE, offsetof(struct kexec_relocate_data, kexec_mach_type)); + DEFINE(KEXEC_R2, offsetof(struct kexec_relocate_data, kexec_r2)); +- return 0; ++ return 0; + } +diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S +index c39303e5c234..cfb4660e9fea 100644 +--- a/arch/arm/kernel/entry-armv.S ++++ b/arch/arm/kernel/entry-armv.S +@@ -222,11 +222,18 @@ __irq_svc: + + #ifdef CONFIG_PREEMPTION + ldr r8, [tsk, #TI_PREEMPT] @ get preempt count +- ldr r0, [tsk, #TI_FLAGS] @ get flags + teq r8, #0 @ if preempt count != 0 ++ bne 1f @ return from exeption ++ ldr r0, [tsk, #TI_FLAGS] @ get flags ++ tst r0, #_TIF_NEED_RESCHED @ if NEED_RESCHED is set ++ blne svc_preempt @ preempt! ++ ++ ldr r8, [tsk, #TI_PREEMPT_LAZY] @ get preempt lazy count ++ teq r8, #0 @ if preempt lazy count != 0 + movne r0, #0 @ force flags to 0 +- tst r0, #_TIF_NEED_RESCHED ++ tst r0, #_TIF_NEED_RESCHED_LAZY + blne svc_preempt ++1: + #endif + + svc_exit r5, irq = 1 @ return from exception +@@ -241,8 +248,14 @@ svc_preempt: + 1: bl preempt_schedule_irq @ irq en/disable is done inside + ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS + tst r0, #_TIF_NEED_RESCHED ++ bne 1b ++ tst r0, #_TIF_NEED_RESCHED_LAZY + reteq r8 @ go again +- b 1b ++ ldr r0, [tsk, #TI_PREEMPT_LAZY] @ get preempt lazy count ++ teq r0, #0 @ if preempt lazy count != 0 ++ beq 1b ++ ret r8 @ go again ++ + #endif + + __und_fault: +diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c +index 688400336ef1..f2a5049c7083 100644 +--- a/arch/arm/kernel/signal.c ++++ b/arch/arm/kernel/signal.c +@@ -607,7 +607,8 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) + */ + trace_hardirqs_off(); + do { +- if (likely(thread_flags & _TIF_NEED_RESCHED)) { ++ if (likely(thread_flags & (_TIF_NEED_RESCHED | ++ _TIF_NEED_RESCHED_LAZY))) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) +diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c +index 978db2d96b44..c0b43ac8db6e 100644 +--- a/arch/arm/kernel/smp.c ++++ b/arch/arm/kernel/smp.c +@@ -51,6 +51,10 @@ + #define CREATE_TRACE_POINTS + #include + ++#ifdef CONFIG_BAREMETAL ++#include ++#endif ++ + /* + * as from 2.5, kernels no longer have an init_tasks structure + * so we need some other way of telling a new secondary core +@@ -66,6 +70,9 @@ enum ipi_msg_type { + IPI_CPU_STOP, + IPI_IRQ_WORK, + IPI_COMPLETION, ++#ifdef CONFIG_BAREMETAL ++ IPI_BAREMETAL_COMM = 8, ++#endif + NR_IPI, + /* + * CPU_BACKTRACE is special and not included in NR_IPI +@@ -542,6 +549,9 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { + [IPI_CPU_STOP] = "CPU stop interrupts", + [IPI_IRQ_WORK] = "IRQ work interrupts", + [IPI_COMPLETION] = "completion interrupts", ++#ifdef CONFIG_BAREMETAL ++ [IPI_BAREMETAL_COMM] = "Baremetal inter-core interrupts", ++#endif + }; + + static void smp_cross_call(const struct cpumask *target, unsigned int ipinr); +@@ -673,6 +683,18 @@ static void do_handle_IPI(int ipinr) + ipi_complete(cpu); + break; + ++#ifdef CONFIG_BAREMETAL ++#define GICC_IAR_MASK 0x1fff ++ case IPI_BAREMETAL_COMM: { ++ /* FIXME: use the fixed source coreID from core1 */ ++ int irqsrc = 1; ++ /*linux core is 0 core, so iterate from 1 core.*/ ++ for(irqsrc = 1; irqsrc < CONFIG_MAX_CPUS; irqsrc++) ++ ipi_baremetal_handle(ipinr, irqsrc); ++ } ++ break; ++#endif ++ + case IPI_CPU_BACKTRACE: + printk_deferred_enter(); + nmi_cpu_backtrace(get_irq_regs()); +diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig +index 0e672fc9a80f..1ee568a27ff5 100644 +--- a/arch/arm/mach-imx/Kconfig ++++ b/arch/arm/mach-imx/Kconfig +@@ -217,6 +217,16 @@ config SOC_LS1021A + help + This enables support for Freescale LS1021A processor. + ++config LS1021A_BAREMETAL ++ bool "NXP LS1021A baremetal support" ++ depends on SOC_LS1021A ++ select BAREMETAL ++ ++config SOC_IMX6Q_BAREMETAL ++ bool "NXP IMX6Q baremetal support" ++ depends on SOC_IMX6Q ++ select BAREMETAL ++ + endif + + if ARCH_MULTI_V7 || ARM_SINGLE_ARMV7M +diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c +index b0db85310331..77877dcb54ed 100644 +--- a/arch/arm/mm/fault.c ++++ b/arch/arm/mm/fault.c +@@ -400,6 +400,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, + if (addr < TASK_SIZE) + return do_page_fault(addr, fsr, regs); + ++ if (interrupts_enabled(regs)) ++ local_irq_enable(); ++ + if (user_mode(regs)) + goto bad_area; + +@@ -470,6 +473,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, + static int + do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + { ++ if (interrupts_enabled(regs)) ++ local_irq_enable(); ++ + do_bad_area(addr, fsr, regs); + return 0; + } +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0002-RT-add-RT-localversion.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0002-RT-add-RT-localversion.patch new file mode 100644 index 000000000..f7c7d3ee4 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0002-RT-add-RT-localversion.patch @@ -0,0 +1,21 @@ +From 5a9357f51ccd92dd11f188a14edf4b92ba1543ee Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Fri, 23 Feb 2024 10:12:23 +0100 +Subject: [PATCH 02/10] RT: add RT localversion + +Signed-off-by: Mike Engel +--- + localversion-rt | 1 + + 1 file changed, 1 insertion(+) + create mode 100644 localversion-rt + +diff --git a/localversion-rt b/localversion-rt +new file mode 100644 +index 000000000000..6e44e540b927 +--- /dev/null ++++ b/localversion-rt +@@ -0,0 +1 @@ ++-rt12 +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0003-arch-arm64-add-NXP-RT-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0003-arch-arm64-add-NXP-RT-support.patch new file mode 100644 index 000000000..95badd0d6 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0003-arch-arm64-add-NXP-RT-support.patch @@ -0,0 +1,5862 @@ +From 163328f80e9cf316752e46023857fb5939140652 Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Fri, 23 Feb 2024 12:20:36 +0100 +Subject: [PATCH 03/10] arch:arm64: add NXP RT support + +Signed-off-by: Mike Engel +--- + arch/arm64/Kconfig | 2 + + arch/arm64/Kconfig.platforms | 30 ++ + arch/arm64/boot/dts/freescale/Makefile | 54 ++- + .../boot/dts/freescale/fii-ls1028a-tsn.dts | 325 ++++++++++++++++++ + .../fsl-ls1028a-rdb-dsa-swp5-eno3.dts | 37 ++ + ...sl-ls1028a-rdb-jailhouse-without-enetc.dts | 98 ++++++ + .../freescale/fsl-ls1028a-rdb-jailhouse.dts | 59 ++++ + .../dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts | 15 + + .../boot/dts/freescale/fsl-ls1028a-rdb.dts | 25 ++ + .../arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 2 +- + .../dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts | 44 +++ + ...sl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts | 263 ++++++++++++++ + .../fsl-ls1043a-rdb-sdk-jailhouse.dts | 267 ++++++++++++++ + .../arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 2 +- + .../dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts | 47 +++ + ...sl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts | 274 +++++++++++++++ + .../fsl-ls1046a-rdb-sdk-jailhouse.dts | 278 +++++++++++++++ + .../arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 2 +- + .../boot/dts/freescale/imx8-ss-audio.dtsi | 20 ++ + .../dts/freescale/imx8dxl-evk-enet0-avb.dts | 9 + + .../dts/freescale/imx8dxl-evk-enet0-avb.dtsi | 54 +++ + .../freescale/imx8dxl-evk-enet0-sja1105.dts | 168 +++++++++ + .../imx8dxl-evk-enet0-tja1100-avb.dts | 9 + + arch/arm64/boot/dts/freescale/imx8dxl-evk.dts | 58 ++++ + .../boot/dts/freescale/imx8dxl-ss-adma.dtsi | 1 + + .../dts/freescale/imx8m-generic-mbox-1.dtsi | 27 ++ + .../dts/freescale/imx8m-generic-mbox.dtsi | 27 ++ + .../dts/freescale/imx8m-rpmsg-ca53-1.dtsi | 37 ++ + .../boot/dts/freescale/imx8m-rpmsg-ca53.dtsi | 37 ++ + .../boot/dts/freescale/imx8mm-evk-avb.dts | 37 ++ + .../dts/freescale/imx8mm-evk-baremetal.dts | 39 +++ + .../boot/dts/freescale/imx8mm-evk-ecat.dts | 10 + + .../freescale/imx8mm-evk-multicore-rpmsg.dts | 10 + + .../freescale/imx8mm-evk-multicore-rtos.dts | 79 +++++ + .../dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts | 228 ++++++++++++ + .../dts/freescale/imx8mm-evk-rpmsg-ca53.dts | 39 +++ + .../boot/dts/freescale/imx8mm-evk-rpmsg.dts | 96 +++++- + .../freescale/imx8mm-evk-virtio-net-ca53.dts | 82 +++++ + .../freescale/imx8mm-evk-virtio-net-cm4.dts | 81 +++++ + .../freescale/imx8mm-evk-virtio-perf-ca53.dts | 78 +++++ + .../freescale/imx8mm-evk-virtio-perf-cm4.dts | 70 ++++ + arch/arm64/boot/dts/freescale/imx8mm.dtsi | 11 + + .../boot/dts/freescale/imx8mp-evk-avb.dts | 42 +++ + .../dts/freescale/imx8mp-evk-baremetal.dts | 37 ++ + .../boot/dts/freescale/imx8mp-evk-dsa.dts | 79 +++++ + .../boot/dts/freescale/imx8mp-evk-ecat.dts | 10 + + .../freescale/imx8mp-evk-multicore-lwip.dts | 21 ++ + .../freescale/imx8mp-evk-multicore-rpmsg.dts | 117 +++++++ + .../freescale/imx8mp-evk-multicore-rtos.dts | 79 +++++ + .../freescale/imx8mp-evk-virtio-net-ca53.dts | 81 +++++ + .../freescale/imx8mp-evk-virtio-net-cm7.dts | 72 ++++ + .../dts/freescale/imx8mp-generic-mbox-1.dtsi | 27 ++ + .../dts/freescale/imx8mp-generic-mbox.dtsi | 27 ++ + .../dts/freescale/imx8mp-rpmsg-ca53-1.dtsi | 37 ++ + .../boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi | 37 ++ + arch/arm64/boot/dts/freescale/imx8mp.dtsi | 10 + + .../dts/freescale/imx93-11x11-evk-avb.dts | 41 +++ + .../freescale/imx93-11x11-evk-baremetal.dts | 31 ++ + .../dts/freescale/imx93-11x11-evk-dsa.dts | 96 ++++++ + .../dts/freescale/imx93-11x11-evk-ecat.dts | 11 + + .../imx93-11x11-evk-multicore-rtos.dts | 38 ++ + .../imx93-11x11-evk-uart-sharing-cm33.dts | 96 ++++++ + .../imx93-11x11-evk-virtio-net-ca55.dts | 55 +++ + .../imx93-11x11-evk-virtio-net-cm33.dts | 53 +++ + .../boot/dts/freescale/imx93-11x11-evk.dts | 60 +++- + .../dts/freescale/imx93-9x9-qsb-baremetal.dts | 31 ++ + .../dts/freescale/imx93-9x9-qsb-inmate.dts | 151 ++++++++ + .../boot/dts/freescale/imx93-9x9-qsb-root.dts | 54 +++ + .../imx93-9x9-qsb-uart-sharing-cm33.dts | 96 ++++++ + .../boot/dts/freescale/imx93-9x9-qsb.dts | 58 ++++ + .../dts/freescale/imx93-generic-mbox.dtsi | 27 ++ + arch/arm64/configs/imx_avb.config | 8 + + arch/arm64/configs/imx_v8_defconfig | 38 +- + arch/arm64/configs/linux-dpaa-ethercat.config | 1 + + arch/arm64/configs/linux-rpmsg-8m-buf.config | 1 + + arch/arm64/configs/lsdk.config | 25 +- + arch/arm64/include/asm/preempt.h | 25 +- + arch/arm64/include/asm/thread_info.h | 8 +- + arch/arm64/kernel/asm-offsets.c | 1 + + arch/arm64/kernel/signal.c | 2 +- + arch/arm64/kernel/smp.c | 25 ++ + 81 files changed, 4813 insertions(+), 26 deletions(-) + create mode 100644 arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts + create mode 100755 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts + create mode 100755 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts + create mode 100755 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts + create mode 100755 arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts + create mode 100644 arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi + create mode 100644 arch/arm64/configs/imx_avb.config + create mode 100644 arch/arm64/configs/linux-dpaa-ethercat.config + create mode 100644 arch/arm64/configs/linux-rpmsg-8m-buf.config + +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 386c2f1f5c86..5f0415085211 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -93,6 +93,7 @@ config ARM64 + select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 + select ARCH_SUPPORTS_NUMA_BALANCING + select ARCH_SUPPORTS_PAGE_TABLE_CHECK ++ select ARCH_SUPPORTS_RT + select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT + select ARCH_WANT_DEFAULT_BPF_JIT + select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT +@@ -199,6 +200,7 @@ config ARM64 + select HAVE_PERF_USER_STACK_DUMP + select HAVE_PREEMPT_DYNAMIC_KEY + select HAVE_REGS_AND_STACK_ACCESS_API ++ select HAVE_PREEMPT_LAZY + select HAVE_POSIX_CPU_TIMERS_TASK_WORK + select HAVE_FUNCTION_ARG_ACCESS_API + select MMU_GATHER_RCU_TABLE_FREE +diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms +index d7ff250db02a..fb56a84ab54f 100644 +--- a/arch/arm64/Kconfig.platforms ++++ b/arch/arm64/Kconfig.platforms +@@ -204,6 +204,24 @@ config ARCH_LAYERSCAPE + help + This enables support for the Freescale Layerscape SoC family. + ++config LS104XA_BAREMETAL ++ bool "NXP LS1043A/LS1046A baremetal support" ++ select BAREMETAL ++ help ++ This enables support for Freescale LS1043A and LS1046A baremetal. ++ ++config LS1028A_BAREMETAL ++ bool "NXP LS1028A baremetal support" ++ select BAREMETAL ++ help ++ This enables support for NXP LS1028A baremetal. ++ ++config LX2160A_BAREMETAL ++ bool "NXP LX2160A baremetal support" ++ select BAREMETAL ++ help ++ This enables support for NXP LX2160A baremetal. ++ + config ARCH_MXC + bool "ARMv8 based NXP i.MX SoC family" + select ARM64_ERRATUM_843419 +@@ -251,6 +269,18 @@ config ARCH_NPCM + General support for NPCM8xx BMC (Arbel). + Nuvoton NPCM8xx BMC based on the Cortex A35. + ++config IMX8M_BAREMETAL ++ bool "NXP IMX8MM/IMX8MP baremetal support" ++ select BAREMETAL ++ help ++ This enables support for NXP i.MX8MM and i.MX8MP baremetal. ++ ++config IMX93_BAREMETAL ++ bool "NXP IMX93 baremetal support" ++ select BAREMETAL ++ help ++ This enables support for NXP i.MX93 baremetal. ++ + config ARCH_QCOM + bool "Qualcomm Platforms" + select GPIOLIB +diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile +index 40006fbe1a43..ad95bb0acce5 100644 +--- a/arch/arm64/boot/dts/freescale/Makefile ++++ b/arch/arm64/boot/dts/freescale/Makefile +@@ -14,11 +14,19 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-kontron-sl28-var3-ads2.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-kontron-sl28-var4.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-jailhouse.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-dpdk.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-jailhouse-without-enetc.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-sdk-bm.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-dsa-swp5-eno3.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fii-ls1028a-tsn.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds-sdk.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk-jailhouse.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk-bm.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-usdpaa.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy-sdk.dtb +@@ -26,7 +34,10 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy-usdpaa.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds-sdk.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk-bm.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk-jailhouse.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-usdpaa.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-shared-mac9-only.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-usdpaa-shared-mac10.dtb +@@ -68,13 +79,29 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-ab2.dtb imx8mm-ab2-m4.dtb imx8mm-ddr4-ab2.dtb i + dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb imx8mm-evk-rpmsg.dtb imx8mm-evk-rm67191.dtb \ + imx8mm-evk-root.dtb imx8mm-evk-inmate.dtb imx8mm-evk-revb-qca-wifi.dtb \ + imx8mm-evk-ecspi-slave.dtb \ ++ imx8mm-evk-baremetal.dtb \ ++ imx8mm-evk-avb.dtb \ + imx8mm-evk-pcie-ep.dtb \ + imx8mm-evk-usd-wifi.dtb \ + imx8mm-evk-qca-wifi.dtb \ + imx8mm-evk-dpdk.dtb \ + imx8mm-evk-rm67199.dtb imx8mm-evk-rm67191-cmd-ram.dtb imx8mm-evk-rm67199-cmd-ram.dtb \ +- imx8mm-evk-lk.dtb imx8mm-evk-rpmsg-wm8524-lpv.dtb ++ imx8mm-evk-lk.dtb imx8mm-evk-rpmsg-wm8524-lpv.dtb \ ++ imx8mm-evk-rpmsg-8m-buf.dtb \ ++ imx8mm-evk-ecat.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-rpmsg-wm8524.dtb ++dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-rpmsg-ca53.dtb \ ++ imx8mm-evk-virtio-perf-ca53.dtb \ ++ imx8mm-evk-virtio-perf-cm4.dtb \ ++ imx8mm-evk-virtio-net-ca53.dtb \ ++ imx8mm-evk-virtio-net-cm4.dtb \ ++ imx8mm-evk-multicore-rtos.dtb \ ++ imx8mm-evk-multicore-rpmsg.dtb \ ++ imx8mp-evk-virtio-net-ca53.dtb \ ++ imx8mp-evk-virtio-net-cm7.dtb \ ++ imx8mp-evk-multicore-rtos.dtb \ ++ imx8mp-evk-multicore-lwip.dtb \ ++ imx8mp-evk-multicore-rpmsg.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-ak4497.dtb imx8mm-evk-ak5558.dtb imx8mm-evk-audio-tdm.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-8mic-revE.dtb imx8mm-evk-8mic-swpdm.dtb \ + imx8mm-evk-iqaudio-dacplus.dtb imx8mm-evk-iqaudio-dacpro.dtb imx8mm-evk-hifiberry-dacplus.dtb \ +@@ -124,12 +151,15 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb imx8mp-evk-rm67191.dtb imx8mp-evk-it626 + imx8mp-evk-iqaudio-dacplus.dtb imx8mp-evk-iqaudio-dacpro.dtb imx8mp-evk-hifiberry-dacplus.dtb \ + imx8mp-evk-hifiberry-dac2.dtb imx8mp-evk-hifiberry-dacplusadc.dtb \ + imx8mp-evk-usdhc1-m2.dtb imx8mp-evk-rm67199.dtb \ +- imx8mp-evk-dpdk.dtb imx8mp-evk-8mic-swpdm.dtb imx8mp-evk-rpmsg-lpv.dtb imx8mp-evk-revA3-8mic-revE.dtb ++ imx8mp-evk-dpdk.dtb imx8mp-evk-8mic-swpdm.dtb imx8mp-evk-rpmsg-lpv.dtb imx8mp-evk-revA3-8mic-revE.dtb \ ++ imx8mp-evk-baremetal.dtb imx8mp-evk-avb.dtb \ ++ imx8mp-evk-ecat.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-msc-sm2s-ep1.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-ab2.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-ddr4-evk.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-ndm.dtb ++dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-dsa.dtb + + imx8mp-evk-revb4-dtbs := imx8mp-evk.dtb imx8mp-evk-revb4.dtbo + imx8mp-evk-revb4-rm67191-dtbs := imx8mp-evk-rm67191.dtb imx8mp-evk-revb4.dtbo +@@ -162,6 +192,7 @@ imx8mp-evk-revb4-8mic-swpdm-dtbs := imx8mp-evk-8mic-swpdm.dtb imx8mp-evk-revb4.d + imx8mp-evk-revb4-8mic-revE-dtbs := imx8mp-evk-revA3-8mic-revE.dtb imx8mp-evk-revb4.dtbo + imx8mp-ddr4-evk-revb4-dtbs := imx8mp-ddr4-evk.dtb imx8mp-evk-revb4.dtbo + imx8mp-evk-revb4-ndm-dtbs := imx8mp-evk-ndm.dtb imx8mp-evk-revb4.dtbo ++imx8mp-evk-revb4-dsa-dtbs := imx8mp-evk-dsa.dtb imx8mp-evk-revb4.dtbo + + dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-rm67191.dtb +@@ -197,6 +228,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-ndm.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-sof-wm8962.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-rpmsg.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-rpmsg-lpv.dtb ++dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-dsa.dtb + + dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb imx8mq-evk-rpmsg.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb imx8mq-evk-rpmsg.dtb imx8mq-evk-pcie1-m2.dtb imx8mq-evk-usd-wifi.dtb \ +@@ -298,7 +330,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qm-mek-revd-root.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8qxp-ai_ml.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-eval-v3.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8dxl-evk.dtb \ +- imx8dxl-evk-enet0.dtb imx8dxl-evk-enet0-tja1100.dtb \ ++ imx8dxl-evk-enet0.dtb imx8dxl-evk-enet0-tja1100.dtb imx8dxl-evk-enet0-tja1100-avb.dtb \ ++ imx8dxl-evk-enet0-avb.dtb imx8dxl-evk-enet0-sja1105.dtb \ + imx8dxl-evk-pcie-ep.dtb \ + imx8dxl-evk-lcdif.dtb \ + imx8dxl-evk-lpspi-slave.dtb \ +@@ -359,6 +392,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-14x14-evk.dtb \ + imx93-14x14-evk-lvds-it6263.dtb imx93-14x14-evk-sja1105.dtb \ + imx93-14x14-evk-flexspi-m2.dtb imx93-14x14-evk-dsi-serdes.dtb + dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb \ ++ imx93-11x11-evk-avb.dtb \ + imx93-11x11-evk-inmate.dtb imx93-11x11-evk-root.dtb imx93-11x11-evk-flexio-i2c.dtb \ + imx93-11x11-evk-lpspi.dtb imx93-11x11-evk-lpspi-slave.dtb \ + imx93-11x11-evk-i3c.dtb imx93-11x11-evk-lpuart.dtb \ +@@ -367,7 +401,14 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb \ + imx93-11x11-evk-flexspi-m2.dtb \ + imx93-11x11-evk-mt9m114.dtb \ + imx93-11x11-evk-ld.dtb \ +- imx93-11x11-evk-rpmsg.dtb imx93-11x11-evk-rpmsg-lpv.dtb ++ imx93-11x11-evk-rpmsg.dtb imx93-11x11-evk-rpmsg-lpv.dtb \ ++ imx93-11x11-evk-virtio-net-ca55.dtb \ ++ imx93-11x11-evk-virtio-net-cm33.dtb \ ++ imx93-11x11-evk-uart-sharing-cm33.dtb \ ++ imx93-11x11-evk-baremetal.dtb \ ++ imx93-11x11-evk-ecat.dtb \ ++ imx93-11x11-evk-multicore-rtos.dtb \ ++ imx93-11x11-evk-dsa.dtb + dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb \ + imx93-9x9-qsb-can1.dtb \ + imx93-9x9-qsb-flexspi-m2.dtb \ +@@ -375,8 +416,11 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb \ + imx93-9x9-qsb-mt9m114.dtb \ + imx93-9x9-qsb-i3c.dtb \ + imx93-9x9-qsb-lpspi.dtb imx93-9x9-qsb-lpspi-slave.dtb \ ++ imx93-9x9-qsb-baremetal.dtb \ + imx93-9x9-qsb-ld.dtb imx93-9x9-qsb-aud-hat.dtb \ +- imx93-9x9-qsb-rpmsg.dtb imx93-9x9-qsb-rpmsg-lpv.dtb ++ imx93-9x9-qsb-rpmsg.dtb imx93-9x9-qsb-rpmsg-lpv.dtb \ ++ imx93-9x9-qsb-uart-sharing-cm33.dtb \ ++ imx93-9x9-qsb-inmate.dtb imx93-9x9-qsb-root.dtb + + dtb-$(CONFIG_ARCH_MXC) += imx91p-9x9-qsb.dtb imx91p-9x9-qsb-aud-hat.dtb \ + imx91p-9x9-qsb-mt9m114.dtb \ +diff --git a/arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts b/arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts +new file mode 100644 +index 000000000000..a28b47206334 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts +@@ -0,0 +1,325 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Device Tree file for Foxconn LS1028A TSN Board. ++ * ++ * Copyright 2020-2022 NXP ++ * ++ * Wes Li ++ * Vladimir Oltean ++ */ ++ ++/dts-v1/; ++#include "fsl-ls1028a.dtsi" ++ ++/ { ++ model = "Foxconn LS1028A TSN Board"; ++ compatible = "fsl,ls1028a-rdb", "fsl,ls1028a"; ++ ++ aliases { ++ crypto = &crypto; ++ serial0 = &duart0; ++ serial1 = &duart1; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x0 0x80000000 0x1 0x0000000>; ++ }; ++ ++ sys_mclk: clock-mclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "1P8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ ++ sb_3v3: regulator-sb3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "3v3_vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&dspi2 { ++ bus-num = <2>; ++ status = "okay"; ++ ++ sja1105_switch0: ethernet-switch@0 { ++ reg = <0x0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "nxp,sja1105s"; ++ dsa,member = <1 1>; ++ /* 20 MHz */ ++ spi-max-frequency = <20000000>; ++ /* Sample data on trailing clock edge */ ++ spi-cpha; ++ /* SPI controller settings for SJA1105 timing requirements */ ++ fsl,spi-cs-sck-delay = <1000>; ++ fsl,spi-sck-cs-delay = <1000>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ label = "sw0p0"; ++ phy-handle = <&sw0p0_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ reg = <0>; ++ }; ++ ++ port@1 { ++ label = "sw0p1"; ++ phy-handle = <&sw0p1_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ reg = <1>; ++ }; ++ ++ port@2 { ++ label = "sw0p2"; ++ phy-handle = <&sw0p2_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ reg = <2>; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ status = "disabled"; ++ }; ++ ++ port@4 { ++ ethernet = <&mscc_felix_port0>; ++ phy-mode = "sgmii"; ++ reg = <4>; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++ }; ++ ++ /* Daughter card 1 */ ++ sja1105_switch1: ethernet-switch@1 { ++ reg = <0x1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "nxp,sja1105s"; ++ dsa,member = <2 2>; ++ /* 20 MHz */ ++ spi-max-frequency = <20000000>; ++ spi-cpha; ++ fsl,spi-cs-sck-delay = <1000>; ++ fsl,spi-sck-cs-delay = <1000>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ label = "sw1p0"; ++ phy-handle = <&sw1p0_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ reg = <0>; ++ }; ++ ++ port@1 { ++ label = "sw1p1"; ++ phy-handle = <&sw1p1_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ reg = <1>; ++ }; ++ ++ port@2 { ++ label = "sw1p2"; ++ phy-handle = <&sw1p2_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ reg = <2>; ++ }; ++ ++ port@3 { ++ label = "sw1p3"; ++ phy-handle = <&sw1p3_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ reg = <3>; ++ }; ++ ++ port@4 { ++ ethernet = <&mscc_felix_port2>; ++ phy-mode = "sgmii"; ++ reg = <4>; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&duart1 { ++ status = "okay"; ++}; ++ ++&enetc_mdio_pf3 { ++ status = "okay"; ++ ++ /* ++ * PHYs on main board ++ */ ++ ++ /* RTL8211FSI */ ++ sw0p0_rgmii_phy: ethernet-phy@7 { ++ reg = <0x7>; ++ }; ++ ++ /* VSC8502 SGMII dual PHY */ ++ sw0p1_rgmii_phy: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ ++ sw0p2_rgmii_phy: ethernet-phy@1 { ++ reg = <0x1>; ++ }; ++ ++ /* ++ * PHYs on daughter board 1 ++ */ ++ ++ /* RTL8211FSI */ ++ sw1p0_rgmii_phy: ethernet-phy@9 { ++ reg = <0x9>; ++ }; ++ ++ sw1p1_rgmii_phy: ethernet-phy@8 { ++ reg = <0x8>; ++ }; ++ ++ /* VSC8502 RGMII dual PHY */ ++ sw1p2_rgmii_phy: ethernet-phy@5 { ++ reg = <0x5>; ++ }; ++ ++ sw1p3_rgmii_phy: ethernet-phy@4 { ++ reg = <0x4>; ++ }; ++}; ++ ++&enetc_port0 { ++ status = "disabled"; ++}; ++ ++&enetc_port1 { ++ status = "disabled"; ++}; ++ ++&enetc_port2 { ++ status = "okay"; ++}; ++ ++&esdhc { ++ cap-sd-highspeed; ++ status = "okay"; ++}; ++ ++&esdhc1 { ++ mmc-hs200-1_8v; ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ i2c-mux@77 { ++ compatible = "nxp,pca9847"; ++ reg = <0x77>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x02>; ++ ++ current-monitor@40 { ++ compatible = "ti,ina220"; ++ reg = <0x40>; ++ shunt-resistor = <500>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x3>; ++ ++ temperature-sensor@4c { ++ compatible = "nxp,sa56004"; ++ reg = <0x4c>; ++ vcc-supply = <&sb_3v3>; ++ }; ++ ++ rtc@51 { ++ compatible = "nxp,pcf2129"; ++ reg = <0x51>; ++ }; ++ }; ++ }; ++}; ++ ++&mscc_felix { ++ status = "okay"; ++}; ++ ++/* Master for SJA1105 on main board */ ++&mscc_felix_port0 { ++ phy-mode = "sgmii"; ++ status = "okay"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++}; ++ ++/* Master for SJA1105 on daughter card 1 */ ++&mscc_felix_port2 { ++ phy-mode = "sgmii"; ++ status = "okay"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++}; ++ ++&mscc_felix_port4 { ++ ethernet = <&enetc_port2>; ++ status = "okay"; ++}; ++ ++&hdptx0 { ++ lane-mapping = <0x4e>; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts +new file mode 100644 +index 000000000000..4a2eebbc9b43 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Device Tree file for NXP LS1028A RDB with dsa master swp5-eno3. ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Hongbo Wang ++ * ++ */ ++ ++/dts-v1/; ++#include "fsl-ls1028a-rdb.dts" ++ ++&enetc_port2 { ++ fixed-link { ++ pause; ++ }; ++}; ++ ++&enetc_port3 { ++ status = "okay"; ++}; ++ ++&mscc_felix_port4 { ++ label = "swp4"; ++ /delete-property/ ethernet; ++ status = "okay"; ++ ++ fixed-link { ++ pause; ++ }; ++}; ++ ++&mscc_felix_port5 { ++ ethernet = <&enetc_port3>; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts +new file mode 100644 +index 000000000000..00ade901c736 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts +@@ -0,0 +1,98 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Device Tree file for NXP LS1028A RDB Board Jailhouse case. ++ * ++ * Copyright 2021-2023 NXP ++ * ++ * Hou Zhiqiang ++ */ ++ ++#include "fsl-ls1028a-rdb.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* Reserve 832MB for Jailhouse from 0xc000,0000 */ ++ /* 4MB */ ++ jh_reserved: jh@0xc0000000 { ++ no-map; ++ reg = <0x0 0xc0000000 0x0 0x400000>; ++ }; ++ /* 1MB */ ++ loader_reserved: loader@0xc0400000 { ++ no-map; ++ reg = <0x0 0xc0400000 0x0 0x00100000>; ++ }; ++ /* 2MB */ ++ ivshmem_reserved: ivshmem@0xc0500000 { ++ no-map; ++ reg = <0x0 0xc0500000 0x0 0x00200000>; ++ }; ++ /* 2MB */ ++ pci_reserved: pci@0xc0700000 { ++ no-map; ++ reg = <0x0 0xc0700000 0x0 0x00200000>; ++ }; ++ /* 823MB */ ++ inmate_reserved: inmate@0xc0900000 { ++ no-map; ++ reg = <0x0 0xc0900000 0x0 0x33700000>; ++ }; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++ /delete-property/ interrupts; ++}; ++ ++&its { ++ status = "disabled"; ++}; ++ ++&duart1 { ++ status = "disabled"; ++}; ++ ++&smmu { ++ status = "disabled"; ++}; ++ ++&enetc_pcie { ++ status = "disabled"; ++}; ++ ++&enetc_port0 { ++ status = "disabled"; ++}; ++ ++&enetc_port2 { ++ status = "disabled"; ++}; ++ ++&mscc_felix { ++ status = "disabled"; ++}; ++ ++&mscc_felix_port0 { ++ status = "disabled"; ++}; ++ ++&mscc_felix_port1 { ++ status = "disabled"; ++}; ++ ++&mscc_felix_port2 { ++ status = "disabled"; ++}; ++ ++&mscc_felix_port3 { ++ status = "disabled"; ++}; ++ ++&mscc_felix_port4 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts +new file mode 100644 +index 000000000000..00a241511258 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts +@@ -0,0 +1,59 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Device Tree file for NXP LS1028A RDB Board Jailhouse case. ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Hongbo Wang ++ * ++ */ ++ ++#include "fsl-ls1028a-rdb.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* Reserve 832MB for Jailhouse from 0xc000,0000 */ ++ /* 4MB */ ++ jh_reserved: jh@0xc0000000 { ++ no-map; ++ reg = <0x0 0xc0000000 0x0 0x400000>; ++ }; ++ /* 1MB */ ++ loader_reserved: loader@0xc0400000 { ++ no-map; ++ reg = <0x0 0xc0400000 0x0 0x00100000>; ++ }; ++ /* 2MB */ ++ ivshmem_reserved: ivshmem@0xc0500000 { ++ no-map; ++ reg = <0x0 0xc0500000 0x0 0x00200000>; ++ }; ++ /* 2MB */ ++ pci_reserved: pci@0xc0700000 { ++ no-map; ++ reg = <0x0 0xc0700000 0x0 0x00200000>; ++ }; ++ /* 823MB */ ++ inmate_reserved: inmate@0xc0900000 { ++ no-map; ++ reg = <0x0 0xc0900000 0x0 0x33700000>; ++ }; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++ /delete-property/ interrupts; ++}; ++ ++&duart1 { ++ status = "disabled"; ++}; ++ ++&gpio3 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts +new file mode 100644 +index 000000000000..dd9a9d7b425a +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts +@@ -0,0 +1,15 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape baremetal ++ * ++ * Copyright 2019-2023 NXP ++ * ++ * Author: Hongbo Wang ++ * ++ */ ++ ++#include "fsl-ls1028a-rdb.dts" ++ ++&enetc_pcie { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts +index 1f308455c613..8f9c6118f48b 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts +@@ -96,6 +96,19 @@ simple-audio-card,codec { + }; + }; + ++&dspi2 { ++ bus-num = <2>; ++ status = "okay"; ++ ++ mikrobus@0 { ++ compatible = "semtech,sx1301"; ++ reg = <0>; ++ spi-max-frequency = <2000000>; ++ fsl,spi-cs-sck-delay = <1000000>; ++ fsl,spi-sck-cs-delay = <50>; ++ }; ++}; ++ + &can0 { + status = "okay"; + +@@ -250,6 +263,18 @@ rtc@51 { + reg = <0x51>; + }; + }; ++ ++ i2c@6 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x6>; ++ ++ pn7120: pn7120@28 { ++ compatible = "nxp,pn7120", "nxp,pn544"; ++ reg = <0x28>; ++ clock-frequency = <1000000>; ++ }; ++ }; + }; + }; + +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi +index 81ad51219c64..36dab630ab43 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi +@@ -1086,7 +1086,7 @@ tmu: tmu@1f80000 { + #thermal-sensor-cells = <1>; + }; + +- pcie@1f0000000 { /* Integrated Endpoint Root Complex */ ++ enetc_pcie: pcie@1f0000000 { /* Integrated Endpoint Root Complex */ + compatible = "pci-host-ecam-generic"; + reg = <0x01 0xf0000000 0x0 0x100000>; + #address-cells = <3>; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts +new file mode 100644 +index 000000000000..a7036efb1729 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape baremetal ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Author: Changming Huang ++ * ++ */ ++ ++#include "fsl-ls1043a-rdb-sdk.dts" ++ ++ ++&usb0 { ++ status = "disabled"; ++}; ++ ++&usb1 { ++ status = "disabled"; ++}; ++ ++&usb2 { ++ status = "disabled"; ++}; ++ ++&pcie1 { ++ status = "okay"; ++}; ++ ++&pcie2 { ++ status = "disabled"; ++}; ++ ++&pcie3 { ++ status = "disabled"; ++}; ++ ++&optee { ++ status = "disabled"; ++}; ++ ++&ifc { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts +new file mode 100755 +index 000000000000..77bd7c1e6ed1 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts +@@ -0,0 +1,263 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape-1043ARDB jailhouse case ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Author: Hongbo Wang ++ * ++ */ ++ ++#include "fsl-ls1043a-rdb.dts" ++#include "qoriq-qman-portals-sdk.dtsi" ++#include "qoriq-bman-portals-sdk.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* Reserve 832MB for Jailhouse from 0xc000,0000 */ ++ /* 4MB */ ++ jh_reserved: jh@0xc0000000 { ++ no-map; ++ reg = <0x0 0xc0000000 0x0 0x400000>; ++ }; ++ /* 1MB */ ++ loader_reserved: loader@0xc0400000 { ++ no-map; ++ reg = <0x0 0xc0400000 0x0 0x00100000>; ++ }; ++ /* 2MB */ ++ ivshmem_reserved: ivshmem@0xc0500000 { ++ no-map; ++ reg = <0x0 0xc0500000 0x0 0x00200000>; ++ }; ++ /* 2MB */ ++ pci_reserved: pci@0xc0700000 { ++ no-map; ++ reg = <0x0 0xc0700000 0x0 0x00200000>; ++ }; ++ /* 823MB */ ++ inmate_reserved: inmate@0xc0900000 { ++ no-map; ++ reg = <0x0 0xc0900000 0x0 0x33700000>; ++ }; ++ }; ++}; ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++/delete-property/ dma-coherent; ++ ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++ ++pcie@3400000 { ++ /delete-property/ iommu-map; ++ dma-coherent; ++}; ++ ++pcie@3500000 { ++ /delete-property/ iommu-map; ++ dma-coherent; ++}; ++ ++pcie@3600000 { ++ /delete-property/ iommu-map; ++ dma-coherent; ++}; ++ ++/delete-node/ iommu@9000000; ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; ++ ++&clockgen { ++ dma-coherent; ++}; ++ ++&scfg { ++ dma-coherent; ++}; ++ ++&crypto { ++ dma-coherent; ++}; ++ ++&dcfg { ++ dma-coherent; ++}; ++ ++&ifc { ++ dma-coherent; ++}; ++ ++&qspi { ++ dma-coherent; ++}; ++ ++&esdhc { ++ dma-coherent; ++}; ++ ++&ddr { ++ dma-coherent; ++}; ++ ++&tmu { ++ dma-coherent; ++}; ++ ++&qman { ++ dma-coherent; ++}; ++ ++&bman { ++ dma-coherent; ++}; ++ ++&bportals { ++ dma-coherent; ++}; ++ ++&qportals { ++ dma-coherent; ++}; ++ ++&dspi0 { ++ dma-coherent; ++}; ++ ++&dspi1 { ++ dma-coherent; ++}; ++ ++&i2c0 { ++ dma-coherent; ++}; ++ ++&i2c1 { ++ dma-coherent; ++}; ++ ++&i2c2 { ++ dma-coherent; ++}; ++ ++&i2c3 { ++ dma-coherent; ++}; ++ ++&duart0 { ++ dma-coherent; ++ /delete-property/ interrupts; ++}; ++ ++&duart1 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&duart2 { ++ dma-coherent; ++}; ++ ++&duart3 { ++ dma-coherent; ++}; ++ ++&gpio1 { ++ dma-coherent; ++}; ++ ++&gpio2 { ++ dma-coherent; ++}; ++ ++&gpio3 { ++ dma-coherent; ++}; ++ ++&gpio4 { ++ dma-coherent; ++}; ++ ++&lpuart0 { ++ dma-coherent; ++}; ++ ++&lpuart1 { ++ dma-coherent; ++}; ++ ++&lpuart2 { ++ dma-coherent; ++}; ++ ++&lpuart3 { ++ dma-coherent; ++}; ++ ++&lpuart4 { ++ dma-coherent; ++}; ++ ++&lpuart5 { ++ dma-coherent; ++}; ++ ++&ftm_alarm0 { ++ dma-coherent; ++}; ++ ++&wdog0 { ++ dma-coherent; ++}; ++ ++&edma0 { ++ dma-coherent; ++}; ++ ++&qdma { ++ dma-coherent; ++}; ++ ++&msi1 { ++ dma-coherent; ++}; ++ ++&msi2 { ++ dma-coherent; ++}; ++ ++&msi3 { ++ dma-coherent; ++}; ++ ++&fman0 { ++ dma-coherent; ++}; ++ ++&ptp_timer0 { ++ dma-coherent; ++}; ++ ++&fsldpaa { ++ dma-coherent; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts +new file mode 100644 +index 000000000000..a7335581c469 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts +@@ -0,0 +1,267 @@ ++ // SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape-1043ARDB jailhouse case ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Author: Hongbo Wang ++ * ++ */ ++ ++#include "fsl-ls1043a-rdb.dts" ++#include "qoriq-qman-portals-sdk.dtsi" ++#include "qoriq-bman-portals-sdk.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* Reserve 832MB for Jailhouse from 0xc000,0000 */ ++ /* 4MB */ ++ jh_reserved: jh@0xc0000000 { ++ no-map; ++ reg = <0x0 0xc0000000 0x0 0x400000>; ++ }; ++ /* 1MB */ ++ loader_reserved: loader@0xc0400000 { ++ no-map; ++ reg = <0x0 0xc0400000 0x0 0x00100000>; ++ }; ++ /* 2MB */ ++ ivshmem_reserved: ivshmem@0xc0500000 { ++ no-map; ++ reg = <0x0 0xc0500000 0x0 0x00200000>; ++ }; ++ /* 2MB */ ++ pci_reserved: pci@0xc0700000 { ++ no-map; ++ reg = <0x0 0xc0700000 0x0 0x00200000>; ++ }; ++ /* 823MB */ ++ inmate_reserved: inmate@0xc0900000 { ++ no-map; ++ reg = <0x0 0xc0900000 0x0 0x33700000>; ++ }; ++ }; ++}; ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++/delete-property/ dma-coherent; ++ ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++ ++pcie@3400000 { ++ /delete-property/ iommu-map; ++ dma-coherent; ++}; ++ ++pcie@3500000 { ++ /delete-property/ iommu-map; ++ dma-coherent; ++}; ++ ++pcie@3600000 { ++ /delete-property/ iommu-map; ++ dma-coherent; ++}; ++ ++/delete-node/ iommu@9000000; ++/delete-node/ qman@1880000; ++/delete-node/ bman@1890000; ++/delete-node/ bman-portals@508000000; ++/delete-node/ qman-portals@500000000; ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; ++ ++&clockgen { ++ dma-coherent; ++}; ++ ++&scfg { ++ dma-coherent; ++}; ++ ++&crypto { ++ dma-coherent; ++}; ++ ++&dcfg { ++ dma-coherent; ++}; ++ ++&ifc { ++ dma-coherent; ++}; ++ ++&qspi { ++ dma-coherent; ++}; ++ ++&esdhc { ++ dma-coherent; ++}; ++ ++&ddr { ++ dma-coherent; ++}; ++ ++&tmu { ++ dma-coherent; ++}; ++ ++&dspi0 { ++ dma-coherent; ++}; ++ ++&dspi1 { ++ dma-coherent; ++}; ++ ++&i2c0 { ++ dma-coherent; ++}; ++ ++&i2c1 { ++ dma-coherent; ++}; ++ ++&i2c2 { ++ dma-coherent; ++}; ++ ++&i2c3 { ++ dma-coherent; ++}; ++ ++&duart0 { ++ dma-coherent; ++ /delete-property/ interrupts; ++}; ++ ++&duart1 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&duart2 { ++ dma-coherent; ++}; ++ ++&duart3 { ++ dma-coherent; ++}; ++ ++&gpio1 { ++ dma-coherent; ++}; ++ ++&gpio2 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&gpio3 { ++ dma-coherent; ++}; ++ ++&gpio4 { ++ dma-coherent; ++}; ++ ++&lpuart0 { ++ dma-coherent; ++}; ++ ++&lpuart1 { ++ dma-coherent; ++}; ++ ++&lpuart2 { ++ dma-coherent; ++}; ++ ++&lpuart3 { ++ dma-coherent; ++}; ++ ++&lpuart4 { ++ dma-coherent; ++}; ++ ++&lpuart5 { ++ dma-coherent; ++}; ++ ++&ftm_alarm0 { ++ dma-coherent; ++}; ++ ++&wdog0 { ++ dma-coherent; ++}; ++ ++&edma0 { ++ dma-coherent; ++}; ++ ++&qdma { ++ dma-coherent; ++}; ++ ++&msi1 { ++ dma-coherent; ++}; ++ ++&msi2 { ++ dma-coherent; ++}; ++ ++&msi3 { ++ dma-coherent; ++}; ++ ++&fman0 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&ptp_timer0 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&fsldpaa { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&bman_fbpr { ++ status = "disabled"; ++}; ++ ++&qman_fqd { ++ status = "disabled"; ++}; ++ ++&qman_pfdr { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +index 16ad696b9478..816a02798525 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +@@ -1061,7 +1061,7 @@ ftm_alarm0: timer@29d0000 { + }; + + firmware { +- optee { ++ optee: optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts +new file mode 100644 +index 000000000000..097a95802919 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape baremetal ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Author: Changming Huang ++ * ++ */ ++ ++#include "fsl-ls1046a-rdb-sdk.dts" ++ ++&usb0 { ++ status = "disabled"; ++}; ++ ++&usb1 { ++ status = "disabled"; ++}; ++ ++&usb2 { ++ status = "disabled"; ++}; ++ ++&pcie1 { ++ status = "okay"; ++}; ++ ++&pcie2 { ++ status = "disabled"; ++}; ++ ++&pcie3 { ++ status = "disabled"; ++}; ++ ++&optee { ++ status = "disabled"; ++}; ++ ++&ifc { ++ status = "disabled"; ++}; ++ ++&gpio1 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts +new file mode 100755 +index 000000000000..35ec99ac4b3e +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts +@@ -0,0 +1,274 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape-1046ARDB jailhouse case ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Author: Hongbo Wang ++ * ++ */ ++ ++#include "fsl-ls1046a-rdb.dts" ++#include "qoriq-qman-portals-sdk.dtsi" ++#include "qoriq-bman-portals-sdk.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* Reserve 832MB for Jailhouse from 0xc000,0000 */ ++ /* 4MB */ ++ jh_reserved: jh@0xc0000000 { ++ no-map; ++ reg = <0x0 0xc0000000 0x0 0x400000>; ++ }; ++ /* 1MB */ ++ loader_reserved: loader@0xc0400000 { ++ no-map; ++ reg = <0x0 0xc0400000 0x0 0x00100000>; ++ }; ++ /* 2MB */ ++ ivshmem_reserved: ivshmem@0xc0500000 { ++ no-map; ++ reg = <0x0 0xc0500000 0x0 0x00200000>; ++ }; ++ /* 2MB */ ++ pci_reserved: pci@0xc0700000 { ++ no-map; ++ reg = <0x0 0xc0700000 0x0 0x00200000>; ++ }; ++ /* 823MB */ ++ inmate_reserved: inmate@0xc0900000 { ++ no-map; ++ reg = <0x0 0xc0900000 0x0 0x33700000>; ++ }; ++ }; ++}; ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++/delete-property/ dma-coherent; ++ ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++ ++pcie@3400000 { ++ /delete-property/ iommu-map; ++}; ++ ++pcie@3500000 { ++ /delete-property/ iommu-map; ++}; ++ ++pcie@3600000 { ++ /delete-property/ iommu-map; ++}; ++ ++/delete-node/ iommu@9000000; ++}; ++ ++&fsldpaa { ++ ethernet@0 { ++ status = "disabled"; ++ }; ++ ethernet@1 { ++ status = "disabled"; ++ }; ++ ethernet@9 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet7>; ++ dma-coherent; ++ }; ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; ++ ++&clockgen { ++ dma-coherent; ++}; ++ ++&scfg { ++ dma-coherent; ++}; ++ ++&crypto { ++ dma-coherent; ++}; ++ ++&dcfg { ++ dma-coherent; ++}; ++ ++&ifc { ++ dma-coherent; ++}; ++ ++&qspi { ++ dma-coherent; ++}; ++ ++&esdhc { ++ dma-coherent; ++}; ++ ++&ddr { ++ dma-coherent; ++}; ++ ++&tmu { ++ dma-coherent; ++}; ++ ++&qman { ++ dma-coherent; ++}; ++ ++&bman { ++ dma-coherent; ++}; ++ ++&bportals { ++ dma-coherent; ++}; ++ ++&qportals { ++ dma-coherent; ++}; ++ ++&dspi { ++ dma-coherent; ++}; ++ ++&i2c0 { ++ dma-coherent; ++}; ++ ++&i2c1 { ++ dma-coherent; ++}; ++ ++&i2c2 { ++ dma-coherent; ++}; ++ ++&i2c3 { ++ dma-coherent; ++}; ++ ++&duart0 { ++ dma-coherent; ++ /delete-property/ interrupts; ++}; ++ ++&duart1 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&duart2 { ++ dma-coherent; ++}; ++ ++&duart3 { ++ dma-coherent; ++}; ++ ++&gpio0 { ++ dma-coherent; ++}; ++ ++&gpio1 { ++ dma-coherent; ++}; ++ ++&gpio2 { ++ dma-coherent; ++}; ++ ++&gpio3 { ++ dma-coherent; ++}; ++ ++&lpuart0 { ++ dma-coherent; ++}; ++ ++&lpuart1 { ++ dma-coherent; ++}; ++ ++&lpuart2 { ++ dma-coherent; ++}; ++ ++&lpuart3 { ++ dma-coherent; ++}; ++ ++&lpuart4 { ++ dma-coherent; ++}; ++ ++&lpuart5 { ++ dma-coherent; ++}; ++ ++&ftm_alarm0 { ++ dma-coherent; ++}; ++ ++&wdog0 { ++ dma-coherent; ++}; ++ ++&edma0 { ++ dma-coherent; ++}; ++ ++&sata { ++ dma-coherent; ++}; ++ ++&qdma { ++ dma-coherent; ++}; ++ ++&msi1 { ++ dma-coherent; ++}; ++ ++&msi2 { ++ dma-coherent; ++}; ++ ++&msi3 { ++ dma-coherent; ++}; ++ ++&fman0 { ++ dma-coherent; ++}; ++ ++&ptp_timer0 { ++ dma-coherent; ++}; ++ ++&fsldpaa { ++ dma-coherent; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts +new file mode 100755 +index 000000000000..8bf8d3eb03ee +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts +@@ -0,0 +1,278 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * DTS file for NXP Layerscape-1046ARDB jailhouse case ++ * ++ * Copyright 2018-2023 NXP ++ * ++ * Author: Hongbo Wang ++ * ++ */ ++ ++#include "fsl-ls1046a-rdb.dts" ++#include "qoriq-qman-portals-sdk.dtsi" ++#include "qoriq-bman-portals-sdk.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* Reserve 832MB for Jailhouse from 0xc000,0000 */ ++ /* 4MB */ ++ jh_reserved: jh@0xc0000000 { ++ no-map; ++ reg = <0x0 0xc0000000 0x0 0x400000>; ++ }; ++ /* 1MB */ ++ loader_reserved: loader@0xc0400000 { ++ no-map; ++ reg = <0x0 0xc0400000 0x0 0x00100000>; ++ }; ++ /* 2MB */ ++ ivshmem_reserved: ivshmem@0xc0500000 { ++ no-map; ++ reg = <0x0 0xc0500000 0x0 0x00200000>; ++ }; ++ /* 2MB */ ++ pci_reserved: pci@0xc0700000 { ++ no-map; ++ reg = <0x0 0xc0700000 0x0 0x00200000>; ++ }; ++ /* 823MB */ ++ inmate_reserved: inmate@0xc0900000 { ++ no-map; ++ reg = <0x0 0xc0900000 0x0 0x33700000>; ++ }; ++ }; ++}; ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++/delete-property/ dma-coherent; ++ ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++ ++pcie@3400000 { ++ /delete-property/ iommu-map; ++}; ++ ++pcie@3500000 { ++ /delete-property/ iommu-map; ++}; ++ ++pcie@3600000 { ++ /delete-property/ iommu-map; ++}; ++ ++/delete-node/ iommu@9000000; ++/delete-node/ qman@1880000; ++/delete-node/ bman@1890000; ++/delete-node/ bman-portals@508000000; ++/delete-node/ qman-portals@500000000; ++}; ++ ++&fsldpaa { ++ ethernet@0 { ++ status = "disabled"; ++ }; ++ ethernet@1 { ++ status = "disabled"; ++ }; ++ ethernet@9 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet7>; ++ dma-coherent; ++ }; ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; ++ ++&clockgen { ++ dma-coherent; ++}; ++ ++&scfg { ++ dma-coherent; ++}; ++ ++&crypto { ++ dma-coherent; ++}; ++ ++&dcfg { ++ dma-coherent; ++}; ++ ++&ifc { ++ dma-coherent; ++}; ++ ++&qspi { ++ dma-coherent; ++}; ++ ++&esdhc { ++ dma-coherent; ++}; ++ ++&ddr { ++ dma-coherent; ++}; ++ ++&tmu { ++ dma-coherent; ++}; ++ ++&dspi { ++ dma-coherent; ++}; ++ ++&i2c0 { ++ dma-coherent; ++}; ++ ++&i2c1 { ++ dma-coherent; ++}; ++ ++&i2c2 { ++ dma-coherent; ++}; ++ ++&i2c3 { ++ dma-coherent; ++}; ++ ++&duart0 { ++ dma-coherent; ++ /delete-property/ interrupts; ++}; ++ ++&duart1 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&duart2 { ++ dma-coherent; ++}; ++ ++&duart3 { ++ dma-coherent; ++}; ++ ++&gpio0 { ++ dma-coherent; ++}; ++ ++&gpio1 { ++ dma-coherent; ++}; ++ ++&gpio2 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&gpio3 { ++ dma-coherent; ++}; ++ ++&lpuart0 { ++ dma-coherent; ++}; ++ ++&lpuart1 { ++ dma-coherent; ++}; ++ ++&lpuart2 { ++ dma-coherent; ++}; ++ ++&lpuart3 { ++ dma-coherent; ++}; ++ ++&lpuart4 { ++ dma-coherent; ++}; ++ ++&lpuart5 { ++ dma-coherent; ++}; ++ ++&ftm_alarm0 { ++ dma-coherent; ++}; ++ ++&wdog0 { ++ dma-coherent; ++}; ++ ++&edma0 { ++ dma-coherent; ++}; ++ ++&sata { ++ dma-coherent; ++}; ++ ++&qdma { ++ dma-coherent; ++}; ++ ++&msi1 { ++ dma-coherent; ++}; ++ ++&msi2 { ++ dma-coherent; ++}; ++ ++&msi3 { ++ dma-coherent; ++}; ++ ++&fman0 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&ptp_timer0 { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&fsldpaa { ++ dma-coherent; ++ status = "disabled"; ++}; ++ ++&bman_fbpr { ++ status = "disabled"; ++}; ++ ++&qman_fqd { ++ status = "disabled"; ++}; ++ ++&qman_pfdr { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +index 96f501c76ea8..7877f13e1682 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +@@ -1028,7 +1028,7 @@ qman_pfdr: qman-pfdr { + }; + + firmware { +- optee { ++ optee: optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi +index c133f06ca748..c4ac0b498c4d 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi +@@ -239,6 +239,15 @@ sai3: sai@59070000 { + status = "disabled"; + }; + ++ gpt5: gpt@590b0000 { ++ reg = <0x590b0000 0x10000>; ++ clocks = <&gpt5_lpcg 1>, ++ <&gpt5_lpcg 1>; ++ clock-names = "ipg", "per"; ++ power-domains = <&pd IMX_SC_R_GPT_5>; ++ status = "disabled"; ++ }; ++ + asrc1: asrc@59800000 { + compatible = "fsl,imx8qm-asrc"; + reg = <0x59800000 0x10000>; +@@ -555,6 +564,17 @@ sai3_lpcg: clock-controller@59470000 { + power-domains = <&pd IMX_SC_R_SAI_3>; + }; + ++ gpt5_lpcg: clock-controller@594b0000 { ++ compatible = "fsl,imx8qxp-lpcg"; ++ reg = <0x594b0000 0x10000>; ++ #clock-cells = <1>; ++ clocks = <&acm IMX_ADMA_ACM_GPT0_MUX_CLK_SEL>, ++ <&audio_ipg_clk>; ++ bit-offset = <0 16>; ++ clock-output-names = "gpt5_lpcg_clk_in", "gpt5_lpcg_ipg_clk"; ++ power-domains = <&pd IMX_SC_R_GPT_5>; ++ }; ++ + asrc1_lpcg: clock-controller@59c00000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x59c00000 0x10000>; +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts +new file mode 100644 +index 000000000000..36cc1a616a9a +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts +@@ -0,0 +1,9 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2022-2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8dxl-evk-enet0.dts" ++#include "imx8dxl-evk-enet0-avb.dtsi" +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi +new file mode 100644 +index 000000000000..d7c268f056cc +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi +@@ -0,0 +1,54 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/* Set GPT Capture input to Ethernet 0 event */ ++&acm { ++ gpt-capture-select = ; ++}; ++ ++/* AVB HW timer*/ ++&gpt5 { ++ compatible = "fsl,avb-gpt"; ++ ++ clocks = <&gpt5_lpcg 1>, ++ <&gpt5_lpcg 1>, ++ <&gpt5_lpcg 0>, ++ <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>; ++ clock-names = "ipg", "per", "clk_in", "audio_pll"; ++ ++ /* - Set ACM_AUD_CLK0 source to ACM_AUD_REC_CLK0 ++ * - Set clk_in to Audio PLL0 Divider ++ * - Enable Audio PLL and its Master Bus clock (AUD_REC_CLK0): keep this in sync with sai nodes ++ */ ++ ++ assigned-clocks = <&acm IMX_ADMA_ACM_AUD_CLK0_SEL>, ++ <&acm IMX_ADMA_ACM_GPT0_MUX_CLK_SEL>, ++ <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>, ++ <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>; ++ ++ assigned-clock-parents = <&aud_rec0_lpcg 0>, ++ <&acm IMX_ADMA_ACM_AUD_CLK0_SEL>; ++ ++ assigned-clock-rates = <0>, <0>, <786432000>, <12288000>; ++ ++ /* Audio PLL is controlled through SCU */ ++ fsl,pll-scu-controlled; ++ ++ timer-channel = <1>; /* Use output compare channel 1*/ ++ prescale = <1>; ++ domain = <0>; ++ rec-channel = <1 0 1>; // capture channel, eth port, ENET TC id ++ ++ interrupts = ; ++ ++ status = "okay"; ++}; ++ ++&fec1 { ++ fsl,rx-phy-delay-100-ns = <670>; ++ fsl,tx-phy-delay-100-ns = <670>; ++ fsl,rx-phy-delay-1000-ns = <0>; ++ fsl,tx-phy-delay-1000-ns = <0>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts +new file mode 100644 +index 000000000000..ddfdadfbe3f8 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts +@@ -0,0 +1,168 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8dxl-evk.dts" ++ ++&iomuxc { ++ pinctrl_lpspi2: lpspi2grp { ++ fsl,pins = < ++ IMX8DXL_USDHC1_VSELECT_ADMA_SPI2_SDO 0x600004c ++ IMX8DXL_USDHC1_WP_ADMA_SPI2_SDI 0x600004c ++ IMX8DXL_USDHC1_RESET_B_ADMA_SPI2_SCK 0x600004c ++ >; ++ }; ++ ++ pinctrl_lpspi2_cs: lpspi2cs { ++ fsl,pins = < ++ IMX8DXL_USDHC1_CD_B_LSIO_GPIO4_IO22 0x21 ++ >; ++ }; ++}; ++ ++&lpspi2 { ++ fsl,spi-num-chipselects = <1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_lpspi2 &pinctrl_lpspi2_cs>; ++ cs-gpios = <&lsio_gpio4 22 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++ ++ sja1105p@0 { ++ compatible = "nxp,sja1105q"; ++ spi-max-frequency = <12500000>; ++ /* SJA1105PQRS operates in SPI MODE 1 : CPOL=0 CPHA=1 */ ++ spi-cpha; ++ /* use queue 5 for managment traffic */ ++ hostprio = <5>; ++ ++ reg = <0>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ label = "cpu"; ++ ethernet = <&fec1>; ++ phy-mode = "rgmii"; ++ rx-internal-delay-ps = <2000>; ++ tx-internal-delay-ps = <2000>; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "swp0"; ++ phy-handle = <&phy0>; ++ phy-mode = "mii"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "swp1"; ++ phy-handle = <&phy1>; ++ phy-mode = "mii"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "swp2"; ++ phy-handle = <&phy2>; ++ phy-mode = "rmii"; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "swp3"; ++ phy-handle = <&phy3>; ++ phy-mode = "rmii"; ++ }; ++ }; ++ }; ++}; ++ ++ðphy1 { ++ status = "disabled"; ++}; ++ ++&fec1 { ++ assigned-clocks = <&clk IMX_SC_R_ENET_0 IMX_SC_C_CLKDIV>; ++ assigned-clock-rates = <12000000>; ++ phy-supply = <&mii_select>; ++ status = "okay"; ++ ++ fsl,magic-packet; ++ phy-mode = "rgmii"; ++ /delete-property/ rx-internal-delay-ps; ++ /delete-property/ phy-handle; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ /* SJA1105Q EVB switch ports : NXP TJA1102 ++ the phys SMI addresses on EVB are hard coded giving ++ first TJA device at offset 0x8 and the 2nd once at offet 0xe */ ++ phy0: ethernet-phy@8 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x8>; ++ max-speed = <100>; ++ phy1: ethernet-phy@9 { ++ reg = <0x9>; ++ max-speed = <100>; ++ }; ++ }; ++ ++ phy2: ethernet-phy@e { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0xe>; ++ max-speed = <100>; ++ phy3: ethernet-phy@f { ++ reg = <0xf>; ++ max-speed = <100>; ++ }; ++ }; ++ }; ++}; ++ ++®_fec1_sel { ++ status = "okay"; ++}; ++ ++/* This would set max7233 (0) to high (intented for PHY power on) and would ++ * enable LPC SPI/SMI on the switch EVB which interferes with ++ * SPI communcation between the iMX and the SJA1105 ++*/ ++®_fec1_io { ++ status = "disabled"; ++}; ++ ++&max7322 { ++ status = "disabled"; ++}; ++ ++&mii_select { ++ /delete-property/ enable-active-high; ++}; ++ ++&eqos { ++ status = "disabled"; ++}; ++ ++&usdhc2 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts +new file mode 100644 +index 000000000000..121b506cbc8c +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts +@@ -0,0 +1,9 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8dxl-evk-enet0-tja1100.dts" ++#include "imx8dxl-evk-enet0-avb.dtsi" +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts +index 139d3f1b8b7a..b5fc609be44f 100644 +--- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts +@@ -323,6 +323,9 @@ &eqos { + phy-handle = <ðphy0>; + nvmem-cells = <&fec_mac1>; + nvmem-cell-names = "mac-address"; ++ snps,force_thresh_dma_mode; ++ snps,mtl-tx-config = <&mtl_tx_setup>; ++ snps,mtl-rx-config = <&mtl_rx_setup>; + status = "okay"; + + mdio { +@@ -347,6 +350,61 @@ vddio0: vddio-regulator { + }; + }; + }; ++ ++ mtl_tx_setup: tx-queues-config { ++ snps,tx-queues-to-use = <5>; ++ snps,tx-sched-sp; ++ queue0 { ++ snps,dcb-algorithm; ++ snps,priority = <0x1>; ++ }; ++ queue1 { ++ snps,dcb-algorithm; ++ snps,priority = <0x2>; ++ }; ++ queue2 { ++ snps,dcb-algorithm; ++ snps,priority = <0x4>; ++ }; ++ queue3 { ++ snps,dcb-algorithm; ++ snps,priority = <0x8>; ++ }; ++ queue4 { ++ snps,dcb-algorithm; ++ snps,priority = <0xf0>; ++ }; ++ }; ++ ++ mtl_rx_setup: rx-queues-config { ++ snps,rx-queues-to-use = <5>; ++ snps,rx-sched-sp; ++ queue0 { ++ snps,dcb-algorithm; ++ snps,priority = <0x1>; ++ snps,map-to-dma-channel = <0>; ++ }; ++ queue1 { ++ snps,dcb-algorithm; ++ snps,priority = <0x2>; ++ snps,map-to-dma-channel = <1>; ++ }; ++ queue2 { ++ snps,dcb-algorithm; ++ snps,priority = <0x4>; ++ snps,map-to-dma-channel = <2>; ++ }; ++ queue3 { ++ snps,dcb-algorithm; ++ snps,priority = <0x8>; ++ snps,map-to-dma-channel = <3>; ++ }; ++ queue4 { ++ snps,dcb-algorithm; ++ snps,priority = <0xf0>; ++ snps,map-to-dma-channel = <4>; ++ }; ++ }; + }; + + /* +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi +index 2e6cd063ae9a..81541d269bb8 100644 +--- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi +@@ -32,6 +32,7 @@ &acm { + <&pd IMX_SC_R_AUDIO_PLL_0>, + <&pd IMX_SC_R_AUDIO_PLL_1>, + <&pd IMX_SC_R_ASRC_0>, ++ <&pd IMX_SC_R_GPT_5>, + <&pd IMX_SC_R_SAI_0>, + <&pd IMX_SC_R_SAI_1>, + <&pd IMX_SC_R_SAI_2>, +diff --git a/arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi +new file mode 100644 +index 000000000000..428e9b8cb4ae +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gen_sw_mbox_1_reserved: gen-sw-mbox-1@b8501000 { ++ reg = <0 0xb8501000 0 0x1000>; ++ no-map; ++ }; ++ ++ }; ++ ++ gen_sw_mbox_1: generic-software-mailbox-1@b8501000 { ++ compatible = "fsl,generic-software-mbox"; ++ reg = <0 0xb8501000 0 0x1000>; ++ #mbox-cells = <3>; ++ /* Use 2 unused SPI interrupts */ ++ interrupts = , ; ++ interrupt-names = "irq", "remote_irq"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi +new file mode 100644 +index 000000000000..e97e82c78aaa +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gen_sw_mbox_reserved: gen-sw-mbox@b8500000 { ++ reg = <0 0xb8500000 0 0x1000>; ++ no-map; ++ }; ++ ++ }; ++ ++ gen_sw_mbox: generic-software-mailbox@b8500000 { ++ compatible = "fsl,generic-software-mbox"; ++ reg = <0 0xb8500000 0 0x1000>; ++ #mbox-cells = <3>; ++ /* Use 2 unused SPI interrupts */ ++ interrupts = , ; ++ interrupt-names = "irq", "remote_irq"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi +new file mode 100644 +index 000000000000..70e33e6d834b +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx8m-generic-mbox-1.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ rpmsg_ca53_1_reserved: rpmsg-ca53-1@b8610000 { ++ reg = <0 0xb8610000 0 0x10000>; ++ no-map; ++ }; ++ ++ vdevbuffer_ca53_1: vdevbuffer-ca53-1@b8800000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb8800000 0 0x100000>; ++ no-map; ++ }; ++ }; ++ ++ rpmsg-ca53-1 { ++ compatible = "fsl,imx8mm-rpmsg"; ++ reg = <0x0 0xb8610000 0x0 0x10000>; /* 64K for one rpmsg instance */ ++ dma-coherent; ++ memory-region = <&vdevbuffer_ca53_1>; ++ mbox-names = "tx", "rx", "rxdb"; ++ mboxes = <&gen_sw_mbox_1 0 0 1 /* Tx channel with ACK */ ++ &gen_sw_mbox_1 1 0 0 /* Rx channel without ACK */ ++ &gen_sw_mbox_1 2 0 1>; /* RXDB channel with ACK */ ++ vdev-nums = <1>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi +new file mode 100644 +index 000000000000..a3b0dbf563e8 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2022-2023 NXP ++ */ ++ ++#include "imx8m-generic-mbox.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ rpmsg_ca53_reserved: rpmsg-ca53@b8600000 { ++ reg = <0 0xb8600000 0 0x10000>; ++ no-map; ++ }; ++ ++ vdevbuffer_ca53: vdevbuffer-ca53@b8700000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb8700000 0 0x100000>; ++ no-map; ++ }; ++ }; ++ ++ rpmsg-ca53 { ++ compatible = "fsl,imx8mm-rpmsg"; ++ reg = <0x0 0xb8600000 0x0 0x10000>; /* 64K for one rpmsg instance */ ++ dma-coherent; ++ memory-region = <&vdevbuffer_ca53>; ++ mbox-names = "tx", "rx", "rxdb"; ++ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */ ++ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */ ++ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */ ++ vdev-nums = <1>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts +new file mode 100644 +index 000000000000..3ed975c348d4 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2020-2021 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mm-evk.dts" ++ ++/* AVB HW timer*/ ++&gpt1 { ++ compatible = "fsl,avb-gpt"; ++ timer-channel = <1>; /* Use output compare channel 1*/ ++ prescale = <1>; ++ domain = <0>; ++ ++ clocks = <&clk IMX8MM_CLK_GPT1_ROOT>, ++ <&clk IMX8MM_CLK_GPT1_ROOT>, <&clk IMX8MM_AUDIO_PLL1>; ++ clock-names = "ipg", "per", "audio_pll"; ++ ++ /* Make the GPT clk root derive from the audio PLL */ ++ assigned-clocks = <&clk IMX8MM_CLK_GPT1>; ++ assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>; ++ assigned-clock-rates = <0>; ++ ++ /* Enble SW sampling for media clock recovery on port 0 */ ++ sw-recovery = <0>; ++ ++ status = "okay"; ++}; ++ ++&fec1 { ++ fsl,rx-phy-delay-100-ns = <670>; ++ fsl,tx-phy-delay-100-ns = <670>; ++ fsl,rx-phy-delay-1000-ns = <0>; ++ fsl,tx-phy-delay-1000-ns = <0>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts +new file mode 100644 +index 000000000000..4a36d0e0c7a1 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2020-2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mm-evk.dts" ++ ++/ { ++ model = "FSL i.MX8MM LPDDR4 EVK RevB board - Baremetal"; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ rpmsg_reserved: rpmsg@b8000000 { ++ no-map; ++ reg = <0 0xb8000000 0 0x400000>; ++ }; ++ bm_reserved: baremetal@60000000 { ++ no-map; ++ reg = <0 0x60000000 0 0x10000000>; ++ }; ++ }; ++}; ++ ++&fec1 { ++ status = "disabled"; ++}; ++ ++&gpio5 { ++ status = "disabled"; ++}; ++ ++&uart3 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts +new file mode 100755 +index 000000000000..cde59ddaa3cf +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx8mm-evk.dts" ++ ++&fec1 { ++ compatible = "fsl,imx8mm-fec-ecat", "fsl,imx8mq-fec-ecat", "fsl,imx6sx-fec-ecat"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts +new file mode 100644 +index 000000000000..16919505668c +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mm-evk-multicore-rtos.dts" ++#include "imx8m-rpmsg-ca53.dtsi" ++#include "imx8m-rpmsg-ca53-1.dtsi" +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts +new file mode 100644 +index 000000000000..9f3dfaaf1650 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts +@@ -0,0 +1,79 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mm-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* ++ * Reserve up to 48MB (16MB x 3) for three FreeRTOS instances running on ++ * three Cortex-A Cores when booting Linux on at least on Cortex-A Core. ++ */ ++ rtos_ca53_reserved: rtos-ca53@93c00000 { ++ no-map; ++ reg = <0 0x93c00000 0x0 0x3000000>; ++ }; ++ ++ /* Reserve 16MB for FreeRTOS running on CM4 */ ++ m4_reserved: m4@80000000 { ++ no-map; ++ reg = <0 0x80000000 0 0x1000000>; ++ }; ++ ++ vdev0vring0: vdev0vring0@b8000000 { ++ reg = <0 0xb8000000 0 0x8000>; ++ no-map; ++ }; ++ ++ vdev0vring1: vdev0vring1@b8008000 { ++ reg = <0 0xb8008000 0 0x8000>; ++ no-map; ++ }; ++ ++ rsc_table: rsc-table@b80ff000 { ++ reg = <0 0xb80ff000 0 0x1000>; ++ no-map; ++ }; ++ ++ vdevbuffer: vdevbuffer@b8400000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb8400000 0 0x100000>; ++ no-map; ++ }; ++ }; ++ ++ imx8mm-cm4 { ++ compatible = "fsl,imx8mm-cm4"; ++ rsc-da = <0xb8000000>; ++ clocks = <&clk IMX8MM_CLK_M4_DIV>; ++ mbox-names = "tx", "rx", "rxdb"; ++ mboxes = <&mu 0 1 ++ &mu 1 1 ++ &mu 3 1>; ++ memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>; ++ syscon = <&src>; ++ fsl,startup-delay-ms = <500>; ++ }; ++ ++ ++}; ++ ++&{/busfreq} { ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts +new file mode 100644 +index 000000000000..ea5dbfd3b793 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts +@@ -0,0 +1,228 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2019-2023 NXP ++ */ ++ ++/dts-v1/; ++#include ++#include "imx8mm-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ m4_reserved: m4@80000000 { ++ no-map; ++ reg = <0 0x80000000 0 0x1000000>; ++ }; ++ ++ vdev0vring0: vdev0vring0@b8000000 { ++ reg = <0 0xb8000000 0 0x100000>; ++ no-map; ++ }; ++ ++ vdev0vring1: vdev0vring1@b8100000 { ++ reg = <0 0xb8100000 0 0x100000>; ++ no-map; ++ }; ++ ++ rsc_table: rsc-table@b8a00000 { ++ reg = <0 0xb8a00000 0 0x1000>; ++ no-map; ++ }; ++ ++ vdevbuffer: vdevbuffer@b8200000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb8200000 0 0x800000>; ++ no-map; ++ }; ++ }; ++ ++ bt_sco_codec: bt_sco_codec { ++ status = "disabled"; ++ }; ++ ++ sound-bt-sco { ++ status = "disabled"; ++ }; ++ ++ sound-wm8524 { ++ status = "disabled"; ++ }; ++ ++ wm8524: audio-codec { ++ status = "disabled"; ++ }; ++ ++ rpmsg_audio: rpmsg_audio { ++ compatible = "fsl,imx8mm-rpmsg-audio"; ++ model = "ak4497-audio"; ++ fsl,platform = "rpmsg-audio-channel"; ++ fsl,enable-lpa; ++ fsl,rpmsg-out; ++ assigned-clocks = <&clk IMX8MM_CLK_SAI1>; ++ assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>; ++ assigned-clock-rates = <49152000>; ++ clocks = <&clk IMX8MM_CLK_SAI1_IPG>, ++ <&clk IMX8MM_CLK_SAI1_ROOT>, ++ <&clk IMX8MM_CLK_SDMA3_ROOT>, ++ <&clk IMX8MM_AUDIO_PLL1_OUT>, ++ <&clk IMX8MM_AUDIO_PLL2_OUT>; ++ clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k"; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_0: uart-rpbus-0 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_1: uart-rpbus-1 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_2: uart-rpbus-2 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_3: uart-rpbus-3 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_4: uart-rpbus-4 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_5: uart-rpbus-5 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_6: uart-rpbus-6 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_7: uart-rpbus-7 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_8: uart-rpbus-8 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_9: uart-rpbus-9 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_10: uart-rpbus-10 { ++ compatible = "fsl,uart-rpbus"; ++ status = "okay"; /* mcore directly print data that receive from acore */ ++ }; ++ ++ imx8mm-cm4 { ++ compatible = "fsl,imx8mm-cm4"; ++ rsc-da = <0xb8000000>; ++ clocks = <&clk IMX8MM_CLK_M4_DIV>; ++ mbox-names = "tx", "rx", "rxdb"; ++ mboxes = <&mu 0 1 ++ &mu 1 1 ++ &mu 3 1>; ++ memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>; ++ syscon = <&src>; ++ fsl,startup-delay-ms = <500>; ++ }; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++/* ++ * ATTENTION: M4 may use IPs like below ++ * ECSPI0/ECSPI2, GPIO1/GPIO5, GPT1, I2C3, I2S3, WDOG1, UART3, UART4, PWM3, SDMA1 ++ */ ++ ++&i2c3 { ++ status = "disabled"; ++}; ++ ++/* the uart3 is used by m4 to support srtm uart service */ ++&uart3 { ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&sdma3 { ++ status = "disabled"; ++}; ++ ++&sai3 { ++ status = "disabled"; ++}; ++ ++&sai1 { ++ status = "disabled"; ++}; ++ ++&sai2 { ++ status = "disabled"; ++}; ++ ++&sai6 { ++ status = "disabled"; ++}; ++ ++&flexspi { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts +new file mode 100644 +index 000000000000..89b686615df5 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx8mm-evk.dts" ++#include "imx8m-rpmsg-ca53.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ rtos_ca53_reserved: rtos-ca53@93c00000 { ++ reg = <0 0x93c00000 0x0 0x24000000>; ++ no-map; ++ }; ++ }; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++/* ++ * ATTENTION: The isolated CA53 core uses IPs below ++ * UART4 ++ */ ++ ++&uart4 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts +index 2a477c74b634..237bf6eafef6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts +@@ -1,10 +1,10 @@ + // SPDX-License-Identifier: (GPL-2.0 OR MIT) + /* +- * Copyright 2019 NXP ++ * Copyright 2019-2023 NXP + */ + + /dts-v1/; +- ++#include + #include "imx8mm-evk.dts" + + / { +@@ -74,6 +74,91 @@ rpmsg_audio: rpmsg_audio { + status = "okay"; + }; + ++ uart_rpbus_0: uart-rpbus-0 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_1: uart-rpbus-1 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_2: uart-rpbus-2 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_3: uart-rpbus-3 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_4: uart-rpbus-4 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_5: uart-rpbus-5 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_6: uart-rpbus-6 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_7: uart-rpbus-7 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_8: uart-rpbus-8 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_9: uart-rpbus-9 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ //flags=; ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_10: uart-rpbus-10 { ++ compatible = "fsl,uart-rpbus"; ++ status = "okay"; /* mcore directly print data that receive from acore */ ++ }; ++ + imx8mm-cm4 { + compatible = "fsl,imx8mm-cm4"; + rsc-da = <0xb8000000>; +@@ -102,13 +187,18 @@ IMX8MM_CLK_DISP_APB + + /* + * ATTENTION: M4 may use IPs like below +- * ECSPI0/ECSPI2, GPIO1/GPIO5, GPT1, I2C3, I2S3, WDOG1, UART4, PWM3, SDMA1 ++ * ECSPI0/ECSPI2, GPIO1/GPIO5, GPT1, I2C3, I2S3, WDOG1, UART3, UART4, PWM3, SDMA1 + */ + + &i2c3 { + status = "disabled"; + }; + ++/* the uart3 is used by m4 to support srtm uart service */ ++&uart3 { ++ status = "disabled"; ++}; ++ + &uart4 { + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts +new file mode 100644 +index 000000000000..f4f3726a52fe +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts +@@ -0,0 +1,82 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx8mm-evk.dts" ++#include "imx8m-generic-mbox.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ virtio_reserved: virtio@b8400000 { ++ no-map; ++ reg = <0 0xb8400000 0x0 0x00100000>; ++ }; ++ ++ /* 512MB */ ++ freertos_reserved: inmate@93c00000 { ++ no-map; ++ reg = <0 0x93c00000 0x0 0x20000000>; ++ }; ++ ++ virtio_buffer: virtio-buffer@b3c00000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb3c00000 0 0x4000000>; ++ }; ++ }; ++ ++ virtio_net@b8400000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xb8400000 0x0 0x1000>; ++ dma-coherent; ++ hypervisor_less; ++ memory-region = <&virtio_buffer>; ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */ ++ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */ ++ }; ++}; ++ ++&{/busfreq} { ++ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */ ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&iomuxc { ++ /* ++ * Used for the 2nd Linux. ++ * TODO: M4 may use these pins. ++ */ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140 ++ MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140 ++ >; ++ }; ++}; ++ ++&uart2 { ++ /* uart2 is used by the 2nd OS, so configure pin and clk */ ++ pinctrl-0 = <&pinctrl_uart2>, <&pinctrl_uart4>; ++ assigned-clocks = <&clk IMX8MM_CLK_UART4>; ++ assigned-clock-parents = <&clk IMX8MM_CLK_24M>; ++}; ++ ++&fec1 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts +new file mode 100644 +index 000000000000..90965238e6dd +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts +@@ -0,0 +1,81 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx8mm-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ cm4_reserved: cm4@80000000 { ++ reg = <0 0x80000000 0x0 0x01000000>; ++ no-map; ++ }; ++ ++ virtio_buffer: virtio-buffer@b3c00000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb3c00000 0 0x4000000>; ++ no-map; ++ }; ++ ++ virtio_reserved: virtio@b8400000 { ++ no-map; ++ reg = <0 0xb8400000 0x0 0x00100000>; ++ }; ++ }; ++ ++ virtio_net@b8400000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xb8400000 0x0 0x1000>; ++ hypervisor_less; ++ memory-region = <&virtio_buffer>; ++ interrupts = ; //MU IRQ to CA53 ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&mu 0 2 ++ &mu 1 2>; ++ }; ++}; ++ ++&{/busfreq} { ++ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */ ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&iomuxc { ++ /* ++ * Used for the 2nd Linux. ++ * TODO: M4 may use these pins. ++ */ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140 ++ MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140 ++ >; ++ }; ++}; ++ ++&uart2 { ++ /* uart2 is used by the 2nd OS, so configure pin and clk */ ++ pinctrl-0 = <&pinctrl_uart2>, <&pinctrl_uart4>; ++ assigned-clocks = <&clk IMX8MM_CLK_UART4>; ++ assigned-clock-parents = <&clk IMX8MM_CLK_24M>; ++}; ++ ++&fec1 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts +new file mode 100644 +index 000000000000..b6adb7aa27d8 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts +@@ -0,0 +1,78 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2022-2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx8mm-evk.dts" ++#include "imx8m-generic-mbox.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ virtio_reserved: virtio@b8400000 { ++ no-map; ++ reg = <0 0xb8400000 0x0 0x00100000>; ++ }; ++ ++ /* 512MB */ ++ freertos_reserved: inmate@93c00000 { ++ no-map; ++ reg = <0 0x93c00000 0x0 0x20000000>; ++ }; ++ ++ virtio_buffer: virtio-buffer@b3c00000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb3c00000 0 0x4000000>; ++ }; ++ }; ++ ++ virtio_trans@b8400000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xb8400000 0x0 0x1000>; ++ hypervisor_less; ++ dma-coherent; ++ memory-region = <&virtio_buffer>; ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */ ++ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */ ++ }; ++}; ++ ++&{/busfreq} { ++ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */ ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&iomuxc { ++ /* ++ * Used for the 2nd Linux. ++ * TODO: M4 may use these pins. ++ */ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140 ++ MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140 ++ >; ++ }; ++}; ++ ++&uart2 { ++ /* uart2 is used by the 2nd OS, so configure pin and clk */ ++ pinctrl-0 = <&pinctrl_uart2>, <&pinctrl_uart4>; ++ assigned-clocks = <&clk IMX8MM_CLK_UART4>; ++ assigned-clock-parents = <&clk IMX8MM_CLK_24M>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts +new file mode 100644 +index 000000000000..9196eaf43015 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts +@@ -0,0 +1,70 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2022-2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx8mm-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ cm4_reserved: cm4@80000000 { ++ reg = <0 0x80000000 0x0 0x01000000>; ++ no-map; ++ }; ++ ++ virtio_reserved: virtio@b8400000 { ++ no-map; ++ reg = <0 0xb8400000 0x0 0x00100000>; ++ }; ++ }; ++ ++ virtio_trans@b8400000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xb8400000 0x0 0x1000>; ++ hypervisor_less; ++ interrupts = ; //MU IRQ to CA53 ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&mu 0 2 ++ &mu 1 2>; ++ }; ++}; ++ ++&{/busfreq} { ++ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */ ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&iomuxc { ++ /* ++ * Used for the 2nd Linux. ++ * TODO: M4 may use these pins. ++ */ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140 ++ MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140 ++ >; ++ }; ++}; ++ ++&uart2 { ++ /* uart2 is used by the 2nd OS, so configure pin and clk */ ++ pinctrl-0 = <&pinctrl_uart2>, <&pinctrl_uart4>; ++ assigned-clocks = <&clk IMX8MM_CLK_UART4>; ++ assigned-clock-parents = <&clk IMX8MM_CLK_24M>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi +index c63b5c467be2..589b52636e85 100755 +--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi +@@ -593,6 +593,17 @@ sdma3: dma-controller@302b0000 { + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin"; + }; + ++ gpt1: gpt@302d0000 { ++ compatible = "fsl,imx8mq-gpt", "fsl,imx7d-gpt"; ++ reg = <0x302d0000 0x10000>; ++ interrupts = ; ++ clocks = <&clk IMX8MM_CLK_GPT1_ROOT>, ++ <&clk IMX8MM_CLK_GPT1_ROOT>, ++ <&clk IMX8MM_CLK_GPT_3M>; ++ clock-names = "ipg", "per", "osc_per"; ++ status = "disabled"; ++ }; ++ + iomuxc: pinctrl@30330000 { + compatible = "fsl,imx8mm-iomuxc"; + reg = <0x30330000 0x10000>; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts +new file mode 100644 +index 000000000000..70e3dba61494 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts +@@ -0,0 +1,42 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2021 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mp-evk.dts" ++ ++/* AVB HW timer*/ ++&gpt1 { ++ compatible = "fsl,avb-gpt"; ++ timer-channel = <1>; /* Use output compare channel 1*/ ++ rec-channel = <1 0 1>; // capture channel, eth port, ENET TC id ++ prescale = <1>; ++ domain = <0>; ++ ++ clocks = <&clk IMX8MP_CLK_GPT1_ROOT>, ++ <&clk IMX8MP_CLK_GPT1_ROOT>, ++ <&clk IMX8MP_AUDIO_PLL1>; ++ clock-names = "ipg", "per", "audio_pll"; ++ ++ /* Make the GPT clk root derive from the audio PLL*/ ++ assigned-clocks = <&clk IMX8MP_CLK_GPT1>; ++ assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; ++ assigned-clock-rates = <0>; ++ ++ gpt1_capin1_sel = <&gpr 0x4 2>; ++ ++ status = "okay"; ++}; ++ ++&fec { ++ fsl,rx-phy-delay-100-ns = <670>; ++ fsl,tx-phy-delay-100-ns = <670>; ++ fsl,rx-phy-delay-1000-ns = <0>; ++ fsl,tx-phy-delay-1000-ns = <0>; ++}; ++ ++ðphy1 { ++ eee-broken-100tx; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts +new file mode 100644 +index 000000000000..ce893a1d27c6 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2020-2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mp-evk.dts" ++ ++/ { ++ model = "NXP i.MX8MPlus EVK board - Baremetal"; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ rpmsg_reserved: rpmsg@55800000 { ++ no-map; ++ reg = <0 0x55800000 0 0x800000>; ++ }; ++ ++ /* baremetal: slave cores reserved memory */ ++ bm_reserved: baremetal@60000000 { ++ no-map; ++ reg = <0 0x60000000 0 0x10000000>; ++ }; ++ }; ++}; ++ ++&fec { ++ status = "disabled"; ++}; ++ ++&uart3 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts +new file mode 100644 +index 000000000000..18de77535a98 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts +@@ -0,0 +1,79 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// Copyright 2023 NXP ++ ++#include "imx8mp-evk.dts" ++ ++/delete-node/&spidev1; ++ ++&ecspi2 { ++ status = "okay"; ++ ++ netcdsa: ethernet-switch@0 { ++ reg = <0x0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "nxp,imxrt1180-netc"; ++ /* 500 kHz */ ++ spi-max-frequency = <500000>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ label = "swp0"; ++ reg = <0>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <100>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ label = "swp1"; ++ reg = <1>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@2 { ++ label = "swp2"; ++ reg = <2>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@3 { ++ /* cpu port connected to eqos */ ++ ethernet = <&eqos>; ++ label = "cpu"; ++ reg = <3>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&pinctrl_ecspi2 { ++ fsl,pins = < ++ MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x84 ++ MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x84 ++ MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x84 ++ >; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts +new file mode 100644 +index 000000000000..60d6028a240a +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx8mp-evk.dts" ++ ++&fec { ++ compatible = "fsl,imx8mp-fec-ecat", "fsl,imx8mq-fec-ecat", "fsl,imx6sx-fec-ecat"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts +new file mode 100644 +index 000000000000..06cf65278b98 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts +@@ -0,0 +1,21 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mp-evk-multicore-rtos.dts" ++ ++&fec { ++ status = "disabled"; ++}; ++ ++&eqos { ++ /delete-property/ clocks; ++ /delete-property/ clock-names; ++ clocks = <&clk IMX8MP_CLK_QOS_ENET_ROOT>, ++ <&clk IMX8MP_CLK_ENET_QOS_TIMER>, ++ <&clk IMX8MP_CLK_ENET_QOS>; ++ clock-names = "pclk", "ptp_ref", "tx"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts +new file mode 100644 +index 000000000000..85f1b55ee381 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts +@@ -0,0 +1,117 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mp-evk-multicore-rtos.dts" ++#include "imx8mp-rpmsg-ca53.dtsi" ++#include "imx8mp-rpmsg-ca53-1.dtsi" ++ ++/ { ++ aliases { ++ i2c0 = &i2c1; ++ i2c1 = &i2c2; ++ i2c2 = &i2c_rpbus_3; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ vdev0vring0: vdev0vring0@55000000 { ++ reg = <0 0x55000000 0 0x8000>; ++ no-map; ++ }; ++ ++ vdev0vring1: vdev0vring1@55008000 { ++ reg = <0 0x55008000 0 0x8000>; ++ no-map; ++ }; ++ ++ vdevbuffer: vdevbuffer@55400000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0x55400000 0 0x100000>; ++ no-map; ++ }; ++ ++ rsc_table: rsc-table@550ff000 { ++ reg = <0 0x550ff000 0 0x1000>; ++ no-map; ++ }; ++ }; ++ ++ sound-wm8960 { ++ status = "disabled"; ++ }; ++ ++ imx8mp-cm7 { ++ clocks = <&clk IMX8MP_CLK_M7_DIV>, ++ <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_AUDPLL_ROOT>; ++ clock-names = "core", "audio"; ++ }; ++}; ++ ++&sai3 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++/delete-node/ &i2c3; ++ ++&i2c_rpbus_3 { ++ compatible = "fsl,i2c-rpbus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pca6416: gpio@20 { ++ compatible = "ti,tca6416"; ++ reg = <0x20>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ ov5640_1: ov5640_mipi@3c { ++ compatible = "ovti,ov5640"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_csi0_pwn>, <&pinctrl_csi0_rst>; ++ clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>; ++ clock-names = "xclk"; ++ assigned-clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>; ++ assigned-clock-parents = <&clk IMX8MP_CLK_24M>; ++ assigned-clock-rates = <24000000>; ++ csi_id = <0>; ++ powerdown-gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&gpio4 0 GPIO_ACTIVE_LOW>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ mipi_csi; ++ status = "disabled"; ++ ++ port { ++ ov5640_mipi_1_ep: endpoint { ++ remote-endpoint = <&mipi_csi1_ep>; ++ data-lanes = <1 2>; ++ clock-lanes = <0>; ++ }; ++ }; ++ }; ++ ++ codec: wm8960@1a { ++ compatible = "wlf,wm8960,lpa"; ++ reg = <0x1a>; ++ wlf,shared-lrclk; ++ SPKVDD1-supply = <®_audio_pwr>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts +new file mode 100644 +index 000000000000..1799cad88062 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts +@@ -0,0 +1,79 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx8mp-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* ++ * Reserve up to 48MB (16MB x 3) for three FreeRTOS instances running on ++ * three Cortex-A Cores when booting Linux on at least on Cortex-A Core. ++ */ ++ ca53_reserved: ca53@c0000000 { ++ no-map; ++ reg = <0 0xc0000000 0x0 0x3000000>; ++ }; ++ ++ /* Reserve 16MB for RTOS running on CM7 */ ++ m7_reserved: m7@80000000 { ++ no-map; ++ reg = <0 0x80000000 0 0x1000000>; ++ }; ++ ++ vdev0vring0: vdev0vring0@55000000 { ++ reg = <0 0x55000000 0 0x8000>; ++ no-map; ++ }; ++ ++ vdev0vring1: vdev0vring1@55008000 { ++ reg = <0 0x55008000 0 0x8000>; ++ no-map; ++ }; ++ ++ vdevbuffer: vdevbuffer@55400000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0x55400000 0 0x100000>; ++ no-map; ++ }; ++ ++ rsc_table: rsc-table@550ff000 { ++ reg = <0 0x550ff000 0 0x1000>; ++ no-map; ++ }; ++ }; ++ ++ imx8mp-cm7 { ++ compatible = "fsl,imx8mn-cm7"; ++ rsc-da = <0x55000000>; ++ clocks = <&clk IMX8MP_CLK_M7_DIV>; ++ clock-names = "core"; ++ mbox-names = "tx", "rx", "rxdb"; ++ mboxes = <&mu 0 1 ++ &mu 1 1 ++ &mu 3 1>; ++ memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>; ++ status = "okay"; ++ fsl,startup-delay-ms = <500>; ++ }; ++}; ++ ++&{/busfreq} { ++ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */ ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts +new file mode 100644 +index 000000000000..489daf4c30d3 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts +@@ -0,0 +1,81 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx8mp-evk.dts" ++#include "imx8mp-generic-mbox.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ virtio_reserved: virtio@fc700000 { ++ no-map; ++ reg = <0 0xfc700000 0x0 0x00100000>; ++ }; ++ ++ /* 512MB */ ++ freertos_reserved: inmate@c0000000 { ++ no-map; ++ reg = <0 0xc0000000 0x0 0x20000000>; ++ }; ++ ++ virtio_buffer: virtio-buffer@f8700000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xf8700000 0 0x4000000>; ++ }; ++ }; ++ ++ virtio_net@fc700000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xfc700000 0x0 0x1000>; ++ dma-coherent; ++ hypervisor_less; ++ memory-region = <&virtio_buffer>; ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */ ++ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */ ++ }; ++}; ++ ++&{/busfreq} { ++ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */ ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&iomuxc { ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX 0x140 ++ MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX 0x140 ++ >; ++ }; ++}; ++ ++&fec { ++ status = "disabled"; ++}; ++ ++&eqos { ++ /delete-property/ clocks; ++ /delete-property/ clock-names; ++ clocks = <&clk IMX8MP_CLK_QOS_ENET_ROOT>, ++ <&clk IMX8MP_CLK_ENET_QOS_TIMER>, ++ <&clk IMX8MP_CLK_ENET_QOS>; ++ clock-names = "pclk", "ptp_ref", "tx"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts +new file mode 100644 +index 000000000000..3f8609b0413d +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts +@@ -0,0 +1,72 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx8mp-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ cm7_reserved: cm7@80000000 { ++ reg = <0 0x80000000 0x0 0x01000000>; ++ no-map; ++ }; ++ ++ virtio_buffer: virtio-buffer@b3c00000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xb3c00000 0 0x4000000>; ++ no-map; ++ }; ++ ++ virtio_reserved: virtio@b8400000 { ++ no-map; ++ reg = <0 0xb8400000 0x0 0x00100000>; ++ }; ++ }; ++ ++ virtio_net@b8400000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xb8400000 0x0 0x1000>; ++ hypervisor_less; ++ memory-region = <&virtio_buffer>; ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&mu 0 2 ++ &mu 1 2>; ++ }; ++}; ++ ++&{/busfreq} { ++ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */ ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "disabled"; ++}; ++ ++ ++&fec { ++ status = "disabled"; ++}; ++ ++&eqos { ++ /delete-property/ clocks; ++ /delete-property/ clock-names; ++ clocks = <&clk IMX8MP_CLK_QOS_ENET_ROOT>, ++ <&clk IMX8MP_CLK_ENET_QOS_TIMER>, ++ <&clk IMX8MP_CLK_ENET_QOS>; ++ clock-names = "pclk", "ptp_ref", "tx"; ++}; ++ ++&i2c3 { ++ status = "disabled"; ++}; ++ ++&sai3 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi +new file mode 100644 +index 000000000000..5f8ba823c0bd +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gen_sw_mbox_1_reserved: gen-sw-mbox-1@fe001000 { ++ reg = <0 0xfe001000 0 0x1000>; ++ no-map; ++ }; ++ ++ }; ++ ++ gen_sw_mbox_1: generic-software-mailbox-1@fe001000 { ++ compatible = "fsl,generic-software-mbox"; ++ reg = <0 0xfe001000 0 0x1000>; ++ #mbox-cells = <3>; ++ /* Use 2 unused SPI interrupts */ ++ interrupts = , ; ++ interrupt-names = "irq", "remote_irq"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi +new file mode 100644 +index 000000000000..8709e076bcc0 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gen_sw_mbox_reserved: gen-sw-mbox@fe000000 { ++ reg = <0 0xfe000000 0 0x1000>; ++ no-map; ++ }; ++ ++ }; ++ ++ gen_sw_mbox: generic-software-mailbox@fe000000 { ++ compatible = "fsl,generic-software-mbox"; ++ reg = <0 0xfe000000 0 0x1000>; ++ #mbox-cells = <3>; ++ /* Use 2 unused SPI interrupts */ ++ interrupts = , ; ++ interrupt-names = "irq", "remote_irq"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi +new file mode 100644 +index 000000000000..0e1f484209ff +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx8mp-generic-mbox-1.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ rpmsg_ca53_1_reserved: rpmsg-ca53-1@fe110000 { ++ reg = <0 0xfe110000 0 0x10000>; ++ no-map; ++ }; ++ ++ vdevbuffer_ca53_1: vdevbuffer-ca53-1@fe300000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xfe300000 0 0x100000>; ++ no-map; ++ }; ++ }; ++ ++ rpmsg-ca53-1 { ++ compatible = "fsl,imx8mm-rpmsg"; ++ reg = <0x0 0xfe110000 0x0 0x10000>; /* 64K for one rpmsg instance */ ++ dma-coherent; ++ memory-region = <&vdevbuffer_ca53_1>; ++ mbox-names = "tx", "rx", "rxdb"; ++ mboxes = <&gen_sw_mbox_1 0 0 1 /* Tx channel with ACK */ ++ &gen_sw_mbox_1 1 0 0 /* Rx channel without ACK */ ++ &gen_sw_mbox_1 2 0 1>; /* RXDB channel with ACK */ ++ vdev-nums = <1>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi +new file mode 100644 +index 000000000000..32e127a6d203 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2022-2023 NXP ++ */ ++ ++#include "imx8mp-generic-mbox.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ rpmsg_ca53_reserved: rpmsg-ca53@fe100000 { ++ reg = <0 0xfe100000 0 0x10000>; ++ no-map; ++ }; ++ ++ vdevbuffer_ca53: vdevbuffer-ca53@fe200000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xfe200000 0 0x100000>; ++ no-map; ++ }; ++ }; ++ ++ rpmsg-ca53 { ++ compatible = "fsl,imx8mm-rpmsg"; ++ reg = <0x0 0xfe100000 0x0 0x10000>; /* 64K for one rpmsg instance */ ++ dma-coherent; ++ memory-region = <&vdevbuffer_ca53>; ++ mbox-names = "tx", "rx", "rxdb"; ++ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */ ++ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */ ++ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */ ++ vdev-nums = <1>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi +index 593b0c6ae72f..4a6b9d168c20 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi +@@ -569,6 +569,16 @@ wdog3: watchdog@302a0000 { + status = "disabled"; + }; + ++ gpt1: gpt@302d0000 { ++ compatible = "fsl,imx8mq-gpt", "fsl,imx7d-gpt"; ++ reg = <0x302d0000 0x10000>; ++ interrupts = ; ++ clocks = <&clk IMX8MP_CLK_GPT1_ROOT>, ++ <&clk IMX8MP_CLK_GPT1_ROOT>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ + iomuxc: pinctrl@30330000 { + compatible = "fsl,imx8mp-iomuxc"; + reg = <0x30330000 0x10000>; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts +new file mode 100644 +index 000000000000..f6dd57285814 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts +@@ -0,0 +1,41 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx93-11x11-evk.dts" ++ ++/* AVB HW timer*/ ++&tpm4 { ++ compatible = "fsl,avb-tpm"; ++ timer-channel = <1>; /* Use output compare channel 1*/ ++ prescale = <1>; ++ domain = <0>; ++ interrupts = ; ++ ++ clocks = <&clk IMX93_CLK_BUS_WAKEUP>, <&clk IMX93_CLK_TPM4_GATE>, <&clk IMX93_CLK_AUDIO_PLL>; ++ clock-names = "ipg", "per", "audio_pll"; ++ ++ /* Set TPM4 clock root to Audio PLL. */ ++ assigned-clocks = <&clk IMX93_CLK_TPM4>; ++ assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>; ++ assigned-clock-rates = <0>; ++ ++ /* Enble SW sampling for media clock recovery on port 0 */ ++ sw-recovery = <0>; ++ ++ status = "okay"; ++}; ++ ++&fec { ++ fsl,rx-phy-delay-100-ns = <670>; ++ fsl,tx-phy-delay-100-ns = <670>; ++ fsl,rx-phy-delay-1000-ns = <0>; ++ fsl,tx-phy-delay-1000-ns = <0>; ++}; ++ ++ðphy2 { ++ eee-broken-100tx; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts +new file mode 100644 +index 000000000000..84f9700437a1 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts +@@ -0,0 +1,31 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx93-11x11-evk.dts" ++ ++/ { ++ model = "NXP i.MX93 11X11 EVK board - Baremetal"; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ bm_reserved: baremetal@b0000000 { ++ no-map; ++ reg = <0 0xb0000000 0 0x10000000>; ++ }; ++ }; ++}; ++ ++&fec { ++ status = "disabled"; ++}; ++ ++&lpuart2 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts +new file mode 100644 +index 000000000000..954e78a84f43 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts +@@ -0,0 +1,96 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx93-11x11-evk.dts" ++ ++&flexcan2 { ++ status = "disabled"; ++}; ++ ++&lpuart7 { ++ status = "disabled"; ++}; ++ ++&lpspi3 { ++ fsl,spi-num-chipselects = <1>; ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&pinctrl_lpspi3>; ++ pinctrl-1 = <&pinctrl_lpspi3>; ++ cs-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>; ++ pinctrl-assert-gpios = <&adp5585gpio 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ ++ netcdsa: ethernet-switch@0 { ++ reg = <0x0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "nxp,imxrt1180-netc"; ++ /* 1 MHz */ ++ spi-max-frequency = <1000000>; ++ /* Sample data on trailing clock edge */ ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ label = "swp0"; ++ reg = <0>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <100>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ label = "swp1"; ++ reg = <1>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@2 { ++ label = "swp2"; ++ reg = <2>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@3 { ++ /* cpu port connected to eqos */ ++ ethernet = <&eqos>; ++ label = "cpu"; ++ reg = <3>; ++ phy-mode = "sgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl_lpspi3: lpspi3grp { ++ fsl,pins = < ++ MX93_PAD_GPIO_IO08__GPIO2_IO08 0x3fe ++ MX93_PAD_GPIO_IO09__LPSPI3_SIN 0x3fe ++ MX93_PAD_GPIO_IO10__LPSPI3_SOUT 0x3fe ++ MX93_PAD_GPIO_IO11__LPSPI3_SCK 0x3fe ++ >; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts +new file mode 100644 +index 000000000000..3626356fb9b6 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts +@@ -0,0 +1,11 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "imx93-11x11-evk.dts" ++ ++ ++&fec { ++ compatible = "fsl,imx93-fec-ecat", "fsl,imx8mp-fec-ecat", "fsl,imx8mq-fec-ecat"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts +new file mode 100644 +index 000000000000..cac3133ddc82 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx93-11x11-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* ++ * Reserve up to 16MB for one possible FreeRTOS instances running on ++ * one Cortex-A Cores when booting Linux on at least on Cortex-A Core. ++ */ ++ rtos_ca55_reserved: rtos-ca55@d0000000 { ++ no-map; ++ reg = <0 0xd0000000 0x0 0x1000000>; ++ }; ++ ++ /* Reserve 16MB for FreeRTOS on M33 */ ++ m33_reserved: m33@a5000000 { ++ no-map; ++ reg = <0 0xa5000000 0 0x1000000>; ++ }; ++ }; ++}; ++ ++&lpuart2 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts +new file mode 100644 +index 000000000000..e55552658d09 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts +@@ -0,0 +1,96 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include ++#include "imx93-11x11-evk.dts" ++ ++/ { ++ uart_rpbus_0: uart-rpbus-0 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_1: uart-rpbus-1 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_2: uart-rpbus-2 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_3: uart-rpbus-3 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_4: uart-rpbus-4 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_5: uart-rpbus-5 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_6: uart-rpbus-6 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_7: uart-rpbus-7 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_8: uart-rpbus-8 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_9: uart-rpbus-9 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_10: uart-rpbus-10 { ++ compatible = "fsl,uart-rpbus"; ++ status = "okay"; /* mcore directly print data that receive from acore */ ++ }; ++}; ++ ++/* ++ * ATTENTION: M33 may use IPs like below ++ * LPUART5 ++ */ ++ ++/* the lpuart5 is used by m33 to support srtm uart service */ ++&lpuart5 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts +new file mode 100644 +index 000000000000..17a6fdeb8ca0 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts +@@ -0,0 +1,55 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx93-11x11-evk.dts" ++#include "imx93-generic-mbox.dtsi" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ virtio_reserved: virtio@fc700000 { ++ no-map; ++ reg = <0 0xfc700000 0x0 0x00100000>; ++ }; ++ ++ /* 512MB */ ++ freertos_reserved: inmate@d0000000 { ++ no-map; ++ reg = <0 0xd0000000 0x0 0x20000000>; ++ }; ++ ++ virtio_buffer: virtio-buffer@f8700000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xf8700000 0 0x4000000>; ++ }; ++ }; ++ ++ virtio_net@fc700000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xfc700000 0x0 0x1000>; ++ dma-coherent; ++ hypervisor_less; ++ memory-region = <&virtio_buffer>; ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */ ++ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */ ++ }; ++}; ++ ++&lpuart2 { ++ status = "disabled"; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&fec { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts +new file mode 100644 +index 000000000000..f92138a94ab8 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts +@@ -0,0 +1,53 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++#include "imx93-11x11-evk.dts" ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ cm33_reserved: cm33@a0000000 { ++ reg = <0 0xa0000000 0x0 0x01000000>; ++ no-map; ++ }; ++ ++ virtio_buffer: virtio-buffer@a1000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0 0xa1000000 0 0x3000000>; ++ no-map; ++ }; ++ ++ virtio_reserved: virtio@a8400000 { ++ reg = <0 0xa8400000 0x0 0x00100000>; ++ no-map; ++ }; ++ }; ++ ++ virtio_net@a8400000 { ++ compatible = "virtio,mmio"; ++ reg = <0x0 0xa8400000 0x0 0x1000>; ++ hypervisor_less; ++ memory-region = <&virtio_buffer>; ++ mbox-names = "mmiowr", "mmioirq"; ++ mboxes = <&mu1 0 2 ++ &mu1 1 2>; ++ }; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&lpuart2 { ++ status = "disabled"; ++}; ++ ++&fec { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +index d23880c3afcf..a597842e652c 100644 +--- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +@@ -331,7 +331,7 @@ &xcvr { + assigned-clock-rates = <12288000>, <200000000>; + status = "okay"; + }; +- ++ + &adc1 { + vref-supply = <®_vref_1v8>; + status = "okay"; +@@ -367,6 +367,9 @@ &eqos { + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy1>; ++ snps,force_thresh_dma_mode; ++ snps,mtl-tx-config = <&mtl_tx_setup>; ++ snps,mtl-rx-config = <&mtl_rx_setup>; + status = "okay"; + + mdio { +@@ -381,6 +384,61 @@ ethphy1: ethernet-phy@1 { + eee-broken-1000t; + }; + }; ++ ++ mtl_tx_setup: tx-queues-config { ++ snps,tx-queues-to-use = <5>; ++ snps,tx-sched-sp; ++ queue0 { ++ snps,dcb-algorithm; ++ snps,priority = <0x1>; ++ }; ++ queue1 { ++ snps,dcb-algorithm; ++ snps,priority = <0x2>; ++ }; ++ queue2 { ++ snps,dcb-algorithm; ++ snps,priority = <0x4>; ++ }; ++ queue3 { ++ snps,dcb-algorithm; ++ snps,priority = <0x8>; ++ }; ++ queue4 { ++ snps,dcb-algorithm; ++ snps,priority = <0xf0>; ++ }; ++ }; ++ ++ mtl_rx_setup: rx-queues-config { ++ snps,rx-queues-to-use = <5>; ++ snps,rx-sched-sp; ++ queue0 { ++ snps,dcb-algorithm; ++ snps,priority = <0x1>; ++ snps,map-to-dma-channel = <0>; ++ }; ++ queue1 { ++ snps,dcb-algorithm; ++ snps,priority = <0x2>; ++ snps,map-to-dma-channel = <1>; ++ }; ++ queue2 { ++ snps,dcb-algorithm; ++ snps,priority = <0x4>; ++ snps,map-to-dma-channel = <2>; ++ }; ++ queue3 { ++ snps,dcb-algorithm; ++ snps,priority = <0x8>; ++ snps,map-to-dma-channel = <3>; ++ }; ++ queue4 { ++ snps,dcb-algorithm; ++ snps,priority = <0xf0>; ++ snps,map-to-dma-channel = <4>; ++ }; ++ }; + }; + + &fec { +diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts +new file mode 100644 +index 000000000000..8b4cbd366ae6 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts +@@ -0,0 +1,31 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx93-9x9-qsb.dts" ++ ++/ { ++ model = "NXP i.MX93 9X9 QSB board - Baremetal"; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ bm_reserved: baremetal@b0000000 { ++ no-map; ++ reg = <0 0xb0000000 0 0x10000000>; ++ }; ++ }; ++}; ++ ++&fec { ++ status = "disabled"; ++}; ++ ++&lpuart2 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts +new file mode 100644 +index 000000000000..cd1f0e0cc401 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts +@@ -0,0 +1,151 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include ++ ++/ { ++ model = "NXP i.MX93 9x9 QSB"; ++ compatible = "fsl,imx93-9x9-qsb", "fsl,imx93"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ aliases { ++ mmc0 = &usdhc1; ++ serial1 = &lpuart2; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ A55_0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a55"; ++ reg = <0x0>; ++ enable-method = "psci"; ++ #cooling-cells = <2>; ++ }; ++ }; ++ ++ psci { ++ compatible = "arm,psci-1.0"; ++ method = "smc"; ++ }; ++ ++ gic: interrupt-controller@48000000 { ++ compatible = "arm,gic-v3"; ++ reg = <0 0x48000000 0 0x10000>, ++ <0 0x48040000 0 0xc0000>; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ interrupts = ; ++ interrupt-parent = <&gic>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ clock-frequency = <24000000>; ++ }; ++ ++ clk_dummy: clock-dummy { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <0>; ++ clock-output-names = "clk_dummy"; ++ }; ++ ++ clk_400m: clock-400m { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <200000000>; ++ clock-output-names = "200m"; ++ }; ++ ++ osc_24m: clock-osc-24m { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ clock-output-names = "osc_24m"; ++ }; ++ ++ pci@fd700000 { ++ compatible = "pci-host-ecam-generic"; ++ device_type = "pci"; ++ bus-range = <0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &gic GIC_SPI 227 IRQ_TYPE_EDGE_RISING>, ++ <0 0 0 2 &gic GIC_SPI 228 IRQ_TYPE_EDGE_RISING>, ++ <0 0 0 3 &gic GIC_SPI 229 IRQ_TYPE_EDGE_RISING>, ++ <0 0 0 4 &gic GIC_SPI 230 IRQ_TYPE_EDGE_RISING>; ++ reg = <0x0 0xfd700000 0x0 0x100000>; ++ ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; ++ }; ++ ++ soc@0 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x0 0x80000000>, ++ <0x28000000 0x0 0x28000000 0x10000000>; ++ ++ aips1: bus@44000000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ reg = <0x44000000 0x800000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ lpuart2: serial@44390000 { ++ compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart"; ++ reg = <0x44390000 0x1000>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ }; ++ ++ aips3: bus@42800000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ reg = <0x42800000 0x800000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ usdhc1: mmc@42850000 { ++ compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc"; ++ reg = <0x42850000 0x10000>; ++ interrupts = ; ++ fsl,tuning-start-tap = <20>; ++ fsl,tuning-step= <2>; ++ status = "disabled"; ++ }; ++ }; ++ }; ++}; ++ ++&lpuart2 { ++ clocks = <&osc_24m>; ++ clock-names = "ipg"; ++ status = "okay"; ++}; ++ ++&usdhc1 { ++ clocks = <&clk_dummy>, ++ <&clk_dummy>, ++ <&clk_400m>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <8>; ++ non-removable; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts +new file mode 100644 +index 000000000000..e61f46be93b7 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts +@@ -0,0 +1,54 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include "imx93-9x9-qsb.dts" ++ ++/{ ++ interrupt-parent = <&gic>; ++ ++ resmem: reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ }; ++}; ++ ++&clk { ++ init-on-array = ; ++}; ++ ++&iomuxc { ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX93_PAD_UART2_TXD__LPUART2_TX 0x31e ++ MX93_PAD_UART2_RXD__LPUART2_RX 0x31e ++ >; ++ }; ++}; ++ ++&lpuart2 { ++ /delete-property/ dmas; ++ /delete-property/ dma-names; ++ status = "disabled"; ++}; ++ ++&lpuart1 { ++ pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart2>; ++ assigned-clocks = <&clk IMX93_CLK_LPUART2>; ++ assigned-clock-parents = <&clk IMX93_CLK_24M>; ++}; ++ ++&usdhc1 { ++ status = "disabled"; ++}; ++ ++&usdhc2 { ++ pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc1>; ++ pinctrl-1 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc1>; ++ pinctrl-2 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc1>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts +new file mode 100644 +index 000000000000..c897b9e9ced2 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts +@@ -0,0 +1,96 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/dts-v1/; ++ ++#include ++#include "imx93-9x9-qsb.dts" ++ ++/ { ++ uart_rpbus_0: uart-rpbus-0 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_1: uart-rpbus-1 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_2: uart-rpbus-2 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_3: uart-rpbus-3 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_4: uart-rpbus-4 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_5: uart-rpbus-5 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_6: uart-rpbus-6 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_7: uart-rpbus-7 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_8: uart-rpbus-8 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_9: uart-rpbus-9 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use lpuart5 */ ++ flags=; ++ status = "okay"; ++ }; ++ ++ uart_rpbus_10: uart-rpbus-10 { ++ compatible = "fsl,uart-rpbus"; ++ status = "okay"; /* mcore directly print data that receive from acore */ ++ }; ++}; ++ ++/* ++ * ATTENTION: M33 may use IPs like below ++ * LPUART5 ++ */ ++ ++/* the lpuart5 is used by m33 to support srtm uart service */ ++&lpuart5 { ++ status = "disabled"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts +index fba9380bdc69..314bd2ef7820 100644 +--- a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts ++++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts +@@ -224,6 +224,9 @@ &eqos { + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy1>; ++ snps,force_thresh_dma_mode; ++ snps,mtl-tx-config = <&mtl_tx_setup>; ++ snps,mtl-rx-config = <&mtl_rx_setup>; + status = "okay"; + + mdio { +@@ -238,6 +241,61 @@ ethphy1: ethernet-phy@1 { + eee-broken-1000t; + }; + }; ++ ++ mtl_tx_setup: tx-queues-config { ++ snps,tx-queues-to-use = <5>; ++ snps,tx-sched-sp; ++ queue0 { ++ snps,dcb-algorithm; ++ snps,priority = <0x1>; ++ }; ++ queue1 { ++ snps,dcb-algorithm; ++ snps,priority = <0x2>; ++ }; ++ queue2 { ++ snps,dcb-algorithm; ++ snps,priority = <0x4>; ++ }; ++ queue3 { ++ snps,dcb-algorithm; ++ snps,priority = <0x8>; ++ }; ++ queue4 { ++ snps,dcb-algorithm; ++ snps,priority = <0xf0>; ++ }; ++ }; ++ ++ mtl_rx_setup: rx-queues-config { ++ snps,rx-queues-to-use = <5>; ++ snps,rx-sched-sp; ++ queue0 { ++ snps,dcb-algorithm; ++ snps,priority = <0x1>; ++ snps,map-to-dma-channel = <0>; ++ }; ++ queue1 { ++ snps,dcb-algorithm; ++ snps,priority = <0x2>; ++ snps,map-to-dma-channel = <1>; ++ }; ++ queue2 { ++ snps,dcb-algorithm; ++ snps,priority = <0x4>; ++ snps,map-to-dma-channel = <2>; ++ }; ++ queue3 { ++ snps,dcb-algorithm; ++ snps,priority = <0x8>; ++ snps,map-to-dma-channel = <3>; ++ }; ++ queue4 { ++ snps,dcb-algorithm; ++ snps,priority = <0xf0>; ++ snps,map-to-dma-channel = <4>; ++ }; ++ }; + }; + + &lpm { +diff --git a/arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi b/arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi +new file mode 100644 +index 000000000000..5e6e1723a05d +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gen_sw_mbox_reserved: gen-sw-mbox@fe000000 { ++ reg = <0 0xfe000000 0 0x1000>; ++ no-map; ++ }; ++ ++ }; ++ ++ gen_sw_mbox: generic-software-mailbox@fe000000 { ++ compatible = "fsl,generic-software-mbox"; ++ reg = <0 0xfe000000 0 0x1000>; ++ #mbox-cells = <3>; ++ /* Use 2 unused SPI interrupts */ ++ interrupts = , ; ++ interrupt-names = "irq", "remote_irq"; ++ }; ++}; +diff --git a/arch/arm64/configs/imx_avb.config b/arch/arm64/configs/imx_avb.config +new file mode 100644 +index 000000000000..1c8ba04c0381 +--- /dev/null ++++ b/arch/arm64/configs/imx_avb.config +@@ -0,0 +1,8 @@ ++CONFIG_EXPERT=y ++CONFIG_PREEMPT_RT=y ++CONFIG_AVB_SUPPORT=y ++CONFIG_NET_SWITCHDEV=y ++CONFIG_DEBUG_INFO=y ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_USERSPACE=y +diff --git a/arch/arm64/configs/imx_v8_defconfig b/arch/arm64/configs/imx_v8_defconfig +index 10979905f06e..2937c1bc49c5 100644 +--- a/arch/arm64/configs/imx_v8_defconfig ++++ b/arch/arm64/configs/imx_v8_defconfig +@@ -5,6 +5,8 @@ CONFIG_NO_HZ_IDLE=y + CONFIG_HIGH_RES_TIMERS=y + CONFIG_BPF_SYSCALL=y + CONFIG_BPF_JIT=y ++CONFIG_BPF_JIT_ALWAYS_ON=y ++CONFIG_XDP_SOCKETS=y + CONFIG_PREEMPT=y + CONFIG_IRQ_TIME_ACCOUNTING=y + CONFIG_BSD_PROCESS_ACCT=y +@@ -136,29 +138,37 @@ CONFIG_BRIDGE_NF_EBTABLES=m + CONFIG_BRIDGE=y + CONFIG_BRIDGE_VLAN_FILTERING=y + CONFIG_NET_DSA=m ++CONFIG_NET_DSA_SJA1105=m ++CONFIG_NET_DSA_SJA1105_PTP=y ++CONFIG_NET_DSA_SJA1105_TAS=y ++CONFIG_NET_DSA_SJA1105_VL=y + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_VLAN_8021Q_MVRP=y + CONFIG_LLC2=y + CONFIG_NET_SCHED=y +-CONFIG_NET_SCH_MULTIQ=m +-CONFIG_NET_SCH_CBS=m +-CONFIG_NET_SCH_ETF=m +-CONFIG_NET_SCH_TAPRIO=m +-CONFIG_NET_SCH_MQPRIO=m +-CONFIG_NET_SCH_INGRESS=m ++CONFIG_NET_SCH_MULTIQ=y ++CONFIG_NET_SCH_CBS=y ++CONFIG_NET_SCH_ETF=y ++CONFIG_NET_SCH_TAPRIO=y ++CONFIG_NET_SCH_MQPRIO=y ++CONFIG_NET_SCH_INGRESS=y + CONFIG_NET_CLS_BASIC=m +-CONFIG_NET_CLS_U32=m ++CONFIG_NET_CLS_U32=y + CONFIG_NET_CLS_FLOWER=m + CONFIG_NET_CLS_ACT=y + CONFIG_NET_ACT_GACT=m + CONFIG_NET_ACT_MIRRED=m +-CONFIG_NET_ACT_SKBEDIT=m ++CONFIG_NET_ACT_SKBEDIT=y + CONFIG_NET_ACT_GATE=m ++CONFIG_NET_EMATCH=y ++CONFIG_NET_EMATCH_STACK=32 ++CONFIG_NET_EMATCH_U32=y ++CONFIG_NET_EMATCH_META=y + CONFIG_TSN=y + CONFIG_QRTR=m + CONFIG_QRTR_SMD=m + CONFIG_QRTR_TUN=m +-CONFIG_NET_PKTGEN=m ++CONFIG_NET_PKTGEN=y + CONFIG_CAN=m + CONFIG_BT=y + CONFIG_BT_RFCOMM=y +@@ -286,6 +296,7 @@ CONFIG_TUN=y + CONFIG_VETH=m + CONFIG_VIRTIO_NET=y + CONFIG_NET_DSA_MSCC_FELIX=m ++CONFIG_NET_DSA_NETC=m + CONFIG_NET_DSA_SJA1105=m + CONFIG_NET_DSA_SJA1105_PTP=y + CONFIG_NET_DSA_SJA1105_TAS=y +@@ -298,6 +309,7 @@ CONFIG_SYSTEMPORT=m + CONFIG_MACB=y + CONFIG_THUNDER_NIC_PF=y + CONFIG_FEC=y ++CONFIG_FEC_ECAT=y + CONFIG_FEC_UIO=y + CONFIG_FSL_FMAN=y + CONFIG_FSL_DPAA_ETH=y +@@ -1131,3 +1143,11 @@ CONFIG_CORESIGHT_STM=m + CONFIG_CORESIGHT_CPU_DEBUG=m + CONFIG_CORESIGHT_CTI=m + CONFIG_MEMTEST=y ++ ++# Preempt RT, depend on CONFIG_EXPERT ++CONFIG_EXPERT=y ++CONFIG_PREEMPT_RT=y ++ ++CONFIG_RPMSG_TTY=m ++CONFIG_GENERIC_SOFTWARE_MAILBOX=y ++CONFIG_VIRTIO_TRANS=y +diff --git a/arch/arm64/configs/linux-dpaa-ethercat.config b/arch/arm64/configs/linux-dpaa-ethercat.config +new file mode 100644 +index 000000000000..15e4b306bc3d +--- /dev/null ++++ b/arch/arm64/configs/linux-dpaa-ethercat.config +@@ -0,0 +1 @@ ++CONFIG_FSL_DPAA_ETHERCAT=y +diff --git a/arch/arm64/configs/linux-rpmsg-8m-buf.config b/arch/arm64/configs/linux-rpmsg-8m-buf.config +new file mode 100644 +index 000000000000..d7780b2b8299 +--- /dev/null ++++ b/arch/arm64/configs/linux-rpmsg-8m-buf.config +@@ -0,0 +1 @@ ++CONFIG_RPMSG_8M_BUF=y +diff --git a/arch/arm64/configs/lsdk.config b/arch/arm64/configs/lsdk.config +index e27248011e58..eb33235e4eab 100644 +--- a/arch/arm64/configs/lsdk.config ++++ b/arch/arm64/configs/lsdk.config +@@ -84,12 +84,25 @@ CONFIG_BRIDGE_NF_EBTABLES=y + CONFIG_BRIDGE_EBT_T_NAT=y + CONFIG_BRIDGE_EBT_DNAT=y + CONFIG_BRIDGE_EBT_SNAT=y ++CONFIG_BRIDGE_EBT_BROUTE=y ++CONFIG_BRIDGE_EBT_802_3=y ++CONFIG_BRIDGE_EBT_IP=y ++CONFIG_BRIDGE_EBT_IP6=y + CONFIG_NETFILTER_XT_MATCH_COMMENT=y + CONFIG_SFP=y + CONFIG_PHY_FSL_LYNX_28G=y + CONFIG_BPF_SYSCALL=y + CONFIG_BPF_JIT_ALWAYS_ON=y + CONFIG_XDP_SOCKETS=y ++CONFIG_NET_SCH_INGRESS=y ++CONFIG_NET_ACT_POLICE=y ++CONFIG_NET_ACT_GACT=y ++CONFIG_NET_ACT_GATE=y ++CONFIG_NET_CLS_MATCHALL=y ++CONFIG_NET_PKTGEN=y ++ ++# Enable felix switch TSN ++CONFIG_MSCC_FELIX_SWITCH_TSN=y + + # GPU + CONFIG_DRM=y +@@ -97,7 +110,6 @@ CONFIG_MXC_GPU_VIV=y + + # disable unneeded options and override default options set by defconfig to deduce the size of modules + # CONFIG_NET_VENDOR_STMICRO is not set +-# CONFIG_MEDIA_SUPPORT is not set + # CONFIG_BACKLIGHT_GENERIC is not set + # CONFIG_TEGRA_HOST1X is not set + # CONFIG_BT is not set +@@ -181,6 +193,7 @@ CONFIG_NET_CLS_FLOWER=y + CONFIG_NET_EMATCH=y + CONFIG_NET_EMATCH_STACK=32 + CONFIG_NET_EMATCH_U32=y ++CONFIG_NET_EMATCH_META=y + CONFIG_NET_CLS_ACT=y + CONFIG_NET_ACT_PEDIT=y + CONFIG_NET_ACT_SKBEDIT=y +@@ -191,8 +204,16 @@ CONFIG_USB_RTL8152=y + CONFIG_USB_USBNET=y + CONFIG_USB_NET_AX8817X=y + CONFIG_USB_NET_AX88179_178A=y +-# CONFIG_NET_PKTGEN is not set + + #build-in drivers + CONFIG_FSL_DPAA2_SWITCH=y + CONFIG_QORIQ_THERMAL=y ++ ++# Preempt RT, depend on CONFIG_EXPERT ++CONFIG_PREEMPT_RT=y ++ ++CONFIG_NFC_NXP_PN5XX=m ++ ++# IVSHMEM ++CONFIG_IVSHMEM_NET=y ++CONFIG_UIO_IVSHMEM=y +diff --git a/arch/arm64/include/asm/preempt.h b/arch/arm64/include/asm/preempt.h +index 0159b625cc7f..a5486918e5ee 100644 +--- a/arch/arm64/include/asm/preempt.h ++++ b/arch/arm64/include/asm/preempt.h +@@ -71,13 +71,36 @@ static inline bool __preempt_count_dec_and_test(void) + * interrupt occurring between the non-atomic READ_ONCE/WRITE_ONCE + * pair. + */ +- return !pc || !READ_ONCE(ti->preempt_count); ++ if (!pc || !READ_ONCE(ti->preempt_count)) ++ return true; ++#ifdef CONFIG_PREEMPT_LAZY ++ if ((pc & ~PREEMPT_NEED_RESCHED)) ++ return false; ++ if (current_thread_info()->preempt_lazy_count) ++ return false; ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++#else ++ return false; ++#endif + } + + static inline bool should_resched(int preempt_offset) + { ++#ifdef CONFIG_PREEMPT_LAZY ++ u64 pc = READ_ONCE(current_thread_info()->preempt_count); ++ if (pc == preempt_offset) ++ return true; ++ ++ if ((pc & ~PREEMPT_NEED_RESCHED) != preempt_offset) ++ return false; ++ ++ if (current_thread_info()->preempt_lazy_count) ++ return false; ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++#else + u64 pc = READ_ONCE(current_thread_info()->preempt_count); + return pc == preempt_offset; ++#endif + } + + #ifdef CONFIG_PREEMPTION +diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h +index 848739c15de8..4b7148fd5551 100644 +--- a/arch/arm64/include/asm/thread_info.h ++++ b/arch/arm64/include/asm/thread_info.h +@@ -26,6 +26,7 @@ struct thread_info { + #ifdef CONFIG_ARM64_SW_TTBR0_PAN + u64 ttbr0; /* saved TTBR0_EL1 */ + #endif ++ int preempt_lazy_count; /* 0 => preemptable, <0 => bug */ + union { + u64 preempt_count; /* 0 => preemptible, <0 => bug */ + struct { +@@ -68,6 +69,7 @@ int arch_dup_task_struct(struct task_struct *dst, + #define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */ + #define TIF_MTE_ASYNC_FAULT 5 /* MTE Asynchronous Tag Check Fault */ + #define TIF_NOTIFY_SIGNAL 6 /* signal notifications exist */ ++#define TIF_NEED_RESCHED_LAZY 7 + #define TIF_SYSCALL_TRACE 8 /* syscall trace active */ + #define TIF_SYSCALL_AUDIT 9 /* syscall auditing */ + #define TIF_SYSCALL_TRACEPOINT 10 /* syscall tracepoint for ftrace */ +@@ -100,8 +102,10 @@ int arch_dup_task_struct(struct task_struct *dst, + #define _TIF_SVE (1 << TIF_SVE) + #define _TIF_MTE_ASYNC_FAULT (1 << TIF_MTE_ASYNC_FAULT) + #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) ++#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) + +-#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ ++#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \ ++ _TIF_SIGPENDING | \ + _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ + _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \ + _TIF_NOTIFY_SIGNAL) +@@ -110,6 +114,8 @@ int arch_dup_task_struct(struct task_struct *dst, + _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ + _TIF_SYSCALL_EMU) + ++#define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) ++ + #ifdef CONFIG_SHADOW_CALL_STACK + #define INIT_SCS \ + .scs_base = init_shadow_call_stack, \ +diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c +index 1197e7679882..e74c0415f67e 100644 +--- a/arch/arm64/kernel/asm-offsets.c ++++ b/arch/arm64/kernel/asm-offsets.c +@@ -32,6 +32,7 @@ int main(void) + DEFINE(TSK_TI_CPU, offsetof(struct task_struct, thread_info.cpu)); + DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); + DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); ++ DEFINE(TSK_TI_PREEMPT_LAZY, offsetof(struct task_struct, thread_info.preempt_lazy_count)); + #ifdef CONFIG_ARM64_SW_TTBR0_PAN + DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0)); + #endif +diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c +index 82f4572c8ddf..2a606c7bf025 100644 +--- a/arch/arm64/kernel/signal.c ++++ b/arch/arm64/kernel/signal.c +@@ -1108,7 +1108,7 @@ static void do_signal(struct pt_regs *regs) + void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags) + { + do { +- if (thread_flags & _TIF_NEED_RESCHED) { ++ if (thread_flags & _TIF_NEED_RESCHED_MASK) { + /* Unmask Debug and SError for the next task */ + local_daif_restore(DAIF_PROCCTX_NOIRQ); + +diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c +index 5241f13c4068..8e534c956720 100644 +--- a/arch/arm64/kernel/smp.c ++++ b/arch/arm64/kernel/smp.c +@@ -54,6 +54,10 @@ + #define CREATE_TRACE_POINTS + #include + ++#ifdef CONFIG_BAREMETAL ++#include ++#endif ++ + DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number); + EXPORT_PER_CPU_SYMBOL(cpu_number); + +@@ -74,6 +78,13 @@ enum ipi_msg_type { + IPI_TIMER, + IPI_IRQ_WORK, + IPI_WAKEUP, ++#ifdef CONFIG_BAREMETAL ++#if defined(CONFIG_IMX8M_BAREMETAL) || defined(CONFIG_IMX93_BAREMETAL) ++ IPI_BAREMETAL_COMM = 9, ++#else ++ IPI_BAREMETAL_COMM = 8, ++#endif ++#endif + NR_IPI + }; + +@@ -770,6 +781,9 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { + [IPI_TIMER] = "Timer broadcast interrupts", + [IPI_IRQ_WORK] = "IRQ work interrupts", + [IPI_WAKEUP] = "CPU wake-up interrupts", ++#ifdef CONFIG_BAREMETAL ++ [IPI_BAREMETAL_COMM] = "Baremetal inter-core interrupts", ++#endif + }; + + static void smp_cross_call(const struct cpumask *target, unsigned int ipinr); +@@ -908,6 +922,17 @@ static void do_handle_IPI(int ipinr) + break; + #endif + ++#ifdef CONFIG_BAREMETAL ++ case IPI_BAREMETAL_COMM: { ++ /* FIXME: use the fixed source coreID from core1 */ ++ int irqsrc = 1; ++ /*linux core is 0 core, so iterate from 1 core.*/ ++ for(irqsrc = 1; irqsrc < CONFIG_MAX_CPUS; irqsrc++) ++ ipi_baremetal_handle(ipinr, irqsrc); ++ } ++ break; ++#endif ++ + default: + pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); + break; +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0004-Documentation-add-NXP-RT-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0004-Documentation-add-NXP-RT-support.patch new file mode 100644 index 000000000..21144d5b7 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0004-Documentation-add-NXP-RT-support.patch @@ -0,0 +1,581 @@ +From e418c26b14e840304aa6e00ef847ec41ac0b995e Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Fri, 23 Feb 2024 12:28:42 +0100 +Subject: [PATCH 04/10] Documentation: add NXP RT support + +Signed-off-by: Mike Engel +--- + .../mailbox/generic-software-mbox.yaml | 65 +++ + .../devicetree/bindings/net/fsl,fec.yaml | 24 ++ + .../devicetree/bindings/tty/rpmsg_tty.yaml | 67 ++++ + Documentation/printk-ringbuffer.txt | 377 ++++++++++++++++++ + 4 files changed, 533 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml + create mode 100644 Documentation/devicetree/bindings/tty/rpmsg_tty.yaml + create mode 100644 Documentation/printk-ringbuffer.txt + +diff --git a/Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml b/Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml +new file mode 100644 +index 000000000000..57c91ab2c80a +--- /dev/null ++++ b/Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml +@@ -0,0 +1,65 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mailbox/generic-software-mbox.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Generic Software Mailbox ++ ++maintainers: ++ - Hou Zhiqiang ++ ++description: | ++ The Generic Software Mailbox is a virtual device, which uses unused ++ interrupt line to notify remote side and shared memory to emulate ++ device MMIO registers. ++ ++properties: ++ compatible: ++ oneOf: ++ - const: fsl,generic-software-mbox ++ reg: ++ maxItems: 1 ++ ++ "#mbox-cells": ++ description: | ++ <&phandle type channel ack> ++ phandle : Label name of controller ++ type : Channel type ++ channel : Channel index ++ ack : 0: Receiver doesn't trigger an ACK interrupt to sender after receive message ++ 1: Receiver triggers an ACK interrupt to sender after receive message ++ ++ This mailbox support 3 type of unidirectional channels, each type ++ has 32 channels. Following types are supported: ++ 0 - TX channel with 32bit transmit register ++ 1 - RX channel with 32bit receive register and IRQ support ++ 2 - RX doorbell channel. ++ const: 2 ++ ++required: ++ - compatible ++ - reg ++ - "#mbox-cells" ++ - interrupts ++ - interrupt-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ reserved-memory { ++ gen-sw-mbox@b8500000 { ++ no-map; ++ reg = <0 0xb8500000 0 0x1000>; ++ }; ++ }; ++ ++ generic-software-mailbox@b8500000 { ++ compatible = "fsl,generic-software-mbox"; ++ reg = <0 0xb8500000 0 0x1000>; ++ #mbox-cells = <3>; ++ interrupts = , ++ ; ++ interrupt-names = "irq", "remote_irq"; ++ }; +diff --git a/Documentation/devicetree/bindings/net/fsl,fec.yaml b/Documentation/devicetree/bindings/net/fsl,fec.yaml +index 18f04d110d6e..f53b6ba17d5d 100644 +--- a/Documentation/devicetree/bindings/net/fsl,fec.yaml ++++ b/Documentation/devicetree/bindings/net/fsl,fec.yaml +@@ -176,6 +176,30 @@ properties: + description: + Register bits of stop mode control, the format is <&gpr req_gpr req_bit>. + ++ fsl,rx-phy-delay-100-ns: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ If present, should specify the delay (MAC-PHY) compensation ++ in ns to be applied on packets timestamps on receive for 100 Mbps link speed ++ ++ fsl,tx-phy-delay-100-ns: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ If present, should specify the delay (MAC-PHY) compensation ++ in ns to be applied on packets timestamps on transmit for 100 Mbps link speed ++ ++ fsl,rx-phy-delay-1000-ns: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ If present, should specify the delay (MAC-PHY) compensation ++ in ns to be applied on packets timestamps on receive for 1 Gbps link speed ++ ++ fsl,tx-phy-delay-1000-ns: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ If present, should specify the delay (MAC-PHY) compensation ++ in ns to be applied on packets timestamps on transmit for 1 Gbps link speed ++ + mii-exclusive: + $ref: /schemas/types.yaml#/definitions/flag + description: +diff --git a/Documentation/devicetree/bindings/tty/rpmsg_tty.yaml b/Documentation/devicetree/bindings/tty/rpmsg_tty.yaml +new file mode 100644 +index 000000000000..9e11fadd16eb +--- /dev/null ++++ b/Documentation/devicetree/bindings/tty/rpmsg_tty.yaml +@@ -0,0 +1,67 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/tty/rpmsg_tty.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: rpmsg tty driver ++ ++maintainers: ++ - Biwen Li ++ ++properties: ++ compatible: ++ const: fsl,uart-rpbus ++ ++ bus_id: ++ items: ++ - description: Used for imx srtm uart application protocol. Specify which real uart(LPUARTx/UARTx, x is instance number) will be used by a virtual tty(/dev/ttyRPMSGx), bus_id = 0xff when bus_id is not specified in dts and specified the flag(IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG). ++ maxItems: 1 ++ ++ flags: ++ items: ++ - description: used for imx srtm uart application protocol(IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG: support multi uart message protocol; IMX_SRTM_UART_SPECIFY_PORT_NUM_MASK: whether specify destination uart id; IMX_SRTM_UART_PORT_NUM_MASK: which destination uart id will be used) ++ maxItems: 1 ++ ++ status: ++ maxItems: 1 ++ ++examples: ++ - | ++ #include ++ ++ uart-rpbus-0 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ flags=; ++ status = "okay"; ++ }; /* /dev/ttyRPMSG0 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 0(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART3(mcore is the owner) */ ++ ++ uart-rpbus-1 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <3>; /* use uart3 */ ++ flags=; ++ status = "okay"; ++ }; /* /dev/ttyRPMSG1 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 1(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART3(mcore is the owner) */ ++ ++ uart-rpbus-2 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <2>; /* use uart2 */ ++ flags=; ++ status = "okay"; ++ }; /* /dev/ttyRPMSG2 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 2(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART2(mcore is the owner) */ ++ ++ uart-rpbus-3 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <4>; /* use uart4 */ ++ flags=; ++ status = "okay"; ++ }; /* [/dev/ttyRPMSG3 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 3(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART4(mcore is the owner), first board] <---MULTI UART MSG PROTOCOL--> [UARTx(mcore is the owner) <---MULTI UART MSG PROTOCOL---> srtm uart channel 8 <---SRTM PROTOCOL--> /dev/ttyRPMSG8 on linux(running on acore), second board ] */ ++ ++ uart-rpbus-4 { ++ compatible = "fsl,uart-rpbus"; ++ bus_id = <5>; /* use uart5 */ ++ status = "okay"; ++ }; /* /dev/ttyRPMSG4 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 4(endpoint on mcore) <-----> UART5(mcore is the owner) <----> GPS device(The device have exclusive use of the UART5, other virtual tty cannot use UART5) */ ++ ++ /* Note: when nothing is specified(include compatible, bus_id, flags, status), it's a normal rpmsg tty. /dev/ttyRPMSG7(running on acore) <--RPMSG--> rpmsg endpoint(running on mcore) */ +diff --git a/Documentation/printk-ringbuffer.txt b/Documentation/printk-ringbuffer.txt +new file mode 100644 +index 000000000000..6bde5dbd8545 +--- /dev/null ++++ b/Documentation/printk-ringbuffer.txt +@@ -0,0 +1,377 @@ ++struct printk_ringbuffer ++------------------------ ++John Ogness ++ ++Overview ++~~~~~~~~ ++As the name suggests, this ring buffer was implemented specifically to serve ++the needs of the printk() infrastructure. The ring buffer itself is not ++specific to printk and could be used for other purposes. _However_, the ++requirements and semantics of printk are rather unique. If you intend to use ++this ring buffer for anything other than printk, you need to be very clear on ++its features, behavior, and pitfalls. ++ ++Features ++^^^^^^^^ ++The printk ring buffer has the following features: ++ ++- single global buffer ++- resides in initialized data section (available at early boot) ++- lockless readers ++- supports multiple writers ++- supports multiple non-consuming readers ++- safe from any context (including NMI) ++- groups bytes into variable length blocks (referenced by entries) ++- entries tagged with sequence numbers ++ ++Behavior ++^^^^^^^^ ++Since the printk ring buffer readers are lockless, there exists no ++synchronization between readers and writers. Basically writers are the tasks ++in control and may overwrite any and all committed data at any time and from ++any context. For this reason readers can miss entries if they are overwritten ++before the reader was able to access the data. The reader API implementation ++is such that reader access to entries is atomic, so there is no risk of ++readers having to deal with partial or corrupt data. Also, entries are ++tagged with sequence numbers so readers can recognize if entries were missed. ++ ++Writing to the ring buffer consists of 2 steps. First a writer must reserve ++an entry of desired size. After this step the writer has exclusive access ++to the memory region. Once the data has been written to memory, it needs to ++be committed to the ring buffer. After this step the entry has been inserted ++into the ring buffer and assigned an appropriate sequence number. ++ ++Once committed, a writer must no longer access the data directly. This is ++because the data may have been overwritten and no longer exists. If a ++writer must access the data, it should either keep a private copy before ++committing the entry or use the reader API to gain access to the data. ++ ++Because of how the data backend is implemented, entries that have been ++reserved but not yet committed act as barriers, preventing future writers ++from filling the ring buffer beyond the location of the reserved but not ++yet committed entry region. For this reason it is *important* that writers ++perform both reserve and commit as quickly as possible. Also, be aware that ++preemption and local interrupts are disabled and writing to the ring buffer ++is processor-reentrant locked during the reserve/commit window. Writers in ++NMI contexts can still preempt any other writers, but as long as these ++writers do not write a large amount of data with respect to the ring buffer ++size, this should not become an issue. ++ ++API ++~~~ ++ ++Declaration ++^^^^^^^^^^^ ++The printk ring buffer can be instantiated as a static structure: ++ ++ /* declare a static struct printk_ringbuffer */ ++ #define DECLARE_STATIC_PRINTKRB(name, szbits, cpulockptr) ++ ++The value of szbits specifies the size of the ring buffer in bits. The ++cpulockptr field is a pointer to a prb_cpulock struct that is used to ++perform processor-reentrant spin locking for the writers. It is specified ++externally because it may be used for multiple ring buffers (or other ++code) to synchronize writers without risk of deadlock. ++ ++Here is an example of a declaration of a printk ring buffer specifying a ++32KB (2^15) ring buffer: ++ ++.... ++DECLARE_STATIC_PRINTKRB_CPULOCK(rb_cpulock); ++DECLARE_STATIC_PRINTKRB(rb, 15, &rb_cpulock); ++.... ++ ++If writers will be using multiple ring buffers and the ordering of that usage ++is not clear, the same prb_cpulock should be used for both ring buffers. ++ ++Writer API ++^^^^^^^^^^ ++The writer API consists of 2 functions. The first is to reserve an entry in ++the ring buffer, the second is to commit that data to the ring buffer. The ++reserved entry information is stored within a provided `struct prb_handle`. ++ ++ /* reserve an entry */ ++ char *prb_reserve(struct prb_handle *h, struct printk_ringbuffer *rb, ++ unsigned int size); ++ ++ /* commit a reserved entry to the ring buffer */ ++ void prb_commit(struct prb_handle *h); ++ ++Here is an example of a function to write data to a ring buffer: ++ ++.... ++int write_data(struct printk_ringbuffer *rb, char *data, int size) ++{ ++ struct prb_handle h; ++ char *buf; ++ ++ buf = prb_reserve(&h, rb, size); ++ if (!buf) ++ return -1; ++ memcpy(buf, data, size); ++ prb_commit(&h); ++ ++ return 0; ++} ++.... ++ ++Pitfalls ++++++++++ ++Be aware that prb_reserve() can fail. A retry might be successful, but it ++depends entirely on whether or not the next part of the ring buffer to ++overwrite belongs to reserved but not yet committed entries of other writers. ++Writers can use the prb_inc_lost() function to allow readers to notice that a ++message was lost. ++ ++Reader API ++^^^^^^^^^^ ++The reader API utilizes a `struct prb_iterator` to track the reader's ++position in the ring buffer. ++ ++ /* declare a pre-initialized static iterator for a ring buffer */ ++ #define DECLARE_STATIC_PRINTKRB_ITER(name, rbaddr) ++ ++ /* initialize iterator for a ring buffer (if static macro NOT used) */ ++ void prb_iter_init(struct prb_iterator *iter, ++ struct printk_ringbuffer *rb, u64 *seq); ++ ++ /* make a deep copy of an iterator */ ++ void prb_iter_copy(struct prb_iterator *dest, ++ struct prb_iterator *src); ++ ++ /* non-blocking, advance to next entry (and read the data) */ ++ int prb_iter_next(struct prb_iterator *iter, char *buf, ++ int size, u64 *seq); ++ ++ /* blocking, advance to next entry (and read the data) */ ++ int prb_iter_wait_next(struct prb_iterator *iter, char *buf, ++ int size, u64 *seq); ++ ++ /* position iterator at the entry seq */ ++ int prb_iter_seek(struct prb_iterator *iter, u64 seq); ++ ++ /* read data at current position */ ++ int prb_iter_data(struct prb_iterator *iter, char *buf, ++ int size, u64 *seq); ++ ++Typically prb_iter_data() is not needed because the data can be retrieved ++directly with prb_iter_next(). ++ ++Here is an example of a non-blocking function that will read all the data in ++a ring buffer: ++ ++.... ++void read_all_data(struct printk_ringbuffer *rb, char *buf, int size) ++{ ++ struct prb_iterator iter; ++ u64 prev_seq = 0; ++ u64 seq; ++ int ret; ++ ++ prb_iter_init(&iter, rb, NULL); ++ ++ for (;;) { ++ ret = prb_iter_next(&iter, buf, size, &seq); ++ if (ret > 0) { ++ if (seq != ++prev_seq) { ++ /* "seq - prev_seq" entries missed */ ++ prev_seq = seq; ++ } ++ /* process buf here */ ++ } else if (ret == 0) { ++ /* hit the end, done */ ++ break; ++ } else if (ret < 0) { ++ /* ++ * iterator is invalid, a writer overtook us, reset the ++ * iterator and keep going, entries were missed ++ */ ++ prb_iter_init(&iter, rb, NULL); ++ } ++ } ++} ++.... ++ ++Pitfalls ++++++++++ ++The reader's iterator can become invalid at any time because the reader was ++overtaken by a writer. Typically the reader should reset the iterator back ++to the current oldest entry (which will be newer than the entry the reader ++was at) and continue, noting the number of entries that were missed. ++ ++Utility API ++^^^^^^^^^^^ ++Several functions are available as convenience for external code. ++ ++ /* query the size of the data buffer */ ++ int prb_buffer_size(struct printk_ringbuffer *rb); ++ ++ /* skip a seq number to signify a lost record */ ++ void prb_inc_lost(struct printk_ringbuffer *rb); ++ ++ /* processor-reentrant spin lock */ ++ void prb_lock(struct prb_cpulock *cpu_lock, unsigned int *cpu_store); ++ ++ /* processor-reentrant spin unlock */ ++ void prb_lock(struct prb_cpulock *cpu_lock, unsigned int *cpu_store); ++ ++Pitfalls ++++++++++ ++Although the value returned by prb_buffer_size() does represent an absolute ++upper bound, the amount of data that can be stored within the ring buffer ++is actually less because of the additional storage space of a header for each ++entry. ++ ++The prb_lock() and prb_unlock() functions can be used to synchronize between ++ring buffer writers and other external activities. The function of a ++processor-reentrant spin lock is to disable preemption and local interrupts ++and synchronize against other processors. It does *not* protect against ++multiple contexts of a single processor, i.e NMI. ++ ++Implementation ++~~~~~~~~~~~~~~ ++This section describes several of the implementation concepts and details to ++help developers better understand the code. ++ ++Entries ++^^^^^^^ ++All ring buffer data is stored within a single static byte array. The reason ++for this is to ensure that any pointers to the data (past and present) will ++always point to valid memory. This is important because the lockless readers ++may be preempted for long periods of time and when they resume may be working ++with expired pointers. ++ ++Entries are identified by start index and size. (The start index plus size ++is the start index of the next entry.) The start index is not simply an ++offset into the byte array, but rather a logical position (lpos) that maps ++directly to byte array offsets. ++ ++For example, for a byte array of 1000, an entry may have have a start index ++of 100. Another entry may have a start index of 1100. And yet another 2100. ++All of these entry are pointing to the same memory region, but only the most ++recent entry is valid. The other entries are pointing to valid memory, but ++represent entries that have been overwritten. ++ ++Note that due to overflowing, the most recent entry is not necessarily the one ++with the highest lpos value. Indeed, the printk ring buffer initializes its ++data such that an overflow happens relatively quickly in order to validate the ++handling of this situation. The implementation assumes that an lpos (unsigned ++long) will never completely wrap while a reader is preempted. If this were to ++become an issue, the seq number (which never wraps) could be used to increase ++the robustness of handling this situation. ++ ++Buffer Wrapping ++^^^^^^^^^^^^^^^ ++If an entry starts near the end of the byte array but would extend beyond it, ++a special terminating entry (size = -1) is inserted into the byte array and ++the real entry is placed at the beginning of the byte array. This can waste ++space at the end of the byte array, but simplifies the implementation by ++allowing writers to always work with contiguous buffers. ++ ++Note that the size field is the first 4 bytes of the entry header. Also note ++that calc_next() always ensures that there are at least 4 bytes left at the ++end of the byte array to allow room for a terminating entry. ++ ++Ring Buffer Pointers ++^^^^^^^^^^^^^^^^^^^^ ++Three pointers (lpos values) are used to manage the ring buffer: ++ ++ - _tail_: points to the oldest entry ++ - _head_: points to where the next new committed entry will be ++ - _reserve_: points to where the next new reserved entry will be ++ ++These pointers always maintain a logical ordering: ++ ++ tail <= head <= reserve ++ ++The reserve pointer moves forward when a writer reserves a new entry. The ++head pointer moves forward when a writer commits a new entry. ++ ++The reserve pointer cannot overwrite the tail pointer in a wrap situation. In ++such a situation, the tail pointer must be "pushed forward", thus ++invalidating that oldest entry. Readers identify if they are accessing a ++valid entry by ensuring their entry pointer is `>= tail && < head`. ++ ++If the tail pointer is equal to the head pointer, it cannot be pushed and any ++reserve operation will fail. The only resolution is for writers to commit ++their reserved entries. ++ ++Processor-Reentrant Locking ++^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++The purpose of the processor-reentrant locking is to limit the interruption ++scenarios of writers to 2 contexts. This allows for a simplified ++implementation where: ++ ++- The reserve/commit window only exists on 1 processor at a time. A reserve ++ can never fail due to uncommitted entries of other processors. ++ ++- When committing entries, it is trivial to handle the situation when ++ subsequent entries have already been committed, i.e. managing the head ++ pointer. ++ ++Performance ++~~~~~~~~~~~ ++Some basic tests were performed on a quad Intel(R) Xeon(R) CPU E5-2697 v4 at ++2.30GHz (36 cores / 72 threads). All tests involved writing a total of ++32,000,000 records at an average of 33 bytes each. Each writer was pinned to ++its own CPU and would write as fast as it could until a total of 32,000,000 ++records were written. All tests involved 2 readers that were both pinned ++together to another CPU. Each reader would read as fast as it could and track ++how many of the 32,000,000 records it could read. All tests used a ring buffer ++of 16KB in size, which holds around 350 records (header + data for each ++entry). ++ ++The only difference between the tests is the number of writers (and thus also ++the number of records per writer). As more writers are added, the time to ++write a record increases. This is because data pointers, modified via cmpxchg, ++and global data access in general become more contended. ++ ++1 writer ++^^^^^^^^ ++ runtime: 0m 18s ++ reader1: 16219900/32000000 (50%) records ++ reader2: 16141582/32000000 (50%) records ++ ++2 writers ++^^^^^^^^^ ++ runtime: 0m 32s ++ reader1: 16327957/32000000 (51%) records ++ reader2: 16313988/32000000 (50%) records ++ ++4 writers ++^^^^^^^^^ ++ runtime: 0m 42s ++ reader1: 16421642/32000000 (51%) records ++ reader2: 16417224/32000000 (51%) records ++ ++8 writers ++^^^^^^^^^ ++ runtime: 0m 43s ++ reader1: 16418300/32000000 (51%) records ++ reader2: 16432222/32000000 (51%) records ++ ++16 writers ++^^^^^^^^^^ ++ runtime: 0m 54s ++ reader1: 16539189/32000000 (51%) records ++ reader2: 16542711/32000000 (51%) records ++ ++32 writers ++^^^^^^^^^^ ++ runtime: 1m 13s ++ reader1: 16731808/32000000 (52%) records ++ reader2: 16735119/32000000 (52%) records ++ ++Comments ++^^^^^^^^ ++It is particularly interesting to compare/contrast the 1-writer and 32-writer ++tests. Despite the writing of the 32,000,000 records taking over 4 times ++longer, the readers (which perform no cmpxchg) were still unable to keep up. ++This shows that the memory contention between the increasing number of CPUs ++also has a dramatic effect on readers. ++ ++It should also be noted that in all cases each reader was able to read >=50% ++of the records. This means that a single reader would have been able to keep ++up with the writer(s) in all cases, becoming slightly easier as more writers ++are added. This was the purpose of pinning 2 readers to 1 CPU: to observe how ++maximum reader performance changes. +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0005-include-add-NXP-RT-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0005-include-add-NXP-RT-support.patch new file mode 100644 index 000000000..00a52e95d --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0005-include-add-NXP-RT-support.patch @@ -0,0 +1,1392 @@ +From b1f8c7c885dc4c9619cfc1232bb380c1dd229a90 Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Fri, 23 Feb 2024 12:30:39 +0100 +Subject: [PATCH 05/10] include: add NXP RT support + +Signed-off-by: Mike Engel +--- + include/dt-bindings/clock/imx8-clock.h | 10 +++ + include/dt-bindings/rpmsg/imx_srtm.h | 20 +++++ + include/linux/clk/imx-pll.h | 26 ++++++ + include/linux/console.h | 33 ++++++- + include/linux/dsa/netc.h | 56 ++++++++++++ + include/linux/dsa/sja1105.h | 2 + + include/linux/entry-common.h | 8 +- + include/linux/ethtool.h | 7 ++ + include/linux/fec.h | 119 +++++++++++++++++++++++++ + include/linux/fsl_qman.h | 8 ++ + include/linux/interrupt.h | 29 ++++++ + include/linux/ipi_baremetal.h | 27 ++++++ + include/linux/lockdep.h | 1 - + include/linux/net.h | 2 + + include/linux/netdevice.h | 48 ++++++++++ + include/linux/preempt.h | 54 ++++++++++- + include/linux/printk.h | 15 ++++ + include/linux/rpmsg/imx_srtm.h | 65 ++++++++++++++ + include/linux/sched.h | 37 ++++++++ + include/linux/serial_8250.h | 5 ++ + include/linux/thread_info.h | 12 ++- + include/linux/trace_events.h | 10 ++- + include/linux/u64_stats_sync.h | 12 --- + include/net/dsa.h | 18 ++++ + include/net/pkt_cls.h | 10 --- + include/net/pkt_sched.h | 11 +++ + include/net/switchdev.h | 1 + + include/soc/mscc/ocelot.h | 5 ++ + include/soc/mscc/ocelot_vcap.h | 1 + + include/uapi/linux/ethtool.h | 30 +++++++ + include/uapi/linux/ethtool_netlink.h | 21 +++++ + include/uapi/linux/virtio_ids.h | 1 + + include/uapi/linux/virtio_mmio.h | 7 +- + include/uapi/linux/virtio_trans.h | 60 +++++++++++++ + 34 files changed, 740 insertions(+), 31 deletions(-) + create mode 100644 include/dt-bindings/rpmsg/imx_srtm.h + create mode 100644 include/linux/clk/imx-pll.h + create mode 100644 include/linux/dsa/netc.h + create mode 100644 include/linux/ipi_baremetal.h + create mode 100644 include/linux/rpmsg/imx_srtm.h + create mode 100644 include/uapi/linux/virtio_trans.h + +diff --git a/include/dt-bindings/clock/imx8-clock.h b/include/dt-bindings/clock/imx8-clock.h +index 2a1122928062..c5d884409872 100644 +--- a/include/dt-bindings/clock/imx8-clock.h ++++ b/include/dt-bindings/clock/imx8-clock.h +@@ -61,4 +61,14 @@ + + #define IMX_ADMA_ACM_CLK_END 50 + ++/* ACM GPT Event Mux Control Register Offset */ ++#define IMX_ADMA_ACM_GPT0_CAPIN1_SEL 0x80004 ++#define IMX_ADMA_ACM_GPT0_CAPIN2_SEL 0x80008 ++#define IMX_ADMA_ACM_GPT1_CAPIN1_SEL 0x90004 ++#define IMX_ADMA_ACM_GPT1_CAPIN2_SEL 0x90008 ++ ++/* ACM GPT Event Mux Select Control */ ++#define IMX_ADMA_ACM_GPT_EVENT_INPUT_ETH0 3 ++#define IMX_ADMA_ACM_GPT_EVENT_INPUT_ETH1 4 ++ + #endif /* __DT_BINDINGS_CLOCK_IMX_H */ +diff --git a/include/dt-bindings/rpmsg/imx_srtm.h b/include/dt-bindings/rpmsg/imx_srtm.h +new file mode 100644 +index 000000000000..644ab9ceb407 +--- /dev/null ++++ b/include/dt-bindings/rpmsg/imx_srtm.h +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 NXP ++ * ++ */ ++ ++#ifndef _DT_BINDINGS_RPMSG_IMX_SRTM_H ++#define _DT_BINDINGS_RPMSG_IMX_SRTM_H ++ ++/* Bit 0 as RPMSG Over UART flag */ ++#define IMX_SRTM_RPMSG_OVER_UART_FLAG (1 << 0) ++#define IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG (1 << 1) ++/* [15:11]: port number, such as /dev/ttySRTM3, 3 is the port number */ ++#define IMX_SRTM_UART_PORT_NUM_SHIFT (11U) ++#define IMX_SRTM_UART_PORT_NUM_MASK (0x1F << 11U) ++/* [10]: 0b1, specify port number; 0b0, not specify port number */ ++#define IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT (10U) ++#define IMX_SRTM_UART_SPECIFY_PORT_NUM_MASK (1 << IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT) ++ ++#endif +diff --git a/include/linux/clk/imx-pll.h b/include/linux/clk/imx-pll.h +new file mode 100644 +index 000000000000..9759ca15a6cc +--- /dev/null ++++ b/include/linux/clk/imx-pll.h +@@ -0,0 +1,26 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2018 NXP ++ * ++ */ ++ ++#ifndef __LINUX_CLK_IMX_PLL_H__ ++#define __LINUX_CLK_IMX_PLL_H__ ++ ++enum clk_imx_pll_error { ++ IMX_CLK_PLL_SUCCESS = 0, ++ IMX_CLK_PLL_INVALID_PARAM, ++ IMX_CLK_PLL_PREC_ERR, ++ IMX_CLK_PLL_LOCK_ERR, ++}; ++ ++struct clk_imx_pll; ++ ++struct clk_imx_pll *clk_imx_pll_get_by_name(const char *name); ++int clk_imx_pll_adjust(struct clk_imx_pll *pll, int *ppb); ++unsigned long clk_imx_pll_get_rate(struct clk_imx_pll *pll, ++ unsigned long parent_rate); ++int clk_imx_pll_set_rate(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate); ++ ++#endif /*__LINUX_CLK_IMX_PLL_H__*/ +diff --git a/include/linux/console.h b/include/linux/console.h +index 8c1686e2c233..8a813cbaf928 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -16,6 +16,7 @@ + + #include + #include ++#include + + struct vc_data; + struct console_font_op; +@@ -137,9 +138,19 @@ static inline int con_debug_leave(void) + #define CON_BRL (32) /* Used for a braille device */ + #define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */ + ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++struct console_atomic_data { ++ u64 seq; ++ char *text; ++ char *ext_text; ++ char *dropped_text; ++}; ++#endif ++ + struct console { + char name[16]; + void (*write)(struct console *, const char *, unsigned); ++ void (*write_atomic)(struct console *, const char *, unsigned); + int (*read)(struct console *, char *, unsigned); + struct tty_driver *(*device)(struct console *, int *); + void (*unblank)(void); +@@ -152,7 +163,26 @@ struct console { + uint ispeed; + uint ospeed; + u64 seq; +- unsigned long dropped; ++ atomic_long_t dropped; ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++ struct console_atomic_data *atomic_data; ++#endif ++ struct task_struct *thread; ++ bool blocked; ++ ++ /* ++ * The per-console lock is used by printing kthreads to synchronize ++ * this console with callers of console_lock(). This is necessary in ++ * order to allow printing kthreads to run in parallel to each other, ++ * while each safely accessing the @blocked field and synchronizing ++ * against direct printing via console_lock/console_unlock. ++ * ++ * Note: For synchronizing against direct printing via ++ * console_trylock/console_unlock, see the static global ++ * variable @console_kthreads_active. ++ */ ++ struct mutex lock; ++ + void *data; + struct console *next; + }; +@@ -167,6 +197,7 @@ extern int console_set_on_cmdline; + extern struct console *early_console; + + enum con_flush_mode { ++ CONSOLE_ATOMIC_FLUSH_PENDING, + CONSOLE_FLUSH_PENDING, + CONSOLE_REPLAY_ALL, + }; +diff --git a/include/linux/dsa/netc.h b/include/linux/dsa/netc.h +new file mode 100644 +index 000000000000..a5aef045f1b5 +--- /dev/null ++++ b/include/linux/dsa/netc.h +@@ -0,0 +1,56 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#ifndef _NET_DSA_NETC_H ++#define _NET_DSA_NETC_H ++ ++#include ++#include ++#include ++#include ++ ++#define ETH_P_NETC 0x88A8 ++#define ETH_P_NETC_META 0x0008 ++ ++#define NETC_DEFAULT_VLAN 1 ++ ++#define IFH_TAG_TYPE_C 0 ++#define IFH_TAG_TYPE_S 1 ++ ++/* IEEE 802.3 Annex 57A: Slow Protocols PDUs (01:80:C2:xx:xx:xx) */ ++#define NETC_LINKLOCAL_FILTER_A 0x0180C2000000ull ++#define NETC_LINKLOCAL_FILTER_A_MASK 0xFFFFFF000000ull ++ ++/* IEEE 1588 Annex F: Transport of PTP over Ethernet (01:1B:19:xx:xx:xx) */ ++#define NETC_LINKLOCAL_FILTER_B 0x011B19000000ull ++#define NETC_LINKLOCAL_FILTER_B_MASK 0xFFFFFF000000ull ++ ++struct netc_deferred_xmit_work { ++ struct dsa_port *dp; ++ struct sk_buff *skb; ++ struct kthread_work work; ++}; ++ ++struct netc_skb_cb { ++ struct sk_buff *clone; ++ u64 tstamp; ++ u8 ts_id; ++}; ++ ++#define NETC_SKB_CB(skb) \ ++ ((struct netc_skb_cb *)((skb)->cb)) ++ ++struct netc_tagger_data { ++ void (*xmit_work_fn)(struct kthread_work *work); ++}; ++ ++static inline struct netc_tagger_data * ++netc_tagger_data(struct dsa_switch *ds) ++{ ++ WARN_ON_ONCE(ds->dst->tag_ops->proto != DSA_TAG_PROTO_NETC); ++ return ds->tagger_data; ++} ++ ++#endif /* _NET_DSA_NETC_H */ +diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h +index c177322f793d..31779f9bc92b 100644 +--- a/include/linux/dsa/sja1105.h ++++ b/include/linux/dsa/sja1105.h +@@ -35,6 +35,8 @@ + #define SJA1105_META_SMAC 0x222222222222ull + #define SJA1105_META_DMAC 0x0180C200000Eull + ++#define SJA1105_MAX_NUM_PCP 8 ++ + enum sja1110_meta_tstamp { + SJA1110_META_TSTAMP_TX = 0, + SJA1110_META_TSTAMP_RX = 1, +diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h +index d95ab85f96ba..3dc3704a3cdb 100644 +--- a/include/linux/entry-common.h ++++ b/include/linux/entry-common.h +@@ -57,9 +57,15 @@ + # define ARCH_EXIT_TO_USER_MODE_WORK (0) + #endif + ++#ifdef CONFIG_PREEMPT_LAZY ++# define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) ++#else ++# define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED) ++#endif ++ + #define EXIT_TO_USER_MODE_WORK \ + (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ +- _TIF_NEED_RESCHED | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ ++ _TIF_NEED_RESCHED_MASK | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ + ARCH_EXIT_TO_USER_MODE_WORK) + + /** +diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h +index 15893c3b2c55..c9fffafc4e6b 100644 +--- a/include/linux/ethtool.h ++++ b/include/linux/ethtool.h +@@ -609,6 +609,8 @@ struct ethtool_module_power_mode_params { + * @get_ethtool_phy_stats: Return extended statistics about the PHY device. + * This is only useful if the device maintains PHY statistics and + * cannot use the standard PHY library helpers. ++ * @get_preempt: Get the network device Frame Preemption parameters. ++ * @set_preempt: Set the network device Frame Preemption parameters. + * @get_phy_tunable: Read the value of a PHY tunable. + * @set_phy_tunable: Set the value of a PHY tunable. + * @get_module_eeprom_by_page: Get a region of plug-in module EEPROM data from +@@ -736,6 +738,11 @@ struct ethtool_ops { + struct ethtool_fecparam *); + int (*set_fecparam)(struct net_device *, + struct ethtool_fecparam *); ++ int (*get_preempt)(struct net_device *, ++ struct ethtool_fp *); ++ int (*set_preempt)(struct net_device *, ++ struct ethtool_fp *); ++ int (*reset_preempt)(struct net_device *, bool enable); + void (*get_ethtool_phy_stats)(struct net_device *, + struct ethtool_stats *, u64 *); + int (*get_phy_tunable)(struct net_device *, +diff --git a/include/linux/fec.h b/include/linux/fec.h +index 9aaf53f07269..e72014b995c4 100644 +--- a/include/linux/fec.h ++++ b/include/linux/fec.h +@@ -19,4 +19,123 @@ struct fec_platform_data { + void (*sleep_mode_enable)(int enabled); + }; + ++/* The number of Tx and Rx buffers. These are allocated from the page ++ * pool. The code may assume these are power of two, so it it best ++ * to keep them that size. ++ * We don't need to allocate pages for the transmitter. We just use ++ * the skbuffer directly. ++ */ ++ ++#define FEC_ENET_XDP_HEADROOM (XDP_PACKET_HEADROOM) ++#define FEC_ENET_RX_PAGES 256 ++#define FEC_ENET_RX_FRSIZE (PAGE_SIZE - FEC_ENET_XDP_HEADROOM \ ++ - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) ++#ifdef CONFIG_AVB_SUPPORT ++#define FEC_RX_RING_SIZE 256 ++#define FEC_ENET_AVB_RX_FRSIZE 1522 ++#else ++#define FEC_RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) ++#endif ++#define FEC_ENET_TX_FRSIZE 2048 ++#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE) ++ ++#ifdef CONFIG_AVB_SUPPORT ++#define FEC_TX_RING_SIZE 256 /* Must be power of two */ ++#else ++#define FEC_TX_RING_SIZE 512 /* Must be power of two */ ++#endif ++ ++#ifdef CONFIG_AVB_SUPPORT ++struct avb_desc { ++ u16 offset; ++ u16 len; ++ u32 ts; ++ u32 flags; ++ u32 private; /* Will be used for saving userspace private value on TX and esc hw descriptor value on RX */ ++}; ++ ++struct avb_tx_desc { ++ struct avb_desc common; ++ ++ unsigned long dma_addr; ++ void *data; ++ u32 esc; ++ unsigned short queue_id; ++ unsigned short sc; ++ unsigned long bufaddr; ++ unsigned short datlen; ++}; ++ ++struct avb_rx_desc { ++ struct avb_desc common; ++ ++ /* end of common rx fields */ ++ unsigned long dma_addr; ++ unsigned short sc; /* Control and status info */ ++ unsigned short queue_id; ++}; ++ ++#define AVB_WAKE_THREAD (1 << 0) ++#define AVB_WAKE_NAPI (1 << 1) ++ ++#define AVB_TX_FLAG_SKB (1 << 0) ++#define AVB_TX_FLAG_HW_TS (1 << 1) ++#define AVB_TX_FLAG_HW_CSUM (1 << 2) ++#define AVB_TX_FLAG_TS (1 << 3) ++ ++struct avb_ops { ++ void (*open)(void *, void *, int); ++ void (*close)(void *); ++ ++ void * (*alloc)(void *); ++ void (*free)(void *, struct avb_desc *); ++ ++ int (*rx)(void *, struct avb_rx_desc *); ++ void * (*dequeue)(void *); ++ ++ int (*tx)(void *, struct avb_tx_desc *); ++ int (*tx_full)(void *); ++ ++ int (*tx_cleanup)(void *, struct avb_tx_desc *); ++ int (*tx_cleanup_ready)(void *); ++ void * (*tx_cleanup_dequeue)(void *); ++ ++ int (*tx_ts)(void *, struct avb_desc *); ++ ++ struct module *owner; ++}; ++ ++#define TX_QUEUE_FLAGS_STRICT_PRIORITY BIT(0) ++#define TX_QUEUE_FLAGS_CREDIT_SHAPER BIT(1) ++ ++#define TX_QUEUE_PROP_MAX 8 ++ ++struct tx_queue_property { ++ unsigned int priority; ++ unsigned int flags; ++}; ++ ++struct tx_queue_properties { ++ int num_queues; ++ struct tx_queue_property queue[TX_QUEUE_PROP_MAX]; ++}; ++ ++int fec_enet_get_tx_queue_properties(int ifindex, struct tx_queue_properties *prop); ++int fec_enet_set_idle_slope(void *data, unsigned int queue_id, u32 idle_slope); ++int fec_enet_avb_register(const char *ifname, const struct avb_ops *avb, void *data); ++struct device *fec_enet_avb_get_device(const char *ifname); ++int fec_enet_avb_unregister(int ifindex, const struct avb_ops *avb); ++int fec_enet_rx_poll_avb(void *data); ++int fec_enet_start_xmit_avb(void *data, struct avb_tx_desc *desc); ++void fec_enet_finish_xmit_avb(void *data, unsigned int queue_id); ++int fec_enet_tx_avb(void *data); ++ ++int fec_ptp_read_cnt(void *data, u32 *cnt); ++int fec_ptp_tc_start(void *data, u8 id, u32 ts_0, u32 ts_1, u32 tcsr_val); ++void fec_ptp_tc_stop(void *data, u8 id); ++int fec_ptp_tc_reload(void *data, u8 id, u32 ts); ++ ++#endif ++ + #endif +diff --git a/include/linux/fsl_qman.h b/include/linux/fsl_qman.h +index 3dc9bfa8658d..abc4c5117da3 100644 +--- a/include/linux/fsl_qman.h ++++ b/include/linux/fsl_qman.h +@@ -1,4 +1,5 @@ + /* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright 2019-2023 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -2120,6 +2121,9 @@ const cpumask_t *qman_affine_cpus(void); + * member of the mask returned from qman_affine_cpus(). + */ + u16 qman_affine_channel(int cpu); ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++u16 qman_affine_channel_ethercat(int cpu); ++#endif + + /** + * qman_get_affine_portal - return the portal pointer affine to cpu +@@ -2127,6 +2131,10 @@ u16 qman_affine_channel(int cpu); + * + */ + void *qman_get_affine_portal(int cpu); ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++void *qman_get_affine_portal_ethercat(int cpu); ++u32 qman_get_affine_last_cpu(void); ++#endif + + /** + * qman_poll_dqrr - process DQRR (fast-path) entries +diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h +index a92bce40b04b..bf82980f569d 100644 +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -605,6 +605,35 @@ extern void __raise_softirq_irqoff(unsigned int nr); + extern void raise_softirq_irqoff(unsigned int nr); + extern void raise_softirq(unsigned int nr); + ++#ifdef CONFIG_PREEMPT_RT ++DECLARE_PER_CPU(struct task_struct *, timersd); ++DECLARE_PER_CPU(unsigned long, pending_timer_softirq); ++ ++extern void raise_timer_softirq(void); ++extern void raise_hrtimer_softirq(void); ++ ++static inline unsigned int local_pending_timers(void) ++{ ++ return __this_cpu_read(pending_timer_softirq); ++} ++ ++#else ++static inline void raise_timer_softirq(void) ++{ ++ raise_softirq(TIMER_SOFTIRQ); ++} ++ ++static inline void raise_hrtimer_softirq(void) ++{ ++ raise_softirq_irqoff(HRTIMER_SOFTIRQ); ++} ++ ++static inline unsigned int local_pending_timers(void) ++{ ++ return local_softirq_pending(); ++} ++#endif ++ + DECLARE_PER_CPU(struct task_struct *, ksoftirqd); + + static inline struct task_struct *this_cpu_ksoftirqd(void) +diff --git a/include/linux/ipi_baremetal.h b/include/linux/ipi_baremetal.h +new file mode 100644 +index 000000000000..5f124be40dcc +--- /dev/null ++++ b/include/linux/ipi_baremetal.h +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * include/linux/ipi_baremetal.h ++ * ++ * Copyright 2018-2023 NXP ++ * ++ */ ++ ++#ifndef __LINUX_IPI_BAREMETAL_H ++#define __LINUX_IPI_BAREMETAL_H ++ ++#include ++ ++#if defined(CONFIG_LS1021A_BAREMETAL) || \ ++ defined(CONFIG_LS1028A_BAREMETAL) || \ ++ defined(CONFIG_IMX93_BAREMETAL) ++#define CONFIG_MAX_CPUS 2 ++#elif defined(CONFIG_IMX8M_BAREMETAL) ++#define CONFIG_MAX_CPUS 4 ++#elif defined(CONFIG_LX2160A_BAREMETAL) ++#define CONFIG_MAX_CPUS 16 ++#else ++#define CONFIG_MAX_CPUS 4 ++#endif ++ ++int ipi_baremetal_handle(u32 irqnr, u32 irqsrc); ++#endif /* !__LINUX_IPI_BAREMETAL_H */ +diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h +index 1f1099dac3f0..1023f349af71 100644 +--- a/include/linux/lockdep.h ++++ b/include/linux/lockdep.h +@@ -435,7 +435,6 @@ enum xhlock_context_t { + XHLOCK_CTX_NR, + }; + +-#define lockdep_init_map_crosslock(m, n, k, s) do {} while (0) + /* + * To initialize a lockdep_map statically use this macro. + * Note that _name must not be NULL. +diff --git a/include/linux/net.h b/include/linux/net.h +index 18d942bbdf6e..38f9d5318f58 100644 +--- a/include/linux/net.h ++++ b/include/linux/net.h +@@ -124,6 +124,8 @@ struct socket { + const struct proto_ops *ops; + + struct socket_wq wq; ++ ++ struct net_device *ndev; + }; + + /* +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 5a04fbf72476..980f2d75a6d2 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -338,6 +338,8 @@ struct gro_list { + */ + #define GRO_HASH_BUCKETS 8 + ++ ++#define NAPINAMSIZ 8 + /* + * Structure for NAPI scheduling similar to tasklet but with weighting + */ +@@ -368,6 +370,7 @@ struct napi_struct { + struct hlist_node napi_hash_node; + unsigned int napi_id; + struct task_struct *thread; ++ char name[NAPINAMSIZ]; + }; + + enum { +@@ -1404,6 +1407,9 @@ struct net_device_ops { + int (*ndo_stop)(struct net_device *dev); + netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, + struct net_device *dev); ++ struct sk_buff* (*ndo_start_recv)(struct net_device *dev, int *err); ++ int (*ndo_fast_recv)(struct net_device *ndev, void __user *buff, size_t len, struct sockaddr __user *addr, int __user *addr_len); ++ int (*ndo_fast_xmit)(struct net_device *ndev, void __user *buff, size_t len); + netdev_features_t (*ndo_features_check)(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features); +@@ -2027,6 +2033,8 @@ struct net_device { + unsigned long mem_start; + unsigned long base_addr; + ++ unsigned int fast_raw_device; ++ + /* + * Some hardware also needs these fields (state,dev_list, + * napi_list,unreg_list,close_list) but they are not +@@ -2532,6 +2540,21 @@ void dev_net_set(struct net_device *dev, struct net *net) + write_pnet(&dev->nd_net, net); + } + ++/** ++ * netif_napi_add_named - initialize a NAPI context ++ * @dev: network device ++ * @napi: NAPI context ++ * @poll: polling function ++ * @weight: default weight ++ * @name: napi instance name ++ * ++ * netif_napi_add_named() must be used to initialize a NAPI context prior to calling ++ * *any* of the other NAPI-related functions. ++ */ ++void netif_napi_add_named(struct net_device *dev, struct napi_struct *napi, ++ int (*poll)(struct napi_struct *, int), int weight, ++ const char *name); ++ + /** + * netdev_priv - access network device private data + * @dev: network device +@@ -2605,6 +2628,27 @@ static inline void netif_napi_add_tx(struct net_device *dev, + netif_napi_add_tx_weight(dev, napi, poll, NAPI_POLL_WEIGHT); + } + ++/** ++ * netif_napi_add_tx_named - initialize a NAPI context ++ * @dev: network device ++ * @napi: NAPI context ++ * @poll: polling function ++ * @weight: default weight ++ * @name: napi instance name ++ * ++ * This variant of netif_napi_add_named() should be used from drivers using NAPI ++ * to exclusively poll a TX queue. ++ * This will avoid we add it into napi_hash[], thus polluting this hash table. ++ */ ++static inline void netif_napi_add_tx_named(struct net_device *dev, ++ struct napi_struct *napi, ++ int (*poll)(struct napi_struct *, int), ++ int weight, const char *name) ++{ ++ set_bit(NAPI_STATE_NO_BUSY_POLL, &napi->state); ++ netif_napi_add_named(dev, napi, poll, weight, name); ++} ++ + /** + * __netif_napi_del - remove a NAPI context + * @napi: NAPI context +@@ -3169,7 +3213,11 @@ struct softnet_data { + int defer_count; + int defer_ipi_scheduled; + struct sk_buff *defer_list; ++#ifndef CONFIG_PREEMPT_RT + call_single_data_t defer_csd; ++#else ++ struct work_struct defer_work; ++#endif + }; + + static inline void input_queue_head_incr(struct softnet_data *sd) +diff --git a/include/linux/preempt.h b/include/linux/preempt.h +index 0df425bf9bd7..12f59cdaaedd 100644 +--- a/include/linux/preempt.h ++++ b/include/linux/preempt.h +@@ -196,6 +196,20 @@ extern void preempt_count_sub(int val); + #define preempt_count_inc() preempt_count_add(1) + #define preempt_count_dec() preempt_count_sub(1) + ++#ifdef CONFIG_PREEMPT_LAZY ++#define add_preempt_lazy_count(val) do { preempt_lazy_count() += (val); } while (0) ++#define sub_preempt_lazy_count(val) do { preempt_lazy_count() -= (val); } while (0) ++#define inc_preempt_lazy_count() add_preempt_lazy_count(1) ++#define dec_preempt_lazy_count() sub_preempt_lazy_count(1) ++#define preempt_lazy_count() (current_thread_info()->preempt_lazy_count) ++#else ++#define add_preempt_lazy_count(val) do { } while (0) ++#define sub_preempt_lazy_count(val) do { } while (0) ++#define inc_preempt_lazy_count() do { } while (0) ++#define dec_preempt_lazy_count() do { } while (0) ++#define preempt_lazy_count() (0) ++#endif ++ + #ifdef CONFIG_PREEMPT_COUNT + + #define preempt_disable() \ +@@ -204,6 +218,12 @@ do { \ + barrier(); \ + } while (0) + ++#define preempt_lazy_disable() \ ++do { \ ++ inc_preempt_lazy_count(); \ ++ barrier(); \ ++} while (0) ++ + #define sched_preempt_enable_no_resched() \ + do { \ + barrier(); \ +@@ -235,6 +255,18 @@ do { \ + __preempt_schedule(); \ + } while (0) + ++/* ++ * open code preempt_check_resched() because it is not exported to modules and ++ * used by local_unlock() or bpf_enable_instrumentation(). ++ */ ++#define preempt_lazy_enable() \ ++do { \ ++ dec_preempt_lazy_count(); \ ++ barrier(); \ ++ if (should_resched(0)) \ ++ __preempt_schedule(); \ ++} while (0) ++ + #else /* !CONFIG_PREEMPTION */ + #define preempt_enable() \ + do { \ +@@ -242,6 +274,12 @@ do { \ + preempt_count_dec(); \ + } while (0) + ++#define preempt_lazy_enable() \ ++do { \ ++ dec_preempt_lazy_count(); \ ++ barrier(); \ ++} while (0) ++ + #define preempt_enable_notrace() \ + do { \ + barrier(); \ +@@ -282,6 +320,9 @@ do { \ + #define preempt_enable_notrace() barrier() + #define preemptible() 0 + ++#define preempt_lazy_disable() barrier() ++#define preempt_lazy_enable() barrier() ++ + #endif /* CONFIG_PREEMPT_COUNT */ + + #ifdef MODULE +@@ -300,7 +341,7 @@ do { \ + } while (0) + #define preempt_fold_need_resched() \ + do { \ +- if (tif_need_resched()) \ ++ if (tif_need_resched_now()) \ + set_preempt_need_resched(); \ + } while (0) + +@@ -416,8 +457,15 @@ extern void migrate_enable(void); + + #else + +-static inline void migrate_disable(void) { } +-static inline void migrate_enable(void) { } ++static inline void migrate_disable(void) ++{ ++ preempt_lazy_disable(); ++} ++ ++static inline void migrate_enable(void) ++{ ++ preempt_lazy_enable(); ++} + + #endif /* CONFIG_SMP */ + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 8c81806c2e99..f8c4e4fa6d7d 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -168,6 +168,9 @@ extern void __printk_safe_exit(void); + */ + #define printk_deferred_enter __printk_safe_enter + #define printk_deferred_exit __printk_safe_exit ++extern void printk_prefer_direct_enter(void); ++extern void printk_prefer_direct_exit(void); ++extern void try_block_console_kthreads(int timeout_ms); + + /* + * Please don't use printk_ratelimit(), because it shares ratelimiting state +@@ -219,6 +222,18 @@ static inline void printk_deferred_exit(void) + { + } + ++static inline void printk_prefer_direct_enter(void) ++{ ++} ++ ++static inline void printk_prefer_direct_exit(void) ++{ ++} ++ ++static inline void try_block_console_kthreads(int timeout_ms) ++{ ++} ++ + static inline int printk_ratelimit(void) + { + return 0; +diff --git a/include/linux/rpmsg/imx_srtm.h b/include/linux/rpmsg/imx_srtm.h +new file mode 100644 +index 000000000000..7c0c53916cce +--- /dev/null ++++ b/include/linux/rpmsg/imx_srtm.h +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright 2022-2023 NXP ++ * ++ * 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. ++ */ ++ ++/* ++ * @file linux/rpmsg/imx_srtm.h ++ * ++ * @brief Global header file for iMX SRTM (Simplified Real Time Message Application Protocol, base on rpmsg) ++ * ++ * @ingroup SRTM ++ */ ++#ifndef __LINUX_RPMSG_IMX_SRTM_H__ ++#define __LINUX_RPMSG_IMX_SRTM_H__ ++ ++/* Category define */ ++#define IMX_SRTM_CATEGORY_LIFECYCLE (0x1) ++#define IMX_SRTM_CATEGORY_PMIC (0x2) ++#define IMX_SRTM_CATEGORY_AUDIO (0x3) ++#define IMX_SRTM_CATEGORY_KEY (0x4) ++#define IMX_SRTM_CATEGORY_GPIO (0x5) ++#define IMX_SRTM_CATEGORY_RTC (0x6) ++#define IMX_SRTM_CATEGORY_SENSOR (0x7) ++#define IMX_SRTM_CATEGORY_AUTO (0x8) ++#define IMX_SRTM_CATEGORY_I2C (0x9) ++#define IMX_SRTM_CATEGORY_PWM (0xA) ++#define IMX_SRTM_CATEGORY_UART (0xB) ++ ++/* srtm version */ ++#define IMX_SRTM_VER_UART (0x0001) ++ ++/* type */ ++#define IMX_SRTM_TYPE_REQUEST (0) ++#define IMX_SRTM_TYPE_RESPONSE (1) ++#define IMX_SRTM_TYPE_NOTIFY (2) ++ ++/* command */ ++#define IMX_SRTM_UART_COMMAND_SEND (1) ++#define IMX_SRTM_UART_COMMAND_HELLO (2) ++ ++/* priority */ ++#define IMX_SRTM_UART_PRIORITY (0x01) ++ ++/* flags */ ++#define IMX_SRTM_RPMSG_OVER_UART_FLAG (1 << 0) ++#define IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG (1 << 1) ++#define IMX_SRTM_UART_PORT_NUM_SHIFT (11U) ++#define IMX_SRTM_UART_PORT_NUM_MASK (0x1F << 11U) ++#define IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT (10U) ++#define IMX_SRTM_UART_SPECIFY_PORT_NUM_MASK (1 << IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT) ++ ++struct imx_srtm_head { ++ u8 cate; ++ u8 major; ++ u8 minor; ++ u8 type; ++ u8 cmd; ++ u8 reserved[5]; ++} __packed; ++ ++#endif /* __LINUX_RPMSG_IMX_SRTM_H__ */ +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 0cac69902ec5..67ec36dbfacf 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -2061,6 +2061,43 @@ static inline int test_tsk_need_resched(struct task_struct *tsk) + return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED)); + } + ++#ifdef CONFIG_PREEMPT_LAZY ++static inline void set_tsk_need_resched_lazy(struct task_struct *tsk) ++{ ++ set_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY); ++} ++ ++static inline void clear_tsk_need_resched_lazy(struct task_struct *tsk) ++{ ++ clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY); ++} ++ ++static inline int test_tsk_need_resched_lazy(struct task_struct *tsk) ++{ ++ return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY)); ++} ++ ++static inline int need_resched_lazy(void) ++{ ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++} ++ ++static inline int need_resched_now(void) ++{ ++ return test_thread_flag(TIF_NEED_RESCHED); ++} ++ ++#else ++static inline void clear_tsk_need_resched_lazy(struct task_struct *tsk) { } ++static inline int need_resched_lazy(void) { return 0; } ++ ++static inline int need_resched_now(void) ++{ ++ return test_thread_flag(TIF_NEED_RESCHED); ++} ++ ++#endif ++ + /* + * cond_resched() and cond_resched_lock(): latency reduction via + * explicit rescheduling in places that are safe. The return +diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h +index 79b328861c5f..35f44352e641 100644 +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -7,6 +7,7 @@ + #ifndef _LINUX_SERIAL_8250_H + #define _LINUX_SERIAL_8250_H + ++#include + #include + #include + #include +@@ -124,6 +125,8 @@ struct uart_8250_port { + #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA + unsigned char msr_saved_flags; + ++ atomic_t console_printing; ++ + struct uart_8250_dma *dma; + const struct uart_8250_ops *ops; + +@@ -179,6 +182,8 @@ void serial8250_init_port(struct uart_8250_port *up); + void serial8250_set_defaults(struct uart_8250_port *up); + void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count); ++void serial8250_console_write_atomic(struct uart_8250_port *up, const char *s, ++ unsigned int count); + int serial8250_console_setup(struct uart_port *port, char *options, bool probe); + int serial8250_console_exit(struct uart_port *port); + +diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h +index 9f392ec76f2b..779e0e96b9cb 100644 +--- a/include/linux/thread_info.h ++++ b/include/linux/thread_info.h +@@ -177,7 +177,17 @@ static __always_inline unsigned long read_ti_thread_flags(struct thread_info *ti + clear_ti_thread_flag(task_thread_info(t), TIF_##fl) + #endif /* !CONFIG_GENERIC_ENTRY */ + +-#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) ++#ifdef CONFIG_PREEMPT_LAZY ++#define tif_need_resched() (test_thread_flag(TIF_NEED_RESCHED) || \ ++ test_thread_flag(TIF_NEED_RESCHED_LAZY)) ++#define tif_need_resched_now() (test_thread_flag(TIF_NEED_RESCHED)) ++#define tif_need_resched_lazy() test_thread_flag(TIF_NEED_RESCHED_LAZY) ++ ++#else ++#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) ++#define tif_need_resched_now() test_thread_flag(TIF_NEED_RESCHED) ++#define tif_need_resched_lazy() 0 ++#endif + + #ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES + static inline int arch_within_stack_frames(const void * const stack, +diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h +index 422f4ca656cf..da13c633d1d8 100644 +--- a/include/linux/trace_events.h ++++ b/include/linux/trace_events.h +@@ -70,6 +70,7 @@ struct trace_entry { + unsigned char flags; + unsigned char preempt_count; + int pid; ++ unsigned char preempt_lazy_count; + }; + + #define TRACE_EVENT_TYPE_MAX \ +@@ -159,9 +160,10 @@ static inline void tracing_generic_entry_update(struct trace_entry *entry, + unsigned int trace_ctx) + { + entry->preempt_count = trace_ctx & 0xff; ++ entry->preempt_lazy_count = (trace_ctx >> 16) & 0xff; + entry->pid = current->pid; + entry->type = type; +- entry->flags = trace_ctx >> 16; ++ entry->flags = trace_ctx >> 24; + } + + unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status); +@@ -172,7 +174,13 @@ enum trace_flag_type { + TRACE_FLAG_NEED_RESCHED = 0x04, + TRACE_FLAG_HARDIRQ = 0x08, + TRACE_FLAG_SOFTIRQ = 0x10, ++#ifdef CONFIG_PREEMPT_LAZY ++ TRACE_FLAG_PREEMPT_RESCHED = 0x00, ++ TRACE_FLAG_NEED_RESCHED_LAZY = 0x20, ++#else ++ TRACE_FLAG_NEED_RESCHED_LAZY = 0x00, + TRACE_FLAG_PREEMPT_RESCHED = 0x20, ++#endif + TRACE_FLAG_NMI = 0x40, + TRACE_FLAG_BH_OFF = 0x80, + }; +diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h +index 46040d66334a..ffe48e69b3f3 100644 +--- a/include/linux/u64_stats_sync.h ++++ b/include/linux/u64_stats_sync.h +@@ -213,16 +213,4 @@ static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp, + return __u64_stats_fetch_retry(syncp, start); + } + +-/* Obsolete interfaces */ +-static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp) +-{ +- return u64_stats_fetch_begin(syncp); +-} +- +-static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp, +- unsigned int start) +-{ +- return u64_stats_fetch_retry(syncp, start); +-} +- + #endif /* _LINUX_U64_STATS_SYNC_H */ +diff --git a/include/net/dsa.h b/include/net/dsa.h +index 765b6a6d98da..71772299cdf0 100644 +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -55,6 +55,7 @@ struct phylink_link_state; + #define DSA_TAG_PROTO_RTL8_4T_VALUE 25 + #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26 + #define DSA_TAG_PROTO_LAN937X_VALUE 27 ++#define DSA_TAG_PROTO_NETC_VALUE 28 + + enum dsa_tag_protocol { + DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, +@@ -85,6 +86,7 @@ enum dsa_tag_protocol { + DSA_TAG_PROTO_RTL8_4T = DSA_TAG_PROTO_RTL8_4T_VALUE, + DSA_TAG_PROTO_RZN1_A5PSW = DSA_TAG_PROTO_RZN1_A5PSW_VALUE, + DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE, ++ DSA_TAG_PROTO_NETC = DSA_TAG_PROTO_NETC_VALUE, + }; + + struct dsa_switch; +@@ -961,6 +963,22 @@ struct dsa_switch_ops { + int (*port_del_dscp_prio)(struct dsa_switch *ds, int port, u8 dscp, + u8 prio); + ++ /* ++ * ethtool --set-frame-preemption ++ */ ++ int (*set_preempt)(struct dsa_switch *ds, int port, ++ struct ethtool_fp *fpcmd); ++ ++ /* ++ * ethtool --show-frame-preemption ++ */ ++ int (*get_preempt)(struct dsa_switch *ds, int port, ++ struct ethtool_fp *fpcmd); ++ ++ /* ++ * ethtool --reset-frame-preemption ++ */ ++ int (*reset_preempt)(struct dsa_switch *ds, int port, bool enable); + /* + * Suspend and resume + */ +diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h +index 4cabb32a2ad9..cd410a87517b 100644 +--- a/include/net/pkt_cls.h ++++ b/include/net/pkt_cls.h +@@ -788,16 +788,6 @@ struct tc_cls_bpf_offload { + bool exts_integrated; + }; + +-struct tc_mqprio_qopt_offload { +- /* struct tc_mqprio_qopt must always be the first element */ +- struct tc_mqprio_qopt qopt; +- u16 mode; +- u16 shaper; +- u32 flags; +- u64 min_rate[TC_QOPT_MAX_QUEUE]; +- u64 max_rate[TC_QOPT_MAX_QUEUE]; +-}; +- + /* This structure holds cookie structure that is passed from user + * to the kernel for actions and classifiers + */ +diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h +index fa9a8df3fa76..822c8b5587ec 100644 +--- a/include/net/pkt_sched.h ++++ b/include/net/pkt_sched.h +@@ -162,6 +162,16 @@ struct tc_etf_qopt_offload { + s32 queue; + }; + ++struct tc_mqprio_qopt_offload { ++ /* struct tc_mqprio_qopt must always be the first element */ ++ struct tc_mqprio_qopt qopt; ++ u16 mode; ++ u16 shaper; ++ u32 flags; ++ u64 min_rate[TC_QOPT_MAX_QUEUE]; ++ u64 max_rate[TC_QOPT_MAX_QUEUE]; ++}; ++ + struct tc_taprio_caps { + bool supports_queue_max_sdu:1; + }; +@@ -175,6 +185,7 @@ struct tc_taprio_sched_entry { + }; + + struct tc_taprio_qopt_offload { ++ struct tc_mqprio_qopt_offload mqprio; + u8 enable; + ktime_t base_time; + u64 cycle_time; +diff --git a/include/net/switchdev.h b/include/net/switchdev.h +index 7dcdc97c0bc3..5b6a4ce1f47c 100644 +--- a/include/net/switchdev.h ++++ b/include/net/switchdev.h +@@ -97,6 +97,7 @@ struct switchdev_obj_port_vlan { + struct switchdev_obj obj; + u16 flags; + u16 vid; ++ u16 proto; + /* If set, the notifier signifies a change of one of the following + * flags for a VLAN that already exists: + * - BRIDGE_VLAN_INFO_PVID +diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h +index ca9ed16b6140..831587238e3f 100644 +--- a/include/soc/mscc/ocelot.h ++++ b/include/soc/mscc/ocelot.h +@@ -1044,6 +1044,7 @@ struct ocelot_port { + + u8 stp_state; + bool vlan_aware; ++ bool qinq_mode; + bool is_dsa_8021q_cpu; + bool learn_ena; + +@@ -1054,6 +1055,7 @@ struct ocelot_port { + bool force_forward; + u8 cut_thru; + u8 preemptable_prios; ++ bool fp_enabled_admin; + + int speed; + }; +@@ -1139,6 +1141,9 @@ struct ocelot { + spinlock_t ptp_clock_lock; + struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM]; + ++ bool qinq_enable; ++ struct kref qinq_refcount; ++ + struct ocelot_fdma *fdma; + }; + +diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h +index c601a4598b0d..f8cde2408890 100644 +--- a/include/soc/mscc/ocelot_vcap.h ++++ b/include/soc/mscc/ocelot_vcap.h +@@ -704,6 +704,7 @@ struct ocelot_vcap_filter { + enum ocelot_vcap_bit dmac_mc; + enum ocelot_vcap_bit dmac_bc; + struct ocelot_vcap_key_vlan vlan; ++ struct ocelot_vcap_key_vlan cvlan; + + enum ocelot_vcap_key_type key_type; + union { +diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h +index dc2aa3d75b39..b662a48658dc 100644 +--- a/include/uapi/linux/ethtool.h ++++ b/include/uapi/linux/ethtool.h +@@ -381,6 +381,32 @@ struct ethtool_eee { + __u32 reserved[2]; + }; + ++/** ++ * struct ethtool_fp - Frame Preemption information ++ * @cmd: ETHTOOL_{G,S}FP ++ * @disabled: Disable hardware preemption supports. ++ * @fp_supported: If frame preemption is supported. ++ * @fp_enabled: If frame preemption should be advertised to the link partner ++ * as enabled. ++ * @supported_queues_mask: Bitmask indicating which queues support being ++ * configured as preemptible (bit 0 -> queue 0, bit N -> queue N). ++ * @preemptible_queues_mask: Bitmask indicating which queues are ++ * configured as preemptible (bit 0 -> queue 0, bit N -> queue N). ++ * @min_frag_size: Minimum size for all non-final fragment size. ++ */ ++struct ethtool_fp { ++ __u32 cmd; ++ __u8 disabled; ++ __u8 fp_supported; ++ __u8 fp_enabled; ++ __u8 fp_status; ++ __u8 fp_active; ++ __u32 supported_queues_mask; ++ __u32 preemptible_queues_mask; ++ __u32 min_frag_size; ++ __u32 reserved[2]; ++}; ++ + /** + * struct ethtool_modinfo - plugin module eeprom information + * @cmd: %ETHTOOL_GMODULEINFO +@@ -1630,6 +1656,10 @@ enum ethtool_fec_config_bits { + #define ETHTOOL_GFECPARAM 0x00000050 /* Get FEC settings */ + #define ETHTOOL_SFECPARAM 0x00000051 /* Set FEC settings */ + ++#define ETHTOOL_GFP 0x00000052 /* Get Frame Preemption settings */ ++#define ETHTOOL_SFP 0x00000053 /* Set Frame Preemption settings */ ++#define ETHTOOL_RFP 0x00000054 /* Reset Frame Preemption settings */ ++ + /* compatibility with older code */ + #define SPARC_ETH_GSET ETHTOOL_GSET + #define SPARC_ETH_SSET ETHTOOL_SSET +diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h +index 69f5bec347c2..47650669c3c1 100644 +--- a/include/uapi/linux/ethtool_netlink.h ++++ b/include/uapi/linux/ethtool_netlink.h +@@ -41,6 +41,8 @@ enum { + ETHTOOL_MSG_TSINFO_GET, + ETHTOOL_MSG_CABLE_TEST_ACT, + ETHTOOL_MSG_CABLE_TEST_TDR_ACT, ++ ETHTOOL_MSG_PREEMPT_GET, ++ ETHTOOL_MSG_PREEMPT_SET, + ETHTOOL_MSG_TUNNEL_INFO_GET, + ETHTOOL_MSG_FEC_GET, + ETHTOOL_MSG_FEC_SET, +@@ -88,6 +90,8 @@ enum { + ETHTOOL_MSG_TSINFO_GET_REPLY, + ETHTOOL_MSG_CABLE_TEST_NTF, + ETHTOOL_MSG_CABLE_TEST_TDR_NTF, ++ ETHTOOL_MSG_PREEMPT_GET_REPLY, ++ ETHTOOL_MSG_PREEMPT_NTF, + ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY, + ETHTOOL_MSG_FEC_GET_REPLY, + ETHTOOL_MSG_FEC_NTF, +@@ -879,6 +883,23 @@ enum { + ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1) + }; + ++/* FRAME PREEMPTION */ ++enum { ++ ETHTOOL_A_PREEMPT_UNSPEC, ++ ETHTOOL_A_PREEMPT_HEADER, /* nest - _A_HEADER_* */ ++ ETHTOOL_A_PREEMPT_DISABLED, /* bool */ ++ ETHTOOL_A_PREEMPT_SUPPORTED, /* u8 */ ++ ETHTOOL_A_PREEMPT_STATUS, /* u8 */ ++ ETHTOOL_A_PREEMPT_ACTIVE, /* u8 */ ++ ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE, /* u32 */ ++ ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED, /* u32 */ ++ ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE, /* u32 */ ++ ++ /* add new constants above here */ ++ __ETHTOOL_A_PREEMPT_CNT, ++ ETHTOOL_A_PREEMPT_MAX = (__ETHTOOL_A_PREEMPT_CNT - 1) ++}; ++ + /* generic netlink info */ + #define ETHTOOL_GENL_NAME "ethtool" + #define ETHTOOL_GENL_VERSION 1 +diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h +index 7aa2eb766205..67f7fe400730 100644 +--- a/include/uapi/linux/virtio_ids.h ++++ b/include/uapi/linux/virtio_ids.h +@@ -68,6 +68,7 @@ + #define VIRTIO_ID_AUDIO_POLICY 39 /* virtio audio policy */ + #define VIRTIO_ID_BT 40 /* virtio bluetooth */ + #define VIRTIO_ID_GPIO 41 /* virtio gpio */ ++#define VIRTIO_ID_TRANS 42 /* virtio transfer test */ + + /* + * Virtio Transitional IDs +diff --git a/include/uapi/linux/virtio_mmio.h b/include/uapi/linux/virtio_mmio.h +index 0650f91bea6c..ee672e1b4a6e 100644 +--- a/include/uapi/linux/virtio_mmio.h ++++ b/include/uapi/linux/virtio_mmio.h +@@ -110,6 +110,9 @@ + /* Device status register - Read Write */ + #define VIRTIO_MMIO_STATUS 0x070 + ++/* Hypervisor-less virtio: Device write operation done status register */ ++#define VIRTIO_MMIO_WD_STATUS 0x074 ++ + /* Selected queue's Descriptor Table address, 64 bits in two halves */ + #define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 + #define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 +@@ -140,7 +143,9 @@ + * the per-driver configuration space - Read Write */ + #define VIRTIO_MMIO_CONFIG 0x100 + +- ++/* Hypervisor-less virtio: write operation space shared with remote */ ++#define VIRTIO_MMIO_RW_OPS_MEM_OFFSET 0x400 ++#define VIRTIO_MMIO_RW_OPS_MEM_SIZE 64 + + /* + * Interrupt flags (re: interrupt status & acknowledge registers) +diff --git a/include/uapi/linux/virtio_trans.h b/include/uapi/linux/virtio_trans.h +new file mode 100644 +index 000000000000..24a10efb370e +--- /dev/null ++++ b/include/uapi/linux/virtio_trans.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright 2022 NXP ++ */ ++ ++#ifndef _LINUX_VIRTIO_TRANS_H ++#define _LINUX_VIRTIO_TRANS_H ++ ++#include ++ ++/* ++ * status: ++ * bit0: TX ready ++ * bit1: RX ready ++ * config: ++ * bit0: TX ++ * bit1: RX ++ * bit2: 0: Backend do NOT copy buffer ++ * 1: Backend do copy buffer ++ * bit3: 0: Backend interrupt mode ++ * 1: Backend polling mode ++ * bit4: 0: Frontend interrupt mode ++ * 1: Frontend polling mode ++ * control: ++ * bit0: start transfer ++ * bit1: reset ++ * pkt_size: packet size in Byte ++ * tx_count: Completed count for TX packet, update by Backend ++ * rx_count: Completed count for RX packet, update by Backend ++ * regression: Packets to test, set by Frontend ++ */ ++ ++#define VT_STATUS 0x0 ++#define VT_CONFIG 0x4 ++#define VT_CONTROL 0x8 ++#define VT_PKT_SIZE 0xc ++#define VT_TX_COUNT 0x10 ++#define VT_RX_COUNT 0x14 ++#define VT_REGRESSION 0x18 ++ ++#define VT_CFG_TX BIT(0) ++#define VT_CFG_RX BIT(1) ++#define VT_CFG_COPY BIT(2) ++#define VT_CFG_B_POLL BIT(3) ++#define VT_CFG_F_POLL BIT(4) ++ ++#define VT_CTRL_START BIT(0) ++#define VT_CTRL_RESET BIT(1) ++ ++struct virtio_trans_config { ++ __le32 status; ++ __le32 config; ++ __le32 control; ++ __le32 pkt_size; ++ __le32 tx_count; ++ __le32 rx_count; ++ __le32 regression; ++}; ++ ++#endif /* _LINUX_VIRTIO_TRANS_H */ +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0006-kernel-add-NXP-RT-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0006-kernel-add-NXP-RT-support.patch new file mode 100644 index 000000000..dbc0ad49b --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0006-kernel-add-NXP-RT-support.patch @@ -0,0 +1,2435 @@ +From 117dccc8d01ab70decb5d6a529f4780aaba20e0b Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Sat, 24 Feb 2024 17:03:36 +0100 +Subject: [PATCH 06/10] kernel: add NXP RT support + +Signed-off-by: Mike Engel +--- + kernel/Kconfig.preempt | 6 + + kernel/bpf/syscall.c | 4 +- + kernel/dma/coherent.c | 15 +- + kernel/entry/common.c | 4 +- + kernel/hung_task.c | 11 +- + kernel/ksysfs.c | 12 + + kernel/panic.c | 10 +- + kernel/printk/internal.h | 2 + + kernel/printk/printk.c | 890 ++++++++++++++++++++++++++++++++---- + kernel/printk/printk_safe.c | 32 ++ + kernel/rcu/rcutorture.c | 6 + + kernel/rcu/tree_stall.h | 2 + + kernel/reboot.c | 16 +- + kernel/sched/core.c | 160 ++++++- + kernel/sched/fair.c | 16 +- + kernel/sched/features.h | 3 + + kernel/sched/sched.h | 9 + + kernel/signal.c | 8 +- + kernel/softirq.c | 82 +++- + kernel/time/hrtimer.c | 4 +- + kernel/time/tick-sched.c | 2 +- + kernel/time/timer.c | 2 +- + kernel/trace/trace.c | 50 +- + kernel/trace/trace_events.c | 1 + + kernel/trace/trace_output.c | 18 +- + kernel/watchdog.c | 4 + + kernel/watchdog_hld.c | 4 + + 27 files changed, 1234 insertions(+), 139 deletions(-) + +diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt +index c2f1fd95a821..260c08efeb48 100644 +--- a/kernel/Kconfig.preempt ++++ b/kernel/Kconfig.preempt +@@ -1,5 +1,11 @@ + # SPDX-License-Identifier: GPL-2.0-only + ++config HAVE_PREEMPT_LAZY ++ bool ++ ++config PREEMPT_LAZY ++ def_bool y if HAVE_PREEMPT_LAZY && PREEMPT_RT ++ + config PREEMPT_NONE_BUILD + bool + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 0c8b7733573e..c0915e2424f1 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -2115,11 +2115,11 @@ static void bpf_prog_get_stats(const struct bpf_prog *prog, + + st = per_cpu_ptr(prog->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&st->syncp); ++ start = u64_stats_fetch_begin(&st->syncp); + tnsecs = u64_stats_read(&st->nsecs); + tcnt = u64_stats_read(&st->cnt); + tmisses = u64_stats_read(&st->misses); +- } while (u64_stats_fetch_retry_irq(&st->syncp, start)); ++ } while (u64_stats_fetch_retry(&st->syncp, start)); + nsecs += tnsecs; + cnt += tcnt; + misses += tmisses; +diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c +index c21abc77c53e..f15ba6c6358e 100644 +--- a/kernel/dma/coherent.c ++++ b/kernel/dma/coherent.c +@@ -36,7 +36,8 @@ static inline dma_addr_t dma_get_device_base(struct device *dev, + } + + static struct dma_coherent_mem *dma_init_coherent_memory(phys_addr_t phys_addr, +- dma_addr_t device_addr, size_t size, bool use_dma_pfn_offset) ++ dma_addr_t device_addr, size_t size, bool use_dma_pfn_offset, ++ bool cacheable) + { + struct dma_coherent_mem *dma_mem; + int pages = size >> PAGE_SHIFT; +@@ -45,7 +46,8 @@ static struct dma_coherent_mem *dma_init_coherent_memory(phys_addr_t phys_addr, + if (!size) + return ERR_PTR(-EINVAL); + +- mem_base = memremap(phys_addr, size, MEMREMAP_WC); ++ mem_base = memremap(phys_addr, size, cacheable ? MEMREMAP_WB : ++ MEMREMAP_WC); + if (!mem_base) + return ERR_PTR(-EINVAL); + +@@ -119,8 +121,10 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + { + struct dma_coherent_mem *mem; + int ret; ++ bool cacheable = dev_is_dma_coherent(dev); + +- mem = dma_init_coherent_memory(phys_addr, device_addr, size, false); ++ mem = dma_init_coherent_memory(phys_addr, device_addr, size, false, ++ cacheable); + if (IS_ERR(mem)) + return PTR_ERR(mem); + +@@ -310,7 +314,7 @@ int dma_init_global_coherent(phys_addr_t phys_addr, size_t size) + { + struct dma_coherent_mem *mem; + +- mem = dma_init_coherent_memory(phys_addr, phys_addr, size, true); ++ mem = dma_init_coherent_memory(phys_addr, phys_addr, size, true, false); + if (IS_ERR(mem)) + return PTR_ERR(mem); + dma_coherent_default_memory = mem; +@@ -335,9 +339,10 @@ static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev) + { + if (!rmem->priv) { + struct dma_coherent_mem *mem; ++ bool cacheable = dev_is_dma_coherent(dev); + + mem = dma_init_coherent_memory(rmem->base, rmem->base, +- rmem->size, true); ++ rmem->size, true, cacheable); + if (IS_ERR(mem)) + return PTR_ERR(mem); + rmem->priv = mem; +diff --git a/kernel/entry/common.c b/kernel/entry/common.c +index be61332c66b5..c6301e520d47 100644 +--- a/kernel/entry/common.c ++++ b/kernel/entry/common.c +@@ -155,7 +155,7 @@ static unsigned long exit_to_user_mode_loop(struct pt_regs *regs, + + local_irq_enable_exit_to_user(ti_work); + +- if (ti_work & _TIF_NEED_RESCHED) ++ if (ti_work & _TIF_NEED_RESCHED_MASK) + schedule(); + + if (ti_work & _TIF_UPROBE) +@@ -386,7 +386,7 @@ void raw_irqentry_exit_cond_resched(void) + rcu_irq_exit_check_preempt(); + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) + WARN_ON_ONCE(!on_thread_stack()); +- if (need_resched()) ++ if (should_resched(0)) + preempt_schedule_irq(); + } + } +diff --git a/kernel/hung_task.c b/kernel/hung_task.c +index c71889f3f3fc..e2d2344cb9f4 100644 +--- a/kernel/hung_task.c ++++ b/kernel/hung_task.c +@@ -127,6 +127,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) + * complain: + */ + if (sysctl_hung_task_warnings) { ++ printk_prefer_direct_enter(); ++ + if (sysctl_hung_task_warnings > 0) + sysctl_hung_task_warnings--; + pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n", +@@ -142,6 +144,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) + + if (sysctl_hung_task_all_cpu_backtrace) + hung_task_show_all_bt = true; ++ ++ printk_prefer_direct_exit(); + } + + touch_nmi_watchdog(); +@@ -212,12 +216,17 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) + } + unlock: + rcu_read_unlock(); +- if (hung_task_show_lock) ++ if (hung_task_show_lock) { ++ printk_prefer_direct_enter(); + debug_show_all_locks(); ++ printk_prefer_direct_exit(); ++ } + + if (hung_task_show_all_bt) { + hung_task_show_all_bt = false; ++ printk_prefer_direct_enter(); + trigger_all_cpu_backtrace(); ++ printk_prefer_direct_exit(); + } + + if (hung_task_call_panic) +diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c +index 65dba9076f31..ab18048e2186 100644 +--- a/kernel/ksysfs.c ++++ b/kernel/ksysfs.c +@@ -142,6 +142,15 @@ KERNEL_ATTR_RO(vmcoreinfo); + + #endif /* CONFIG_CRASH_CORE */ + ++#if defined(CONFIG_PREEMPT_RT) ++static ssize_t realtime_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%d\n", 1); ++} ++KERNEL_ATTR_RO(realtime); ++#endif ++ + /* whether file capabilities are enabled */ + static ssize_t fscaps_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +@@ -232,6 +241,9 @@ static struct attribute * kernel_attrs[] = { + #ifndef CONFIG_TINY_RCU + &rcu_expedited_attr.attr, + &rcu_normal_attr.attr, ++#endif ++#ifdef CONFIG_PREEMPT_RT ++ &realtime_attr.attr, + #endif + NULL + }; +diff --git a/kernel/panic.c b/kernel/panic.c +index 63e94f3bd8dc..97cc495d95f8 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -322,7 +322,6 @@ void panic(const char *fmt, ...) + panic_smp_self_stop(); + + console_verbose(); +- bust_spinlocks(1); + va_start(args, fmt); + len = vscnprintf(buf, sizeof(buf), fmt, args); + va_end(args); +@@ -339,6 +338,11 @@ void panic(const char *fmt, ...) + dump_stack(); + #endif + ++ /* If atomic consoles are available, flush the kernel log. */ ++ console_flush_on_panic(CONSOLE_ATOMIC_FLUSH_PENDING); ++ ++ bust_spinlocks(1); ++ + /* + * If kgdb is enabled, give it a chance to run before we stop all + * the other CPUs or else we won't be able to debug processes left +@@ -653,6 +657,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint, + { + disable_trace_on_warning(); + ++ printk_prefer_direct_enter(); ++ + if (file) + pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS\n", + raw_smp_processor_id(), current->pid, file, line, +@@ -681,6 +687,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint, + + /* Just a warning, don't kill lockdep. */ + add_taint(taint, LOCKDEP_STILL_OK); ++ ++ printk_prefer_direct_exit(); + } + + #ifndef __WARN_FLAGS +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index d947ca6c84f9..e7d8578860ad 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -20,6 +20,8 @@ enum printk_info_flags { + LOG_CONT = 8, /* text is a fragment of a continuation line */ + }; + ++extern bool block_console_kthreads; ++ + __printf(4, 0) + int vprintk_store(int facility, int level, + const struct dev_printk_info *dev_info, +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index cc53fb77f77c..b245b2f60e6a 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -220,6 +221,36 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, + } + #endif /* CONFIG_PRINTK && CONFIG_SYSCTL */ + ++/* ++ * Used to synchronize printing kthreads against direct printing via ++ * console_trylock/console_unlock. ++ * ++ * Values: ++ * -1 = console kthreads atomically blocked (via global trylock) ++ * 0 = no kthread printing, console not locked (via trylock) ++ * >0 = kthread(s) actively printing ++ * ++ * Note: For synchronizing against direct printing via ++ * console_lock/console_unlock, see the @lock variable in ++ * struct console. ++ */ ++static atomic_t console_kthreads_active = ATOMIC_INIT(0); ++ ++#define console_kthreads_atomic_tryblock() \ ++ (atomic_cmpxchg(&console_kthreads_active, 0, -1) == 0) ++#define console_kthreads_atomic_unblock() \ ++ atomic_cmpxchg(&console_kthreads_active, -1, 0) ++#define console_kthreads_atomically_blocked() \ ++ (atomic_read(&console_kthreads_active) == -1) ++ ++#define console_kthread_printing_tryenter() \ ++ atomic_inc_unless_negative(&console_kthreads_active) ++#define console_kthread_printing_exit() \ ++ atomic_dec(&console_kthreads_active) ++ ++/* Block console kthreads to avoid processing new messages. */ ++bool block_console_kthreads; ++ + /* + * Helper macros to handle lockdep when locking/unlocking console_sem. We use + * macros instead of functions so that _RET_IP_ contains useful information. +@@ -268,14 +299,49 @@ static bool panic_in_progress(void) + } + + /* +- * This is used for debugging the mess that is the VT code by +- * keeping track if we have the console semaphore held. It's +- * definitely not the perfect debug tool (we don't know if _WE_ +- * hold it and are racing, but it helps tracking those weird code +- * paths in the console code where we end up in places I want +- * locked without the console semaphore held). ++ * Tracks whether kthread printers are all blocked. A value of true implies ++ * that the console is locked via console_lock() or the console is suspended. ++ * Writing to this variable requires holding @console_sem. ++ */ ++static bool console_kthreads_blocked; ++ ++/* ++ * Block all kthread printers from a schedulable context. ++ * ++ * Requires holding @console_sem. ++ */ ++static void console_kthreads_block(void) ++{ ++ struct console *con; ++ ++ for_each_console(con) { ++ mutex_lock(&con->lock); ++ con->blocked = true; ++ mutex_unlock(&con->lock); ++ } ++ ++ console_kthreads_blocked = true; ++} ++ ++/* ++ * Unblock all kthread printers from a schedulable context. ++ * ++ * Requires holding @console_sem. + */ +-static int console_locked, console_suspended; ++static void console_kthreads_unblock(void) ++{ ++ struct console *con; ++ ++ for_each_console(con) { ++ mutex_lock(&con->lock); ++ con->blocked = false; ++ mutex_unlock(&con->lock); ++ } ++ ++ console_kthreads_blocked = false; ++} ++ ++static int console_suspended; + + /* + * Array of consoles built from command line options (console=) +@@ -358,7 +424,75 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; + /* syslog_lock protects syslog_* variables and write access to clear_seq. */ + static DEFINE_MUTEX(syslog_lock); + ++/* ++ * A flag to signify if printk_activate_kthreads() has already started the ++ * kthread printers. If true, any later registered consoles must start their ++ * own kthread directly. The flag is write protected by the console_lock. ++ */ ++static bool printk_kthreads_available; ++ + #ifdef CONFIG_PRINTK ++static atomic_t printk_prefer_direct = ATOMIC_INIT(0); ++ ++/** ++ * printk_prefer_direct_enter - cause printk() calls to attempt direct ++ * printing to all enabled consoles ++ * ++ * Since it is not possible to call into the console printing code from any ++ * context, there is no guarantee that direct printing will occur. ++ * ++ * This globally effects all printk() callers. ++ * ++ * Context: Any context. ++ */ ++void printk_prefer_direct_enter(void) ++{ ++ atomic_inc(&printk_prefer_direct); ++} ++ ++/** ++ * printk_prefer_direct_exit - restore printk() behavior ++ * ++ * Context: Any context. ++ */ ++void printk_prefer_direct_exit(void) ++{ ++ WARN_ON(atomic_dec_if_positive(&printk_prefer_direct) < 0); ++} ++ ++/* ++ * Calling printk() always wakes kthread printers so that they can ++ * flush the new message to their respective consoles. Also, if direct ++ * printing is allowed, printk() tries to flush the messages directly. ++ * ++ * Direct printing is allowed in situations when the kthreads ++ * are not available or the system is in a problematic state. ++ * ++ * See the implementation about possible races. ++ */ ++static inline bool allow_direct_printing(void) ++{ ++ /* ++ * Checking kthread availability is a possible race because the ++ * kthread printers can become permanently disabled during runtime. ++ * However, doing that requires holding the console_lock, so any ++ * pending messages will be direct printed by console_unlock(). ++ */ ++ if (!printk_kthreads_available) ++ return true; ++ ++ /* ++ * Prefer direct printing when the system is in a problematic state. ++ * The context that sets this state will always see the updated value. ++ * The other contexts do not care. Anyway, direct printing is just a ++ * best effort. The direct output is only possible when console_lock ++ * is not already taken and no kthread printers are actively printing. ++ */ ++ return (system_state > SYSTEM_RUNNING || ++ oops_in_progress || ++ atomic_read(&printk_prefer_direct)); ++} ++ + DECLARE_WAIT_QUEUE_HEAD(log_wait); + /* All 3 protected by @syslog_lock. */ + /* the next printk record to read by syslog(READ) or /proc/kmsg */ +@@ -1847,6 +1981,7 @@ static int console_lock_spinning_disable_and_check(void) + return 1; + } + ++#if !IS_ENABLED(CONFIG_PREEMPT_RT) + /** + * console_trylock_spinning - try to get console_lock by busy waiting + * +@@ -1920,6 +2055,7 @@ static int console_trylock_spinning(void) + + return 1; + } ++#endif /* CONFIG_PREEMPT_RT */ + + /* + * Call the specified console driver, asking it to write out the specified +@@ -1927,19 +2063,28 @@ static int console_trylock_spinning(void) + * dropped, a dropped message will be written out first. + */ + static void call_console_driver(struct console *con, const char *text, size_t len, +- char *dropped_text) ++ char *dropped_text, bool atomic_printing) + { ++ unsigned long dropped = 0; + size_t dropped_len; + +- if (con->dropped && dropped_text) { ++ if (dropped_text) ++ dropped = atomic_long_xchg_relaxed(&con->dropped, 0); ++ ++ if (dropped) { + dropped_len = snprintf(dropped_text, DROPPED_TEXT_MAX, + "** %lu printk messages dropped **\n", +- con->dropped); +- con->dropped = 0; +- con->write(con, dropped_text, dropped_len); ++ dropped); ++ if (atomic_printing) ++ con->write_atomic(con, dropped_text, dropped_len); ++ else ++ con->write(con, dropped_text, dropped_len); + } + +- con->write(con, text, len); ++ if (atomic_printing) ++ con->write_atomic(con, text, len); ++ else ++ con->write(con, text, len); + } + + /* +@@ -2249,10 +2394,22 @@ asmlinkage int vprintk_emit(int facility, int level, + printed_len = vprintk_store(facility, level, dev_info, fmt, args); + + /* If called from the scheduler, we can not call up(). */ +- if (!in_sched) { ++ if (!in_sched && allow_direct_printing()) { ++#if IS_ENABLED(CONFIG_PREEMPT_RT) ++ /* ++ * Use the non-spinning trylock since PREEMPT_RT does not ++ * support console lock handovers. ++ * ++ * Direct printing will most likely involve taking spinlocks. ++ * For PREEMPT_RT, this is only allowed if in a preemptible ++ * context. ++ */ ++ if (preemptible() && console_trylock()) ++ console_unlock(); ++#else + /* + * The caller may be holding system-critical or +- * timing-sensitive locks. Disable preemption during ++ * timing-sensitive locks. Disable preemption during direct + * printing of all remaining records to all consoles so that + * this context can return as soon as possible. Hopefully + * another printk() caller will take over the printing. +@@ -2267,6 +2424,7 @@ asmlinkage int vprintk_emit(int facility, int level, + if (console_trylock_spinning()) + console_unlock(); + preempt_enable(); ++#endif + } + + if (in_sched) +@@ -2297,9 +2455,81 @@ asmlinkage __visible int _printk(const char *fmt, ...) + } + EXPORT_SYMBOL(_printk); + ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++static void __free_atomic_data(struct console_atomic_data *d) ++{ ++ kfree(d->text); ++ kfree(d->ext_text); ++ kfree(d->dropped_text); ++} ++ ++static void free_atomic_data(struct console_atomic_data *d) ++{ ++ int count = 1; ++ int i; ++ ++ if (!d) ++ return; ++ ++#ifdef CONFIG_HAVE_NMI ++ count = 2; ++#endif ++ ++ for (i = 0; i < count; i++) ++ __free_atomic_data(&d[i]); ++ kfree(d); ++} ++ ++static int __alloc_atomic_data(struct console_atomic_data *d, short flags) ++{ ++ d->text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL); ++ if (!d->text) ++ return -1; ++ ++ if (flags & CON_EXTENDED) { ++ d->ext_text = kmalloc(CONSOLE_EXT_LOG_MAX, GFP_KERNEL); ++ if (!d->ext_text) ++ return -1; ++ } else { ++ d->dropped_text = kmalloc(DROPPED_TEXT_MAX, GFP_KERNEL); ++ if (!d->dropped_text) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static struct console_atomic_data *alloc_atomic_data(short flags) ++{ ++ struct console_atomic_data *d; ++ int count = 1; ++ int i; ++ ++#ifdef CONFIG_HAVE_NMI ++ count = 2; ++#endif ++ ++ d = kzalloc(sizeof(*d) * count, GFP_KERNEL); ++ if (!d) ++ goto err_out; ++ ++ for (i = 0; i < count; i++) { ++ if (__alloc_atomic_data(&d[i], flags) != 0) ++ goto err_out; ++ } ++ ++ return d; ++err_out: ++ free_atomic_data(d); ++ return NULL; ++} ++#endif /* CONFIG_HAVE_ATOMIC_CONSOLE */ ++ + static bool pr_flush(int timeout_ms, bool reset_on_progress); + static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress); + ++static void printk_start_kthread(struct console *con); ++ + #else /* CONFIG_PRINTK */ + + #define CONSOLE_LOG_MAX 0 +@@ -2310,6 +2540,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + #define prb_first_valid_seq(rb) 0 + #define prb_next_seq(rb) 0 + ++#define free_atomic_data(d) ++ + static u64 syslog_seq; + + static size_t record_print_text(const struct printk_record *r, +@@ -2328,12 +2560,14 @@ static ssize_t msg_print_ext_body(char *buf, size_t size, + static void console_lock_spinning_enable(void) { } + static int console_lock_spinning_disable_and_check(void) { return 0; } + static void call_console_driver(struct console *con, const char *text, size_t len, +- char *dropped_text) ++ char *dropped_text, bool atomic_printing) + { + } + static bool suppress_message_printing(int level) { return false; } + static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; } + static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; } ++static void printk_start_kthread(struct console *con) { } ++static bool allow_direct_printing(void) { return true; } + + #endif /* CONFIG_PRINTK */ + +@@ -2552,6 +2786,14 @@ static int console_cpu_notify(unsigned int cpu) + /* If trylock fails, someone else is doing the printing */ + if (console_trylock()) + console_unlock(); ++ else { ++ /* ++ * If a new CPU comes online, the conditions for ++ * printer_should_wake() may have changed for some ++ * kthread printer with !CON_ANYTIME. ++ */ ++ wake_up_klogd(); ++ } + } + return 0; + } +@@ -2594,7 +2836,7 @@ void console_lock(void) + down_console_sem(); + if (console_suspended) + return; +- console_locked = 1; ++ console_kthreads_block(); + console_may_schedule = 1; + } + EXPORT_SYMBOL(console_lock); +@@ -2618,30 +2860,36 @@ int console_trylock(void) + up_console_sem(); + return 0; + } +- console_locked = 1; ++ if (!console_kthreads_atomic_tryblock()) { ++ up_console_sem(); ++ return 0; ++ } + console_may_schedule = 0; + return 1; + } + EXPORT_SYMBOL(console_trylock); + ++/* ++ * This is used to help to make sure that certain paths within the VT code are ++ * running with the console lock held. It is definitely not the perfect debug ++ * tool (it is not known if the VT code is the task holding the console lock), ++ * but it helps tracking those weird code paths in the console code such as ++ * when the console is suspended: where the console is not locked but no ++ * console printing may occur. ++ * ++ * Note: This returns true when the console is suspended but is not locked. ++ * This is intentional because the VT code must consider that situation ++ * the same as if the console was locked. ++ */ + int is_console_locked(void) + { +- return console_locked; ++ return (console_kthreads_blocked || atomic_read(&console_kthreads_active)); + } + EXPORT_SYMBOL(is_console_locked); + +-/* +- * Check if the given console is currently capable and allowed to print +- * records. +- * +- * Requires the console_lock. +- */ +-static inline bool console_is_usable(struct console *con) ++static inline bool __console_is_usable(short flags) + { +- if (!(con->flags & CON_ENABLED)) +- return false; +- +- if (!con->write) ++ if (!(flags & CON_ENABLED)) + return false; + + /* +@@ -2650,18 +2898,116 @@ static inline bool console_is_usable(struct console *con) + * cope (CON_ANYTIME) don't call them until this CPU is officially up. + */ + if (!cpu_online(raw_smp_processor_id()) && +- !(con->flags & CON_ANYTIME)) ++ !(flags & CON_ANYTIME)) + return false; + + return true; + } + ++/* ++ * Check if the given console is currently capable and allowed to print ++ * records. ++ * ++ * Requires holding the console_lock. ++ */ ++static inline bool console_is_usable(struct console *con, bool atomic_printing) ++{ ++ if (atomic_printing) { ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++ if (!con->write_atomic) ++ return false; ++ if (!con->atomic_data) ++ return false; ++#else ++ return false; ++#endif ++ } else if (!con->write) { ++ return false; ++ } ++ ++ return __console_is_usable(con->flags); ++} ++ + static void __console_unlock(void) + { +- console_locked = 0; ++ /* ++ * Depending on whether console_lock() or console_trylock() was used, ++ * appropriately allow the kthread printers to continue. ++ */ ++ if (console_kthreads_blocked) ++ console_kthreads_unblock(); ++ else ++ console_kthreads_atomic_unblock(); ++ ++ /* ++ * New records may have arrived while the console was locked. ++ * Wake the kthread printers to print them. ++ */ ++ wake_up_klogd(); ++ + up_console_sem(); + } + ++static u64 read_console_seq(struct console *con) ++{ ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++ unsigned long flags; ++ u64 seq2; ++ u64 seq; ++ ++ if (!con->atomic_data) ++ return con->seq; ++ ++ printk_cpu_sync_get_irqsave(flags); ++ ++ seq = con->seq; ++ seq2 = con->atomic_data[0].seq; ++ if (seq2 > seq) ++ seq = seq2; ++#ifdef CONFIG_HAVE_NMI ++ seq2 = con->atomic_data[1].seq; ++ if (seq2 > seq) ++ seq = seq2; ++#endif ++ ++ printk_cpu_sync_put_irqrestore(flags); ++ ++ return seq; ++#else /* CONFIG_HAVE_ATOMIC_CONSOLE */ ++ return con->seq; ++#endif ++} ++ ++static void write_console_seq(struct console *con, u64 val, bool atomic_printing) ++{ ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++ unsigned long flags; ++ u64 *seq; ++ ++ if (!con->atomic_data) { ++ con->seq = val; ++ return; ++ } ++ ++ printk_cpu_sync_get_irqsave(flags); ++ ++ if (atomic_printing) { ++ seq = &con->atomic_data[0].seq; ++#ifdef CONFIG_HAVE_NMI ++ if (in_nmi()) ++ seq = &con->atomic_data[1].seq; ++#endif ++ } else { ++ seq = &con->seq; ++ } ++ *seq = val; ++ ++ printk_cpu_sync_put_irqrestore(flags); ++#else /* CONFIG_HAVE_ATOMIC_CONSOLE */ ++ con->seq = val; ++#endif ++} ++ + /* + * Print one record for the given console. The record printed is whatever + * record is the next available record for the given console. +@@ -2674,36 +3020,47 @@ static void __console_unlock(void) + * If dropped messages should be printed, @dropped_text is a buffer of size + * DROPPED_TEXT_MAX. Otherwise @dropped_text must be NULL. + * ++ * @atomic_printing specifies if atomic printing should be used. ++ * + * @handover will be set to true if a printk waiter has taken over the + * console_lock, in which case the caller is no longer holding the +- * console_lock. Otherwise it is set to false. ++ * console_lock. Otherwise it is set to false. A NULL pointer may be provided ++ * to disable allowing the console_lock to be taken over by a printk waiter. + * + * Returns false if the given console has no next record to print, otherwise + * true. + * +- * Requires the console_lock. ++ * Requires the console_lock if @handover is non-NULL. ++ * Requires con->lock otherwise. + */ +-static bool console_emit_next_record(struct console *con, char *text, char *ext_text, +- char *dropped_text, bool *handover) ++static bool __console_emit_next_record(struct console *con, char *text, char *ext_text, ++ char *dropped_text, bool atomic_printing, ++ bool *handover) + { +- static int panic_console_dropped; ++ static atomic_t panic_console_dropped = ATOMIC_INIT(0); + struct printk_info info; + struct printk_record r; + unsigned long flags; + char *write_text; + size_t len; ++ u64 seq; + + prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX); + +- *handover = false; ++ if (handover) ++ *handover = false; + +- if (!prb_read_valid(prb, con->seq, &r)) ++ seq = read_console_seq(con); ++ ++ if (!prb_read_valid(prb, seq, &r)) + return false; + +- if (con->seq != r.info->seq) { +- con->dropped += r.info->seq - con->seq; +- con->seq = r.info->seq; +- if (panic_in_progress() && panic_console_dropped++ > 10) { ++ if (seq != r.info->seq) { ++ atomic_long_add((unsigned long)(r.info->seq - seq), &con->dropped); ++ write_console_seq(con, r.info->seq, atomic_printing); ++ seq = r.info->seq; ++ if (panic_in_progress() && ++ atomic_fetch_inc_relaxed(&panic_console_dropped) > 10) { + suppress_panic_printk = 1; + pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n"); + } +@@ -2711,7 +3068,7 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_ + + /* Skip record that has level above the console loglevel. */ + if (suppress_message_printing(r.info->level)) { +- con->seq++; ++ write_console_seq(con, seq + 1, atomic_printing); + goto skip; + } + +@@ -2725,31 +3082,65 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_ + len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time); + } + +- /* +- * While actively printing out messages, if another printk() +- * were to occur on another CPU, it may wait for this one to +- * finish. This task can not be preempted if there is a +- * waiter waiting to take over. +- * +- * Interrupts are disabled because the hand over to a waiter +- * must not be interrupted until the hand over is completed +- * (@console_waiter is cleared). +- */ +- printk_safe_enter_irqsave(flags); +- console_lock_spinning_enable(); ++ if (handover) { ++ /* ++ * While actively printing out messages, if another printk() ++ * were to occur on another CPU, it may wait for this one to ++ * finish. This task can not be preempted if there is a ++ * waiter waiting to take over. ++ * ++ * Interrupts are disabled because the hand over to a waiter ++ * must not be interrupted until the hand over is completed ++ * (@console_waiter is cleared). ++ */ ++ printk_safe_enter_irqsave(flags); ++ console_lock_spinning_enable(); + +- stop_critical_timings(); /* don't trace print latency */ +- call_console_driver(con, write_text, len, dropped_text); +- start_critical_timings(); ++ /* don't trace irqsoff print latency */ ++ stop_critical_timings(); ++ } + +- con->seq++; ++ call_console_driver(con, write_text, len, dropped_text, atomic_printing); + +- *handover = console_lock_spinning_disable_and_check(); +- printk_safe_exit_irqrestore(flags); ++ write_console_seq(con, seq + 1, atomic_printing); ++ ++ if (handover) { ++ start_critical_timings(); ++ *handover = console_lock_spinning_disable_and_check(); ++ printk_safe_exit_irqrestore(flags); ++ } + skip: + return true; + } + ++/* ++ * Print a record for a given console, but allow another printk() caller to ++ * take over the console_lock and continue printing. ++ * ++ * Requires the console_lock, but depending on @handover after the call, the ++ * caller may no longer have the console_lock. ++ * ++ * See __console_emit_next_record() for argument and return details. ++ */ ++static bool console_emit_next_record_transferable(struct console *con, char *text, char *ext_text, ++ char *dropped_text, bool *handover) ++{ ++ /* ++ * Handovers are only supported if threaded printers are atomically ++ * blocked. The context taking over the console_lock may be atomic. ++ * ++ * PREEMPT_RT also does not support handovers because the spinning ++ * waiter can cause large latencies. ++ */ ++ if (!console_kthreads_atomically_blocked() || ++ IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ *handover = false; ++ handover = NULL; ++ } ++ ++ return __console_emit_next_record(con, text, ext_text, dropped_text, false, handover); ++} ++ + /* + * Print out all remaining records to all consoles. + * +@@ -2768,8 +3159,8 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_ + * were flushed to all usable consoles. A returned false informs the caller + * that everything was not flushed (either there were no usable consoles or + * another context has taken over printing or it is a panic situation and this +- * is not the panic CPU). Regardless the reason, the caller should assume it +- * is not useful to immediately try again. ++ * is not the panic CPU or direct printing is not preferred). Regardless the ++ * reason, the caller should assume it is not useful to immediately try again. + * + * Requires the console_lock. + */ +@@ -2786,24 +3177,26 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + *handover = false; + + do { ++ /* Let the kthread printers do the work if they can. */ ++ if (!allow_direct_printing()) ++ return false; ++ + any_progress = false; + + for_each_console(con) { + bool progress; + +- if (!console_is_usable(con)) ++ if (!console_is_usable(con, false)) + continue; + any_usable = true; + + if (con->flags & CON_EXTENDED) { + /* Extended consoles do not print "dropped messages". */ +- progress = console_emit_next_record(con, &text[0], +- &ext_text[0], NULL, +- handover); ++ progress = console_emit_next_record_transferable(con, &text[0], ++ &ext_text[0], NULL, handover); + } else { +- progress = console_emit_next_record(con, &text[0], +- NULL, &dropped_text[0], +- handover); ++ progress = console_emit_next_record_transferable(con, &text[0], ++ NULL, &dropped_text[0], handover); + } + if (*handover) + return false; +@@ -2828,6 +3221,68 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + return any_usable; + } + ++#if defined(CONFIG_HAVE_ATOMIC_CONSOLE) && defined(CONFIG_PRINTK) ++static bool console_emit_next_record(struct console *con, char *text, char *ext_text, ++ char *dropped_text, bool atomic_printing); ++ ++static void atomic_console_flush_all(void) ++{ ++ unsigned long flags; ++ struct console *con; ++ bool any_progress; ++ int index = 0; ++ ++ if (console_suspended) ++ return; ++ ++#ifdef CONFIG_HAVE_NMI ++ if (in_nmi()) ++ index = 1; ++#endif ++ ++ printk_cpu_sync_get_irqsave(flags); ++ ++ do { ++ any_progress = false; ++ ++ for_each_console(con) { ++ bool progress; ++ ++ if (!console_is_usable(con, true)) ++ continue; ++ ++ if (con->flags & CON_EXTENDED) { ++ /* Extended consoles do not print "dropped messages". */ ++ progress = console_emit_next_record(con, ++ &con->atomic_data->text[index], ++ &con->atomic_data->ext_text[index], ++ NULL, ++ true); ++ } else { ++ progress = console_emit_next_record(con, ++ &con->atomic_data->text[index], ++ NULL, ++ &con->atomic_data->dropped_text[index], ++ true); ++ } ++ ++ if (!progress) ++ continue; ++ any_progress = true; ++ ++ touch_softlockup_watchdog_sync(); ++ clocksource_touch_watchdog(); ++ rcu_cpu_stall_reset(); ++ touch_nmi_watchdog(); ++ } ++ } while (any_progress); ++ ++ printk_cpu_sync_put_irqrestore(flags); ++} ++#else /* CONFIG_HAVE_ATOMIC_CONSOLE && CONFIG_PRINTK */ ++#define atomic_console_flush_all() ++#endif ++ + /** + * console_unlock - unlock the console system + * +@@ -2918,10 +3373,13 @@ void console_unblank(void) + if (oops_in_progress) { + if (down_trylock_console_sem() != 0) + return; ++ if (!console_kthreads_atomic_tryblock()) { ++ up_console_sem(); ++ return; ++ } + } else + console_lock(); + +- console_locked = 1; + console_may_schedule = 0; + for_each_console(c) + if ((c->flags & CON_ENABLED) && c->unblank) +@@ -2940,6 +3398,11 @@ void console_unblank(void) + */ + void console_flush_on_panic(enum con_flush_mode mode) + { ++ if (mode == CONSOLE_ATOMIC_FLUSH_PENDING) { ++ atomic_console_flush_all(); ++ return; ++ } ++ + /* + * If someone else is holding the console lock, trylock will fail + * and may_schedule may be set. Ignore and proceed to unlock so +@@ -2956,7 +3419,7 @@ void console_flush_on_panic(enum con_flush_mode mode) + + seq = prb_first_valid_seq(prb); + for_each_console(c) +- c->seq = seq; ++ write_console_seq(c, seq, false); + } + console_unlock(); + } +@@ -3196,16 +3659,27 @@ void register_console(struct console *newcon) + console_drivers->next = newcon; + } + +- newcon->dropped = 0; ++ atomic_long_set(&newcon->dropped, 0); ++ newcon->thread = NULL; ++ newcon->blocked = true; ++ mutex_init(&newcon->lock); ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++ newcon->atomic_data = NULL; ++#endif ++ + if (newcon->flags & CON_PRINTBUFFER) { + /* Get a consistent copy of @syslog_seq. */ + mutex_lock(&syslog_lock); +- newcon->seq = syslog_seq; ++ write_console_seq(newcon, syslog_seq, false); + mutex_unlock(&syslog_lock); + } else { + /* Begin with next message. */ +- newcon->seq = prb_next_seq(prb); ++ write_console_seq(newcon, prb_next_seq(prb), false); + } ++ ++ if (printk_kthreads_available) ++ printk_start_kthread(newcon); ++ + console_unlock(); + console_sysfs_notify(); + +@@ -3229,6 +3703,7 @@ EXPORT_SYMBOL(register_console); + + int unregister_console(struct console *console) + { ++ struct task_struct *thd; + struct console *con; + int res; + +@@ -3266,9 +3741,26 @@ int unregister_console(struct console *console) + console_drivers->flags |= CON_CONSDEV; + + console->flags &= ~CON_ENABLED; ++ ++ /* ++ * console->thread can only be cleared under the console lock. But ++ * stopping the thread must be done without the console lock. The ++ * task that clears @thread is the task that stops the kthread. ++ */ ++ thd = console->thread; ++ console->thread = NULL; ++ + console_unlock(); ++ ++ if (thd) ++ kthread_stop(thd); ++ + console_sysfs_notify(); + ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++ free_atomic_data(console->atomic_data); ++#endif ++ + if (console->exit) + res = console->exit(console); + +@@ -3362,6 +3854,20 @@ static int __init printk_late_init(void) + } + late_initcall(printk_late_init); + ++static int __init printk_activate_kthreads(void) ++{ ++ struct console *con; ++ ++ console_lock(); ++ printk_kthreads_available = true; ++ for_each_console(con) ++ printk_start_kthread(con); ++ console_unlock(); ++ ++ return 0; ++} ++early_initcall(printk_activate_kthreads); ++ + #if defined CONFIG_PRINTK + /* If @con is specified, only wait for that console. Otherwise wait for all. */ + static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) +@@ -3385,7 +3891,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + for_each_console(c) { + if (con && con != c) + continue; +- if (!console_is_usable(c)) ++ if (!console_is_usable(c, false)) + continue; + printk_seq = c->seq; + if (printk_seq < seq) +@@ -3444,11 +3950,214 @@ static bool pr_flush(int timeout_ms, bool reset_on_progress) + return __pr_flush(NULL, timeout_ms, reset_on_progress); + } + ++static void __printk_fallback_preferred_direct(void) ++{ ++ printk_prefer_direct_enter(); ++ pr_err("falling back to preferred direct printing\n"); ++ printk_kthreads_available = false; ++} ++ ++/* ++ * Enter preferred direct printing, but never exit. Mark console threads as ++ * unavailable. The system is then forever in preferred direct printing and ++ * any printing threads will exit. ++ * ++ * Must *not* be called under console_lock. Use ++ * __printk_fallback_preferred_direct() if already holding console_lock. ++ */ ++static void printk_fallback_preferred_direct(void) ++{ ++ console_lock(); ++ __printk_fallback_preferred_direct(); ++ console_unlock(); ++} ++ ++/* ++ * Print a record for a given console, not allowing another printk() caller ++ * to take over. This is appropriate for contexts that do not have the ++ * console_lock. ++ * ++ * See __console_emit_next_record() for argument and return details. ++ */ ++static bool console_emit_next_record(struct console *con, char *text, char *ext_text, ++ char *dropped_text, bool atomic_printing) ++{ ++ return __console_emit_next_record(con, text, ext_text, dropped_text, ++ atomic_printing, NULL); ++} ++ ++static bool printer_should_wake(struct console *con, u64 seq) ++{ ++ short flags; ++ ++ if (kthread_should_stop() || !printk_kthreads_available) ++ return true; ++ ++ if (con->blocked || ++ console_kthreads_atomically_blocked() || ++ block_console_kthreads || ++ system_state > SYSTEM_RUNNING || ++ oops_in_progress) { ++ return false; ++ } ++ ++ /* ++ * This is an unsafe read from con->flags, but a false positive is ++ * not a problem. Worst case it would allow the printer to wake up ++ * although it is disabled. But the printer will notice that when ++ * attempting to print and instead go back to sleep. ++ */ ++ flags = data_race(READ_ONCE(con->flags)); ++ ++ if (!__console_is_usable(flags)) ++ return false; ++ ++ return prb_read_valid(prb, seq, NULL); ++} ++ ++static int printk_kthread_func(void *data) ++{ ++ struct console *con = data; ++ char *dropped_text = NULL; ++ char *ext_text = NULL; ++ u64 seq = 0; ++ char *text; ++ int error; ++ ++#ifdef CONFIG_HAVE_ATOMIC_CONSOLE ++ if (con->write_atomic) ++ con->atomic_data = alloc_atomic_data(con->flags); ++#endif ++ ++ text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL); ++ if (!text) { ++ con_printk(KERN_ERR, con, "failed to allocate text buffer\n"); ++ printk_fallback_preferred_direct(); ++ goto out; ++ } ++ ++ if (con->flags & CON_EXTENDED) { ++ ext_text = kmalloc(CONSOLE_EXT_LOG_MAX, GFP_KERNEL); ++ if (!ext_text) { ++ con_printk(KERN_ERR, con, "failed to allocate ext_text buffer\n"); ++ printk_fallback_preferred_direct(); ++ goto out; ++ } ++ } else { ++ dropped_text = kmalloc(DROPPED_TEXT_MAX, GFP_KERNEL); ++ if (!dropped_text) { ++ con_printk(KERN_ERR, con, "failed to allocate dropped_text buffer\n"); ++ printk_fallback_preferred_direct(); ++ goto out; ++ } ++ } ++ ++ con_printk(KERN_INFO, con, "printing thread started\n"); ++ for (;;) { ++ /* ++ * Guarantee this task is visible on the waitqueue before ++ * checking the wake condition. ++ * ++ * The full memory barrier within set_current_state() of ++ * prepare_to_wait_event() pairs with the full memory barrier ++ * within wq_has_sleeper(). ++ * ++ * This pairs with __wake_up_klogd:A. ++ */ ++ error = wait_event_interruptible(log_wait, ++ printer_should_wake(con, seq)); /* LMM(printk_kthread_func:A) */ ++ ++ if (kthread_should_stop() || !printk_kthreads_available) ++ break; ++ ++ if (error) ++ continue; ++ ++ error = mutex_lock_interruptible(&con->lock); ++ if (error) ++ continue; ++ ++ if (con->blocked || ++ !console_kthread_printing_tryenter()) { ++ /* Another context has locked the console_lock. */ ++ mutex_unlock(&con->lock); ++ continue; ++ } ++ ++ /* ++ * Although this context has not locked the console_lock, it ++ * is known that the console_lock is not locked and it is not ++ * possible for any other context to lock the console_lock. ++ * Therefore it is safe to read con->flags. ++ */ ++ ++ if (!__console_is_usable(con->flags)) { ++ console_kthread_printing_exit(); ++ mutex_unlock(&con->lock); ++ continue; ++ } ++ ++ /* ++ * Even though the printk kthread is always preemptible, it is ++ * still not allowed to call cond_resched() from within ++ * console drivers. The task may become non-preemptible in the ++ * console driver call chain. For example, vt_console_print() ++ * takes a spinlock and then can call into fbcon_redraw(), ++ * which can conditionally invoke cond_resched(). ++ */ ++ console_may_schedule = 0; ++ console_emit_next_record(con, text, ext_text, dropped_text, false); ++ ++ seq = con->seq; ++ ++ console_kthread_printing_exit(); ++ ++ mutex_unlock(&con->lock); ++ } ++ ++ con_printk(KERN_INFO, con, "printing thread stopped\n"); ++out: ++ kfree(dropped_text); ++ kfree(ext_text); ++ kfree(text); ++ ++ console_lock(); ++ /* ++ * If this kthread is being stopped by another task, con->thread will ++ * already be NULL. That is fine. The important thing is that it is ++ * NULL after the kthread exits. ++ */ ++ con->thread = NULL; ++ console_unlock(); ++ ++ return 0; ++} ++ ++/* Must be called under console_lock. */ ++static void printk_start_kthread(struct console *con) ++{ ++ /* ++ * Do not start a kthread if there is no write() callback. The ++ * kthreads assume the write() callback exists. ++ */ ++ if (!con->write) ++ return; ++ ++ con->thread = kthread_run(printk_kthread_func, con, ++ "pr/%s%d", con->name, con->index); ++ if (IS_ERR(con->thread)) { ++ con->thread = NULL; ++ con_printk(KERN_ERR, con, "unable to start printing thread\n"); ++ __printk_fallback_preferred_direct(); ++ return; ++ } ++} ++ + /* + * Delayed printk version, for scheduler-internal messages: + */ +-#define PRINTK_PENDING_WAKEUP 0x01 +-#define PRINTK_PENDING_OUTPUT 0x02 ++#define PRINTK_PENDING_WAKEUP 0x01 ++#define PRINTK_PENDING_DIRECT_OUTPUT 0x02 + + static DEFINE_PER_CPU(int, printk_pending); + +@@ -3456,10 +4165,14 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work) + { + int pending = this_cpu_xchg(printk_pending, 0); + +- if (pending & PRINTK_PENDING_OUTPUT) { ++ if (pending & PRINTK_PENDING_DIRECT_OUTPUT) { ++ printk_prefer_direct_enter(); ++ + /* If trylock fails, someone else is doing the printing */ + if (console_trylock()) + console_unlock(); ++ ++ printk_prefer_direct_exit(); + } + + if (pending & PRINTK_PENDING_WAKEUP) +@@ -3484,10 +4197,11 @@ static void __wake_up_klogd(int val) + * prepare_to_wait_event(), which is called after ___wait_event() adds + * the waiter but before it has checked the wait condition. + * +- * This pairs with devkmsg_read:A and syslog_print:A. ++ * This pairs with devkmsg_read:A, syslog_print:A, and ++ * printk_kthread_func:A. + */ + if (wq_has_sleeper(&log_wait) || /* LMM(__wake_up_klogd:A) */ +- (val & PRINTK_PENDING_OUTPUT)) { ++ (val & PRINTK_PENDING_DIRECT_OUTPUT)) { + this_cpu_or(printk_pending, val); + irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); + } +@@ -3527,7 +4241,17 @@ void defer_console_output(void) + * New messages may have been added directly to the ringbuffer + * using vprintk_store(), so wake any waiters as well. + */ +- __wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT); ++ int val = PRINTK_PENDING_WAKEUP; ++ ++ /* ++ * Make sure that some context will print the messages when direct ++ * printing is allowed. This happens in situations when the kthreads ++ * may not be as reliable or perhaps unusable. ++ */ ++ if (allow_direct_printing()) ++ val |= PRINTK_PENDING_DIRECT_OUTPUT; ++ ++ __wake_up_klogd(val); + } + + void printk_trigger_flush(void) +diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c +index 6d10927a07d8..8e8fd2fb0a5b 100644 +--- a/kernel/printk/printk_safe.c ++++ b/kernel/printk/printk_safe.c +@@ -8,7 +8,9 @@ + #include + #include + #include ++#include + #include ++#include + + #include "internal.h" + +@@ -45,3 +47,33 @@ asmlinkage int vprintk(const char *fmt, va_list args) + return vprintk_default(fmt, args); + } + EXPORT_SYMBOL(vprintk); ++ ++/** ++ * try_block_console_kthreads() - Try to block console kthreads and ++ * make the global console_lock() avaialble ++ * ++ * @timeout_ms: The maximum time (in ms) to wait. ++ * ++ * Prevent console kthreads from starting processing new messages. Wait ++ * until the global console_lock() become available. ++ * ++ * Context: Can be called in any context. ++ */ ++void try_block_console_kthreads(int timeout_ms) ++{ ++ block_console_kthreads = true; ++ ++ /* Do not wait when the console lock could not be safely taken. */ ++ if (this_cpu_read(printk_context) || in_nmi()) ++ return; ++ ++ while (timeout_ms > 0) { ++ if (console_trylock()) { ++ console_unlock(); ++ return; ++ } ++ ++ udelay(1000); ++ timeout_ms -= 1; ++ } ++} +diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c +index 503c2aa845a4..dcd8c0e44c00 100644 +--- a/kernel/rcu/rcutorture.c ++++ b/kernel/rcu/rcutorture.c +@@ -2363,6 +2363,12 @@ static int rcutorture_booster_init(unsigned int cpu) + WARN_ON_ONCE(!t); + sp.sched_priority = 2; + sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); ++#ifdef CONFIG_PREEMPT_RT ++ t = per_cpu(timersd, cpu); ++ WARN_ON_ONCE(!t); ++ sp.sched_priority = 2; ++ sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); ++#endif + } + + /* Don't allow time recalculation while creating a new task. */ +diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h +index 5653560573e2..dcbbcf93d608 100644 +--- a/kernel/rcu/tree_stall.h ++++ b/kernel/rcu/tree_stall.h +@@ -642,6 +642,7 @@ static void print_cpu_stall(unsigned long gps) + * See Documentation/RCU/stallwarn.rst for info on how to debug + * RCU CPU stall warnings. + */ ++ printk_prefer_direct_enter(); + trace_rcu_stall_warning(rcu_state.name, TPS("SelfDetected")); + pr_err("INFO: %s self-detected stall on CPU\n", rcu_state.name); + raw_spin_lock_irqsave_rcu_node(rdp->mynode, flags); +@@ -676,6 +677,7 @@ static void print_cpu_stall(unsigned long gps) + */ + set_tsk_need_resched(current); + set_preempt_need_resched(); ++ printk_prefer_direct_exit(); + } + + static void check_cpu_stall(struct rcu_data *rdp) +diff --git a/kernel/reboot.c b/kernel/reboot.c +index 3bba88c7ffc6..57cedc330660 100644 +--- a/kernel/reboot.c ++++ b/kernel/reboot.c +@@ -82,6 +82,7 @@ void kernel_restart_prepare(char *cmd) + { + blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); + system_state = SYSTEM_RESTART; ++ try_block_console_kthreads(10000); + usermodehelper_disable(); + device_shutdown(); + } +@@ -282,6 +283,7 @@ static void kernel_shutdown_prepare(enum system_states state) + blocking_notifier_call_chain(&reboot_notifier_list, + (state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL); + system_state = state; ++ try_block_console_kthreads(10000); + usermodehelper_disable(); + device_shutdown(); + } +@@ -836,9 +838,11 @@ static int __orderly_reboot(void) + ret = run_cmd(reboot_cmd); + + if (ret) { ++ printk_prefer_direct_enter(); + pr_warn("Failed to start orderly reboot: forcing the issue\n"); + emergency_sync(); + kernel_restart(NULL); ++ printk_prefer_direct_exit(); + } + + return ret; +@@ -851,6 +855,7 @@ static int __orderly_poweroff(bool force) + ret = run_cmd(poweroff_cmd); + + if (ret && force) { ++ printk_prefer_direct_enter(); + pr_warn("Failed to start orderly shutdown: forcing the issue\n"); + + /* +@@ -860,6 +865,7 @@ static int __orderly_poweroff(bool force) + */ + emergency_sync(); + kernel_power_off(); ++ printk_prefer_direct_exit(); + } + + return ret; +@@ -917,6 +923,8 @@ EXPORT_SYMBOL_GPL(orderly_reboot); + */ + static void hw_failure_emergency_poweroff_func(struct work_struct *work) + { ++ printk_prefer_direct_enter(); ++ + /* + * We have reached here after the emergency shutdown waiting period has + * expired. This means orderly_poweroff has not been able to shut off +@@ -933,6 +941,8 @@ static void hw_failure_emergency_poweroff_func(struct work_struct *work) + */ + pr_emerg("Hardware protection shutdown failed. Trying emergency restart\n"); + emergency_restart(); ++ ++ printk_prefer_direct_exit(); + } + + static DECLARE_DELAYED_WORK(hw_failure_emergency_poweroff_work, +@@ -971,11 +981,13 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced) + { + static atomic_t allow_proceed = ATOMIC_INIT(1); + ++ printk_prefer_direct_enter(); ++ + pr_emerg("HARDWARE PROTECTION shutdown (%s)\n", reason); + + /* Shutdown should be initiated only once. */ + if (!atomic_dec_and_test(&allow_proceed)) +- return; ++ goto out; + + /* + * Queue a backup emergency shutdown in the event of +@@ -983,6 +995,8 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced) + */ + hw_failure_emergency_poweroff(ms_until_forced); + orderly_poweroff(true); ++out: ++ printk_prefer_direct_exit(); + } + EXPORT_SYMBOL_GPL(hw_protection_shutdown); + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 0f6a92737c91..f26292bed420 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -1040,6 +1040,46 @@ void resched_curr(struct rq *rq) + trace_sched_wake_idle_without_ipi(cpu); + } + ++#ifdef CONFIG_PREEMPT_LAZY ++ ++static int tsk_is_polling(struct task_struct *p) ++{ ++#ifdef TIF_POLLING_NRFLAG ++ return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); ++#else ++ return 0; ++#endif ++} ++ ++void resched_curr_lazy(struct rq *rq) ++{ ++ struct task_struct *curr = rq->curr; ++ int cpu; ++ ++ if (!sched_feat(PREEMPT_LAZY)) { ++ resched_curr(rq); ++ return; ++ } ++ ++ if (test_tsk_need_resched(curr)) ++ return; ++ ++ if (test_tsk_need_resched_lazy(curr)) ++ return; ++ ++ set_tsk_need_resched_lazy(curr); ++ ++ cpu = cpu_of(rq); ++ if (cpu == smp_processor_id()) ++ return; ++ ++ /* NEED_RESCHED_LAZY must be visible before we test polling */ ++ smp_mb(); ++ if (!tsk_is_polling(curr)) ++ smp_send_reschedule(cpu); ++} ++#endif ++ + void resched_cpu(int cpu) + { + struct rq *rq = cpu_rq(cpu); +@@ -2224,6 +2264,7 @@ void migrate_disable(void) + preempt_disable(); + this_rq()->nr_pinned++; + p->migration_disabled = 1; ++ preempt_lazy_disable(); + preempt_enable(); + } + EXPORT_SYMBOL_GPL(migrate_disable); +@@ -2255,6 +2296,7 @@ void migrate_enable(void) + barrier(); + p->migration_disabled = 0; + this_rq()->nr_pinned--; ++ preempt_lazy_enable(); + preempt_enable(); + } + EXPORT_SYMBOL_GPL(migrate_enable); +@@ -3277,6 +3319,76 @@ int migrate_swap(struct task_struct *cur, struct task_struct *p, + } + #endif /* CONFIG_NUMA_BALANCING */ + ++#ifdef CONFIG_PREEMPT_RT ++ ++/* ++ * Consider: ++ * ++ * set_special_state(X); ++ * ++ * do_things() ++ * // Somewhere in there is an rtlock that can be contended: ++ * current_save_and_set_rtlock_wait_state(); ++ * [...] ++ * schedule_rtlock(); (A) ++ * [...] ++ * current_restore_rtlock_saved_state(); ++ * ++ * schedule(); (B) ++ * ++ * If p->saved_state is anything else than TASK_RUNNING, then p blocked on an ++ * rtlock (A) *before* voluntarily calling into schedule() (B) after setting its ++ * state to X. For things like ptrace (X=TASK_TRACED), the task could have more ++ * work to do upon acquiring the lock in do_things() before whoever called ++ * wait_task_inactive() should return. IOW, we have to wait for: ++ * ++ * p.saved_state = TASK_RUNNING ++ * p.__state = X ++ * ++ * which implies the task isn't blocked on an RT lock and got to schedule() (B). ++ * ++ * Also see comments in ttwu_state_match(). ++ */ ++ ++static __always_inline bool state_mismatch(struct task_struct *p, unsigned int match_state) ++{ ++ unsigned long flags; ++ bool mismatch; ++ ++ raw_spin_lock_irqsave(&p->pi_lock, flags); ++ if (READ_ONCE(p->__state) & match_state) ++ mismatch = false; ++ else if (READ_ONCE(p->saved_state) & match_state) ++ mismatch = false; ++ else ++ mismatch = true; ++ ++ raw_spin_unlock_irqrestore(&p->pi_lock, flags); ++ return mismatch; ++} ++static __always_inline bool state_match(struct task_struct *p, unsigned int match_state, ++ bool *wait) ++{ ++ if (READ_ONCE(p->__state) & match_state) ++ return true; ++ if (READ_ONCE(p->saved_state) & match_state) { ++ *wait = true; ++ return true; ++ } ++ return false; ++} ++#else ++static __always_inline bool state_mismatch(struct task_struct *p, unsigned int match_state) ++{ ++ return !(READ_ONCE(p->__state) & match_state); ++} ++static __always_inline bool state_match(struct task_struct *p, unsigned int match_state, ++ bool *wait) ++{ ++ return (READ_ONCE(p->__state) & match_state); ++} ++#endif ++ + /* + * wait_task_inactive - wait for a thread to unschedule. + * +@@ -3295,7 +3407,7 @@ int migrate_swap(struct task_struct *cur, struct task_struct *p, + */ + unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state) + { +- int running, queued; ++ bool running, wait; + struct rq_flags rf; + unsigned long ncsw; + struct rq *rq; +@@ -3321,7 +3433,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state + * is actually now running somewhere else! + */ + while (task_on_cpu(rq, p)) { +- if (!(READ_ONCE(p->__state) & match_state)) ++ if (state_mismatch(p, match_state)) + return 0; + cpu_relax(); + } +@@ -3334,9 +3446,10 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state + rq = task_rq_lock(p, &rf); + trace_sched_wait_task(p); + running = task_on_cpu(rq, p); +- queued = task_on_rq_queued(p); ++ wait = task_on_rq_queued(p); + ncsw = 0; +- if (READ_ONCE(p->__state) & match_state) ++ ++ if (state_match(p, match_state, &wait)) + ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ + task_rq_unlock(rq, p, &rf); + +@@ -3366,7 +3479,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state + * running right now), it's preempted, and we should + * yield - it could be a while. + */ +- if (unlikely(queued)) { ++ if (unlikely(wait)) { + ktime_t to = NSEC_PER_SEC / HZ; + + set_current_state(TASK_UNINTERRUPTIBLE); +@@ -4647,6 +4760,9 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) + p->on_cpu = 0; + #endif + init_task_preempt_count(p); ++#ifdef CONFIG_HAVE_PREEMPT_LAZY ++ task_thread_info(p)->preempt_lazy_count = 0; ++#endif + #ifdef CONFIG_SMP + plist_node_init(&p->pushable_tasks, MAX_PRIO); + RB_CLEAR_NODE(&p->pushable_dl_tasks); +@@ -6517,6 +6633,7 @@ static void __sched notrace __schedule(unsigned int sched_mode) + + next = pick_next_task(rq, prev, &rf); + clear_tsk_need_resched(prev); ++ clear_tsk_need_resched_lazy(prev); + clear_preempt_need_resched(); + #ifdef CONFIG_SCHED_DEBUG + rq->last_seen_need_resched_ns = 0; +@@ -6731,6 +6848,30 @@ static void __sched notrace preempt_schedule_common(void) + } while (need_resched()); + } + ++#ifdef CONFIG_PREEMPT_LAZY ++/* ++ * If TIF_NEED_RESCHED is then we allow to be scheduled away since this is ++ * set by a RT task. Oterwise we try to avoid beeing scheduled out as long as ++ * preempt_lazy_count counter >0. ++ */ ++static __always_inline int preemptible_lazy(void) ++{ ++ if (test_thread_flag(TIF_NEED_RESCHED)) ++ return 1; ++ if (current_thread_info()->preempt_lazy_count) ++ return 0; ++ return 1; ++} ++ ++#else ++ ++static inline int preemptible_lazy(void) ++{ ++ return 1; ++} ++ ++#endif ++ + #ifdef CONFIG_PREEMPTION + /* + * This is the entry point to schedule() from in-kernel preemption +@@ -6744,6 +6885,8 @@ asmlinkage __visible void __sched notrace preempt_schedule(void) + */ + if (likely(!preemptible())) + return; ++ if (!preemptible_lazy()) ++ return; + preempt_schedule_common(); + } + NOKPROBE_SYMBOL(preempt_schedule); +@@ -6791,6 +6934,9 @@ asmlinkage __visible void __sched notrace preempt_schedule_notrace(void) + if (likely(!preemptible())) + return; + ++ if (!preemptible_lazy()) ++ return; ++ + do { + /* + * Because the function tracer can trace preempt_count_sub() +@@ -9056,7 +9202,9 @@ void __init init_idle(struct task_struct *idle, int cpu) + + /* Set the preempt count _outside_ the spinlocks! */ + init_idle_preempt_count(idle, cpu); +- ++#ifdef CONFIG_HAVE_PREEMPT_LAZY ++ task_thread_info(idle)->preempt_lazy_count = 0; ++#endif + /* + * The idle tasks have their own, simple scheduling class: + */ +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 612873ec2197..9493473e8e16 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -4930,7 +4930,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) + ideal_runtime = sched_slice(cfs_rq, curr); + delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; + if (delta_exec > ideal_runtime) { +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + /* + * The current task ran long enough, ensure it doesn't get + * re-elected due to buddy favours. +@@ -4954,7 +4954,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) + return; + + if (delta > ideal_runtime) +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + } + + static void +@@ -5100,7 +5100,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) + * validating it and just reschedule. + */ + if (queued) { +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + return; + } + /* +@@ -5249,7 +5249,7 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) + * hierarchy can be throttled + */ + if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr)) +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + } + + static __always_inline +@@ -6000,7 +6000,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p) + + if (delta < 0) { + if (task_current(rq, p)) +- resched_curr(rq); ++ resched_curr_lazy(rq); + return; + } + hrtick_start(rq, delta); +@@ -7729,7 +7729,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ + return; + + preempt: +- resched_curr(rq); ++ resched_curr_lazy(rq); + /* + * Only set the backward buddy when the current task is still + * on the rq. This can happen when a wakeup gets interleaved +@@ -11892,7 +11892,7 @@ static void task_fork_fair(struct task_struct *p) + * 'current' within the tree based on its new key value. + */ + swap(curr->vruntime, se->vruntime); +- resched_curr(rq); ++ resched_curr_lazy(rq); + } + + se->vruntime -= cfs_rq->min_vruntime; +@@ -11919,7 +11919,7 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) + */ + if (task_current(rq, p)) { + if (p->prio > oldprio) +- resched_curr(rq); ++ resched_curr_lazy(rq); + } else + check_preempt_curr(rq, p, 0); + } +diff --git a/kernel/sched/features.h b/kernel/sched/features.h +index ee7f23c76bd3..e13090e33f3c 100644 +--- a/kernel/sched/features.h ++++ b/kernel/sched/features.h +@@ -48,6 +48,9 @@ SCHED_FEAT(NONTASK_CAPACITY, true) + + #ifdef CONFIG_PREEMPT_RT + SCHED_FEAT(TTWU_QUEUE, false) ++# ifdef CONFIG_PREEMPT_LAZY ++SCHED_FEAT(PREEMPT_LAZY, true) ++# endif + #else + + /* +diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h +index b62d53d7c264..f2577f511a41 100644 +--- a/kernel/sched/sched.h ++++ b/kernel/sched/sched.h +@@ -2350,6 +2350,15 @@ extern void reweight_task(struct task_struct *p, int prio); + extern void resched_curr(struct rq *rq); + extern void resched_cpu(int cpu); + ++#ifdef CONFIG_PREEMPT_LAZY ++extern void resched_curr_lazy(struct rq *rq); ++#else ++static inline void resched_curr_lazy(struct rq *rq) ++{ ++ resched_curr(rq); ++} ++#endif ++ + extern struct rt_bandwidth def_rt_bandwidth; + extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime); + extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq); +diff --git a/kernel/signal.c b/kernel/signal.c +index 5d45f5da2b36..58e919c7c936 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -2302,13 +2302,13 @@ static int ptrace_stop(int exit_code, int why, unsigned long message, + /* + * Don't want to allow preemption here, because + * sys_ptrace() needs this task to be inactive. +- * +- * XXX: implement read_unlock_no_resched(). + */ +- preempt_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); + read_unlock(&tasklist_lock); + cgroup_enter_frozen(); +- preempt_enable_no_resched(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable_no_resched(); + schedule(); + cgroup_leave_frozen(true); + +diff --git a/kernel/softirq.c b/kernel/softirq.c +index c8a6913c067d..82f3e68fbe22 100644 +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -637,6 +637,24 @@ static inline void tick_irq_exit(void) + #endif + } + ++#ifdef CONFIG_PREEMPT_RT ++DEFINE_PER_CPU(struct task_struct *, timersd); ++DEFINE_PER_CPU(unsigned long, pending_timer_softirq); ++ ++static void wake_timersd(void) ++{ ++ struct task_struct *tsk = __this_cpu_read(timersd); ++ ++ if (tsk) ++ wake_up_process(tsk); ++} ++ ++#else ++ ++static inline void wake_timersd(void) { } ++ ++#endif ++ + static inline void __irq_exit_rcu(void) + { + #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED +@@ -649,6 +667,10 @@ static inline void __irq_exit_rcu(void) + if (!in_interrupt() && local_softirq_pending()) + invoke_softirq(); + ++ if (IS_ENABLED(CONFIG_PREEMPT_RT) && local_pending_timers() && ++ !(in_nmi() | in_hardirq())) ++ wake_timersd(); ++ + tick_irq_exit(); + } + +@@ -976,12 +998,70 @@ static struct smp_hotplug_thread softirq_threads = { + .thread_comm = "ksoftirqd/%u", + }; + ++#ifdef CONFIG_PREEMPT_RT ++static void timersd_setup(unsigned int cpu) ++{ ++ sched_set_fifo_low(current); ++} ++ ++static int timersd_should_run(unsigned int cpu) ++{ ++ return local_pending_timers(); ++} ++ ++static void run_timersd(unsigned int cpu) ++{ ++ unsigned int timer_si; ++ ++ ksoftirqd_run_begin(); ++ ++ timer_si = local_pending_timers(); ++ __this_cpu_write(pending_timer_softirq, 0); ++ or_softirq_pending(timer_si); ++ ++ __do_softirq(); ++ ++ ksoftirqd_run_end(); ++} ++ ++static void raise_ktimers_thread(unsigned int nr) ++{ ++ trace_softirq_raise(nr); ++ __this_cpu_or(pending_timer_softirq, 1 << nr); ++} ++ ++void raise_hrtimer_softirq(void) ++{ ++ raise_ktimers_thread(HRTIMER_SOFTIRQ); ++} ++ ++void raise_timer_softirq(void) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ raise_ktimers_thread(TIMER_SOFTIRQ); ++ wake_timersd(); ++ local_irq_restore(flags); ++} ++ ++static struct smp_hotplug_thread timer_threads = { ++ .store = &timersd, ++ .setup = timersd_setup, ++ .thread_should_run = timersd_should_run, ++ .thread_fn = run_timersd, ++ .thread_comm = "ktimers/%u", ++}; ++#endif ++ + static __init int spawn_ksoftirqd(void) + { + cpuhp_setup_state_nocalls(CPUHP_SOFTIRQ_DEAD, "softirq:dead", NULL, + takeover_tasklets); + BUG_ON(smpboot_register_percpu_thread(&softirq_threads)); +- ++#ifdef CONFIG_PREEMPT_RT ++ BUG_ON(smpboot_register_percpu_thread(&timer_threads)); ++#endif + return 0; + } + early_initcall(spawn_ksoftirqd); +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index e4f0e3b0c4f4..9e2cfba065de 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1805,7 +1805,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) + if (!ktime_before(now, cpu_base->softirq_expires_next)) { + cpu_base->softirq_expires_next = KTIME_MAX; + cpu_base->softirq_activated = 1; +- raise_softirq_irqoff(HRTIMER_SOFTIRQ); ++ raise_hrtimer_softirq(); + } + + __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); +@@ -1918,7 +1918,7 @@ void hrtimer_run_queues(void) + if (!ktime_before(now, cpu_base->softirq_expires_next)) { + cpu_base->softirq_expires_next = KTIME_MAX; + cpu_base->softirq_activated = 1; +- raise_softirq_irqoff(HRTIMER_SOFTIRQ); ++ raise_hrtimer_softirq(); + } + + __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); +diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c +index 798e1841d286..b52e1861b913 100644 +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -800,7 +800,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) + + static inline bool local_timer_softirq_pending(void) + { +- return local_softirq_pending() & BIT(TIMER_SOFTIRQ); ++ return local_pending_timers() & BIT(TIMER_SOFTIRQ); + } + + static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu) +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index 717fcb9fb14a..e6219da89933 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1822,7 +1822,7 @@ static void run_local_timers(void) + if (time_before(jiffies, base->next_expiry)) + return; + } +- raise_softirq(TIMER_SOFTIRQ); ++ raise_timer_softirq(); + } + + /* +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 9db92a6e1463..0efcfac975b6 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -2658,11 +2658,19 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status) + if (softirq_count() >> (SOFTIRQ_SHIFT + 1)) + trace_flags |= TRACE_FLAG_BH_OFF; + +- if (tif_need_resched()) ++ if (tif_need_resched_now()) + trace_flags |= TRACE_FLAG_NEED_RESCHED; ++#ifdef CONFIG_PREEMPT_LAZY ++ /* Run out of bits. Share the LAZY and PREEMPT_RESCHED */ ++ if (need_resched_lazy()) ++ trace_flags |= TRACE_FLAG_NEED_RESCHED_LAZY; ++#else + if (test_preempt_need_resched()) + trace_flags |= TRACE_FLAG_PREEMPT_RESCHED; +- return (trace_flags << 16) | (min_t(unsigned int, pc & 0xff, 0xf)) | ++#endif ++ ++ return (trace_flags << 24) | (min_t(unsigned int, pc & 0xff, 0xf)) | ++ (preempt_lazy_count() & 0xff) << 16 | + (min_t(unsigned int, migration_disable_value(), 0xf)) << 4; + } + +@@ -4255,15 +4263,17 @@ unsigned long trace_total_entries(struct trace_array *tr) + + static void print_lat_help_header(struct seq_file *m) + { +- seq_puts(m, "# _------=> CPU# \n" +- "# / _-----=> irqs-off/BH-disabled\n" +- "# | / _----=> need-resched \n" +- "# || / _---=> hardirq/softirq \n" +- "# ||| / _--=> preempt-depth \n" +- "# |||| / _-=> migrate-disable \n" +- "# ||||| / delay \n" +- "# cmd pid |||||| time | caller \n" +- "# \\ / |||||| \\ | / \n"); ++ seq_puts(m, "# _--------=> CPU# \n" ++ "# / _-------=> irqs-off/BH-disabled\n" ++ "# | / _------=> need-resched \n" ++ "# || / _-----=> need-resched-lazy\n" ++ "# ||| / _----=> hardirq/softirq \n" ++ "# |||| / _---=> preempt-depth \n" ++ "# ||||| / _--=> preempt-lazy-depth\n" ++ "# |||||| / _-=> migrate-disable \n" ++ "# ||||||| / delay \n" ++ "# cmd pid |||||||| time | caller \n" ++ "# \\ / |||||||| \\ | / \n"); + } + + static void print_event_info(struct array_buffer *buf, struct seq_file *m) +@@ -4297,14 +4307,16 @@ static void print_func_help_header_irq(struct array_buffer *buf, struct seq_file + + print_event_info(buf, m); + +- seq_printf(m, "# %.*s _-----=> irqs-off/BH-disabled\n", prec, space); +- seq_printf(m, "# %.*s / _----=> need-resched\n", prec, space); +- seq_printf(m, "# %.*s| / _---=> hardirq/softirq\n", prec, space); +- seq_printf(m, "# %.*s|| / _--=> preempt-depth\n", prec, space); +- seq_printf(m, "# %.*s||| / _-=> migrate-disable\n", prec, space); +- seq_printf(m, "# %.*s|||| / delay\n", prec, space); +- seq_printf(m, "# TASK-PID %.*s CPU# ||||| TIMESTAMP FUNCTION\n", prec, " TGID "); +- seq_printf(m, "# | | %.*s | ||||| | |\n", prec, " | "); ++ seq_printf(m, "# %.*s _-------=> irqs-off/BH-disabled\n", prec, space); ++ seq_printf(m, "# %.*s / _------=> need-resched\n", prec, space); ++ seq_printf(m, "# %.*s| / _-----=> need-resched-lazy\n", prec, space); ++ seq_printf(m, "# %.*s|| / _----=> hardirq/softirq\n", prec, space); ++ seq_printf(m, "# %.*s||| / _---=> preempt-depth\n", prec, space); ++ seq_printf(m, "# %.*s|||| / _--=> preempt-lazy-depth\n", prec, space); ++ seq_printf(m, "# %.*s||||| / _-=> migrate-disable\n", prec, space); ++ seq_printf(m, "# %.*s|||||| / delay\n", prec, space); ++ seq_printf(m, "# TASK-PID %.*s CPU# ||||||| TIMESTAMP FUNCTION\n", prec, " TGID "); ++ seq_printf(m, "# | | %.*s | ||||||| | |\n", prec, " | "); + } + + void +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 9da418442a06..1d8c513d1121 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -208,6 +208,7 @@ static int trace_define_common_fields(void) + /* Holds both preempt_count and migrate_disable */ + __common_field(unsigned char, preempt_count); + __common_field(int, pid); ++ __common_field(unsigned char, preempt_lazy_count); + + return ret; + } +diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c +index 5cd4fb656306..3c227e2843ae 100644 +--- a/kernel/trace/trace_output.c ++++ b/kernel/trace/trace_output.c +@@ -442,6 +442,7 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) + { + char hardsoft_irq; + char need_resched; ++ char need_resched_lazy; + char irqs_off; + int hardirq; + int softirq; +@@ -462,20 +463,27 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) + + switch (entry->flags & (TRACE_FLAG_NEED_RESCHED | + TRACE_FLAG_PREEMPT_RESCHED)) { ++#ifndef CONFIG_PREEMPT_LAZY + case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_PREEMPT_RESCHED: + need_resched = 'N'; + break; ++#endif + case TRACE_FLAG_NEED_RESCHED: + need_resched = 'n'; + break; ++#ifndef CONFIG_PREEMPT_LAZY + case TRACE_FLAG_PREEMPT_RESCHED: + need_resched = 'p'; + break; ++#endif + default: + need_resched = '.'; + break; + } + ++ need_resched_lazy = ++ (entry->flags & TRACE_FLAG_NEED_RESCHED_LAZY) ? 'L' : '.'; ++ + hardsoft_irq = + (nmi && hardirq) ? 'Z' : + nmi ? 'z' : +@@ -484,14 +492,20 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) + softirq ? 's' : + '.' ; + +- trace_seq_printf(s, "%c%c%c", +- irqs_off, need_resched, hardsoft_irq); ++ trace_seq_printf(s, "%c%c%c%c", ++ irqs_off, need_resched, need_resched_lazy, ++ hardsoft_irq); + + if (entry->preempt_count & 0xf) + trace_seq_printf(s, "%x", entry->preempt_count & 0xf); + else + trace_seq_putc(s, '.'); + ++ if (entry->preempt_lazy_count) ++ trace_seq_printf(s, "%x", entry->preempt_lazy_count); ++ else ++ trace_seq_putc(s, '.'); ++ + if (entry->preempt_count & 0xf0) + trace_seq_printf(s, "%x", entry->preempt_count >> 4); + else +diff --git a/kernel/watchdog.c b/kernel/watchdog.c +index 8e61f21e7e33..41596c415111 100644 +--- a/kernel/watchdog.c ++++ b/kernel/watchdog.c +@@ -424,6 +424,8 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) + /* Start period for the next softlockup warning. */ + update_report_ts(); + ++ printk_prefer_direct_enter(); ++ + pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", + smp_processor_id(), duration, + current->comm, task_pid_nr(current)); +@@ -442,6 +444,8 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) + add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK); + if (softlockup_panic) + panic("softlockup: hung tasks"); ++ ++ printk_prefer_direct_exit(); + } + + return HRTIMER_RESTART; +diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c +index 1e8a49dc956e..7c977b945c92 100644 +--- a/kernel/watchdog_hld.c ++++ b/kernel/watchdog_hld.c +@@ -135,6 +135,8 @@ static void watchdog_overflow_callback(struct perf_event *event, + if (__this_cpu_read(hard_watchdog_warn) == true) + return; + ++ printk_prefer_direct_enter(); ++ + pr_emerg("Watchdog detected hard LOCKUP on cpu %d\n", + this_cpu); + print_modules(); +@@ -155,6 +157,8 @@ static void watchdog_overflow_callback(struct perf_event *event, + if (hardlockup_panic) + nmi_panic(regs, "Hard LOCKUP"); + ++ printk_prefer_direct_exit(); ++ + __this_cpu_write(hard_watchdog_warn, true); + return; + } +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0007-drivers-add-NXP-RT-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0007-drivers-add-NXP-RT-support.patch new file mode 100644 index 000000000..023bdfd1a --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0007-drivers-add-NXP-RT-support.patch @@ -0,0 +1,21976 @@ +From cb81c271e9e609d9dbd19d5d26a298c723c30225 Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Sat, 24 Feb 2024 18:16:35 +0100 +Subject: [PATCH 07/10] drivers: add NXP RT support + +Signed-off-by: Mike Engel +--- + drivers/base/Kconfig | 2 +- + drivers/block/zram/zram_drv.c | 36 + + drivers/block/zram/zram_drv.h | 3 + + drivers/char/tpm/tpm_tis.c | 29 +- + drivers/clk/imx/Makefile | 1 + + drivers/clk/imx/clk-frac-pll.c | 130 + + drivers/clk/imx/clk-fracn-gppll.c | 208 +- + drivers/clk/imx/clk-imx8dxl-acm.c | 49 + + drivers/clk/imx/clk-imx8mq.c | 2 +- + drivers/clk/imx/clk-pll.c | 83 + + drivers/clk/imx/clk-pll.h | 33 + + drivers/clk/imx/clk-pll14xx.c | 120 + + drivers/clk/imx/clk-pllv3.c | 109 + + drivers/clk/imx/clk-scu.c | 86 + + drivers/firmware/imx/scu-pd.c | 1 + + drivers/gpu/drm/i915/Kconfig | 1 - + drivers/gpu/drm/i915/display/intel_crtc.c | 15 +- + drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 5 +- + .../drm/i915/gt/intel_execlists_submission.c | 17 +- + drivers/gpu/drm/i915/i915_irq.c | 6 +- + drivers/gpu/drm/i915/i915_request.c | 2 - + drivers/gpu/drm/i915/i915_trace.h | 6 +- + drivers/gpu/drm/i915/i915_utils.h | 2 +- + drivers/irqchip/Kconfig | 4 + + drivers/irqchip/Makefile | 1 + + drivers/irqchip/ipi-baremetal.c | 454 +++ + drivers/irqchip/irq-gic-v3.c | 10 +- + drivers/irqchip/irq-gic.c | 4 +- + drivers/mailbox/Kconfig | 9 + + drivers/mailbox/Makefile | 2 + + drivers/mailbox/generic-software-mailbox.c | 322 ++ + drivers/mailbox/mailbox.c | 2 +- + drivers/mxc/ipu3/ipu_common.c | 10 +- + drivers/mxc/ipu3/ipu_device.c | 2 +- + drivers/net/dsa/Kconfig | 2 + + drivers/net/dsa/Makefile | 1 + + drivers/net/dsa/netc/Kconfig | 10 + + drivers/net/dsa/netc/Makefile | 12 + + drivers/net/dsa/netc/netc.h | 102 + + drivers/net/dsa/netc/netc_config.c | 322 ++ + drivers/net/dsa/netc/netc_config.h | 288 ++ + drivers/net/dsa/netc/netc_devlink.c | 111 + + drivers/net/dsa/netc/netc_ethtool.c | 344 ++ + drivers/net/dsa/netc/netc_main.c | 928 +++++ + drivers/net/dsa/netc/netc_ptp.c | 12 + + drivers/net/dsa/netc/netc_spi.c | 119 + + drivers/net/dsa/ocelot/felix.c | 184 +- + drivers/net/dsa/ocelot/felix.h | 5 + + drivers/net/dsa/ocelot/felix_tsn.c | 6 +- + drivers/net/dsa/ocelot/felix_vsc9959.c | 101 + + drivers/net/dsa/sja1105/sja1105.h | 5 + + drivers/net/dsa/sja1105/sja1105_clocking.c | 21 +- + drivers/net/dsa/sja1105/sja1105_main.c | 64 +- + drivers/net/dsa/sja1105/sja1105_tas.c | 4 + + drivers/net/ethernet/alacritech/slic.h | 12 +- + drivers/net/ethernet/amazon/ena/ena_ethtool.c | 4 +- + drivers/net/ethernet/amazon/ena/ena_netdev.c | 12 +- + .../net/ethernet/aquantia/atlantic/aq_main.c | 1 + + .../net/ethernet/aquantia/atlantic/aq_ring.c | 8 +- + drivers/net/ethernet/asix/ax88796c_main.c | 4 +- + drivers/net/ethernet/broadcom/b44.c | 8 +- + drivers/net/ethernet/broadcom/bcmsysport.c | 12 +- + .../ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h | 2 +- + drivers/net/ethernet/cortina/gemini.c | 24 +- + .../net/ethernet/emulex/benet/be_ethtool.c | 12 +- + drivers/net/ethernet/emulex/benet/be_main.c | 16 +- + drivers/net/ethernet/freescale/Kconfig | 20 + + drivers/net/ethernet/freescale/Makefile | 2 + + drivers/net/ethernet/freescale/enetc/enetc.h | 5 + + .../ethernet/freescale/enetc/enetc_ethtool.c | 152 + + .../net/ethernet/freescale/enetc/enetc_hw.h | 6 + + .../net/ethernet/freescale/enetc/enetc_pf.c | 16 +- + .../net/ethernet/freescale/enetc/enetc_ptp.c | 15 +- + .../net/ethernet/freescale/enetc/enetc_tsn.c | 194 +- + drivers/net/ethernet/freescale/fec.h | 100 +- + drivers/net/ethernet/freescale/fec_ecat.c | 3008 +++++++++++++++++ + drivers/net/ethernet/freescale/fec_ecat.h | 713 ++++ + drivers/net/ethernet/freescale/fec_main.c | 1460 +++++++- + drivers/net/ethernet/freescale/fec_ptp.c | 451 ++- + drivers/net/ethernet/freescale/fec_uio.c | 4 +- + .../net/ethernet/freescale/gianfar_ethtool.c | 29 + + .../net/ethernet/freescale/sdk_dpaa/Kconfig | 11 +- + .../net/ethernet/freescale/sdk_dpaa/Makefile | 3 + + .../ethernet/freescale/sdk_dpaa/dpaa_eth.h | 13 +- + .../freescale/sdk_dpaa/dpaa_eth_common.c | 56 + + .../ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 28 +- + .../freescale/sdk_dpaa/dpaa_ethercat.c | 1217 +++++++ + .../ethernet/fungible/funeth/funeth_txrx.h | 4 +- + drivers/net/ethernet/google/gve/gve_ethtool.c | 16 +- + drivers/net/ethernet/google/gve/gve_main.c | 12 +- + drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + + .../net/ethernet/hisilicon/hns3/hns3_enet.c | 5 +- + drivers/net/ethernet/huawei/hinic/hinic_rx.c | 4 +- + drivers/net/ethernet/huawei/hinic/hinic_tx.c | 4 +- + .../net/ethernet/intel/fm10k/fm10k_netdev.c | 8 +- + drivers/net/ethernet/intel/i40e/i40e.h | 1 + + .../net/ethernet/intel/i40e/i40e_ethtool.c | 8 +- + drivers/net/ethernet/intel/i40e/i40e_main.c | 20 +- + drivers/net/ethernet/intel/iavf/iavf.h | 1 + + .../net/ethernet/intel/iavf/iavf_ethtool.c | 8 +- + drivers/net/ethernet/intel/ice/ice.h | 1 + + drivers/net/ethernet/intel/ice/ice_main.c | 4 +- + drivers/net/ethernet/intel/igb/igb_ethtool.c | 12 +- + drivers/net/ethernet/intel/igb/igb_main.c | 8 +- + drivers/net/ethernet/intel/igc/igc_ethtool.c | 12 +- + drivers/net/ethernet/intel/igc/igc_main.c | 8 +- + .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 8 +- + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 +- + drivers/net/ethernet/intel/ixgbevf/ethtool.c | 12 +- + .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 8 +- + drivers/net/ethernet/marvell/mvneta.c | 10 +- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 8 +- + drivers/net/ethernet/marvell/sky2.c | 8 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 +- + .../net/ethernet/mellanox/mlx5/core/en_main.c | 1 + + .../net/ethernet/mellanox/mlxsw/spectrum.c | 4 +- + .../ethernet/microchip/lan966x/lan966x_tc.c | 1 + + .../net/ethernet/microchip/sparx5/sparx5_tc.c | 1 + + drivers/net/ethernet/microsoft/mana/mana_en.c | 8 +- + .../ethernet/microsoft/mana/mana_ethtool.c | 8 +- + drivers/net/ethernet/mscc/ocelot.c | 52 +- + drivers/net/ethernet/mscc/ocelot_flower.c | 30 +- + drivers/net/ethernet/mscc/ocelot_ptp.c | 1 + + drivers/net/ethernet/mscc/ocelot_vcap.c | 173 +- + .../ethernet/netronome/nfp/nfp_net_common.c | 8 +- + .../ethernet/netronome/nfp/nfp_net_ethtool.c | 8 +- + .../net/ethernet/netronome/nfp/nfp_net_repr.c | 4 +- + drivers/net/ethernet/nvidia/forcedeth.c | 8 +- + .../net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 4 +- + drivers/net/ethernet/realtek/8139too.c | 8 +- + drivers/net/ethernet/socionext/sni_ave.c | 8 +- + .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 38 +- + drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 19 +- + drivers/net/ethernet/stmicro/stmmac/dwmac5.h | 6 +- + .../ethernet/stmicro/stmmac/dwxgmac2_core.c | 3 +- + drivers/net/ethernet/stmicro/stmmac/hwif.h | 11 +- + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + + .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 103 + + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 40 +- + .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 37 +- + drivers/net/ethernet/ti/am65-cpsw-nuss.c | 4 +- + drivers/net/ethernet/ti/cpsw_priv.c | 1 + + drivers/net/ethernet/ti/netcp_core.c | 8 +- + drivers/net/ethernet/via/via-rhine.c | 8 +- + .../net/ethernet/xilinx/xilinx_axienet_main.c | 8 +- + drivers/net/hyperv/netvsc_drv.c | 32 +- + drivers/net/ifb.c | 12 +- + drivers/net/ipvlan/ipvlan_main.c | 4 +- + drivers/net/loopback.c | 4 +- + drivers/net/macsec.c | 12 +- + drivers/net/macvlan.c | 4 +- + drivers/net/mhi_net.c | 8 +- + drivers/net/netdevsim/netdev.c | 4 +- + drivers/net/phy/phy.c | 5 +- + drivers/net/team/team.c | 4 +- + drivers/net/team/team_mode_loadbalance.c | 4 +- + drivers/net/veth.c | 12 +- + drivers/net/virtio_net.c | 16 +- + drivers/net/vrf.c | 4 +- + drivers/net/vxlan/vxlan_vnifilter.c | 4 +- + drivers/net/wwan/mhi_wwan_mbim.c | 8 +- + drivers/net/xen-netfront.c | 8 +- + drivers/nfc/Kconfig | 1 + + drivers/nfc/Makefile | 1 + + drivers/nfc/pn5xx/Kconfig | 12 + + drivers/nfc/pn5xx/Makefile | 6 + + drivers/nfc/pn5xx/README.md | 2 + + drivers/nfc/pn5xx/pn5xx_i2c.c | 672 ++++ + drivers/nfc/pn5xx/pn5xx_i2c.h | 38 + + drivers/nfc/pn5xx/sample_devicetree.txt | 17 + + drivers/rpmsg/Kconfig | 16 +- + drivers/rpmsg/Makefile | 1 + + drivers/rpmsg/imx_rpmsg.c | 57 +- + drivers/rpmsg/imx_rpmsg_tty.c | 18 +- + drivers/rpmsg/rpmsg_perf.c | 545 +++ + drivers/rpmsg/virtio_rpmsg_bus.c | 5 + + drivers/rtc/Kconfig | 1 + + drivers/spi/spi.c | 4 +- + drivers/staging/fsl_qbman/qman_driver.c | 50 + + drivers/staging/fsl_qbman/qman_high.c | 38 + + drivers/staging/fsl_qbman/qman_private.h | 6 + + drivers/tty/Kconfig | 2 + + drivers/tty/rpmsg_tty.c | 192 +- + drivers/tty/serial/8250/8250.h | 41 +- + drivers/tty/serial/8250/8250_aspeed_vuart.c | 2 +- + drivers/tty/serial/8250/8250_bcm7271.c | 21 +- + drivers/tty/serial/8250/8250_core.c | 24 +- + drivers/tty/serial/8250/8250_exar.c | 4 +- + drivers/tty/serial/8250/8250_fsl.c | 3 +- + drivers/tty/serial/8250/8250_ingenic.c | 3 +- + drivers/tty/serial/8250/8250_mtk.c | 32 +- + drivers/tty/serial/8250/8250_omap.c | 20 +- + drivers/tty/serial/8250/8250_port.c | 158 +- + drivers/tty/serial/8250/Kconfig | 1 + + drivers/tty/serial/amba-pl011.c | 17 +- + drivers/tty/serial/omap-serial.c | 12 +- + drivers/tty/sysrq.c | 2 + + drivers/vdpa/vdpa_user/iova_domain.h | 1 - + drivers/virtio/Kconfig | 8 + + drivers/virtio/Makefile | 1 + + drivers/virtio/virtio_mmio.c | 318 +- + drivers/virtio/virtio_ring.c | 2 - + drivers/virtio/virtio_trans.c | 793 +++++ + 203 files changed, 15306 insertions(+), 832 deletions(-) + create mode 100644 drivers/clk/imx/clk-pll.c + create mode 100644 drivers/clk/imx/clk-pll.h + create mode 100644 drivers/irqchip/ipi-baremetal.c + create mode 100644 drivers/mailbox/generic-software-mailbox.c + create mode 100644 drivers/net/dsa/netc/Kconfig + create mode 100644 drivers/net/dsa/netc/Makefile + create mode 100644 drivers/net/dsa/netc/netc.h + create mode 100644 drivers/net/dsa/netc/netc_config.c + create mode 100644 drivers/net/dsa/netc/netc_config.h + create mode 100644 drivers/net/dsa/netc/netc_devlink.c + create mode 100644 drivers/net/dsa/netc/netc_ethtool.c + create mode 100644 drivers/net/dsa/netc/netc_main.c + create mode 100644 drivers/net/dsa/netc/netc_ptp.c + create mode 100644 drivers/net/dsa/netc/netc_spi.c + create mode 100644 drivers/net/ethernet/freescale/fec_ecat.c + create mode 100644 drivers/net/ethernet/freescale/fec_ecat.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c + create mode 100644 drivers/nfc/pn5xx/Kconfig + create mode 100644 drivers/nfc/pn5xx/Makefile + create mode 100644 drivers/nfc/pn5xx/README.md + create mode 100644 drivers/nfc/pn5xx/pn5xx_i2c.c + create mode 100644 drivers/nfc/pn5xx/pn5xx_i2c.h + create mode 100644 drivers/nfc/pn5xx/sample_devicetree.txt + create mode 100644 drivers/rpmsg/rpmsg_perf.c + create mode 100644 drivers/virtio/virtio_trans.c + +diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig +index 6f04b831a5c0..5cb0ba920813 100644 +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -199,7 +199,7 @@ source "drivers/base/regmap/Kconfig" + + config DMA_SHARED_BUFFER + bool +- default n ++ default y + select IRQ_WORK + help + This option enables the framework for buffer-sharing between +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index 966aab902d19..ee69e4443691 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -57,6 +57,40 @@ static void zram_free_page(struct zram *zram, size_t index); + static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, + u32 index, int offset, struct bio *bio); + ++#ifdef CONFIG_PREEMPT_RT ++static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) ++{ ++ size_t index; ++ ++ for (index = 0; index < num_pages; index++) ++ spin_lock_init(&zram->table[index].lock); ++} ++ ++static int zram_slot_trylock(struct zram *zram, u32 index) ++{ ++ int ret; ++ ++ ret = spin_trylock(&zram->table[index].lock); ++ if (ret) ++ __set_bit(ZRAM_LOCK, &zram->table[index].flags); ++ return ret; ++} ++ ++static void zram_slot_lock(struct zram *zram, u32 index) ++{ ++ spin_lock(&zram->table[index].lock); ++ __set_bit(ZRAM_LOCK, &zram->table[index].flags); ++} ++ ++static void zram_slot_unlock(struct zram *zram, u32 index) ++{ ++ __clear_bit(ZRAM_LOCK, &zram->table[index].flags); ++ spin_unlock(&zram->table[index].lock); ++} ++ ++#else ++ ++static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) { } + + static int zram_slot_trylock(struct zram *zram, u32 index) + { +@@ -72,6 +106,7 @@ static void zram_slot_unlock(struct zram *zram, u32 index) + { + bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags); + } ++#endif + + static inline bool init_done(struct zram *zram) + { +@@ -1187,6 +1222,7 @@ static bool zram_meta_alloc(struct zram *zram, u64 disksize) + + if (!huge_class_size) + huge_class_size = zs_huge_class_size(zram->mem_pool); ++ zram_meta_init_table_locks(zram, num_pages); + return true; + } + +diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h +index a2bda53020fd..ae7950b26db5 100644 +--- a/drivers/block/zram/zram_drv.h ++++ b/drivers/block/zram/zram_drv.h +@@ -62,6 +62,9 @@ struct zram_table_entry { + unsigned long element; + }; + unsigned long flags; ++#ifdef CONFIG_PREEMPT_RT ++ spinlock_t lock; ++#endif + #ifdef CONFIG_ZRAM_MEMORY_TRACKING + ktime_t ac_time; + #endif +diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c +index 0d084d6652c4..5d620322bdc2 100644 +--- a/drivers/char/tpm/tpm_tis.c ++++ b/drivers/char/tpm/tpm_tis.c +@@ -50,6 +50,31 @@ static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *da + return container_of(data, struct tpm_tis_tcg_phy, priv); + } + ++#ifdef CONFIG_PREEMPT_RT ++/* ++ * Flushes previous write operations to chip so that a subsequent ++ * ioread*()s won't stall a cpu. ++ */ ++static inline void tpm_tis_flush(void __iomem *iobase) ++{ ++ ioread8(iobase + TPM_ACCESS(0)); ++} ++#else ++#define tpm_tis_flush(iobase) do { } while (0) ++#endif ++ ++static inline void tpm_tis_iowrite8(u8 b, void __iomem *iobase, u32 addr) ++{ ++ iowrite8(b, iobase + addr); ++ tpm_tis_flush(iobase); ++} ++ ++static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr) ++{ ++ iowrite32(b, iobase + addr); ++ tpm_tis_flush(iobase); ++} ++ + static int interrupts = -1; + module_param(interrupts, int, 0444); + MODULE_PARM_DESC(interrupts, "Enable interrupts"); +@@ -202,12 +227,12 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, + switch (io_mode) { + case TPM_TIS_PHYS_8: + while (len--) +- iowrite8(*value++, phy->iobase + addr); ++ tpm_tis_iowrite8(*value++, phy->iobase, addr); + break; + case TPM_TIS_PHYS_16: + return -EINVAL; + case TPM_TIS_PHYS_32: +- iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase + addr); ++ tpm_tis_iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase, addr); + break; + } + +diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile +index bc6579e0cb0b..53e75b26648f 100644 +--- a/drivers/clk/imx/Makefile ++++ b/drivers/clk/imx/Makefile +@@ -16,6 +16,7 @@ mxc-clk-objs += clk-gate-93.o + mxc-clk-objs += clk-gate-exclusive.o + mxc-clk-objs += clk-pfd.o + mxc-clk-objs += clk-pfdv2.o ++mxc-clk-objs += clk-pll.o + mxc-clk-objs += clk-pllv1.o + mxc-clk-objs += clk-pllv2.o + mxc-clk-objs += clk-pllv3.o +diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c +index c703056fae85..2085d8e91ca8 100644 +--- a/drivers/clk/imx/clk-frac-pll.c ++++ b/drivers/clk/imx/clk-frac-pll.c +@@ -17,6 +17,7 @@ + #include + + #include "clk.h" ++#include "clk-pll.h" + + #define PLL_CFG0 0x0 + #define PLL_CFG1 0x4 +@@ -35,7 +36,11 @@ + #define PLL_FRAC_ACK_TIMEOUT 500000 + + struct clk_frac_pll { ++ u32 orig_divff; ++ u32 orig_divfi; ++ u32 orig_pllcfg0; + struct clk_hw hw; ++ struct clk_imx_pll imx_pll; + void __iomem *base; + }; + +@@ -202,6 +207,126 @@ static const struct clk_ops clk_frac_pll_ops = { + .set_rate = clk_pll_set_rate, + }; + ++/* This function fetches the original PLL parameters to use ++ * them later for ppb adjustment ++ */ ++static void imx_frac_pll_init(struct clk_imx_pll *pll) ++{ ++ struct clk_frac_pll *frac_pll; ++ u32 val; ++ ++ frac_pll = (struct clk_frac_pll *) container_of(pll, ++ struct clk_frac_pll, imx_pll); ++ ++ val = readl_relaxed(frac_pll->base + PLL_CFG1); ++ ++ frac_pll->orig_divff = (val >> 7) & PLL_FRAC_DIV_MASK; ++ frac_pll->orig_divfi = val & PLL_INT_DIV_MASK; ++ ++ frac_pll->orig_pllcfg0 = readl_relaxed(frac_pll->base + PLL_CFG0); ++} ++ ++/** ++ * imx_frac_pll_adjust - Adjust the Audio pll by ppb. ++ * ++ * This function adjust the audio pll by ppb (part per billion) and returns ++ * the exact number of ppb adjusted. ++ * The adjustment is done by only modifying the Fractional Divide part ++ * of the audio PLL. ++ * Since the pllout = parent_rate * 8 / 2 * (1 + DIVFI + DIVFF / 2^24) ++ * and the adjusted value is ++ * pllout_new = pllout * (1 + ppb/1e9) which equals: ++ * parent_rate * 8 / 2 * (1 + DIVFI + DIVFF_new / 2^24) ++ * The new divff is calculated as the following: ++ * DIVFF_new = ((1 + DIVFI) * ppb * 2^24 + DIVFF * 1e9 + DIVFF * ppb) / (1e9) ++ */ ++ ++static int imx_frac_pll_adjust(struct clk_imx_pll *pll, int *ppb) ++{ ++ u64 temp64; ++ u32 val; ++ s64 applied_ppb; ++ struct clk_frac_pll *frac_pll; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ int req_ppb = *ppb; ++ ++ frac_pll = (struct clk_frac_pll *) container_of(pll, ++ struct clk_frac_pll, imx_pll); ++ ++ /*Calcultate the new PLL Numerator*/ ++ temp64 = ((u64) frac_pll->orig_divfi + 1) * PLL_FRAC_DENOM * req_ppb ++ + (u64) frac_pll->orig_divff * 1000000000 ++ + (u64) frac_pll->orig_divff * req_ppb; ++ ++ do_div(temp64, 1000000000); ++ ++ if (temp64 >= PLL_FRAC_DENOM) { ++ rc = -IMX_CLK_PLL_PREC_ERR; ++ goto exit; ++ } ++ ++ /* clear the NEW_DIV_VAL */ ++ val = frac_pll->orig_pllcfg0; ++ val &= ~PLL_NEWDIV_VAL; ++ writel_relaxed(val, frac_pll->base + PLL_CFG0); ++ ++ /* Write the PLL control settings with the new DIVFF ++ * NOTE: This sets the reserved bit (bit 31) to zero ++ */ ++ ++ val = 0; ++ val |= (((u32)temp64 << 7) | frac_pll->orig_divfi); ++ writel_relaxed(val, frac_pll->base + PLL_CFG1); ++ ++ /* Set the NEW_DIV_VAL to reload the DIVFI and DIVFF */ ++ val = frac_pll->orig_pllcfg0; ++ val |= PLL_NEWDIV_VAL; ++ writel_relaxed(val, frac_pll->base + PLL_CFG0); ++ ++ /*Calculate and return the actual applied ppb*/ ++ applied_ppb = div64_s64((s64) (temp64 - frac_pll->orig_divff) * 1000000000, ++ frac_pll->orig_divff + ((s64) frac_pll->orig_divfi + 1) * PLL_FRAC_DENOM); ++ ++ *ppb = (int) applied_ppb; ++ ++ exit: ++ return rc; ++} ++ ++static unsigned long imx_frac_pll_get_rate(struct clk_imx_pll *pll, ++ unsigned long parent_rate) ++{ ++ struct clk_frac_pll *frac_pll; ++ ++ frac_pll = (struct clk_frac_pll *) container_of(pll, ++ struct clk_frac_pll, imx_pll); ++ ++ return clk_pll_recalc_rate(&frac_pll->hw, parent_rate); ++} ++ ++static int imx_frac_pll_set_rate(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_frac_pll *frac_pll; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ frac_pll = (struct clk_frac_pll *) container_of(pll, ++ struct clk_frac_pll, imx_pll); ++ ++ if (clk_pll_set_rate(&frac_pll->hw, rate, parent_rate) < 0) ++ rc = -IMX_CLK_PLL_INVALID_PARAM; ++ ++ return rc; ++} ++ ++static const struct clk_imx_pll_ops imx_clk_frac_pll_ops = { ++ .set_rate = imx_frac_pll_set_rate, ++ .get_rate = imx_frac_pll_get_rate, ++ .adjust = imx_frac_pll_adjust, ++ .init = imx_frac_pll_init, ++}; ++ + struct clk_hw *imx_clk_hw_frac_pll(const char *name, + const char *parent_name, + void __iomem *base) +@@ -232,6 +357,11 @@ struct clk_hw *imx_clk_hw_frac_pll(const char *name, + return ERR_PTR(ret); + } + ++ pll->imx_pll.ops = &imx_clk_frac_pll_ops; ++ ++ if (imx_pll_register(&pll->imx_pll, name) < 0) ++ pr_warn("Failed to register %s into imx pll\n", name); ++ + return hw; + } + EXPORT_SYMBOL_GPL(imx_clk_hw_frac_pll); +diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c +index d611e81cf15b..c1bd42a4e479 100644 +--- a/drivers/clk/imx/clk-fracn-gppll.c ++++ b/drivers/clk/imx/clk-fracn-gppll.c +@@ -13,6 +13,7 @@ + #include + + #include "clk.h" ++#include "clk-pll.h" + + #define PLL_CTRL 0x0 + #define HW_CTRL_SEL BIT(16) +@@ -53,10 +54,21 @@ + .odiv = (_odiv), \ + } + ++ ++/* MFN : Numerator of the fractional part of divider (30-bits, signed) */ ++#define MFN_MAX_VALUE ((s32)(GENMASK(29, 0) >> 1)) ++#define MFN_MIN_VALUE ((s32)(-MFN_MAX_VALUE - 1)) ++ + struct clk_fracn_gppll { + struct clk_hw hw; + void __iomem *base; + const struct imx_fracn_gppll_rate_table *rate_table; ++ u32 orig_mfd; ++ u32 orig_mfi; ++ u32 orig_odiv; ++ u32 orig_rdiv; ++ s32 orig_mfn; ++ struct clk_imx_pll imx_pll; + int rate_count; + }; + +@@ -79,7 +91,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { + PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6), + PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), + PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12), +- PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10), ++ PLL_FRACN_GP(393216000U, 163, 1680000, 2000000, 0, 10), + PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12) + }; + +@@ -123,18 +135,19 @@ static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate, + return rate_table[pll->rate_count - 1].rate; + } + +-static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++/* This function calculates the actual rate based on the configured PLL registers */ ++static unsigned long __clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + { + struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); +- const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; + u32 pll_numerator, pll_denominator, pll_div; +- u32 mfi, mfn, mfd, rdiv, odiv; ++ u32 mfi, mfd, rdiv, odiv; ++ s32 mfn; + u64 fvco = parent_rate; +- long rate = 0; +- int i; + + pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR); +- mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator); ++ ++ /* Numerator is 30-bits signed value */ ++ mfn = sign_extend32(FIELD_GET(PLL_MFN_MASK, pll_numerator), 29); + + pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR); + mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator); +@@ -145,22 +158,6 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon + rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div); + odiv = FIELD_GET(PLL_ODIV_MASK, pll_div); + +- /* +- * Sometimes, the recalculated rate has deviation due to +- * the frac part. So find the accurate pll rate from the table +- * first, if no match rate in the table, use the rate calculated +- * from the equation below. +- */ +- for (i = 0; i < pll->rate_count; i++) { +- if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi && +- rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv && +- rate_table[i].odiv == odiv) +- rate = rate_table[i].rate; +- } +- +- if (rate) +- return (unsigned long)rate; +- + if (!rdiv) + rdiv = rdiv + 1; + +@@ -176,12 +173,49 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon + } + + /* Fvco = Fref * (MFI + MFN / MFD) */ +- fvco = fvco * mfi * mfd + fvco * mfn; ++ fvco *= (mfi * mfd + mfn); + do_div(fvco, mfd * rdiv * odiv); + + return (unsigned long)fvco; + } + ++static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++{ ++ struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); ++ const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; ++ u32 pll_numerator, pll_denominator, pll_div; ++ u32 mfi, mfn, mfd, rdiv, odiv; ++ long rate = 0; ++ int i; ++ ++ pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR); ++ mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator); ++ ++ pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR); ++ mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator); ++ ++ pll_div = readl_relaxed(pll->base + PLL_DIV); ++ mfi = FIELD_GET(PLL_MFI_MASK, pll_div); ++ ++ rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div); ++ odiv = FIELD_GET(PLL_ODIV_MASK, pll_div); ++ ++ /* ++ * Sometimes, the recalculated rate has deviation due to ++ * the frac part. So find the accurate pll rate from the table ++ * first, if no match rate in the table, use the rate calculated ++ * from the equation below. ++ */ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi && ++ rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv && ++ rate_table[i].odiv == odiv) ++ rate = rate_table[i].rate; ++ } ++ ++ return rate ? (unsigned long) rate : __clk_fracn_gppll_recalc_rate(hw, parent_rate); ++} ++ + static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll) + { + u32 val; +@@ -199,6 +233,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, + int ret; + + rate = imx_get_pll_settings(pll, drate); ++ if (!rate) { ++ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, ++ drate, clk_hw_get_name(hw)); ++ return -EINVAL; ++ } + + /* Hardware control select disable. PLL is control by register */ + tmp = readl_relaxed(pll->base + PLL_CTRL); +@@ -306,6 +345,122 @@ static const struct clk_ops clk_fracn_gppll_ops = { + .set_rate = clk_fracn_gppll_set_rate, + }; + ++/* This function fetches the original PLL parameters to use ++ * them later for ppb adjustment ++ */ ++static void imx_fracn_gppll_init(struct clk_imx_pll *pll) ++{ ++ struct clk_fracn_gppll *fracn_pll; ++ u32 pll_numerator, pll_denominator, pll_div, mfn; ++ ++ fracn_pll = (struct clk_fracn_gppll *) container_of(pll, ++ struct clk_fracn_gppll, imx_pll); ++ ++ pll_numerator = readl_relaxed(fracn_pll->base + PLL_NUMERATOR); ++ mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator); ++ ++ /* Numerator is 30-bits signed value */ ++ fracn_pll->orig_mfn = sign_extend32(mfn, 29); ++ ++ pll_denominator = readl_relaxed(fracn_pll->base + PLL_DENOMINATOR); ++ fracn_pll->orig_mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator); ++ ++ pll_div = readl_relaxed(fracn_pll->base + PLL_DIV); ++ fracn_pll->orig_mfi = FIELD_GET(PLL_MFI_MASK, pll_div); ++ ++ fracn_pll->orig_rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div); ++ fracn_pll->orig_odiv = FIELD_GET(PLL_ODIV_MASK, pll_div); ++} ++ ++/** ++ * imx_fracn_gppll_adjust - Adjust the Audio pll by ppb. ++ * ++ * This function adjusts the audio pll by ppb (part per billion) and returns ++ * the exact number of ppb adjusted. ++ * The adjustment is done by only modifying the numerator of the fractional part ++ * of the audio PLL. ++ * Since the pllout = (ref * (mfi + mfn/mfd)) / (rdiv * odiv) ++ * and the adjusted value is ++ * pllout_new = pllout * (1 + ppb/1e9) which equals: ++ * (ref * (mfi + mfn_new/mfd)) / (rdiv * odiv) ++ * The new numerator (mfn_new) is calculated as following: ++ * mfn_new = (1e9 * mfn + (mfi * mfd + mfn) * ppb) / (1e9) ++ */ ++ ++static int imx_fracn_gppll_adjust(struct clk_imx_pll *pll, int *ppb) ++{ ++ s64 temp64; ++ s64 applied_ppb; ++ struct clk_fracn_gppll *fracn_pll; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ int req_ppb = *ppb; ++ ++ fracn_pll = (struct clk_fracn_gppll *) container_of(pll, ++ struct clk_fracn_gppll, imx_pll); ++ ++ /* Calculate the new numerator value */ ++ temp64 = ((s64) fracn_pll->orig_mfn * 1000000000) ++ + ((s64) fracn_pll->orig_mfi * fracn_pll->orig_mfd + (s64) fracn_pll->orig_mfn) * req_ppb; ++ ++ temp64 = div_s64(temp64, 1000000000); ++ ++ /* Sanity check on the new numerator value: ++ * - the value is inside the 30-bits signed values range ++ * - mfn/mfd should be in the range [-2, 2] ++ */ ++ if (temp64 > MFN_MAX_VALUE || temp64 < MFN_MIN_VALUE || (abs(temp64) > (2 * fracn_pll->orig_mfd))) { ++ rc = -IMX_CLK_PLL_PREC_ERR; ++ goto exit; ++ } ++ ++ /* Write the PLL control settings with the new numerator */ ++ ++ writel_relaxed(FIELD_PREP(PLL_MFN_MASK, temp64), fracn_pll->base + PLL_NUMERATOR); ++ ++ /* Calculate and return the actual applied ppb */ ++ applied_ppb = div64_s64((s64) (temp64 - fracn_pll->orig_mfn) * 1000000000, ++ fracn_pll->orig_mfn + fracn_pll->orig_mfd * (s64) fracn_pll->orig_mfi); ++ ++ *ppb = (int) applied_ppb; ++ ++ exit: ++ return rc; ++} ++ ++static unsigned long imx_fracn_gppll_get_rate(struct clk_imx_pll *pll, ++ unsigned long parent_rate) ++{ ++ struct clk_fracn_gppll *fracn_pll; ++ ++ fracn_pll = (struct clk_fracn_gppll *) container_of(pll, ++ struct clk_fracn_gppll, imx_pll); ++ ++ return __clk_fracn_gppll_recalc_rate(&fracn_pll->hw, parent_rate); ++} ++ ++static int imx_fracn_gppll_set_rate(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_fracn_gppll *fracn_pll; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ fracn_pll = (struct clk_fracn_gppll *) container_of(pll, ++ struct clk_fracn_gppll, imx_pll); ++ ++ if (clk_fracn_gppll_set_rate(&fracn_pll->hw, rate, parent_rate) < 0) ++ rc = -IMX_CLK_PLL_INVALID_PARAM; ++ ++ return rc; ++} ++ ++static const struct clk_imx_pll_ops imx_clk_fracn_gppll_ops = { ++ .set_rate = imx_fracn_gppll_set_rate, ++ .get_rate = imx_fracn_gppll_get_rate, ++ .adjust = imx_fracn_gppll_adjust, ++ .init = imx_fracn_gppll_init, ++}; ++ + struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk) + { +@@ -338,6 +493,11 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo + return ERR_PTR(ret); + } + ++ pll->imx_pll.ops = &imx_clk_fracn_gppll_ops; ++ ++ if (imx_pll_register(&pll->imx_pll, name) < 0) ++ pr_warn("%s: failed to register %s into imx pll\n", __func__, name); ++ + return hw; + } + EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll); +diff --git a/drivers/clk/imx/clk-imx8dxl-acm.c b/drivers/clk/imx/clk-imx8dxl-acm.c +index b11254522bc5..bef8d33f543b 100644 +--- a/drivers/clk/imx/clk-imx8dxl-acm.c ++++ b/drivers/clk/imx/clk-imx8dxl-acm.c +@@ -55,6 +55,14 @@ static const char *mclk_out_sels[] = { + "dummy", + }; + ++static const char *gpt_mux_clk_sels[] = { ++ "aud_pll_div_clk0_lpcg_clk", ++ "aud_pll_div_clk1_lpcg_clk", ++ "acm_aud_clk0_sel", ++ "acm_aud_clk1_sel", ++ "dummy", ++}; ++ + static const char *sai_mclk_sels[] = { + "aud_pll_div_clk0_lpcg_clk", + "aud_pll_div_clk1_lpcg_clk", +@@ -76,6 +84,41 @@ static const char *mqs_mclk_sels[] = { + "acm_aud_clk1_sel", + }; + ++/* The number of cells for the GPT capture device tree attribute */ ++#define OF_GPT_CAPTURE_CELLS_NB 2 ++ ++static void imx8dxl_acm_gpt_input_mux(struct device_node *np, struct imx8dxl_acm_priv *priv) ++{ ++ u32 len, reg_offset, event_sel_control, num_capture_select; ++ int i, offset; ++ ++ if (!of_get_property(np, "gpt-capture-select", &len)) ++ return; ++ ++ num_capture_select = len / (sizeof(u32) * OF_GPT_CAPTURE_CELLS_NB); ++ ++ for (i = 0; i < num_capture_select; i++) { ++ offset = i * OF_GPT_CAPTURE_CELLS_NB; ++ if (of_property_read_u32_index(np, ++ "gpt-capture-select", ++ offset, ®_offset)) { ++ pr_err("failed to read gpt register offset cell at offset %d\n", ++ offset); ++ return; ++ } ++ ++ if (of_property_read_u32_index(np, ++ "gpt-capture-select", ++ offset + 1, &event_sel_control)) { ++ pr_err("failed to read gpt event select control cell at offset %d\n", ++ offset + 1); ++ return; ++ } ++ ++ writel_relaxed(event_sel_control, priv->reg + reg_offset); ++ } ++} ++ + static int imx8dxl_acm_clk_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -137,6 +180,8 @@ static int imx8dxl_acm_clk_probe(struct platform_device *pdev) + clks[IMX_ADMA_ACM_MCLKOUT0_SEL] = imx_dev_clk_mux(dev, "acm_mclkout0_sel", base+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels)); + clks[IMX_ADMA_ACM_MCLKOUT1_SEL] = imx_dev_clk_mux(dev, "acm_mclkout1_sel", base+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels)); + ++ clks[IMX_ADMA_ACM_GPT0_MUX_CLK_SEL] = imx_dev_clk_mux(dev, "acm_gpt0_mux_clk_sel", base+0x080000, 0, 3, gpt_mux_clk_sels, ARRAY_SIZE(gpt_mux_clk_sels)); ++ + clks[IMX_ADMA_ACM_SAI0_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai0_mclk_sel", base+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI1_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai1_mclk_sel", base+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); + clks[IMX_ADMA_ACM_SAI2_MCLK_SEL] = imx_dev_clk_mux(dev, "acm_sai2_mclk_sel", base+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels)); +@@ -153,6 +198,8 @@ static int imx8dxl_acm_clk_probe(struct platform_device *pdev) + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); + ++ imx8dxl_acm_gpt_input_mux(np, priv); ++ + pm_runtime_put_sync(&pdev->dev); + + return ret; +@@ -182,6 +229,7 @@ static int __maybe_unused imx8dxl_acm_runtime_suspend(struct device *dev) + priv->regs[1] = readl_relaxed(priv->reg + 0x010000); + priv->regs[2] = readl_relaxed(priv->reg + 0x020000); + priv->regs[3] = readl_relaxed(priv->reg + 0x030000); ++ priv->regs[8] = readl_relaxed(priv->reg + 0x080000); + priv->regs[14] = readl_relaxed(priv->reg + 0x0E0000); + priv->regs[15] = readl_relaxed(priv->reg + 0x0F0000); + priv->regs[16] = readl_relaxed(priv->reg + 0x100000); +@@ -200,6 +248,7 @@ static int __maybe_unused imx8dxl_acm_runtime_resume(struct device *dev) + writel_relaxed(priv->regs[1], priv->reg + 0x010000); + writel_relaxed(priv->regs[2], priv->reg + 0x020000); + writel_relaxed(priv->regs[3], priv->reg + 0x030000); ++ writel_relaxed(priv->regs[8], priv->reg + 0x080000); + writel_relaxed(priv->regs[14], priv->reg + 0x0E0000); + writel_relaxed(priv->regs[15], priv->reg + 0x0F0000); + writel_relaxed(priv->regs[16], priv->reg + 0x100000); +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index 8e49b49ddc3e..1e9de317ed54 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -216,7 +216,7 @@ static const char * const imx8mq_pwm4_sels[] = {"osc_25m", "sys2_pll_100m", "sys + "sys3_pll_out", "clk_ext2", "sys1_pll_80m", "video_pll1_out", }; + + static const char * const imx8mq_gpt1_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_400m", "sys1_pll_40m", +- "sys1_pll_80m", "audio_pll1_out", "clk_ext1", }; ++ "video_pll1_out", "sys1_pll_80m", "audio_pll1_out", "clk_ext1", }; + + static const char * const imx8mq_wdog_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_160m", "vpu_pll_out", + "sys2_pll_125m", "sys3_pll_out", "sys1_pll_80m", "sys2_pll_166m", }; +diff --git a/drivers/clk/imx/clk-pll.c b/drivers/clk/imx/clk-pll.c +new file mode 100644 +index 000000000000..b77375a11add +--- /dev/null ++++ b/drivers/clk/imx/clk-pll.c +@@ -0,0 +1,83 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2018 NXP ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "clk-pll.h" ++ ++ ++static struct clk_imx_pll *clk_imx_pll_array[MAX_IMX_PLL_NUM] = { NULL }; ++ ++struct clk_imx_pll *clk_imx_pll_get_by_name(const char *name) ++{ ++ int i; ++ struct clk_imx_pll *pll = NULL; ++ ++ for (i = 0; i < MAX_IMX_PLL_NUM; i++) { ++ if (clk_imx_pll_array[i] && clk_imx_pll_array[i]->ops ++ && !strncmp(clk_imx_pll_array[i]->pll_name, name, MAX_PLL_NAME_SIZE)) { ++ ++ pll = clk_imx_pll_array[i]; ++ ++ /* Init all PLL original parameters*/ ++ if (pll && pll->ops && pll->ops->init) ++ pll->ops->init(pll); ++ ++ break; ++ } ++ } ++ ++ return pll; ++} ++EXPORT_SYMBOL(clk_imx_pll_get_by_name); ++ ++int clk_imx_pll_adjust(struct clk_imx_pll *pll, int *ppb) ++{ ++ if (pll && pll->ops && pll->ops->adjust) ++ return pll->ops->adjust(pll, ppb); ++ ++ return -IMX_CLK_PLL_INVALID_PARAM; ++} ++EXPORT_SYMBOL(clk_imx_pll_adjust); ++ ++unsigned long clk_imx_pll_get_rate(struct clk_imx_pll *pll, ++ unsigned long parent_rate) ++{ ++ if (pll && pll->ops && pll->ops->get_rate) ++ return pll->ops->get_rate(pll, parent_rate); ++ ++ return 0; ++} ++EXPORT_SYMBOL(clk_imx_pll_get_rate); ++ ++int clk_imx_pll_set_rate(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ if (pll && pll->ops && pll->ops->set_rate) ++ return pll->ops->set_rate(pll, rate, parent_rate); ++ ++ return -IMX_CLK_PLL_INVALID_PARAM; ++} ++EXPORT_SYMBOL(clk_imx_pll_set_rate); ++ ++int imx_pll_register(struct clk_imx_pll *pll, const char *name) ++{ ++ int i; ++ ++ strncpy(pll->pll_name, name, MAX_PLL_NAME_SIZE); ++ ++ for (i = 0; i < MAX_IMX_PLL_NUM; i++) { ++ if (!clk_imx_pll_array[i]) { ++ clk_imx_pll_array[i] = pll; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} +diff --git a/drivers/clk/imx/clk-pll.h b/drivers/clk/imx/clk-pll.h +new file mode 100644 +index 000000000000..f12167842059 +--- /dev/null ++++ b/drivers/clk/imx/clk-pll.h +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2018 NXP ++ * ++ */ ++ ++#ifndef __IMX_CLK_PLL_H ++#define __IMX_CLK_PLL_H ++ ++#include ++ ++#define MAX_IMX_PLL_NUM 16 ++#define MAX_PLL_NAME_SIZE 64 ++ ++struct clk_imx_pll; ++ ++struct clk_imx_pll_ops { ++ int (*set_rate)(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate); ++ unsigned long (*get_rate)(struct clk_imx_pll *pll, ++ unsigned long parent_rate); ++ int (*adjust)(struct clk_imx_pll *pll, int *ppb); ++ void (*init)(struct clk_imx_pll *pll); ++}; ++ ++struct clk_imx_pll { ++ char pll_name[MAX_PLL_NAME_SIZE]; ++ const struct clk_imx_pll_ops *ops; ++}; ++ ++int imx_pll_register(struct clk_imx_pll *pll, const char *name); ++ ++#endif /*__IMX_CLK_PLL_H*/ +diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c +index c3a29e0d345e..50b848f23fd4 100644 +--- a/drivers/clk/imx/clk-pll14xx.c ++++ b/drivers/clk/imx/clk-pll14xx.c +@@ -16,6 +16,7 @@ + #include + + #include "clk.h" ++#include "clk-pll.h" + + #define GNRL_CTL 0x0 + #define DIV_CTL0 0x4 +@@ -37,8 +38,13 @@ + struct clk_pll14xx { + struct clk_hw hw; + void __iomem *base; ++ u32 orig_mdiv; ++ u32 orig_pdiv; ++ u32 orig_sdiv; ++ short int orig_kdiv; + enum imx_pll14xx_type type; + const struct imx_pll14xx_rate_table *rate_table; ++ struct clk_imx_pll imx_pll; + int rate_count; + }; + +@@ -519,6 +525,113 @@ static const struct clk_ops clk_pll1443x_ops = { + .set_rate = clk_pll1443x_set_rate, + }; + ++/* This function fetches the original PLL parameters to use ++ * them later for ppb adjustment ++ */ ++static void imx_pll1443x_init(struct clk_imx_pll *pll) ++{ ++ struct clk_pll14xx *pll14xx; ++ u32 pll_div_ctl0, pll_div_ctl1; ++ ++ pll14xx = (struct clk_pll14xx *) container_of(pll, ++ struct clk_pll14xx, imx_pll); ++ ++ pll_div_ctl0 = readl_relaxed(pll14xx->base + DIV_CTL0); ++ pll_div_ctl1 = readl_relaxed(pll14xx->base + DIV_CTL1); ++ ++ pll14xx->orig_kdiv = FIELD_GET(KDIV_MASK, pll_div_ctl1); ++ pll14xx->orig_mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0); ++ pll14xx->orig_pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0); ++ pll14xx->orig_sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0); ++} ++ ++/** ++ * imx_pll1443x_adjust - Adjust the Audio pll by ppb. ++ * ++ * This function adjust the audio pll by ppb (part per billion) and returns ++ * the exact number of ppb adjusted. ++ * The adjustment is done by only modifying the delta-sigma modulator(DSM) part ++ * of the audio PLL. ++ * Since the pllout = (parent_rate * (m + k/65536)) / (p * 2^s) ++ * and the adjusted value is ++ * pllout_new = pllout * (1 + ppb/1e9) which equals: ++ * (parent_rate * (m + k_new/65536)) / (p * 2^s) ++ * The new DSM (k_new) is calculated as the following: ++ * k_new = (1e9 * k + (m * 65536 + k) * ppb) / (1e9) ++ */ ++ ++static int imx_pll1443x_adjust(struct clk_imx_pll *pll, int *ppb) ++{ ++ s64 temp64; ++ s64 applied_ppb; ++ struct clk_pll14xx *pll14xx; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ int req_ppb = *ppb; ++ ++ pll14xx = (struct clk_pll14xx *) container_of(pll, ++ struct clk_pll14xx, imx_pll); ++ ++ /* Calcultate the new DSM value */ ++ temp64 = ((s64) pll14xx->orig_kdiv * 1000000000) ++ + ((s64) pll14xx->orig_mdiv * 65536 + (s64) pll14xx->orig_kdiv) * req_ppb; ++ ++ temp64 = div_s64(temp64, 1000000000); ++ ++ if (temp64 > KDIV_MAX || temp64 < KDIV_MIN) { ++ rc = -IMX_CLK_PLL_PREC_ERR; ++ goto exit; ++ } ++ ++ /* Write the PLL control settings with the new DSM ++ */ ++ ++ writel_relaxed(FIELD_PREP(KDIV_MASK, temp64), pll14xx->base + DIV_CTL1); ++ ++ /* Calculate and return the actual applied ppb */ ++ applied_ppb = div64_s64((s64) (temp64 - pll14xx->orig_kdiv) * 1000000000, ++ pll14xx->orig_kdiv + 65536 * (s64) pll14xx->orig_mdiv); ++ ++ *ppb = (int) applied_ppb; ++ ++ exit: ++ return rc; ++} ++ ++static unsigned long imx_pll1443x_get_rate(struct clk_imx_pll *pll, ++ unsigned long parent_rate) ++{ ++ struct clk_pll14xx *pll14xx; ++ ++ pll14xx = (struct clk_pll14xx *) container_of(pll, ++ struct clk_pll14xx, imx_pll); ++ ++ return clk_pll14xx_recalc_rate(&pll14xx->hw, parent_rate); ++} ++ ++static int imx_pll1443x_set_rate(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_pll14xx *pll14xx; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ pll14xx = (struct clk_pll14xx *) container_of(pll, ++ struct clk_pll14xx, imx_pll); ++ ++ if (clk_pll1443x_set_rate(&pll14xx->hw, rate, parent_rate) < 0) ++ rc = -IMX_CLK_PLL_INVALID_PARAM; ++ ++ return rc; ++} ++ ++static const struct clk_imx_pll_ops imx_clk_pll1443x_ops = { ++ .set_rate = imx_pll1443x_set_rate, ++ .get_rate = imx_pll1443x_get_rate, ++ .adjust = imx_pll1443x_adjust, ++ .init = imx_pll1443x_init, ++}; ++ ++ + struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name, + const char *parent_name, void __iomem *base, + const struct imx_pll14xx_clk *pll_clk) +@@ -573,6 +686,13 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name, + return ERR_PTR(ret); + } + ++ if (pll_clk->type == PLL_1443X) { ++ pll->imx_pll.ops = &imx_clk_pll1443x_ops; ++ ++ if (imx_pll_register(&pll->imx_pll, name) < 0) ++ pr_warn("Failed to register %s into imx pll\n", name); ++ } ++ + return hw; + } + EXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx); +diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c +index aeabb9b15675..dbd5f081d1e7 100644 +--- a/drivers/clk/imx/clk-pllv3.c ++++ b/drivers/clk/imx/clk-pllv3.c +@@ -14,6 +14,7 @@ + #include + #include + #include "clk.h" ++#include "clk-pll.h" + + #define PLL_NUM_OFFSET 0x10 + #define PLL_DENOM_OFFSET 0x20 +@@ -47,6 +48,10 @@ + */ + struct clk_pllv3 { + struct clk_hw hw; ++ struct clk_imx_pll imx_pll; ++ u32 orig_num; ++ u32 orig_denom; ++ u32 orig_div; + void __iomem *base; + u32 power_bit; + bool powerup_set; +@@ -440,6 +445,106 @@ static const struct clk_ops clk_pllv3_vf610_ops = { + .set_rate = clk_pllv3_vf610_set_rate, + }; + ++/** ++ * imx_pllv3_av_adjust - Adjust the Audio pll by ppb. ++ * ++ * This function adjust the audio pll by ppb (part per billion) and returns ++ * the exact number of ppb adjusted. ++ * The adjustment is done by only modifying the Audio PLL Numerator. ++ * Since the pllout = parent * (div + num/denom) and the adjusted Value is ++ * pllout_new = PLL_out * (1 + ppb/1e9) ++ * Also pllout_new = parent * (div + new_num/denom) ++ * The new numerator is calculated as the following: ++ * new_num = (div * ppb * denom + num * 1e9 + num * ppb) / (1e9) ++ */ ++ ++static int imx_pllv3_av_adjust(struct clk_imx_pll *pll, int *ppb) ++{ ++ struct clk_pllv3 *av_pll; ++ u64 temp64; ++ s32 applied_ppb; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ int req_ppb = *ppb; ++ ++ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3, ++ imx_pll); ++ ++ /*Calcultate the new PLL Numerator*/ ++ temp64 = (u64) av_pll->orig_denom * av_pll->orig_div * req_ppb ++ + (u64) av_pll->orig_num * 1000000000 ++ + (u64) av_pll->orig_num * req_ppb; ++ ++ do_div(temp64, 1000000000); ++ ++ if (temp64 >= av_pll->orig_denom) { ++ rc = -IMX_CLK_PLL_PREC_ERR; ++ goto exit; ++ } ++ ++ /*Write the new PLL num*/ ++ writel_relaxed((u32) temp64, av_pll->base + av_pll->num_offset); ++ ++ /*Calculate and return the actual applied ppb*/ ++ applied_ppb = div64_s64((s64) (temp64 - av_pll->orig_num) * 1000000000, ++ av_pll->orig_num ++ + (s64) av_pll->orig_denom * av_pll->orig_div); ++ ++ *ppb = (int) applied_ppb; ++ ++exit: ++ return rc; ++ ++} ++ ++/* This function fetches the original PLL parameters to use ++ * them later for ppb adjustment ++ */ ++static void imx_pllv3_av_init(struct clk_imx_pll *pll) ++{ ++ struct clk_pllv3 *av_pll; ++ ++ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3, ++ imx_pll); ++ ++ av_pll->orig_num = readl_relaxed(av_pll->base + av_pll->num_offset); ++ av_pll->orig_denom = readl_relaxed(av_pll->base + av_pll->denom_offset); ++ av_pll->orig_div = readl_relaxed(av_pll->base) & av_pll->div_mask; ++} ++ ++static unsigned long imx_pllv3_av_get_rate(struct clk_imx_pll *pll, ++ unsigned long parent_rate) ++{ ++ struct clk_pllv3 *av_pll; ++ ++ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3, ++ imx_pll); ++ ++ return clk_pllv3_av_recalc_rate(&av_pll->hw, parent_rate); ++} ++ ++static int imx_pllv3_av_set_rate(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_pllv3 *av_pll; ++ int rc = IMX_CLK_PLL_SUCCESS; ++ ++ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3, ++ imx_pll); ++ ++ if (clk_pllv3_av_set_rate(&av_pll->hw, rate, parent_rate) < 0) ++ rc = -IMX_CLK_PLL_INVALID_PARAM; ++ ++ return rc; ++} ++ ++static const struct clk_imx_pll_ops imx_clk_pllv3_av_ops = { ++ .set_rate = imx_pllv3_av_set_rate, ++ .get_rate = imx_pllv3_av_get_rate, ++ .adjust = imx_pllv3_av_adjust, ++ .init = imx_pllv3_av_init, ++}; ++ + static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +@@ -495,6 +600,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name, + fallthrough; + case IMX_PLLV3_AV: + ops = &clk_pllv3_av_ops; ++ pll->imx_pll.ops = &imx_clk_pllv3_av_ops; + break; + case IMX_PLLV3_ENET_IMX7: + pll->power_bit = IMX7_ENET_PLL_POWER; +@@ -532,5 +638,8 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name, + return ERR_PTR(ret); + } + ++ if (imx_pll_register(&pll->imx_pll, name) < 0) ++ pr_warn("Failed to register %s into imx pll\n", name); ++ + return hw; + } +diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c +index 6c54017529d5..bc683fb0dda9 100644 +--- a/drivers/clk/imx/clk-scu.c ++++ b/drivers/clk/imx/clk-scu.c +@@ -18,6 +18,7 @@ + #include + + #include "clk-scu.h" ++#include "clk-pll.h" + + #define IMX_SIP_CPUFREQ 0xC2000001 + #define IMX_SIP_SET_CPUFREQ 0x00 +@@ -56,6 +57,8 @@ struct clk_scu { + u8 parent_index; + bool is_enabled; + u32 rate; ++ unsigned long original_rate; ++ struct clk_imx_pll imx_pll; + }; + + /* +@@ -449,6 +452,82 @@ static const struct clk_ops clk_scu_pi_ops = { + .set_rate = clk_scu_set_rate, + }; + ++static void imx_scu_init(struct clk_imx_pll *pll) ++{ ++ struct clk_scu *clk; ++ ++ clk = (struct clk_scu *) container_of(pll, struct clk_scu, imx_pll); ++ ++ clk->original_rate = clk_scu_recalc_rate(&clk->hw, 0); ++ ++ pr_info("SCU clock %p for PLL API init with original rate %lu\n", ++ clk, clk->original_rate); ++ ++ return; ++} ++ ++/* SCU is stating possible variation of +/-250Khz which gives around 300 ppm @ 786MHz ++ * Set a maximum adjustement at 250 ppm ++ */ ++#define IMX_SCU_MAX_PPB_ADJUSTEMENT 250000 ++ ++static int imx_scu_adjust(struct clk_imx_pll *pll, int *ppb) ++{ ++ struct clk_scu * clk = (struct clk_scu *) container_of(pll, ++ struct clk_scu, imx_pll); ++ unsigned long new_rate; ++ int delta; ++ ++ if (!clk->original_rate) { ++ pr_warn_once("failed to get original rate for clock\n"); ++ return -IMX_CLK_PLL_LOCK_ERR; ++ } ++ ++ if (abs(*ppb) > IMX_SCU_MAX_PPB_ADJUSTEMENT) { ++ return -IMX_CLK_PLL_PREC_ERR; ++ } ++ ++ if (*ppb < 0) ++ delta = -1; ++ else ++ delta = 1; ++ ++ delta *= (int)div64_u64((u64)clk->original_rate * (u64)abs(*ppb), ++ 1000000000); ++ ++ new_rate = clk->original_rate + delta; ++ ++ if (clk_scu_set_rate(&clk->hw, new_rate, 0) < 0) ++ return -IMX_CLK_PLL_INVALID_PARAM; ++ ++ return IMX_CLK_PLL_SUCCESS; ++} ++ ++static int imx_scu_set_rate(struct clk_imx_pll *pll, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_scu * clk = (struct clk_scu *) container_of(pll, ++ struct clk_scu, imx_pll); ++ ++ return clk_scu_set_rate(&clk->hw, rate, 0); ++} ++ ++static unsigned long imx_scu_get_rate(struct clk_imx_pll *pll, ++ unsigned long parent_rate) ++{ ++ struct clk_scu * clk = (struct clk_scu *) container_of(pll, ++ struct clk_scu, imx_pll); ++ ++ return clk_scu_recalc_rate(&clk->hw, 0); ++} ++ ++static const struct clk_imx_pll_ops imx_clk_scu_ops = { ++ .set_rate = imx_scu_set_rate, ++ .get_rate = imx_scu_get_rate, ++ .adjust = imx_scu_adjust, ++ .init = imx_scu_init, ++}; ++ + struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, + const char * const *parents, int num_parents, + u32 rsrc_id, u8 clk_type) +@@ -497,6 +576,13 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, + if (dev) + dev_set_drvdata(dev, clk); + ++ if (rsrc_id == IMX_SC_R_AUDIO_PLL_0 && clk_type == IMX_SC_PM_CLK_PLL) { ++ clk->imx_pll.ops = &imx_clk_scu_ops; ++ ++ if (imx_pll_register(&clk->imx_pll, name) < 0) ++ pr_warn("%s: failed to register %s into imx pll\n", __func__, name); ++ } ++ + return hw; + } + +diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c +index fbef30aa49ba..ce31ff3aab1c 100755 +--- a/drivers/firmware/imx/scu-pd.c ++++ b/drivers/firmware/imx/scu-pd.c +@@ -147,6 +147,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { + { "esai1", IMX_SC_R_ESAI_1, 1, false, 0 }, + { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 }, + { "spdif1", IMX_SC_R_SPDIF_1, 1, false, 0 }, ++ { "gpt", IMX_SC_R_GPT_5, 4, true, 5 }, + { "sai", IMX_SC_R_SAI_0, 3, true, 0 }, + { "sai3", IMX_SC_R_SAI_3, 1, false, 0 }, + { "sai4", IMX_SC_R_SAI_4, 1, false, 0 }, +diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig +index 6b10868ec72f..1fbdb7b4e6e1 100644 +--- a/drivers/gpu/drm/i915/Kconfig ++++ b/drivers/gpu/drm/i915/Kconfig +@@ -3,7 +3,6 @@ config DRM_I915 + tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" + depends on DRM + depends on X86 && PCI +- depends on !PREEMPT_RT + select INTEL_GTT if X86 + select INTERVAL_TREE + # we need shmfs for the swappable backing store, and in particular +diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c +index 6792a9056f46..43cedfef104f 100644 +--- a/drivers/gpu/drm/i915/display/intel_crtc.c ++++ b/drivers/gpu/drm/i915/display/intel_crtc.c +@@ -521,7 +521,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) + */ + intel_psr_wait_for_idle_locked(new_crtc_state); + +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + + crtc->debug.min_vbl = min; + crtc->debug.max_vbl = max; +@@ -546,11 +547,13 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) + break; + } + +- local_irq_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_enable(); + + timeout = schedule_timeout(timeout); + +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + } + + finish_wait(wq, &wait); +@@ -583,7 +586,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) + return; + + irq_disable: +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + } + + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) +@@ -684,7 +688,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) + */ + intel_vrr_send_push(new_crtc_state); + +- local_irq_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_enable(); + + if (intel_vgpu_active(dev_priv)) + return; +diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +index ecc990ec1b95..8d04b10681f0 100644 +--- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c ++++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +@@ -312,10 +312,9 @@ void __intel_breadcrumbs_park(struct intel_breadcrumbs *b) + /* Kick the work once more to drain the signalers, and disarm the irq */ + irq_work_sync(&b->irq_work); + while (READ_ONCE(b->irq_armed) && !atomic_read(&b->active)) { +- local_irq_disable(); +- signal_irq_work(&b->irq_work); +- local_irq_enable(); ++ irq_work_queue(&b->irq_work); + cond_resched(); ++ irq_work_sync(&b->irq_work); + } + } + +diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +index fc4a84628985..fc937697fe14 100644 +--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c ++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +@@ -1302,7 +1302,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + * and context switches) submission. + */ + +- spin_lock(&sched_engine->lock); ++ spin_lock_irq(&sched_engine->lock); + + /* + * If the queue is higher priority than the last +@@ -1402,7 +1402,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + * Even if ELSP[1] is occupied and not worthy + * of timeslices, our queue might be. + */ +- spin_unlock(&sched_engine->lock); ++ spin_unlock_irq(&sched_engine->lock); + return; + } + } +@@ -1428,7 +1428,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + + if (last && !can_merge_rq(last, rq)) { + spin_unlock(&ve->base.sched_engine->lock); +- spin_unlock(&engine->sched_engine->lock); ++ spin_unlock_irq(&engine->sched_engine->lock); + return; /* leave this for another sibling */ + } + +@@ -1590,7 +1590,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + */ + sched_engine->queue_priority_hint = queue_prio(sched_engine); + i915_sched_engine_reset_on_empty(sched_engine); +- spin_unlock(&sched_engine->lock); ++ spin_unlock_irq(&sched_engine->lock); + + /* + * We can skip poking the HW if we ended up with exactly the same set +@@ -1616,13 +1616,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + } + } + +-static void execlists_dequeue_irq(struct intel_engine_cs *engine) +-{ +- local_irq_disable(); /* Suspend interrupts across request submission */ +- execlists_dequeue(engine); +- local_irq_enable(); /* flush irq_work (e.g. breadcrumb enabling) */ +-} +- + static void clear_ports(struct i915_request **ports, int count) + { + memset_p((void **)ports, NULL, count); +@@ -2476,7 +2469,7 @@ static void execlists_submission_tasklet(struct tasklet_struct *t) + } + + if (!engine->execlists.pending[0]) { +- execlists_dequeue_irq(engine); ++ execlists_dequeue(engine); + start_timeslice(engine); + } + +diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c +index f93ffa6626a5..6e9d033cf808 100644 +--- a/drivers/gpu/drm/i915/i915_irq.c ++++ b/drivers/gpu/drm/i915/i915_irq.c +@@ -917,7 +917,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, + */ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + +- /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); + + /* Get optional system timestamp before query. */ + if (stime) +@@ -981,7 +982,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, + if (etime) + *etime = ktime_get(); + +- /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + +diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c +index 7ce126a01cbf..64a032dfaa90 100644 +--- a/drivers/gpu/drm/i915/i915_request.c ++++ b/drivers/gpu/drm/i915/i915_request.c +@@ -609,7 +609,6 @@ bool __i915_request_submit(struct i915_request *request) + + RQ_TRACE(request, "\n"); + +- GEM_BUG_ON(!irqs_disabled()); + lockdep_assert_held(&engine->sched_engine->lock); + + /* +@@ -718,7 +717,6 @@ void __i915_request_unsubmit(struct i915_request *request) + */ + RQ_TRACE(request, "\n"); + +- GEM_BUG_ON(!irqs_disabled()); + lockdep_assert_held(&engine->sched_engine->lock); + + /* +diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h +index 37b5c9e9d260..73f29d8008f0 100644 +--- a/drivers/gpu/drm/i915/i915_trace.h ++++ b/drivers/gpu/drm/i915/i915_trace.h +@@ -6,6 +6,10 @@ + #if !defined(_I915_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) + #define _I915_TRACE_H_ + ++#ifdef CONFIG_PREEMPT_RT ++#define NOTRACE ++#endif ++ + #include + #include + #include +@@ -323,7 +327,7 @@ DEFINE_EVENT(i915_request, i915_request_add, + TP_ARGS(rq) + ); + +-#if defined(CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS) ++#if defined(CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS) && !defined(NOTRACE) + DEFINE_EVENT(i915_request, i915_request_guc_submit, + TP_PROTO(struct i915_request *rq), + TP_ARGS(rq) +diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h +index 6c14d13364bf..de58855e6926 100644 +--- a/drivers/gpu/drm/i915/i915_utils.h ++++ b/drivers/gpu/drm/i915/i915_utils.h +@@ -294,7 +294,7 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) + #define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) + + /* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */ +-#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) ++#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT) + # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic()) + #else + # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0) +diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig +index 1602a37db178..b11fdbf93b80 100644 +--- a/drivers/irqchip/Kconfig ++++ b/drivers/irqchip/Kconfig +@@ -706,4 +706,8 @@ config SUNPLUS_SP7021_INTC + chained controller, routing all interrupt source in P-Chip to + the primary controller on C-Chip. + ++config BAREMETAL ++ bool ++ depends on ARM_GIC || ARM_GIC_V3 ++ + endmenu +diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile +index 87b49a10962c..1c6fe6f29519 100644 +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -121,3 +121,4 @@ obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o + obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o + obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o + obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o ++obj-$(CONFIG_BAREMETAL) += ipi-baremetal.o +\ No newline at end of file +diff --git a/drivers/irqchip/ipi-baremetal.c b/drivers/irqchip/ipi-baremetal.c +new file mode 100644 +index 000000000000..58f88546b6f0 +--- /dev/null ++++ b/drivers/irqchip/ipi-baremetal.c +@@ -0,0 +1,454 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * IPI for inter-core communiction for NXP Layerscape baremetal ++ * ++ * Copyright 2018-2023 NXP ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int pid; ++int mycoreid; ++ ++#undef IPI_BAREMETAL_SIGNAL ++ ++#define DEVICE_NAME "ipi_bm" ++ ++/* ++ * choose 50 as baremetal signal number. ++ * real-time signals are in the range of 33 to 64. ++ */ ++#define SIG_BM 50 ++ ++#ifndef IPI_BAREMETAL_SIGNAL ++void __iomem *share_base; ++#ifdef CONFIG_SOC_IMX6Q_BAREMETAL ++#define GICD_BASE 0x00A01000 ++#define GICD_SIZE 0x1000 ++#define GICC_BASE 0x00A00100 ++#define GICC_SIZE 0x1000 ++#define GIC_DIST_IGROUP 0x080 ++#define GIC_DIST_CTRL 0x000 ++#define GIC_CPU_CTRL 0x00 ++#define GICD_ENABLE 0x3 ++#define GICC_ENABLE 0x7 ++#endif ++#if defined(CONFIG_SOC_IMX6Q_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_BASE 0x10000000UL ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (128 * 1024 * 1024) ++#define CONFIG_SYS_DDR_SDRAM_MASTER_SIZE (512 * 1024 * 1024) ++#elif defined(CONFIG_LX2160A_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_BASE 0x80000000UL ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (64 * 1024 * 1024) ++#define CONFIG_SYS_DDR_SDRAM_MASTER_SIZE (512 * 1024 * 1024) ++#elif defined(CONFIG_IMX8M_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_ADDR (0x60000000) ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (32 * 1024 * 1024) ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_RESERVE_SIZE (32 * 1024 *1024) ++#elif defined(CONFIG_IMX93_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_ADDR (0xb0000000) ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (32 * 1024 * 1024) ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_RESERVE_SIZE (32 * 1024 *1024) ++#else ++#define CONFIG_SYS_DDR_SDRAM_BASE 0x80000000UL ++#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (256 * 1024 * 1024) ++#define CONFIG_SYS_DDR_SDRAM_MASTER_SIZE (512 * 1024 * 1024) ++#endif ++ ++#if defined(CONFIG_IMX8M_BAREMETAL) || defined(CONFIG_IMX93_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_SHARE_BASE (CONFIG_SYS_DDR_SDRAM_SLAVE_ADDR \ ++ + CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE*(CONFIG_MAX_CPUS-1)) ++#define CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE (4 * 1024 * 1024) ++#else ++#define CONFIG_SYS_DDR_SDRAM_SHARE_BASE \ ++ (CONFIG_SYS_DDR_SDRAM_BASE + CONFIG_SYS_DDR_SDRAM_MASTER_SIZE \ ++ + CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE * (CONFIG_MAX_CPUS - 1)) ++ ++#define CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE (16 * 1024 * 1024) ++#endif ++ ++#if defined(CONFIG_SOC_IMX6Q_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE \ ++ ((128 * 1024 * 1024) - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE) ++#elif defined(CONFIG_LX2160A_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE \ ++ ((64 * 1024 * 1024) - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE) ++#elif defined(CONFIG_IMX8M_BAREMETAL) || defined(CONFIG_IMX93_BAREMETAL) ++#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE (CONFIG_SYS_DDR_SDRAM_SLAVE_RESERVE_SIZE \ ++ - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE) ++#else ++#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE \ ++ ((256 * 1024 * 1024) - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE) ++#endif ++#define CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_BASE \ ++ (CONFIG_SYS_DDR_SDRAM_SHARE_BASE + CONFIG_SYS_DDR_SDRAM_SHARE_SIZE) ++ ++/* number of descriptor for each ring */ ++#define ICC_RING_ENTRY 128 ++/* size of each block */ ++#define ICC_BLOCK_UNIT_SIZE (4 * 1024) ++/* 2M space for core's ring and desc struct */ ++#define ICC_RING_DESC_SPACE (2 * 1024 * 1024) ++ ++/* share memory size for each core icc */ ++#define ICC_CORE_MEM_SPACE (CONFIG_SYS_DDR_SDRAM_SHARE_SIZE / CONFIG_MAX_CPUS) ++/* share memory base for core x */ ++#define ICC_CORE_MEM_BASE_PHY(x) \ ++ (CONFIG_SYS_DDR_SDRAM_SHARE_BASE + (x) * ICC_CORE_MEM_SPACE) ++/* share memory base for core x */ ++#define ICC_CORE_MEM_BASE(x) \ ++ ((unsigned long)share_base + (x) * ICC_CORE_MEM_SPACE) ++/* the ring struct addr of core x ring y */ ++#define ICC_CORE_RING_BASE(x, y) \ ++ (ICC_CORE_MEM_BASE(x) + (y) * sizeof(struct icc_ring)) ++/* the desc struct addr of core x */ ++#define ICC_CORE_DESC_BASE_PHY(x) \ ++ (ICC_CORE_MEM_BASE_PHY(x) + CONFIG_MAX_CPUS * sizeof(struct icc_ring)) ++/* ++ * The core x block memory base addr for icc data transfer. ++ * The beginning 2M space of core x icc memory is for ++ * core x ring and desc struct. ++ */ ++#define ICC_CORE_BLOCK_BASE_PHY(x) \ ++ (ICC_CORE_MEM_BASE_PHY(x) + ICC_RING_DESC_SPACE) ++#define ICC_CORE_BLOCK_BASE(x) (ICC_CORE_MEM_BASE(x) + ICC_RING_DESC_SPACE) ++#define ICC_CORE_BLOCK_END_PHY(x) \ ++ (ICC_CORE_MEM_BASE_PHY(x) + ICC_CORE_MEM_SPACE) ++#define ICC_CORE_BLOCK_END(x) (ICC_CORE_MEM_BASE(x) + ICC_CORE_MEM_SPACE) ++#define ICC_CORE_BLOCK_COUNT \ ++ ((ICC_CORE_MEM_SPACE - ICC_RING_DESC_SPACE)/ICC_BLOCK_UNIT_SIZE) ++ ++#define ICC_PHY2VIRT(x) \ ++ (((void *)x - ICC_CORE_MEM_BASE_PHY(mycoreid)) \ ++ + ICC_CORE_MEM_BASE(mycoreid)) ++#define ICC_VIRT2PHY(x) \ ++ (((void *)x - ICC_CORE_MEM_BASE(mycoreid)) \ ++ + ICC_CORE_MEM_BASE_PHY(mycoreid)) ++ ++#define IPIDEV_IOCIRQ 1 ++ ++#define ICC_CMD_TX_DATA 0x00 ++#define ICC_CMD_DUMP_TIME 0x01 ++ ++struct icc_desc { ++ unsigned long block_addr; /* block address */ ++ unsigned int byte_count; /* available bytes */ ++ unsigned int option_mode; /* option mode for this icc irq */ ++}; ++ ++struct icc_ring { ++ unsigned int src_coreid; /* which core created the ring */ ++ unsigned int dest_coreid; /* which core the ring sends SGI to */ ++ unsigned int interrupt; /* which interrupt (SGI) be used */ ++ unsigned int desc_num; /* number of descriptor */ ++ struct icc_desc *desc; /* pointer of the first descriptor */ ++ unsigned int desc_head; /* modified by producer */ ++ unsigned int desc_tail; /* modified by consumer */ ++ unsigned long busy_counts; /* statistic: ring full */ ++ unsigned long interrupt_counts; /* statistic: total sent number */ ++ unsigned int irq_status; /* status of the ring, set by producer, reset by consumer */ ++}; ++#endif ++ ++int ipi_baremetal_open(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++ssize_t ipi_baremetal_read(struct file *file, ++ char __user *buff, size_t count, loff_t *offp) ++{ ++ return 0; ++} ++ ++ssize_t ipi_baremetal_write(struct file *file, ++ const char __user *buff, size_t count, loff_t *offp) ++{ ++ char mybuf[10]; ++ int ret; ++ ++ /* read the value from user space */ ++ if (count > 10) ++ return -EINVAL; ++ copy_from_user(mybuf, buff, count); ++ ret = kstrtoint(mybuf, 0, &pid); ++ if (ret) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ipi_baremetal_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++#ifndef CONFIG_LS1021A_BAREMETAL ++static long ipi_baremetal_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long val; ++ unsigned long __user *argp = (unsigned long __user *)arg; ++ int err; ++#if defined(CONFIG_LX2160A_BAREMETAL) ++ unsigned long i, cluster, mask; ++#endif ++ ++ err = copy_from_user(&val, argp, sizeof(val)); ++ if (err) ++ return -EFAULT; ++ ++ val |= ((unsigned long)1 << 40); ++ ++#if defined(CONFIG_LX2160A_BAREMETAL) ++ val = *(unsigned long *)arg; ++ ++ for (i = 0; i < 16; i++) { ++ if ((val >> i) & 0x1) { ++ cluster = i / 2; ++ mask = i % 2; ++ val |= (1 << mask) | (cluster << 16); ++ } ++ } ++#endif ++ switch (cmd) { ++ case IPIDEV_IOCIRQ: ++ write_sysreg_s(val, SYS_ICC_SGI1R_EL1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++#endif ++ ++static int icc_ring_empty(struct icc_ring *ring) ++{ ++ if (ring->desc_tail == ring->desc_head) ++ return 1; ++ return 0; ++} ++ ++/* how many rx blocks are valid waiting to be handled */ ++static int icc_ring_valid(struct icc_ring *ring) ++{ ++ int valid; ++ ++ if (icc_ring_empty(ring)) ++ return 0; ++ ++ if (ring->desc_head > ring->desc_tail) ++ valid = ring->desc_head - ring->desc_tail; ++ else ++ valid = ring->desc_num - ring->desc_tail + ring->desc_head; ++ return valid; ++} ++ ++int ipi_baremetal_handle(u32 irqnr, u32 irqsrc) ++{ ++#ifdef IPI_BAREMETAL_SIGNAL ++ struct siginfo info; ++ struct task_struct *t; ++ int si_data; ++ int ret; ++ ++ if (!pid) ++ return 0; ++ ++ si_data = (irqnr << 16) | irqsrc; ++ /* send the signal */ ++ memset(&info, 0, sizeof(struct siginfo)); ++ info.si_signo = SIG_BM; ++ info.si_code = SI_QUEUE; ++ info.si_int = si_data; ++ ++ rcu_read_lock(); ++ /* find the task_struct associated with this pid */ ++ t = find_task_by_vpid(pid); ++ if (t == NULL) { ++ pr_info("no such pid\n"); ++ rcu_read_unlock(); ++ return -ENODEV; ++ } ++ rcu_read_unlock(); ++ ++ /* send the signal */ ++ ret = send_sig_info(SIG_BM, &info, t); ++ if (ret < 0) { ++ pr_info("error sending signal\n"); ++ return ret; ++ } ++#else ++ struct icc_ring *ring; ++ struct icc_desc *desc; ++ struct icc_desc *desc_phy; ++ unsigned long block_addr; ++ unsigned int byte_count, option_mode; ++ int i, valid; ++ int hw_irq, src_coreid; ++ ++ hw_irq = irqnr; ++ src_coreid = irqsrc; ++ ++ if (src_coreid == mycoreid) { ++ pr_err("Do not support self-icc now!\n"); ++ return -1; ++ } ++ ++ /* get the ring for this core from source core */ ++ ring = (struct icc_ring *)ICC_CORE_RING_BASE(src_coreid, mycoreid); ++ valid = icc_ring_valid(ring); ++ for (i = 0; i < valid; i++) { ++ desc_phy = ring->desc + ring->desc_tail; ++ desc = ICC_PHY2VIRT(desc_phy); ++ option_mode = desc->option_mode; ++ ++ if (option_mode & ICC_CMD_DUMP_TIME) { ++ pr_info("Get the SGI from CoreID: %d\n", src_coreid); ++ } else { ++ block_addr = desc->block_addr; ++ byte_count = desc->byte_count; ++ ++ if ((*(char *)ICC_PHY2VIRT(block_addr)) != 0x5a) ++ pr_info("Get the ICC from core %d; block: 0x%lx, bytes: %d, value: 0x%x\n", ++ src_coreid, block_addr, byte_count, ++ (*(char *)ICC_PHY2VIRT(block_addr))); ++ } ++ ++ /* add desc_tail */ ++ ring->desc_tail = (ring->desc_tail + 1) % ring->desc_num; ++ } ++#endif ++ return 0; ++} ++ ++static const struct vm_operations_struct shd_mmap_mem_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++ ++static int shd_mmap_mem(struct file *file, struct vm_area_struct *vma) ++{ ++ size_t size = vma->vm_end - vma->vm_start; ++ ++#if defined(CONFIG_LS1021A_BAREMETAL) || defined(CONFIG_SOC_IMX6Q_BAREMETAL) ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++#else ++ vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); ++#endif ++ vma->vm_ops = &shd_mmap_mem_ops; ++ ++ /* Remap-pfn-range will mark the range VM_IO */ ++ if (remap_pfn_range(vma, ++ vma->vm_start, ++ vma->vm_pgoff, ++ size, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++const struct file_operations ipi_bm_ops = { ++ .owner = THIS_MODULE, ++ .open = ipi_baremetal_open, ++ .release = ipi_baremetal_release, ++ .read = ipi_baremetal_read, ++ .write = ipi_baremetal_write, ++ .mmap = shd_mmap_mem, ++#ifndef CONFIG_LS1021A_BAREMETAL ++ .unlocked_ioctl = ipi_baremetal_ioctl, ++#endif ++}; ++ ++static struct miscdevice ipi_bm_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = DEVICE_NAME, ++ .fops = &ipi_bm_ops, ++}; ++ ++#ifdef CONFIG_SOC_IMX6Q_BAREMETAL ++void gic_enable_dist(void) ++{ ++ void __iomem *gicd_base, *gicc_base; ++ ++ gicd_base = ioremap((phys_addr_t)GICD_BASE, GICD_SIZE); ++ if (!gicd_base) { ++ pr_err("failed to remap gicd base for ICC\n"); ++ return -ENOMEM; ++ } ++ gicc_base = ioremap((phys_addr_t)GICC_BASE, GICC_SIZE); ++ if (!gicc_base) { ++ pr_err("failed to remap gicc base for ICC\n"); ++ return -ENOMEM; ++ } ++ /* set the SGI interrupts for this core to group 1 */ ++ writel(0xffffffff, gicd_base + GIC_DIST_IGROUP); ++ writel(GICD_ENABLE, gicd_base + GIC_DIST_CTRL); ++ writel(GICC_ENABLE, gicc_base + GIC_CPU_CTRL); ++ iounmap(gicd_base); ++ iounmap(gicc_base); ++} ++#endif ++ ++static int __init ipi_baremetal_init(void) ++{ ++ int ret; ++ ++ pr_info("NXP inter-core communiction IRQ driver\n"); ++#ifndef IPI_BAREMETAL_SIGNAL ++#if defined(CONFIG_LS1021A_BAREMETAL) || defined(CONFIG_SOC_IMX6Q_BAREMETAL) ++ share_base = ioremap((phys_addr_t)CONFIG_SYS_DDR_SDRAM_SHARE_BASE, ++ CONFIG_SYS_DDR_SDRAM_SHARE_SIZE); ++#else ++ share_base = ioremap_cache((phys_addr_t)CONFIG_SYS_DDR_SDRAM_SHARE_BASE, ++ CONFIG_SYS_DDR_SDRAM_SHARE_SIZE); ++#endif ++ if (!share_base) { ++ pr_err("failed to remap share base (%lu/%u) for ICC\n", ++ CONFIG_SYS_DDR_SDRAM_SHARE_BASE, ++ CONFIG_SYS_DDR_SDRAM_SHARE_SIZE); ++ return -ENOMEM; ++ } ++ mycoreid = 0; ++#ifdef CONFIG_SOC_IMX6Q_BAREMETAL ++ gic_enable_dist(); ++#endif ++#endif ++ ret = misc_register(&ipi_bm_misc); ++ if (ret < 0) { ++ pr_info("Register ipi_bm error! ret: %d\n", ret); ++ return ret; ++ } ++ pr_info("ipi_bm device created!\n"); ++ return 0; ++} ++ ++static void __exit ipi_baremetal_exit(void) ++{ ++ pid = 0; ++#ifndef IPI_BAREMETAL_SIGNAL ++ iounmap(share_base); ++#endif ++ misc_deregister(&ipi_bm_misc); ++ pr_info("ipi_bm device deleted!\n"); ++} ++ ++module_init(ipi_baremetal_init); ++module_exit(ipi_baremetal_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("NXP"); ++MODULE_DESCRIPTION("NXP inter-core communiction IPI driver"); +diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c +index eccd6bb52a0b..9d06b08b8baf 100644 +--- a/drivers/irqchip/irq-gic-v3.c ++++ b/drivers/irqchip/irq-gic-v3.c +@@ -27,6 +27,10 @@ + #include + #include + ++#ifdef CONFIG_BAREMETAL ++#include ++#endif ++ + #include + #include + #include +@@ -1392,14 +1396,14 @@ static void __init gic_smp_init(void) + "irqchip/arm/gicv3:starting", + gic_starting_cpu, NULL); + +- /* Register all 8 non-secure SGIs */ +- base_sgi = __irq_domain_alloc_irqs(gic_data.domain, -1, 8, ++ /* Register all 16 non-secure SGIs */ ++ base_sgi = __irq_domain_alloc_irqs(gic_data.domain, -1, 16, + NUMA_NO_NODE, &sgi_fwspec, + false, NULL); + if (WARN_ON(base_sgi <= 0)) + return; + +- set_smp_ipi_range(base_sgi, 8); ++ set_smp_ipi_range(base_sgi, 16); + } + + static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, +diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c +index 4c7bae0ec8f9..40fa366baec3 100644 +--- a/drivers/irqchip/irq-gic.c ++++ b/drivers/irqchip/irq-gic.c +@@ -867,13 +867,13 @@ static __init void gic_smp_init(void) + "irqchip/arm/gic:starting", + gic_starting_cpu, NULL); + +- base_sgi = __irq_domain_alloc_irqs(gic_data[0].domain, -1, 8, ++ base_sgi = __irq_domain_alloc_irqs(gic_data[0].domain, -1, 16, + NUMA_NO_NODE, &sgi_fwspec, + false, NULL); + if (WARN_ON(base_sgi <= 0)) + return; + +- set_smp_ipi_range(base_sgi, 8); ++ set_smp_ipi_range(base_sgi, 16); + } + #else + #define gic_smp_init() do { } while(0) +diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig +index 05d6fae800e3..0557e99d8dee 100644 +--- a/drivers/mailbox/Kconfig ++++ b/drivers/mailbox/Kconfig +@@ -294,4 +294,13 @@ config QCOM_IPCC + acts as an interrupt controller for receiving interrupts from clients. + Say Y here if you want to build this driver. + ++config GENERIC_SOFTWARE_MAILBOX ++ tristate "Generic software Mailbox driver" ++ depends on OF ++ select GENERIC_IRQ_INJECTION ++ select GIC_GENTLE_CONFIG if ARM_GIC_V3 ++ help ++ This driver leverages unused interrupt line and shared memory to ++ implement a mailbox, which is used to send messages between different ++ OSes. + endif +diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile +index fc9376117111..38d6994df5e1 100644 +--- a/drivers/mailbox/Makefile ++++ b/drivers/mailbox/Makefile +@@ -62,3 +62,5 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o + obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o + + obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o ++ ++obj-$(CONFIG_GENERIC_SOFTWARE_MAILBOX) += generic-software-mailbox.o +diff --git a/drivers/mailbox/generic-software-mailbox.c b/drivers/mailbox/generic-software-mailbox.c +new file mode 100644 +index 000000000000..1938f45de6ec +--- /dev/null ++++ b/drivers/mailbox/generic-software-mailbox.c +@@ -0,0 +1,322 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2022-2023 NXP ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Generic software Registers: ++ * ++ * TX_STATUS[n]: TX channel n status ++ * RX_STATUS[n]: RX channel n status ++ * 0: indicates message in T/RX_CH[n] is invalid and channel ready. ++ * 1: indicates message in T/RX_CH[n] is valid and channel busy. ++ * 2: indicates message in T/RX_CH[n] has been received by the peer. ++ * RXDB_STATUS[n]: RX doorbell channel n status ++ * 0: indicates channel ready. ++ * 1: indicates channel busy. ++ * 2: indicates channel doorbell has been received by the peer. ++ * TX_CH[n]: Transmit data register for channel n ++ * RX_CH[n]: Receive data register for channel n ++ * ++ * To send a message: ++ * Update the data register TX_CH[n] with the message, then set the ++ * TX_STATUS[n] to 1, inject a interrupt to remote side; after the ++ * transmission done set the TX_STATUS[n] back to 0. ++ * ++ * When received a message: ++ * Get the received data from RX_CH[n] and then set the RX_STATUS[n] to ++ * 2 and inject a interrupt to notify the remote side transmission done. ++ */ ++ ++#define MBOX_TX_CHAN (4) ++#define MBOX_RX_CHAN (4) ++#define MBOX_RXDB_CHAN (4) ++#define RX_CHAN_SHFT (MBOX_TX_CHAN) ++#define RXDB_CHAN_SHFT (MBOX_TX_CHAN + MBOX_RX_CHAN) ++#define MBOX_CHAN_MAX (MBOX_TX_CHAN + MBOX_RX_CHAN + MBOX_RXDB_CHAN) ++ ++struct sw_mbox_reg { ++ uint32_t tx_status[MBOX_TX_CHAN]; ++ uint32_t rx_status[MBOX_RX_CHAN]; ++ uint32_t rxdb_status[MBOX_RXDB_CHAN]; ++ uint32_t tx_ch[MBOX_TX_CHAN]; ++ uint32_t rx_ch[MBOX_RX_CHAN]; ++ uint32_t rxdb_ch[MBOX_RX_CHAN]; ++ uint32_t ch_ack_flags; /*from bit0 each bit for each channel(tx_ch, rx_ch, rxdb_ch), 1: ack, 0:noack */ ++}; ++ ++enum sw_mbox_channel_status { ++ S_READY, ++ S_BUSY, ++ S_DONE, ++}; ++ ++enum sw_mbox_type { ++ SW_TYPE_TX, /* Tx */ ++ SW_TYPE_RX, /* Rx */ ++ SW_TYPE_RXDB, /* Rx doorbell */ ++}; ++ ++struct sw_mbox_con_priv { ++ uint32_t idx; ++ enum sw_mbox_type type; ++ struct sw_mbox *priv; ++}; ++ ++struct sw_mbox { ++ struct device *dev; ++ struct sw_mbox_reg __iomem *base; ++ struct sw_mbox_con_priv cp[MBOX_CHAN_MAX]; ++ struct mbox_chan chan[MBOX_CHAN_MAX]; ++ struct mbox_controller controller; ++ int irq; ++ int remote_irq; ++}; ++ ++static int sw_mbox_send_data(struct mbox_chan *chan, void *msg) ++{ ++ struct sw_mbox_con_priv *cp = chan->con_priv; ++ struct sw_mbox *mbox = cp->priv; ++ uint32_t idx = cp->idx; ++ uint32_t *data = msg; ++ int ret; ++ ++ if (cp->type != SW_TYPE_TX) { ++ dev_err(mbox->dev, "Channel type error\n"); ++ return -EINVAL; ++ } ++ ++ writel(*data, &mbox->base->tx_ch[idx]); ++ writel(S_BUSY, &mbox->base->tx_status[idx]); ++ ret = irq_set_irqchip_state(mbox->remote_irq, IRQCHIP_STATE_PENDING, ++ true); ++ if (ret) { ++ dev_err(mbox->dev, "Fail to inject IRQ\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t sw_mbox_interrupt(int irq, void *dev_id) ++{ ++ struct sw_mbox *mbox = dev_id; ++ irqreturn_t ret = IRQ_NONE; ++ uint32_t rxdb_status; ++ uint32_t rx_status; ++ uint32_t tx_status; ++ uint32_t rx_ch; ++ int i; ++ ++ for (i = 0; i < MBOX_TX_CHAN; i++) { ++ tx_status = readl(&mbox->base->tx_status[i]); ++ if (tx_status == S_DONE) { ++ writel(S_READY, &mbox->base->tx_status[i]); ++ mbox_chan_txdone(&mbox->chan[i], 0); ++ ret = IRQ_HANDLED; ++ } ++ } ++ ++ for (i = 0; i < MBOX_RX_CHAN; i++) { ++ rx_status = readl(&mbox->base->rx_status[i]); ++ if (rx_status == S_BUSY) { ++ rx_ch = readl(&mbox->base->rx_ch[i]); ++ mbox_chan_received_data(&mbox->chan[i + RX_CHAN_SHFT], ++ (void *)&rx_ch); ++ if (mbox->base->ch_ack_flags & (1 << (i + RX_CHAN_SHFT))) { ++ /* Sender need ACK */ ++ writel(S_DONE, &mbox->base->rx_status[i]); ++ irq_set_irqchip_state(mbox->remote_irq, ++ IRQCHIP_STATE_PENDING, true); ++ } else { ++ /* set status to be ready if sender doesn't need ACK */ ++ writel(S_READY, &mbox->base->rx_status[i]); ++ } ++ ret = IRQ_HANDLED; ++ } ++ } ++ ++ for (i = 0; i < MBOX_RXDB_CHAN; i++) { ++ rxdb_status = readl(&mbox->base->rxdb_status[i]); ++ if (rxdb_status == S_BUSY) { ++ mbox_chan_received_data(&mbox->chan[i + RXDB_CHAN_SHFT], ++ NULL); ++ if (mbox->base->ch_ack_flags & (1 << (i + RXDB_CHAN_SHFT))) { ++ /* Sender need ACK */ ++ writel(S_DONE, &mbox->base->rxdb_status[i]); ++ irq_set_irqchip_state(mbox->remote_irq, ++ IRQCHIP_STATE_PENDING, true); ++ } else { ++ /* set status to be ready if sender doesn't need ACK */ ++ writel(S_READY, &mbox->base->rxdb_status[i]); ++ } ++ ret = IRQ_HANDLED; ++ } ++ } ++ ++ return ret; ++} ++ ++static int sw_mbox_startup(struct mbox_chan *chan) ++{ ++ return 0; ++} ++ ++static void sw_mbox_shutdown(struct mbox_chan *chan) ++{ ++} ++ ++static const struct mbox_chan_ops sw_mbox_ops = { ++ .send_data = sw_mbox_send_data, ++ .startup = sw_mbox_startup, ++ .shutdown = sw_mbox_shutdown, ++}; ++ ++ ++static struct mbox_chan *sw_mbox_xlate(struct mbox_controller *mbox, ++ const struct of_phandle_args *sp) ++{ ++ struct mbox_chan *chan; ++ struct sw_mbox_con_priv *cp; ++ struct sw_mbox *sw_mb; ++ uint32_t type, idx, chan_idx, ack; ++ ++ if (sp->args_count != 3) { ++ dev_err(mbox->dev, "Invalid argument count %d\n", ++ sp->args_count); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ type = sp->args[0]; ++ idx = sp->args[1]; ++ ack = sp->args[2]; ++ ++ switch (type) { ++ case SW_TYPE_TX: ++ chan_idx = idx; ++ break; ++ case SW_TYPE_RX: ++ chan_idx = RX_CHAN_SHFT + idx; ++ break; ++ case SW_TYPE_RXDB: ++ chan_idx = RXDB_CHAN_SHFT + idx; ++ break; ++ default: ++ dev_err(mbox->dev, "Invalid chan type: %d\n", type); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (chan_idx >= MBOX_CHAN_MAX) { ++ dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", ++ chan_idx, type, idx); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ chan = &mbox->chans[chan_idx]; ++ cp = chan->con_priv; ++ sw_mb = cp->priv; ++ if (ack) ++ sw_mb->base->ch_ack_flags |= 1 << chan_idx; ++ else ++ sw_mb->base->ch_ack_flags &= ~(1 << chan_idx); ++ ++ return chan; ++} ++ ++static const struct of_device_id sw_mbox_of_match[] = { ++ { .compatible = "fsl,generic-software-mbox", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sw_mbox_of_match); ++ ++static int sw_mailbox_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct sw_mbox *mbox; ++ int err, i; ++ ++ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); ++ if (!mbox) ++ return -ENOMEM; ++ mbox->dev = dev; ++ ++ mbox->irq = platform_get_irq_byname(pdev, "irq"); ++ if (mbox->irq <= 0) { ++ dev_err(dev, "Failed to get irq\n"); ++ return mbox->irq; ++ } ++ mbox->remote_irq = platform_get_irq_byname(pdev, "remote_irq"); ++ if (mbox->remote_irq <= 0) { ++ dev_err(dev, "Failed to get remote irq\n"); ++ return mbox->remote_irq; ++ } ++ ++ err = devm_request_irq(dev, mbox->irq, sw_mbox_interrupt, IRQF_SHARED, ++ pdev->name, mbox); ++ if (err) ++ return err; ++ ++ mbox->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(mbox->base)) ++ return PTR_ERR(mbox->base); ++ ++ memset_io(mbox->base->tx_status, 0, 4 * MBOX_TX_CHAN); ++ memset_io(mbox->base->rx_status, 0, 4 * MBOX_RX_CHAN); ++ memset_io(mbox->base->rxdb_status, 0, 4 * MBOX_RXDB_CHAN); ++ ++ mbox->controller.dev = dev; ++ mbox->controller.chans = mbox->chan; ++ mbox->controller.num_chans = MBOX_CHAN_MAX; ++ mbox->controller.ops = &sw_mbox_ops; ++ mbox->controller.of_xlate = sw_mbox_xlate; ++ mbox->controller.txdone_irq = true; ++ ++ for (i = 0; i < MBOX_CHAN_MAX; i++) { ++ mbox->chan[i].con_priv = &mbox->cp[i]; ++ mbox->cp[i].priv = mbox; ++ mbox->cp[i].idx = i; ++ } ++ ++ err = devm_mbox_controller_register(dev, &mbox->controller); ++ if (err) { ++ dev_err(dev, "Failed to register mailbox %d\n", err); ++ return err; ++ } ++ ++ platform_set_drvdata(pdev, mbox); ++ ++ return 0; ++} ++ ++static struct platform_driver sw_mbox_driver = { ++ .driver = { ++ .name = "generic-software-mailbox", ++ .of_match_table = sw_mbox_of_match, ++ }, ++ .probe = sw_mailbox_probe, ++}; ++ ++static int __init sw_mbox_init(void) ++{ ++ return platform_driver_register(&sw_mbox_driver); ++} ++ ++static void __exit sw_mbox_exit(void) ++{ ++ platform_driver_unregister(&sw_mbox_driver); ++} ++ ++module_init(sw_mbox_init); ++module_exit(sw_mbox_exit); ++ ++MODULE_DESCRIPTION("Generic Software mailbox driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index 4229b9b5da98..8e2eba4a0a96 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -158,7 +158,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) + void mbox_chan_received_data(struct mbox_chan *chan, void *mssg) + { + /* No buffering the received data */ +- if (chan->cl->rx_callback) ++ if (chan->cl && chan->cl->rx_callback) + chan->cl->rx_callback(chan->cl, mssg); + } + EXPORT_SYMBOL_GPL(mbox_chan_received_data); +diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c +index 4ba7b6df7986..145fc0f1b4f9 100644 +--- a/drivers/mxc/ipu3/ipu_common.c ++++ b/drivers/mxc/ipu3/ipu_common.c +@@ -2923,8 +2923,9 @@ static irqreturn_t ipu_sync_irq_handler(int irq, void *desc) + uint32_t line, bit, int_stat, int_ctrl; + irqreturn_t result = IRQ_NONE; + const int int_reg[] = { 1, 2, 3, 4, 11, 12, 13, 14, 15, 0 }; ++ unsigned long flags; + +- spin_lock(&ipu->int_reg_spin_lock); ++ spin_lock_irqsave(&ipu->int_reg_spin_lock, flags); + + for (i = 0; int_reg[i] != 0; i++) { + int_stat = ipu_cm_read(ipu, +@@ -2949,7 +2950,7 @@ static irqreturn_t ipu_sync_irq_handler(int irq, void *desc) + } + } + +- spin_unlock(&ipu->int_reg_spin_lock); ++ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, flags); + + return result; + } +@@ -2960,8 +2961,9 @@ static irqreturn_t ipu_err_irq_handler(int irq, void *desc) + int i; + uint32_t int_stat; + const int err_reg[] = { 5, 6, 9, 10, 0 }; ++ unsigned long flags; + +- spin_lock(&ipu->int_reg_spin_lock); ++ spin_lock_irqsave(&ipu->int_reg_spin_lock, flags); + + for (i = 0; err_reg[i] != 0; i++) { + int_stat = ipu_cm_read(ipu, +@@ -2980,7 +2982,7 @@ static irqreturn_t ipu_err_irq_handler(int irq, void *desc) + } + } + +- spin_unlock(&ipu->int_reg_spin_lock); ++ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, flags); + + return IRQ_HANDLED; + } +diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c +index f4417c7f5cda..2dcd6511bcb4 100644 +--- a/drivers/mxc/ipu3/ipu_device.c ++++ b/drivers/mxc/ipu3/ipu_device.c +@@ -3249,7 +3249,7 @@ static int ipu_task_thread(void *argv) + uint32_t size; + unsigned long flags; + unsigned int cpu; +- struct cpumask cpu_mask; ++ struct cpumask cpu_mask = CPU_MASK_NONE; + struct ipu_thread_data *data = (struct ipu_thread_data *)argv; + + thread_id++; +diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig +index 07507b4820d7..b5c3cd5d0e65 100644 +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -62,6 +62,8 @@ source "drivers/net/dsa/xrs700x/Kconfig" + + source "drivers/net/dsa/realtek/Kconfig" + ++source "drivers/net/dsa/netc/Kconfig" ++ + config NET_DSA_RZN1_A5PSW + tristate "Renesas RZ/N1 A5PSW Ethernet switch support" + depends on OF && ARCH_RZN1 +diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile +index 16eb879e0cb4..47bec77c5839 100644 +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -24,3 +24,4 @@ obj-y += qca/ + obj-y += realtek/ + obj-y += sja1105/ + obj-y += xrs700x/ ++obj-y += netc/ +\ No newline at end of file +diff --git a/drivers/net/dsa/netc/Kconfig b/drivers/net/dsa/netc/Kconfig +new file mode 100644 +index 000000000000..40dbdd5e8a37 +--- /dev/null ++++ b/drivers/net/dsa/netc/Kconfig +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++config NET_DSA_NETC ++ tristate "NXP NETC Ethernet switch family support" ++ depends on NET_DSA && SPI ++ select NET_DSA_TAG_NETC ++ help ++ This is the driver for the NXP ENTC Ethernet switch family. ++ These are managed over an SPI interface. Probing is handled ++ based on OF bindings and so is the linkage to PHYLINK. +diff --git a/drivers/net/dsa/netc/Makefile b/drivers/net/dsa/netc/Makefile +new file mode 100644 +index 000000000000..72d6d8e2a52f +--- /dev/null ++++ b/drivers/net/dsa/netc/Makefile +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ ++obj-$(CONFIG_NET_DSA_NETC) += netcdsa.o ++ ++netcdsa-objs := \ ++ netc_spi.o \ ++ netc_config.o \ ++ netc_ethtool.o \ ++ netc_devlink.o \ ++ netc_ptp.o \ ++ netc_main.o ++ +diff --git a/drivers/net/dsa/netc/netc.h b/drivers/net/dsa/netc/netc.h +new file mode 100644 +index 000000000000..cf9e27aff73f +--- /dev/null ++++ b/drivers/net/dsa/netc/netc.h +@@ -0,0 +1,102 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#ifndef _NETC_H ++#define _NETC_H ++ ++#include ++#include ++#include ++#include ++#include ++#include "netc_config.h" ++ ++struct netc_private; ++ ++enum { ++ NETC_SPEED_AUTO, ++ NETC_SPEED_10MBPS, ++ NETC_SPEED_100MBPS, ++ NETC_SPEED_1000MBPS, ++ NETC_SPEED_2500MBPS, ++ NETC_SPEED_MAX, ++}; ++ ++enum netc_internal_phy_t { ++ NETC_NO_PHY = 0, ++}; ++ ++struct netc_info { ++ const char *name; ++ int device_id; ++ int num_ports; ++ enum dsa_tag_protocol tag_proto; ++ int ptp_ts_bits; ++ bool multiple_cascade_ports; ++ bool can_limit_mcast_flood; ++}; ++ ++struct netc_private { ++ const struct netc_info *info; ++ struct netc_config config; ++ int cpu_port; ++ phy_interface_t phy_mode[NETC_MAX_NUM_PORTS]; ++ bool fixed_link[NETC_MAX_NUM_PORTS]; ++ unsigned long ucast_egress_floods; ++ unsigned long bcast_egress_floods; ++ unsigned long hwts_tx_en; ++ ++ size_t max_xfer_len; ++ struct spi_device *spidev; ++ struct dsa_switch *ds; ++ u16 bridge_pvid[NETC_MAX_NUM_PORTS]; ++ u16 tag_8021q_pvid[NETC_MAX_NUM_PORTS]; ++ /* Serializes transmission of management frames so that ++ * the switch doesn't confuse them with one another. ++ */ ++ struct mutex mgmt_lock; ++ ++ struct devlink_region **regions; ++}; ++ ++int netc_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, ++ struct netlink_ext_ack *extack); ++void netc_frame_memory_partitioning(struct netc_private *priv); ++ ++/* From netc_devlink.c */ ++int netc_devlink_setup(struct dsa_switch *ds); ++void netc_devlink_teardown(struct dsa_switch *ds); ++int netc_devlink_info_get(struct dsa_switch *ds, ++ struct devlink_info_req *req, ++ struct netlink_ext_ack *extack); ++ ++/* From netc_spi.c */ ++int netc_xfer_cmd(const struct netc_private *priv, ++ enum netc_spi_rw_mode rw, enum netc_cmd cmd, ++ void *param, size_t param_len, ++ void *resp, size_t resp_len); ++int netc_xfer_set_cmd(const struct netc_private *priv, ++ enum netc_cmd cmd, ++ void *param, size_t param_len); ++int netc_xfer_get_cmd(const struct netc_private *priv, ++ enum netc_cmd cmd, uint32_t id, ++ void *resp, size_t resp_len); ++ ++int netc_xfer_write_reg(const struct netc_private *priv, ++ uint32_t reg, uint32_t value); ++int netc_xfer_read_reg(const struct netc_private *priv, ++ uint32_t reg, uint32_t *value); ++ ++/* From netc_ethtool.c */ ++void netc_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); ++void netc_get_strings(struct dsa_switch *ds, int port, ++ uint32_t stringset, uint8_t *data); ++int netc_get_sset_count(struct dsa_switch *ds, int port, int sset); ++ ++/* From netc_ptp.c */ ++void netc_ptp_txtstamp_skb(struct dsa_switch *ds, int port, ++ struct sk_buff *skb); ++ ++#endif /* _NETC_H */ +diff --git a/drivers/net/dsa/netc/netc_config.c b/drivers/net/dsa/netc/netc_config.c +new file mode 100644 +index 000000000000..e4590c7684c9 +--- /dev/null ++++ b/drivers/net/dsa/netc/netc_config.c +@@ -0,0 +1,322 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include ++#include ++#include ++#include ++#include "netc.h" ++ ++int netc_get_devinfo(struct netc_private *priv, struct netc_config *config) ++{ ++ struct netc_cmd_sysinfo info; ++ int rc; ++ ++ rc = netc_xfer_get_cmd(priv, NETC_CMD_SYS_INFO_GET, 0, ++ &info, sizeof(info)); ++ if (rc < 0) ++ return rc; ++ ++ config->device_id = info.device_id; ++ config->vendor_id = info.vendor_id; ++ config->version_major = info.version_major; ++ config->version_minor = info.version_minor; ++ config->version_revision = info.version_revision; ++ config->cpu_port_mode = info.cpu_port; ++ ++ return 0; ++} ++ ++int netc_port_mtu_set(struct netc_private *priv, int port, int mtu) ++{ ++ struct netc_cmd_port_mtu mtu_cmd = {0}; ++ ++ mtu_cmd.port = (uint8_t)port; ++ mtu_cmd.mtu = (uint16_t)mtu; ++ ++ return netc_xfer_set_cmd(priv, NETC_CMD_PORT_MTU_SET, ++ &mtu_cmd, sizeof(mtu_cmd)); ++} ++ ++int netc_port_mtu_get(struct netc_private *priv, int port, int *mtu) ++{ ++ int rc; ++ struct netc_cmd_port_mtu mtu_resp = {0}; ++ ++ rc = netc_xfer_get_cmd(priv, NETC_CMD_PORT_MTU_GET, port, ++ &mtu_resp, sizeof(mtu_resp)); ++ ++ if (rc != 0) ++ return rc; ++ ++ *mtu = mtu_resp.mtu; ++ ++ return 0; ++} ++ ++/* Set link speed in the MAC configuration for a specific port. */ ++int netc_port_phylink_mode_set(struct netc_private *priv, ++ struct netc_mac_config *mac) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_port_phylink_mode phylink_mode = {0}; ++ int rc; ++ ++ phylink_mode.port = mac->port; ++ phylink_mode.duplex = mac->duplex; ++ phylink_mode.speed = mac->speed; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_PHYLINK_MODE_SET, ++ &phylink_mode, sizeof(phylink_mode)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to write phylink_mode: %d\n", rc); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++/* Get link speed in the MAC configuration for a specific port. */ ++int netc_port_phylink_status_get(struct netc_private *priv, ++ struct netc_mac_config *mac) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_port_phylink_status phylink_status = {0}; ++ int rc; ++ ++ rc = netc_xfer_get_cmd(priv, NETC_CMD_PORT_PHYLINK_STATUS_GET, ++ mac->port, ++ &phylink_status, sizeof(phylink_status)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to get phylink status: %d\n", rc); ++ return rc; ++ } ++ ++ mac->link = phylink_status.link; ++ mac->speed = phylink_status.speed; ++ mac->duplex = phylink_status.duplex; ++ ++ return 0; ++} ++ ++int netc_port_pvid_set(struct netc_private *priv, int port, uint16_t pvid) ++{ ++ int rc = 0; ++ struct netc_cmd_port_pvid cmd_pvid = {0}; ++ ++ cmd_pvid.port = (uint8_t)port; ++ cmd_pvid.pvid = pvid; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_PVID_SET, ++ &cmd_pvid, sizeof(cmd_pvid)); ++ ++ return rc; ++} ++ ++int netc_port_link_set(struct netc_private *priv, int port, bool up) ++{ ++ int rc = 0; ++ struct netc_cmd_port_link egress = {0}; ++ ++ egress.port = (uint8_t)port; ++ egress.link = up; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_LINK_SET, ++ &egress, sizeof(egress)); ++ ++ return rc; ++} ++ ++int netc_port_dropuntag_set(struct netc_private *priv, int port, bool drop) ++{ ++ int rc = 0; ++ struct netc_cmd_port_dropuntag dropuntag = {0}; ++ ++ dropuntag.port = (uint8_t)port; ++ dropuntag.drop = (uint16_t)drop; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_DROPUNTAG_SET, ++ &dropuntag, sizeof(dropuntag)); ++ ++ return rc; ++} ++ ++int netc_port_dsa_add(struct netc_private *priv, int cpu_port, ++ int slave_port, const unsigned char *mac_addr) ++{ ++ int rc = 0; ++ struct netc_cmd_port_dsa_add dsa_add = {0}; ++ ++ dsa_add.cpu_port = (uint8_t)cpu_port; ++ dsa_add.slave_port = (uint8_t)slave_port; ++ ether_addr_copy(dsa_add.mac_addr, mac_addr); ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_DSA_ADD, ++ &dsa_add, sizeof(dsa_add)); ++ ++ return rc; ++} ++ ++int netc_port_dsa_del(struct netc_private *priv, int slave_port) ++{ ++ int rc = 0; ++ struct netc_cmd_port_dsa_del dsa_del = {0}; ++ ++ dsa_del.slave_port = (uint8_t)slave_port; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_DSA_DEL, ++ &dsa_del, sizeof(dsa_del)); ++ ++ return rc; ++} ++ ++int netc_vlan_entry_add(struct netc_private *priv, ++ uint16_t vid, int port, bool untagged) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_vlan cmd_vlan = {0}; ++ int rc; ++ ++ cmd_vlan.vid = vid; ++ cmd_vlan.port = (uint8_t)port; ++ cmd_vlan.untagged = untagged; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_VLAN_ADD, ++ &cmd_vlan, sizeof(cmd_vlan)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to add vlan entry: %d\n", rc); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++int netc_vlan_entry_del(struct netc_private *priv, uint16_t vid, int port) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_vlan cmd_vlan = {0}; ++ int rc; ++ ++ cmd_vlan.vid = vid; ++ cmd_vlan.port = (uint8_t)port; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_VLAN_DEL, ++ &cmd_vlan, sizeof(cmd_vlan)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to add vlan entry: %d\n", rc); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++int netc_vlan_entry_read(struct netc_private *priv, ++ struct netc_vlan_entry *vlan, ++ uint32_t entry_id, uint32_t *next_id) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_vlan_dump vlan_dump = {0}; ++ int rc; ++ ++ rc = netc_xfer_get_cmd(priv, NETC_CMD_VLAN_DUMP, entry_id, ++ &vlan_dump, sizeof(vlan_dump)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to read vlan entry 0x%08x: %d\n", ++ entry_id, rc); ++ return rc; ++ } ++ ++ vlan->entry_id = entry_id; ++ vlan->vid = vlan_dump.vid; ++ vlan->port_map = vlan_dump.port_map; ++ *next_id = vlan_dump.resume_entry_id; ++ ++ return 0; ++} ++ ++int netc_fdb_entry_add(struct netc_private *priv, ++ const unsigned char *mac_addr, ++ uint16_t vid, int port) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_fdb fdb_add = {0}; ++ int rc; ++ ++ ether_addr_copy(fdb_add.mac_addr, mac_addr); ++ fdb_add.vid = vid; ++ fdb_add.port = (uint8_t)port; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_FDB_ADD, ++ &fdb_add, sizeof(fdb_add)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to add fdb: %d\n", rc); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++int netc_fdb_entry_del(struct netc_private *priv, ++ const unsigned char *mac_addr, ++ uint16_t vid) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_fdb_del fdb_del = {0}; ++ int rc; ++ ++ ether_addr_copy(fdb_del.mac_addr, mac_addr); ++ fdb_del.vid = vid; ++ ++ rc = netc_xfer_set_cmd(priv, NETC_CMD_FDB_DEL, ++ &fdb_del, sizeof(fdb_del)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to delete fdb: %d\n", rc); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++int netc_fdb_entry_get(struct netc_private *priv, struct netc_fdb_entry *fdb, ++ uint32_t entry_id, uint32_t *next_id) ++{ ++ struct device *dev = priv->ds->dev; ++ struct netc_cmd_fdb_dump fdb_dump = {0}; ++ int rc; ++ ++ rc = netc_xfer_get_cmd(priv, NETC_CMD_FDB_DUMP, entry_id, ++ &fdb_dump, sizeof(fdb_dump)); ++ if (rc < 0) { ++ dev_err(dev, "Failed to get fdb entry: %d\n", rc); ++ return rc; ++ } ++ ++ *next_id = fdb_dump.resume_entry_id; ++ ++ ether_addr_copy(fdb->mac_addr, fdb_dump.mac_addr); ++ fdb->vid = fdb_dump.vid; ++ fdb->port_map = fdb_dump.port_map; ++ fdb->dynamic = fdb_dump.dynamic; ++ ++ return 0; ++} ++ ++int netc_config_setup(struct netc_config *config) ++{ ++ if (config->vlan_max_count) { ++ config->vlan = kcalloc(config->vlan_max_count, ++ sizeof(*config->vlan), ++ GFP_KERNEL); ++ if (!config->vlan) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++void netc_config_free(struct netc_config *config) ++{ ++ kfree(config->vlan); ++} +diff --git a/drivers/net/dsa/netc/netc_config.h b/drivers/net/dsa/netc/netc_config.h +new file mode 100644 +index 000000000000..1b181e7ef56b +--- /dev/null ++++ b/drivers/net/dsa/netc/netc_config.h +@@ -0,0 +1,288 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#ifndef _NETC_CONFIG_H ++#define _NETC_CONFIG_H ++ ++#include ++#include ++ ++#define NETC_RT1180_DEVICE_ID 0xe001 ++#define NETC_NUM_PORTS 5 ++#define NETC_MAX_NUM_PORTS NETC_NUM_PORTS ++#define NETC_NUM_TC 8 ++ ++#define NETC_ETHTOOL_STATS_NUM_MAX 120 ++ ++#define NETC_SPI_WORD_BITS 8 ++#define NETC_SPI_MSG_WORD_BYTES 4 ++#define NETC_SPI_MSG_HEADER_SIZE 16 ++#define NETC_SPI_MSG_PARAM_SIZE 12 ++#define NETC_SPI_MSG_MAXLEN 4096 ++#define NETC_SPI_MSG_RESPONSE_TIME 1000 /* us */ ++ ++#define NETC_CMD_DIR_SHIFT 31 ++#define NETC_CMD_LEN_SHIFT 16 ++ ++enum netc_spi_rw_mode { ++ SPI_READ = 0, ++ SPI_WRITE = 1, ++}; ++ ++struct netc_cmd_hdr { ++ uint32_t cmd; ++ uint8_t param[NETC_SPI_MSG_PARAM_SIZE]; ++}; ++ ++/* Command */ ++enum netc_cmd { ++ /* port related command */ ++ NETC_CMD_SYS_INFO_GET = 0x1, ++ NETC_CMD_PORT_DSA_ADD, ++ NETC_CMD_PORT_DSA_DEL, ++ NETC_CMD_PORT_MTU_SET, ++ NETC_CMD_PORT_MTU_GET, ++ NETC_CMD_PORT_PHYLINK_MODE_SET, ++ NETC_CMD_PORT_PHYLINK_STATUS_GET, ++ NETC_CMD_PORT_ETHTOOL_STATS_GET, ++ NETC_CMD_PORT_PVID_SET, ++ NETC_CMD_PORT_LINK_SET, ++ NETC_CMD_PORT_DROPUNTAG_SET, ++ ++ NETC_CMD_FDB_ADD = 0x1000, ++ NETC_CMD_FDB_DEL, ++ NETC_CMD_FDB_DUMP, ++ NETC_CMD_VLAN_ADD, ++ NETC_CMD_VLAN_DEL, ++ NETC_CMD_VLAN_DUMP, ++ NETC_CMD_FORWARD_MASK_SET, ++ ++ NETC_CMD_PTP_SYNC_SET = 0x2000, ++ ++ NETC_CMD_QBV_SET = 0x3000, ++ NETC_CMD_QBV_GET, ++ NETC_CMD_QBU_SET, ++ NETC_CMD_QBU_GET, ++ NETC_CMD_QCI_SET, ++ NETC_CMD_QCI_GET, ++ NETC_CMD_8021CB_SET, ++ NETC_CMD_8021CB_GET, ++ ++ NETC_CMD_REG_SET = 0x4000, ++ NETC_CMD_REG_GET, ++ NETC_CMD_MAX_NUM, ++}; ++ ++struct netc_cmd_sysinfo { ++ uint16_t device_id; ++ uint16_t vendor_id; ++ uint8_t version_major; ++ uint8_t version_minor; ++ uint8_t version_revision; ++ uint8_t cpu_port; ++}; ++ ++/* command data for NETC_CMD_PORT_DSA_ADD */ ++struct netc_cmd_port_dsa_add { ++ uint8_t cpu_port; /* switch port 0, 1, 2 or 3 */ ++ uint8_t slave_port; /* switch port 0, 1, 2 or 3 */ ++ uint8_t mac_addr[ETH_ALEN]; /* MAC address of master interface */ ++}; ++ ++/* command data for NETC_CMD_PORT_DSA_DEL */ ++struct netc_cmd_port_dsa_del { ++ uint8_t slave_port; /* switch port 0, 1, 2 or 3 */ ++ uint8_t reserved[3]; ++}; ++ ++/* command data for NETC_CMD_PORT_MTU_SET */ ++struct netc_cmd_port_mtu { ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ uint8_t reserved; ++ uint16_t mtu; ++}; ++ ++/* command data for NETC_CMD_PORT_PHYLINK_MODE_SET */ ++struct netc_cmd_port_phylink_mode { ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ bool duplex; /* 0: half duplex; 1: full duplex */ ++ uint16_t speed; /* 10: 10Mbps ; 100: 100Mbps ; 1000: 1000Mbps */ ++}; ++ ++/* command data for NETC_CMD_PORT_PVID_SET */ ++struct netc_cmd_port_pvid { ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ uint8_t reserved; ++ uint16_t pvid; ++}; ++ ++/* command data for netc_cmd_port_link */ ++struct netc_cmd_port_link { ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ bool link; /* 0: down; 1: up */ ++ uint8_t reserved[2]; ++}; ++ ++/* command data for netc_cmd_port_dropuntag */ ++struct netc_cmd_port_dropuntag { ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ uint8_t reserved; ++ uint16_t drop; ++}; ++ ++/* command data for NETC_CMD_FDB_ADD */ ++struct netc_cmd_fdb { ++ uint8_t mac_addr[ETH_ALEN]; ++ uint16_t vid; ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ uint8_t reserved[3]; ++}; ++ ++/* command data for NETC_CMD_FDB_DEL */ ++struct netc_cmd_fdb_del { ++ uint8_t mac_addr[ETH_ALEN]; ++ uint16_t vid; ++}; ++ ++/* command data for NETC_CMD_VLAN_ADD */ ++struct netc_cmd_vlan { ++ uint16_t vid; ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ bool untagged; ++}; ++ ++/* data returned for NETC_CMD_PORT_PHYLINK_STATUS_GET */ ++struct netc_cmd_port_phylink_status { ++ uint8_t port; /* switch port 0, 1, 2 or 3 */ ++ bool link; ++ uint16_t speed; ++ bool duplex; /* 0: down; 1: up */ ++ uint8_t reserved[3]; ++}; ++ ++/* command param */ ++struct netc_cmd_read_param { ++ uint32_t id; ++}; ++ ++/* command data for NETC_CMD_REG_SET */ ++struct netc_cmd_reg_cmd { ++ uint32_t reg; ++ uint32_t value; ++}; ++ ++/* data returned for NETC_CMD_FDB_DUMP */ ++struct netc_cmd_fdb_dump { ++ uint8_t mac_addr[ETH_ALEN]; ++ uint16_t vid; ++ /* bit 0: switch port 0 etc. */ ++ uint32_t port_map; ++ bool dynamic; ++ uint8_t reserved[3]; ++ /* non-zero means there are remaining entries, 0 means no more entries */ ++ uint32_t resume_entry_id; ++}; ++ ++/* data returned for NETC_CMD_VLAN_DUMP */ ++struct netc_cmd_vlan_dump { ++ uint16_t vid; ++ bool untagged; ++ uint8_t reserved; ++ /* bit 0: switch port 0 etc. */ ++ uint32_t port_map; ++ /* non-zero means there are remaining entries, 0 means no more entries */ ++ uint32_t resume_entry_id; ++}; ++ ++struct netc_cmd_port_ethtool_stats { ++ uint64_t values[NETC_ETHTOOL_STATS_NUM_MAX]; ++}; ++ ++struct netc_mac_config { ++ uint8_t port; ++ uint16_t speed; ++ uint16_t vlanid; ++ bool link; ++ bool egress; ++ bool ingress; ++ bool duplex; ++ bool drptag; ++ bool drpuntag; ++ bool retag; ++}; ++ ++struct netc_fdb_entry { ++ uint8_t mac_addr[ETH_ALEN]; ++ uint16_t vid; ++ uint32_t port_map; /* bit 0: switch port 0 etc. */ ++ bool dynamic; ++}; ++ ++struct netc_vlan_entry { ++ uint16_t vid; ++ uint16_t port; ++ uint32_t port_map; ++ uint32_t tag_ports; ++ uint32_t entry_id; ++}; ++ ++struct netc_config { ++ uint16_t device_id; ++ uint16_t vendor_id; ++ uint8_t version_major; ++ uint8_t version_minor; ++ uint8_t version_revision; ++ uint8_t cpu_port_mode; ++ uint16_t tpid; ++ uint16_t tpid2; ++ struct netc_mac_config mac[NETC_MAX_NUM_PORTS]; ++ int cpu_port; ++ int vlan_count; ++ int vlan_max_count; ++ struct netc_vlan_entry *vlan; ++}; ++ ++struct netc_private; ++ ++int netc_get_devinfo(struct netc_private *priv, struct netc_config *config); ++ ++int netc_port_phylink_mode_set(struct netc_private *priv, ++ struct netc_mac_config *mac); ++int netc_port_phylink_stats_get(struct netc_private *priv, ++ struct netc_mac_config *mac); ++int netc_port_pvid_set(struct netc_private *priv, int port, uint16_t pvid); ++int netc_port_link_set(struct netc_private *priv, int port, bool up); ++int netc_port_dropuntag_set(struct netc_private *priv, int port, bool drop); ++ ++int netc_port_mtu_set(struct netc_private *priv, int port, int mtu); ++int netc_port_mtu_get(struct netc_private *priv, int port, int *mtu); ++ ++int netc_port_pvid_set(struct netc_private *priv, int port, uint16_t pvid); ++ ++int netc_port_dsa_add(struct netc_private *priv, int cpu_port, ++ int slave_port, const unsigned char *mac_addr); ++int netc_port_dsa_del(struct netc_private *priv, int slave_port); ++ ++int netc_fdb_entry_add(struct netc_private *priv, ++ const unsigned char *mac_addr, ++ uint16_t vid, int port); ++int netc_fdb_entry_del(struct netc_private *priv, ++ const unsigned char *mac_addr, ++ uint16_t vid); ++int netc_fdb_entry_get(struct netc_private *priv, ++ struct netc_fdb_entry *fdb, ++ uint32_t entry_id, uint32_t *next_id); ++ ++int netc_vlan_entry_add(struct netc_private *priv, ++ uint16_t vid, int port, bool untagged); ++int netc_vlan_entry_del(struct netc_private *priv, uint16_t vid, int port); ++int netc_vlan_entry_get(struct netc_private *priv, ++ struct netc_vlan_entry *vlan, ++ uint32_t entry_id, uint32_t *next_id); ++ ++int netc_config_setup(struct netc_config *config); ++void netc_config_free(struct netc_config *config); ++ ++#endif /* _NETC_CONFIG_H */ +diff --git a/drivers/net/dsa/netc/netc_devlink.c b/drivers/net/dsa/netc/netc_devlink.c +new file mode 100644 +index 000000000000..bcf0de99b0cd +--- /dev/null ++++ b/drivers/net/dsa/netc/netc_devlink.c +@@ -0,0 +1,111 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "netc.h" ++ ++static size_t netc_config_get_size(struct netc_private *priv) ++{ ++ return sizeof(struct netc_config); ++} ++ ++static int ++netc_region_config_snapshot(struct devlink *dl, ++ const struct devlink_region_ops *ops, ++ struct netlink_ext_ack *extack, ++ u8 **data) ++{ ++ struct dsa_switch *ds = dsa_devlink_to_ds(dl); ++ struct netc_private *priv = ds->priv; ++ size_t len; ++ ++ len = netc_config_get_size(priv); ++ *data = kcalloc(len, sizeof(u8), GFP_KERNEL); ++ if (!*data) ++ return -ENOMEM; ++ ++ return netc_xfer_get_cmd(priv, NETC_CMD_SYS_INFO_GET, 0, *data, len); ++} ++ ++static struct devlink_region_ops netc_region_config_ops = { ++ .name = "config", ++ .snapshot = netc_region_config_snapshot, ++ .destructor = kfree, ++}; ++ ++enum netc_region_id { ++ NETC_REGION_CONFIG = 0, ++}; ++ ++struct netc_region { ++ const struct devlink_region_ops *ops; ++ size_t (*get_size)(struct netc_private *priv); ++}; ++ ++static struct netc_region netc_regions[] = { ++ [NETC_REGION_CONFIG] = { ++ .ops = &netc_region_config_ops, ++ .get_size = netc_config_get_size, ++ }, ++}; ++ ++int netc_devlink_info_get(struct dsa_switch *ds, ++ struct devlink_info_req *req, ++ struct netlink_ext_ack *extack) ++{ ++ struct netc_private *priv = ds->priv; ++ int rc; ++ ++ rc = devlink_info_driver_name_put(req, "netc"); ++ if (rc) ++ return rc; ++ ++ rc = devlink_info_version_fixed_put(req, ++ DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, ++ priv->info->name); ++ return rc; ++} ++ ++int netc_devlink_setup(struct dsa_switch *ds) ++{ ++ int i, num_regions = ARRAY_SIZE(netc_regions); ++ struct netc_private *priv = ds->priv; ++ const struct devlink_region_ops *ops; ++ struct devlink_region *region; ++ u64 size; ++ ++ priv->regions = kcalloc(num_regions, sizeof(struct devlink_region *), ++ GFP_KERNEL); ++ if (!priv->regions) ++ return -ENOMEM; ++ ++ for (i = 0; i < num_regions; i++) { ++ size = netc_regions[i].get_size(priv); ++ ops = netc_regions[i].ops; ++ ++ region = dsa_devlink_region_create(ds, ops, 1, size); ++ if (IS_ERR(region)) { ++ while (--i >= 0) ++ dsa_devlink_region_destroy(priv->regions[i]); ++ ++ kfree(priv->regions); ++ return PTR_ERR(region); ++ } ++ ++ priv->regions[i] = region; ++ } ++ ++ return 0; ++} ++ ++void netc_devlink_teardown(struct dsa_switch *ds) ++{ ++ int i, num_regions = ARRAY_SIZE(netc_regions); ++ struct netc_private *priv = ds->priv; ++ ++ for (i = 0; i < num_regions; i++) ++ dsa_devlink_region_destroy(priv->regions[i]); ++ ++ kfree(priv->regions); ++} +diff --git a/drivers/net/dsa/netc/netc_ethtool.c b/drivers/net/dsa/netc/netc_ethtool.c +new file mode 100644 +index 000000000000..7e6ab46ffee6 +--- /dev/null ++++ b/drivers/net/dsa/netc/netc_ethtool.c +@@ -0,0 +1,344 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "netc.h" ++ ++enum netc_stat_index { ++ /* RX stats */ ++ NETC_STAT_RX_BYTES, ++ NETC_STAT_RX_VALID_BYTES, ++ NETC_STAT_RX_PAUSE_FRAMES, ++ NETC_STAT_RX_VALID_FRAMES, ++ NETC_STAT_RX_VLAN_FRAMES, ++ NETC_STAT_RX_UC_FRAMES, ++ NETC_STAT_RX_MC_FRAMES, ++ NETC_STAT_RX_BC_FRAMES, ++ NETC_STAT_RX_FRAMES, ++ NETC_STAT_RX_MIN_FRAMES, ++ NETC_STAT_RX_64_FRAMES, ++ NETC_STAT_RX_65_127_FRAMES, ++ NETC_STAT_RX_128_255_FRAMES, ++ NETC_STAT_RX_256_511_FRAMES, ++ NETC_STAT_RX_512_1023_FRAMES, ++ NETC_STAT_RX_1024_1522_FRAMES, ++ NETC_STAT_RX_1523_MAX_FRAMES, ++ NETC_STAT_RX_CONTROL_FRAMES, ++ ++ /* TX stats */ ++ NETC_STAT_TX_BYTES, ++ NETC_STAT_TX_VALID_BYTES, ++ NETC_STAT_TX_PAUSE_FRAMES, ++ NETC_STAT_TX_VALID_FRAMES, ++ NETC_STAT_TX_VLAN_FRAMES, ++ NETC_STAT_TX_UC_FRAMES, ++ NETC_STAT_TX_MC_FRAMES, ++ NETC_STAT_TX_BC_FRAMES, ++ NETC_STAT_TX_FRAMES, ++ NETC_STAT_TX_MIN_FRAMES, ++ NETC_STAT_TX_64_FRAMES, ++ NETC_STAT_TX_65_127_FRAMES, ++ NETC_STAT_TX_128_255_FRAMES, ++ NETC_STAT_TX_256_511_FRAMES, ++ NETC_STAT_TX_512_1023_FRAMES, ++ NETC_STAT_TX_1024_1522_FRAMES, ++ NETC_STAT_TX_1523_MAX_FRAMES, ++ NETC_STAT_TX_CONTROL_FRAMES, ++ ++ NETC_STAT_RX_VALID_REASSEMBLED_FRAMES, ++ NETC_STAT_RX_ADDITIONAL_MPACKETS, ++ NETC_STAT_RX_ERROR_FRAME_REASSEMBLY, ++ NETC_STAT_RX_ERROR_FRAME_SMD, ++ NETC_STAT_TX_ADDITIONAL_MPACKETS, ++ NETC_STAT_TX_HOLD_TRANSITIONS, ++ ++ /* Error stats */ ++ NETC_STAT_RX_ERROR, ++ NETC_STAT_RX_ERROR_UNDERSIZE, ++ NETC_STAT_RX_ERROR_OVERSIZE, ++ NETC_STAT_RX_ERROR_FCS, ++ NETC_STAT_RX_ERROR_FRAGMENT, ++ NETC_STAT_RX_ERROR_JABBER, ++ NETC_STAT_RX_ERROR_DISCARD, ++ NETC_STAT_RX_ERROR_NO_TRUNCATED, ++ NETC_STAT_TX_ERROR_FCS, ++ NETC_STAT_TX_ERROR_UNDERSIZE, ++ ++ /* Discard stats */ ++ NETC_STAT_RX_DISCARD_COUNT, ++ NETC_STAT_RX_DISCARD_REASON0, ++ NETC_STAT_RX_DISCARD_TABLE_ID, ++ NETC_STAT_RX_DISCARD_ENTRY_ID, ++ NETC_STAT_TX_DISCARD_COUNT, ++ NETC_STAT_TX_DISCARD_REASON0, ++ NETC_STAT_TX_DISCARD_TABLE_ID, ++ NETC_STAT_TX_DISCARD_ENTRY_ID, ++ NETC_STAT_BRIDGE_DISCARD_COUNT, ++ NETC_STAT_BRIDGE_DISCARD_REASON0, ++ NETC_STAT_BRIDGE_DISCARD_TABLE_ID, ++ NETC_STAT_BRIDGE_DISCARD_ENTRY_ID, ++ ++ /* Q0 stats */ ++ NETC_STAT_Q0_REJECTED_BYTES, ++ NETC_STAT_Q0_REJECTED_FRAMES, ++ NETC_STAT_Q0_DEQUEUE_BYTES, ++ NETC_STAT_Q0_DEQUEUE_FRAMES, ++ NETC_STAT_Q0_DROPPED_BYTES, ++ NETC_STAT_Q0_DROPPED_FRAMES, ++ NETC_STAT_Q0_FRAMES, ++ ++ /* Q1 stats */ ++ NETC_STAT_Q1_REJECTED_BYTES, ++ NETC_STAT_Q1_REJECTED_FRAMES, ++ NETC_STAT_Q1_DEQUEUE_BYTES, ++ NETC_STAT_Q1_DEQUEUE_FRAMES, ++ NETC_STAT_Q1_DROPPED_BYTES, ++ NETC_STAT_Q1_DROPPED_FRAMES, ++ NETC_STAT_Q1_FRAMES, ++ ++ /* Q2 stats */ ++ NETC_STAT_Q2_REJECTED_BYTES, ++ NETC_STAT_Q2_REJECTED_FRAMES, ++ NETC_STAT_Q2_DEQUEUE_BYTES, ++ NETC_STAT_Q2_DEQUEUE_FRAMES, ++ NETC_STAT_Q2_DROPPED_BYTES, ++ NETC_STAT_Q2_DROPPED_FRAMES, ++ NETC_STAT_Q2_FRAMES, ++ ++ /* Q3 stats */ ++ NETC_STAT_Q3_REJECTED_BYTES, ++ NETC_STAT_Q3_REJECTED_FRAMES, ++ NETC_STAT_Q3_DEQUEUE_BYTES, ++ NETC_STAT_Q3_DEQUEUE_FRAMES, ++ NETC_STAT_Q3_DROPPED_BYTES, ++ NETC_STAT_Q3_DROPPED_FRAMES, ++ NETC_STAT_Q3_FRAMES, ++ ++ /* Q4 stats */ ++ NETC_STAT_Q4_REJECTED_BYTES, ++ NETC_STAT_Q4_REJECTED_FRAMES, ++ NETC_STAT_Q4_DEQUEUE_BYTES, ++ NETC_STAT_Q4_DEQUEUE_FRAMES, ++ NETC_STAT_Q4_DROPPED_BYTES, ++ NETC_STAT_Q4_DROPPED_FRAMES, ++ NETC_STAT_Q4_FRAMES, ++ ++ /* Q5 stats */ ++ NETC_STAT_Q5_REJECTED_BYTES, ++ NETC_STAT_Q5_REJECTED_FRAMES, ++ NETC_STAT_Q5_DEQUEUE_BYTES, ++ NETC_STAT_Q5_DEQUEUE_FRAMES, ++ NETC_STAT_Q5_DROPPED_BYTES, ++ NETC_STAT_Q5_DROPPED_FRAMES, ++ NETC_STAT_Q5_FRAMES, ++ ++ /* Q6 stats */ ++ NETC_STAT_Q6_REJECTED_BYTES, ++ NETC_STAT_Q6_REJECTED_FRAMES, ++ NETC_STAT_Q6_DEQUEUE_BYTES, ++ NETC_STAT_Q6_DEQUEUE_FRAMES, ++ NETC_STAT_Q6_DROPPED_BYTES, ++ NETC_STAT_Q6_DROPPED_FRAMES, ++ NETC_STAT_Q6_FRAMES, ++ ++ /* Q7 stats */ ++ NETC_STAT_Q7_REJECTED_BYTES, ++ NETC_STAT_Q7_REJECTED_FRAMES, ++ NETC_STAT_Q7_DEQUEUE_BYTES, ++ NETC_STAT_Q7_DEQUEUE_FRAMES, ++ NETC_STAT_Q7_DROPPED_BYTES, ++ NETC_STAT_Q7_DROPPED_FRAMES, ++ NETC_STAT_Q7_FRAMES, ++ NETC_STAT_NUM, ++}; ++ ++char netc_stat_name[][ETH_GSTRING_LEN] = { ++ /* RX stats */ ++ [NETC_STAT_RX_BYTES] = "in-bytes", ++ [NETC_STAT_RX_VALID_BYTES] = "in-valid-bytes", ++ [NETC_STAT_RX_PAUSE_FRAMES] = "in-pause-frames", ++ [NETC_STAT_RX_VALID_FRAMES] = "in-valid-frames", ++ [NETC_STAT_RX_VLAN_FRAMES] = "in-vlan-frames", ++ [NETC_STAT_RX_UC_FRAMES] = "in-uc-frames", ++ [NETC_STAT_RX_MC_FRAMES] = "in-mc-frames", ++ [NETC_STAT_RX_BC_FRAMES] = "in-bc-frames", ++ [NETC_STAT_RX_FRAMES] = "in-frames", ++ [NETC_STAT_RX_MIN_FRAMES] = "in-min-frames", ++ [NETC_STAT_RX_64_FRAMES] = "in-64-frames", ++ [NETC_STAT_RX_65_127_FRAMES] = "in-65-127-frames", ++ [NETC_STAT_RX_128_255_FRAMES] = "in-128-255-frames", ++ [NETC_STAT_RX_256_511_FRAMES] = "in-256-511-frames", ++ [NETC_STAT_RX_512_1023_FRAMES] = "in-512-1023-frames", ++ [NETC_STAT_RX_1024_1522_FRAMES] = "in-1024-1522-frames", ++ [NETC_STAT_RX_1523_MAX_FRAMES] = "in-1523-max-frames", ++ [NETC_STAT_RX_CONTROL_FRAMES] = "in-control-frames", ++ ++ /* TX stats */ ++ [NETC_STAT_TX_BYTES] = "out-bytes", ++ [NETC_STAT_TX_VALID_BYTES] = "out-valid-bytes", ++ [NETC_STAT_TX_PAUSE_FRAMES] = "out-pause-frames", ++ [NETC_STAT_TX_VALID_FRAMES] = "out-valid-frames", ++ [NETC_STAT_TX_VLAN_FRAMES] = "out-vlan-frames", ++ [NETC_STAT_TX_UC_FRAMES] = "out-uc-frames", ++ [NETC_STAT_TX_MC_FRAMES] = "out-mc-frames", ++ [NETC_STAT_TX_BC_FRAMES] = "out-bc-frames", ++ [NETC_STAT_TX_FRAMES] = "out-frames", ++ [NETC_STAT_TX_MIN_FRAMES] = "out-min-frames", ++ [NETC_STAT_TX_64_FRAMES] = "out-64-frames", ++ [NETC_STAT_TX_65_127_FRAMES] = "out-65-127-frames", ++ [NETC_STAT_TX_128_255_FRAMES] = "out-128-255-frames", ++ [NETC_STAT_TX_256_511_FRAMES] = "out-256-511-frames", ++ [NETC_STAT_TX_512_1023_FRAMES] = "out-512-1023-frames", ++ [NETC_STAT_TX_1024_1522_FRAMES] = "out-1024-1522-frames", ++ [NETC_STAT_TX_1523_MAX_FRAMES] = "out-1523-max-frames", ++ [NETC_STAT_TX_CONTROL_FRAMES] = "out-control-frames", ++ ++ [NETC_STAT_RX_VALID_REASSEMBLED_FRAMES] = "in-valid-reassembled-frames", ++ [NETC_STAT_RX_ADDITIONAL_MPACKETS] = "in-additional-mPackets", ++ [NETC_STAT_RX_ERROR_FRAME_REASSEMBLY] = "in-error-frame-reassembly", ++ [NETC_STAT_RX_ERROR_FRAME_SMD] = "in-error-frame-smd", ++ [NETC_STAT_TX_ADDITIONAL_MPACKETS] = "out-additional-mPackets", ++ [NETC_STAT_TX_HOLD_TRANSITIONS] = "out-hold-transitions", ++ ++ /* Error stats */ ++ [NETC_STAT_RX_ERROR] = "in-error", ++ [NETC_STAT_RX_ERROR_UNDERSIZE] = "in-error-undersize", ++ [NETC_STAT_RX_ERROR_OVERSIZE] = "in-error-oversize", ++ [NETC_STAT_RX_ERROR_FCS] = "in-error-fcs", ++ [NETC_STAT_RX_ERROR_FRAGMENT] = "in-error-fragment", ++ [NETC_STAT_RX_ERROR_JABBER] = "in-error-jabber", ++ [NETC_STAT_RX_ERROR_DISCARD] = "in-error-discard", ++ [NETC_STAT_RX_ERROR_NO_TRUNCATED] = "in-error-dicard-no-truncated", ++ [NETC_STAT_TX_ERROR_FCS] = "out-error-fcs", ++ [NETC_STAT_TX_ERROR_UNDERSIZE] = "out-error-undersize", ++ ++ /* Discard stats */ ++ [NETC_STAT_RX_DISCARD_COUNT] = "in-discard-count", ++ [NETC_STAT_RX_DISCARD_REASON0] = "in-discard-reason0", ++ [NETC_STAT_RX_DISCARD_TABLE_ID] = "in-discard-table-id", ++ [NETC_STAT_RX_DISCARD_ENTRY_ID] = "in-discard-entry-id", ++ [NETC_STAT_TX_DISCARD_COUNT] = "out-discard-count", ++ [NETC_STAT_TX_DISCARD_REASON0] = "out-discard-reason0", ++ [NETC_STAT_TX_DISCARD_TABLE_ID] = "out-discard-table-id", ++ [NETC_STAT_TX_DISCARD_ENTRY_ID] = "out-discard-entry-id", ++ [NETC_STAT_BRIDGE_DISCARD_COUNT] = "bridge-discard-count", ++ [NETC_STAT_BRIDGE_DISCARD_REASON0] = "bridge-discard-reason0", ++ [NETC_STAT_BRIDGE_DISCARD_TABLE_ID] = "bridge-discard-table-id", ++ [NETC_STAT_BRIDGE_DISCARD_ENTRY_ID] = "bridge-discard-entry-id", ++ ++ /* Q0 stats */ ++ [NETC_STAT_Q0_REJECTED_BYTES] = "q0-rejected-bytes", ++ [NETC_STAT_Q0_REJECTED_FRAMES] = "q0-rejected-frames", ++ [NETC_STAT_Q0_DEQUEUE_BYTES] = "q0-dequeue-bytes", ++ [NETC_STAT_Q0_DEQUEUE_FRAMES] = "q0-dequeue-frames", ++ [NETC_STAT_Q0_DROPPED_BYTES] = "q0-dropped-bytes", ++ [NETC_STAT_Q0_DROPPED_FRAMES] = "q0-dropped-frames", ++ [NETC_STAT_Q0_FRAMES] = "q0-frames", ++ ++ /* Q1 stats */ ++ [NETC_STAT_Q1_REJECTED_BYTES] = "q1-rejected-bytes", ++ [NETC_STAT_Q1_REJECTED_FRAMES] = "q1-rejected-frames", ++ [NETC_STAT_Q1_DEQUEUE_BYTES] = "q1-dequeue-bytes", ++ [NETC_STAT_Q1_DEQUEUE_FRAMES] = "q1-dequeue-frames", ++ [NETC_STAT_Q1_DROPPED_BYTES] = "q1-dropped-bytes", ++ [NETC_STAT_Q1_DROPPED_FRAMES] = "q1-dropped-frames", ++ [NETC_STAT_Q1_FRAMES] = "q1-frames", ++ ++ /* Q2 stats */ ++ [NETC_STAT_Q2_REJECTED_BYTES] = "q2-rejected-bytes", ++ [NETC_STAT_Q2_REJECTED_FRAMES] = "q2-rejected-frames", ++ [NETC_STAT_Q2_DEQUEUE_BYTES] = "q2-dequeue-bytes", ++ [NETC_STAT_Q2_DEQUEUE_FRAMES] = "q2-dequeue-frames", ++ [NETC_STAT_Q2_DROPPED_BYTES] = "q2-dropped-bytes", ++ [NETC_STAT_Q2_DROPPED_FRAMES] = "q2-dropped-frames", ++ [NETC_STAT_Q2_FRAMES] = "q2-frames", ++ ++ /* Q3 stats */ ++ [NETC_STAT_Q3_REJECTED_BYTES] = "q3-rejected-bytes", ++ [NETC_STAT_Q3_REJECTED_FRAMES] = "q3-rejected-frames", ++ [NETC_STAT_Q3_DEQUEUE_BYTES] = "q3-dequeue-bytes", ++ [NETC_STAT_Q3_DEQUEUE_FRAMES] = "q3-dequeue-frames", ++ [NETC_STAT_Q3_DROPPED_BYTES] = "q3-dropped-bytes", ++ [NETC_STAT_Q3_DROPPED_FRAMES] = "q3-dropped-frames", ++ [NETC_STAT_Q3_FRAMES] = "q3-frames", ++ ++ /* Q4 stats */ ++ [NETC_STAT_Q4_REJECTED_BYTES] = "q4-rejected-bytes", ++ [NETC_STAT_Q4_REJECTED_FRAMES] = "q4-rejected-frames", ++ [NETC_STAT_Q4_DEQUEUE_BYTES] = "q4-dequeue-bytes", ++ [NETC_STAT_Q4_DEQUEUE_FRAMES] = "q4-dequeue-frames", ++ [NETC_STAT_Q4_DROPPED_BYTES] = "q4-dropped-bytes", ++ [NETC_STAT_Q4_DROPPED_FRAMES] = "q4-dropped-frames", ++ [NETC_STAT_Q4_FRAMES] = "q4-frames", ++ ++ /* Q5 stats */ ++ [NETC_STAT_Q5_REJECTED_BYTES] = "q5-rejected-bytes", ++ [NETC_STAT_Q5_REJECTED_FRAMES] = "q5-rejected-frames", ++ [NETC_STAT_Q5_DEQUEUE_BYTES] = "q5-dequeue-bytes", ++ [NETC_STAT_Q5_DEQUEUE_FRAMES] = "q5-dequeue-frames", ++ [NETC_STAT_Q5_DROPPED_BYTES] = "q5-dropped-bytes", ++ [NETC_STAT_Q5_DROPPED_FRAMES] = "q5-dropped-frames", ++ [NETC_STAT_Q5_FRAMES] = "q5-frames", ++ ++ /* Q6 stats */ ++ [NETC_STAT_Q6_REJECTED_BYTES] = "q6-rejected-bytes", ++ [NETC_STAT_Q6_REJECTED_FRAMES] = "q6-rejected-frames", ++ [NETC_STAT_Q6_DEQUEUE_BYTES] = "q6-dequeue-bytes", ++ [NETC_STAT_Q6_DEQUEUE_FRAMES] = "q6-dequeue-frames", ++ [NETC_STAT_Q6_DROPPED_BYTES] = "q6-dropped-bytes", ++ [NETC_STAT_Q6_DROPPED_FRAMES] = "q6-dropped-frames", ++ [NETC_STAT_Q6_FRAMES] = "q6-frames", ++ ++ /* Q7 stats */ ++ [NETC_STAT_Q7_REJECTED_BYTES] = "q7-rejected-bytes", ++ [NETC_STAT_Q7_REJECTED_FRAMES] = "q7-rejected-frames", ++ [NETC_STAT_Q7_DEQUEUE_BYTES] = "q7-dequeue-bytes", ++ [NETC_STAT_Q7_DEQUEUE_FRAMES] = "q7-dequeue-frames", ++ [NETC_STAT_Q7_DROPPED_BYTES] = "q7-dropped-bytes", ++ [NETC_STAT_Q7_DROPPED_FRAMES] = "q7-dropped-frames", ++ [NETC_STAT_Q7_FRAMES] = "q7-frames", ++}; ++ ++void netc_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) ++{ ++ struct netc_private *priv = ds->priv; ++ struct netc_cmd_port_ethtool_stats stats; ++ int rc; ++ enum netc_stat_index i; ++ ++ rc = netc_xfer_get_cmd(priv, NETC_CMD_PORT_ETHTOOL_STATS_GET, ++ port, &stats, sizeof(stats)); ++ ++ if (rc) { ++ dev_err(ds->dev, ++ "Failed to get port %d stats\n", port); ++ return; ++ } ++ ++ for (i = 0; i < NETC_STAT_NUM; i++) ++ data[i] = stats.values[i]; ++} ++ ++void netc_get_strings(struct dsa_switch *ds, int port, ++ u32 stringset, u8 *data) ++{ ++ enum netc_stat_index i; ++ char *p = data; ++ ++ if (stringset != ETH_SS_STATS) ++ return; ++ ++ for (i = 0; i < NETC_STAT_NUM; i++) { ++ strscpy(p, netc_stat_name[i], ETH_GSTRING_LEN); ++ p += ETH_GSTRING_LEN; ++ } ++} ++ ++int netc_get_sset_count(struct dsa_switch *ds, int port, int sset) ++{ ++ if (sset != ETH_SS_STATS) ++ return -EOPNOTSUPP; ++ ++ return NETC_STAT_NUM; ++} +diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c +new file mode 100644 +index 000000000000..5ba2b8d7ac93 +--- /dev/null ++++ b/drivers/net/dsa/netc/netc_main.c +@@ -0,0 +1,928 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "netc.h" ++ ++int netc_is_vlan_configured(struct netc_private *priv, uint16_t vid) ++{ ++ struct netc_vlan_entry *vlan; ++ int count, i; ++ ++ vlan = priv->config.vlan; ++ count = priv->config.vlan_count; ++ ++ for (i = 0; i < count; i++) { ++ if (vlan[i].vid == vid) ++ return i; ++ } ++ ++ /* Return an invalid entry index if not found */ ++ return -1; ++} ++ ++static bool vid_is_netc_dsa_8021q(struct dsa_switch *ds, u16 vid) ++{ ++ int port; ++ struct dsa_port *dp; ++ unsigned int bridge_num; ++ u16 standalone_vid, bridge_vid; ++ ++ for (port = 0; port < ds->num_ports; port++) { ++ dp = dsa_to_port(ds, port); ++ standalone_vid = dsa_tag_8021q_standalone_vid(dp); ++ ++ if (vid == standalone_vid) ++ return true; ++ ++ if (dp->bridge) { ++ bridge_num = dsa_port_bridge_num_get(dp); ++ bridge_vid = dsa_tag_8021q_bridge_vid(bridge_num); ++ ++ if (vid == bridge_vid) ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static int netc_drop_untagged(struct dsa_switch *ds, int port, bool drop) ++{ ++ struct netc_private *priv = ds->priv; ++ struct netc_mac_config *mac; ++ ++ mac = &priv->config.mac[port]; ++ if (mac->drpuntag == drop) ++ return 0; ++ ++ mac->drpuntag = drop; ++ ++ return netc_port_dropuntag_set(priv, port, drop); ++} ++ ++static int netc_pvid_apply(struct netc_private *priv, int port, uint16_t pvid) ++{ ++ struct netc_mac_config *mac; ++ ++ mac = &priv->config.mac[port]; ++ if (mac->vlanid == pvid) ++ return 0; ++ ++ mac->vlanid = pvid; ++ ++ return netc_port_pvid_set(priv, port, pvid); ++} ++ ++static int netc_commit_pvid(struct dsa_switch *ds, int port) ++{ ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct net_device *br = dsa_port_bridge_dev_get(dp); ++ struct netc_private *priv = ds->priv; ++ bool drop_untagged = false; ++ int rc; ++ uint16_t pvid; ++ ++ if (br && br_vlan_enabled(br)) ++ pvid = priv->bridge_pvid[port]; ++ else ++ pvid = priv->tag_8021q_pvid[port]; ++ ++ rc = netc_pvid_apply(priv, port, pvid); ++ if (rc) ++ return rc; ++ ++ /* ++ * Only force dropping of untagged packets when the port is under a ++ * VLAN-aware bridge. When the tag_8021q pvid is used, we are ++ * deliberately removing the RX VLAN from the port's VMEMB_PORT list, ++ * to prevent DSA tag spoofing from the link partner. Untagged packets ++ * are the only ones that should be received with tag_8021q, so ++ * definitely don't drop them. ++ */ ++ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) ++ drop_untagged = true; ++ ++ return netc_drop_untagged(ds, port, drop_untagged); ++} ++ ++static int netc_fdb_add(struct dsa_switch *ds, int port, ++ const unsigned char *addr, uint16_t vid, ++ struct dsa_db db) ++{ ++ struct netc_private *priv = ds->priv; ++ ++ if (!vid) { ++ switch (db.type) { ++ case DSA_DB_PORT: ++ vid = dsa_tag_8021q_standalone_vid(db.dp); ++ break; ++ case DSA_DB_BRIDGE: ++ vid = dsa_tag_8021q_bridge_vid(db.bridge.num); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ /* Allow enough time between consecutive calls for adding FDB entry */ ++ usleep_range(NETC_SPI_MSG_RESPONSE_TIME, ++ NETC_SPI_MSG_RESPONSE_TIME * 10); ++ ++ return netc_fdb_entry_add(priv, addr, vid, port); ++} ++ ++static int netc_fdb_del(struct dsa_switch *ds, int port, ++ const unsigned char *addr, uint16_t vid, ++ struct dsa_db db) ++{ ++ struct netc_private *priv = ds->priv; ++ ++ if (!vid) { ++ switch (db.type) { ++ case DSA_DB_PORT: ++ vid = dsa_tag_8021q_standalone_vid(db.dp); ++ break; ++ case DSA_DB_BRIDGE: ++ vid = dsa_tag_8021q_bridge_vid(db.bridge.num); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return netc_fdb_entry_del(priv, addr, vid); ++} ++ ++static int netc_fdb_dump(struct dsa_switch *ds, int port, ++ dsa_fdb_dump_cb_t *cb, void *data) ++{ ++ struct netc_private *priv = ds->priv; ++ struct device *dev = ds->dev; ++ u32 entry_id = 0, next_id = 0; ++ int rc; ++ ++ while (1) { ++ struct netc_fdb_entry fdb = {0}; ++ ++ rc = netc_fdb_entry_get(priv, &fdb, entry_id, &next_id); ++ /* No fdb entry at i, not an issue */ ++ if (rc) { ++ dev_err(dev, "Failed to dump FDB: %d\n", rc); ++ return rc; ++ } ++ ++ if (next_id == 0) /* This entry is empty */ ++ return 0; ++ ++ /* ++ * FDB dump callback is per port. This means we have to ++ * disregard a valid entry if it's not for this port, even if ++ * only to revisit it later. This is inefficient because the ++ * 1024-sized FDB table needs to be traversed 4 times through ++ * SPI during a 'bridge fdb show' command. ++ */ ++ if (fdb.port_map & BIT(port)) { ++ /* Need to hide the dsa_8021q VLANs from the user. */ ++ if (vid_is_netc_dsa_8021q(ds, fdb.vid)) ++ fdb.vid = 0; ++ ++ rc = cb(fdb.mac_addr, fdb.vid, fdb.dynamic, data); ++ if (rc) ++ return rc; ++ } ++ ++ entry_id = next_id; ++ ++ if (entry_id == 0 || entry_id == 0xffffffff) ++ break; ++ } ++ ++ return 0; ++} ++ ++static int netc_parse_ports_node(struct netc_private *priv, ++ struct device_node *ports_node) ++{ ++ struct device *dev = &priv->spidev->dev; ++ struct device_node *child; ++ ++ for_each_available_child_of_node(ports_node, child) { ++ struct device_node *phy_node; ++ phy_interface_t phy_mode; ++ u32 index; ++ int err; ++ ++ /* Get switch port number from DT */ ++ if (of_property_read_u32(child, "reg", &index) < 0) { ++ dev_err(dev, "Port number not defined in device tree\n"); ++ of_node_put(child); ++ return -ENODEV; ++ } ++ ++ /* Get PHY mode from DT */ ++ err = of_get_phy_mode(child, &phy_mode); ++ if (err) { ++ dev_err(dev, "Failed to read phy-mode or phy-interface-type %d\n", ++ index); ++ of_node_put(child); ++ return -ENODEV; ++ } ++ ++ phy_node = of_parse_phandle(child, "phy-handle", 0); ++ if (!phy_node) { ++ if (!of_phy_is_fixed_link(child)) { ++ dev_err(dev, "phy-handle or fixed-link properties missing!\n"); ++ of_node_put(child); ++ return -ENODEV; ++ } ++ /* phy-handle is missing, but fixed-link isn't. ++ * So it's a fixed link. Default to PHY role. ++ */ ++ priv->fixed_link[index] = true; ++ } else { ++ of_node_put(phy_node); ++ } ++ ++ priv->phy_mode[index] = phy_mode; ++ } ++ ++ return 0; ++} ++ ++static int netc_parse_dt(struct netc_private *priv) ++{ ++ struct device *dev = &priv->spidev->dev; ++ struct device_node *switch_node = dev->of_node; ++ struct device_node *ports_node; ++ int rc; ++ ++ ports_node = of_get_child_by_name(switch_node, "ports"); ++ if (!ports_node) ++ ports_node = of_get_child_by_name(switch_node, "ethernet-ports"); ++ if (!ports_node) { ++ dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); ++ return -ENODEV; ++ } ++ ++ rc = netc_parse_ports_node(priv, ports_node); ++ of_node_put(ports_node); ++ ++ return rc; ++} ++ ++static void netc_mac_link_down(struct dsa_switch *ds, int port, ++ unsigned int mode, ++ phy_interface_t interface) ++{ ++ struct netc_private *priv = ds->priv; ++ struct netc_mac_config *mac; ++ ++ mac = &priv->config.mac[port]; ++ ++ mac->egress = false; ++ ++ netc_port_link_set(priv, port, false); ++} ++ ++static void netc_mac_link_up(struct dsa_switch *ds, int port, ++ unsigned int mode, ++ phy_interface_t interface, ++ struct phy_device *phydev, ++ int speed, int duplex, ++ bool tx_pause, bool rx_pause) ++{ ++ struct netc_private *priv = ds->priv; ++ struct netc_mac_config *mac; ++ ++ mac = &priv->config.mac[port]; ++ ++ mac->speed = speed; ++ mac->egress = true; ++ ++ netc_port_phylink_mode_set(priv, mac); ++ netc_port_link_set(priv, port, true); ++} ++ ++static void netc_phylink_get_caps(struct dsa_switch *ds, int port, ++ struct phylink_config *config) ++{ ++ struct netc_private *priv = ds->priv; ++ phy_interface_t phy_mode; ++ ++ /* ++ * This driver does not make use of the speed, duplex, pause or the ++ * advertisement in its mac_config, so it is safe to mark this driver ++ * as non-legacy. ++ */ ++ config->legacy_pre_march2020 = false; ++ ++ phy_mode = priv->phy_mode[port]; ++ __set_bit(phy_mode, config->supported_interfaces); ++ ++ /* ++ * The MAC does not support pause frames, and also doesn't ++ * support half-duplex traffic modes. ++ */ ++ config->mac_capabilities = MAC_10FD | MAC_100FD; ++ config->mac_capabilities |= MAC_1000FD; ++} ++ ++static int netc_bridge_member(struct dsa_switch *ds, int port, ++ struct dsa_bridge bridge, bool member) ++{ ++ int rc; ++ ++ rc = netc_commit_pvid(ds, port); ++ if (rc) ++ return rc; ++ ++ return 0; ++} ++ ++static int netc_bridge_join(struct dsa_switch *ds, int port, ++ struct dsa_bridge bridge, ++ bool *tx_fwd_offload, ++ struct netlink_ext_ack *extack) ++{ ++ int rc; ++ ++ rc = netc_bridge_member(ds, port, bridge, true); ++ if (rc) ++ return rc; ++ ++ rc = dsa_tag_8021q_bridge_join(ds, port, bridge); ++ if (rc) { ++ netc_bridge_member(ds, port, bridge, false); ++ return rc; ++ } ++ ++ *tx_fwd_offload = true; ++ ++ return 0; ++} ++ ++static void netc_bridge_leave(struct dsa_switch *ds, int port, ++ struct dsa_bridge bridge) ++{ ++ dsa_tag_8021q_bridge_leave(ds, port, bridge); ++ netc_bridge_member(ds, port, bridge, false); ++} ++ ++static enum dsa_tag_protocol ++netc_get_tag_protocol(struct dsa_switch *ds, int port, ++ enum dsa_tag_protocol mp) ++{ ++ struct netc_private *priv = ds->priv; ++ ++ return priv->info->tag_proto; ++} ++ ++int netc_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, ++ struct netlink_ext_ack *extack) ++{ ++ struct netc_private *priv = ds->priv; ++ struct netc_config *config = &priv->config; ++ int rc; ++ ++ if (enabled) { ++ /* Enable VLAN filtering. */ ++ config->tpid = ETH_P_8021Q; ++ config->tpid2 = ETH_P_8021AD; ++ } else { ++ /* Disable VLAN filtering. */ ++ config->tpid = ETH_P_8021Q; ++ config->tpid2 = ETH_P_NETC; ++ } ++ ++ for (port = 0; port < ds->num_ports; port++) { ++ if (dsa_is_unused_port(ds, port)) ++ continue; ++ ++ rc = netc_commit_pvid(ds, port); ++ if (rc) ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static int netc_bridge_vlan_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan, ++ struct netlink_ext_ack *extack) ++{ ++ struct netc_private *priv = ds->priv; ++ uint16_t flags = vlan->flags; ++ bool untagged = false; ++ int rc; ++ ++ /* Be sure to deny the configuration done by tag_8021q. */ ++ if (vid_is_netc_dsa_8021q(ds, vlan->vid)) { ++ NL_SET_ERR_MSG_MOD(extack, ++ "VLAN ID 3072-3076 & 3088 reserved for dsa_8021q operation"); ++ return -EBUSY; ++ } ++ ++ /* Always install bridge VLANs as egress-tagged on CPU and DSA ports */ ++ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) ++ flags = 0; ++ ++ if (flags & BRIDGE_VLAN_INFO_UNTAGGED) ++ untagged = true; ++ ++ rc = netc_vlan_entry_add(priv, vlan->vid, port, untagged); ++ if (rc) ++ return rc; ++ ++ if (vlan->flags & BRIDGE_VLAN_INFO_PVID) ++ priv->bridge_pvid[port] = vlan->vid; ++ ++ /* Allow enough time between adding VLAN entry and setting PVID */ ++ usleep_range(NETC_SPI_MSG_RESPONSE_TIME, ++ NETC_SPI_MSG_RESPONSE_TIME * 10); ++ ++ return netc_commit_pvid(ds, port); ++} ++ ++static int netc_bridge_vlan_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan) ++{ ++ struct netc_private *priv = ds->priv; ++ int rc; ++ ++ rc = netc_vlan_entry_del(priv, vlan->vid, port); ++ if (rc) ++ return rc; ++ ++ /* ++ * In case the pvid was deleted, make sure that untagged packets will ++ * be dropped. ++ */ ++ return netc_commit_pvid(ds, port); ++} ++ ++static int netc_8021q_vlan_add(struct dsa_switch *ds, int port, ++ uint16_t vid, uint16_t flags) ++{ ++ struct netc_private *priv = ds->priv; ++ int rc; ++ ++ rc = netc_vlan_entry_add(priv, vid, port, false); ++ if (rc) ++ return rc; ++ ++ if (flags & BRIDGE_VLAN_INFO_PVID) ++ priv->tag_8021q_pvid[port] = vid; ++ ++ /* Allow enough time between adding VLAN entry and setting PVID */ ++ usleep_range(NETC_SPI_MSG_RESPONSE_TIME, ++ NETC_SPI_MSG_RESPONSE_TIME * 10); ++ ++ return netc_commit_pvid(ds, port); ++} ++ ++static int netc_8021q_vlan_del(struct dsa_switch *ds, int port, uint16_t vid) ++{ ++ struct netc_private *priv = ds->priv; ++ ++ return netc_vlan_entry_del(priv, vid, port); ++} ++ ++static int netc_prechangeupper(struct dsa_switch *ds, int port, ++ struct netdev_notifier_changeupper_info *info) ++{ ++ struct netlink_ext_ack *extack = info->info.extack; ++ struct net_device *upper = info->upper_dev; ++ struct dsa_switch_tree *dst = ds->dst; ++ struct dsa_port *dp; ++ ++ if (is_vlan_dev(upper)) { ++ NL_SET_ERR_MSG_MOD(extack, "8021q uppers are not supported"); ++ return -EBUSY; ++ } ++ ++ if (netif_is_bridge_master(upper)) { ++ list_for_each_entry(dp, &dst->ports, list) { ++ struct net_device *br = dsa_port_bridge_dev_get(dp); ++ ++ if (br && br != upper && br_vlan_enabled(br)) { ++ NL_SET_ERR_MSG_MOD(extack, ++ "Only one VLAN-aware bridge is supported"); ++ return -EBUSY; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#define work_to_xmit_work(w) \ ++ container_of((w), struct netc_deferred_xmit_work, work) ++ ++static void netc_port_deferred_xmit(struct kthread_work *work) ++{ ++ struct netc_deferred_xmit_work *xmit_work = work_to_xmit_work(work); ++ struct sk_buff *clone, *skb = xmit_work->skb; ++ struct dsa_switch *ds = xmit_work->dp->ds; ++ int port = xmit_work->dp->index; ++ ++ clone = NETC_SKB_CB(skb)->clone; ++ ++ /* Transfer skb to the host port. */ ++ dsa_enqueue_skb(skb, dsa_to_port(ds, port)->slave); ++ ++ /* The clone, if there, was made by dsa_skb_tx_timestamp */ ++ if (clone) ++ netc_ptp_txtstamp_skb(ds, port, clone); ++ ++ kfree(xmit_work); ++} ++ ++static int netc_connect_tag_protocol(struct dsa_switch *ds, ++ enum dsa_tag_protocol proto) ++{ ++ struct netc_private *priv = ds->priv; ++ struct netc_tagger_data *tagger_data; ++ ++ if (proto != priv->info->tag_proto) ++ return -EPROTONOSUPPORT; ++ ++ tagger_data = netc_tagger_data(ds); ++ tagger_data->xmit_work_fn = netc_port_deferred_xmit; ++ ++ return 0; ++} ++ ++static int netc_change_mtu(struct dsa_switch *ds, int port, int new_mtu) ++{ ++ struct netc_private *priv = ds->priv; ++ int maxlen = new_mtu + ETH_HLEN + ETH_FCS_LEN; ++ ++ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) ++ maxlen += VLAN_HLEN; ++ ++ return netc_port_mtu_set(priv, port, maxlen); ++} ++ ++static int netc_get_max_mtu(struct dsa_switch *ds, int port) ++{ ++ return 2000 - VLAN_ETH_HLEN - ETH_FCS_LEN; ++} ++ ++static int netc_mac_init(struct netc_private *priv) ++{ ++ struct netc_mac_config *mac; ++ struct dsa_switch *ds = priv->ds; ++ struct dsa_port *dp; ++ ++ mac = priv->config.mac; ++ ++ dsa_switch_for_each_port(dp, ds) { ++ mac[dp->index].port = dp->index; ++ mac[dp->index].speed = 1000; ++ mac[dp->index].vlanid = 1; ++ mac[dp->index].drpuntag = false; ++ mac[dp->index].retag = false; ++ ++ if (dsa_port_is_dsa(dp)) ++ dp->learning = true; ++ ++ /* Disallow untagged packets from being received on the ++ * CPU and DSA ports. ++ */ ++ if (dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)) ++ mac[dp->index].drpuntag = true; ++ } ++ ++ return 0; ++} ++ ++static int netc_dsa_init(struct netc_private *priv) ++{ ++ struct dsa_switch *ds = priv->ds; ++ struct dsa_port *dp, *cpu_dp = NULL; ++ const u8 *mac; ++ int port; ++ ++ for (port = 0; port < ds->num_ports; port++) { ++ if (dsa_is_cpu_port(ds, port)) { ++ cpu_dp = dsa_to_port(ds, port); ++ break; ++ } ++ } ++ ++ if (!cpu_dp) { ++ dev_err(ds->dev, "Failed to find cpu port\n"); ++ return -ENODEV; ++ } ++ ++ if (!is_zero_ether_addr(cpu_dp->mac)) ++ mac = cpu_dp->mac; ++ else ++ mac = cpu_dp->master->dev_addr; ++ ++ pr_info("NETC DSA: cpu port:%d master:%s\n", ++ cpu_dp->index, cpu_dp->master->name); ++ ++ for (port = 0; port < ds->num_ports; port++) { ++ dp = dsa_to_port(ds, port); ++ ++ if (dsa_port_is_unused(dp)) ++ continue; ++ if (dsa_port_is_cpu(dp)) ++ continue; ++ ++ pr_info("NETC DSA: add switch port:%d\n", port); ++ ++ netc_port_dsa_add(priv, cpu_dp->index, port, mac); ++ } ++ ++ return 0; ++} ++ ++static int netc_setup(struct dsa_switch *ds) ++{ ++ struct netc_private *priv = ds->priv; ++ int port; ++ int rc; ++ ++ rc = netc_config_setup(&priv->config); ++ if (rc < 0) { ++ dev_err(ds->dev, "Failed to setup config: %d\n", rc); ++ return rc; ++ } ++ ++ netc_mac_init(priv); ++ netc_dsa_init(priv); ++ ++ for (port = 0; port < ds->num_ports; port++) { ++ priv->tag_8021q_pvid[port] = NETC_DEFAULT_VLAN; ++ priv->bridge_pvid[port] = NETC_DEFAULT_VLAN; ++ } ++ ++ rc = netc_devlink_setup(ds); ++ if (rc < 0) ++ goto out_config_free; ++ ++ rtnl_lock(); ++ rc = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q)); ++ rtnl_unlock(); ++ if (rc) ++ goto out_devlink_teardown; ++ ++ /* ++ * On netc, VLAN filtering per se is always enabled in hardware. ++ * The only thing we can do to disable it is lie about what the 802.1Q ++ * EtherType is. ++ * So it will still try to apply VLAN filtering, but all ingress ++ * traffic (except frames received with EtherType of ETH_P_NETC) ++ * will be internally tagged with a distorted VLAN header where the ++ * TPID is ETH_P_NETC, and the VLAN ID is the port pvid. ++ */ ++ ds->vlan_filtering_is_global = true; ++ ds->untag_bridge_pvid = true; ++ ds->fdb_isolation = true; ++ /* tag_8021q has 3 bits for the VBID, and the value 0 is reserved */ ++ ds->max_num_bridges = 7; ++ ++ /* Advertise the 8 egress queues */ ++ ds->num_tx_queues = NETC_NUM_TC; ++ ++ ds->mtu_enforcement_ingress = true; ++ ds->assisted_learning_on_cpu_port = true; ++ ++ return 0; ++ ++out_devlink_teardown: ++ netc_devlink_teardown(ds); ++out_config_free: ++ netc_config_free(&priv->config); ++ ++ return rc; ++} ++ ++static void netc_teardown(struct dsa_switch *ds) ++{ ++ struct netc_private *priv = ds->priv; ++ ++ rtnl_lock(); ++ dsa_tag_8021q_unregister(ds); ++ rtnl_unlock(); ++ ++ netc_devlink_teardown(ds); ++ netc_config_free(&priv->config); ++} ++ ++static const struct dsa_switch_ops netc_switch_ops = { ++ .get_tag_protocol = netc_get_tag_protocol, ++ .connect_tag_protocol = netc_connect_tag_protocol, ++ .setup = netc_setup, ++ .teardown = netc_teardown, ++ .port_change_mtu = netc_change_mtu, ++ .port_max_mtu = netc_get_max_mtu, ++ .phylink_get_caps = netc_phylink_get_caps, ++ .phylink_mac_link_up = netc_mac_link_up, ++ .phylink_mac_link_down = netc_mac_link_down, ++ .get_strings = netc_get_strings, ++ .get_ethtool_stats = netc_get_ethtool_stats, ++ .get_sset_count = netc_get_sset_count, ++ .port_fdb_dump = netc_fdb_dump, ++ .port_fdb_add = netc_fdb_add, ++ .port_fdb_del = netc_fdb_del, ++ .port_bridge_join = netc_bridge_join, ++ .port_bridge_leave = netc_bridge_leave, ++ .port_vlan_filtering = netc_vlan_filtering, ++ .port_vlan_add = netc_bridge_vlan_add, ++ .port_vlan_del = netc_bridge_vlan_del, ++ .devlink_info_get = netc_devlink_info_get, ++ .tag_8021q_vlan_add = netc_8021q_vlan_add, ++ .tag_8021q_vlan_del = netc_8021q_vlan_del, ++ .port_prechangeupper = netc_prechangeupper, ++}; ++ ++static const struct of_device_id netc_dt_ids[]; ++static int netc_check_device_id(struct netc_private *priv) ++{ ++ struct device *dev = &priv->spidev->dev; ++ struct netc_config *config = &priv->config; ++ int rc; ++ ++ rc = netc_get_devinfo(priv, config); ++ if (rc < 0) ++ return rc; ++ ++ if (config->device_id != priv->info->device_id) { ++ dev_err(dev, "Device tree specifies device ID 0x%x, but found 0x%x please fix it!\n", ++ priv->info->device_id, config->device_id); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int netc_probe(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ struct netc_private *priv; ++ struct dsa_switch *ds; ++ size_t max_xfer, max_msg; ++ int rc; ++ ++ if (!dev->of_node) { ++ dev_err(dev, "No DTS bindings for netc driver\n"); ++ return -EINVAL; ++ } ++ ++ priv = devm_kzalloc(dev, sizeof(struct netc_private), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ /* ++ * Populate our driver private structure (priv) based on ++ * the device tree node that was probed (spi) ++ */ ++ priv->spidev = spi; ++ spi_set_drvdata(spi, priv); ++ ++ /* Configure the SPI bus */ ++ spi->bits_per_word = NETC_SPI_WORD_BITS; ++ rc = spi_setup(spi); ++ if (rc < 0) { ++ dev_err(dev, "Could not init SPI\n"); ++ return rc; ++ } ++ ++ max_xfer = spi_max_transfer_size(spi); ++ max_msg = spi_max_message_size(spi); ++ ++ /* ++ * We need to send at least one 64-bit word of SPI payload per message ++ * in order to be able to make useful progress. ++ */ ++ if (max_msg < NETC_SPI_MSG_HEADER_SIZE + 8) { ++ dev_err(dev, "SPI master cannot send large enough buffers, aborting\n"); ++ return -EINVAL; ++ } ++ ++ priv->max_xfer_len = NETC_SPI_MSG_MAXLEN; ++ if (priv->max_xfer_len > max_xfer) ++ priv->max_xfer_len = max_xfer; ++ if (priv->max_xfer_len > max_msg - NETC_SPI_MSG_HEADER_SIZE) ++ priv->max_xfer_len = max_msg - NETC_SPI_MSG_HEADER_SIZE; ++ ++ priv->info = of_device_get_match_data(dev); ++ ++ /* Detect hardware device */ ++ rc = netc_check_device_id(priv); ++ if (rc < 0) { ++ dev_err(dev, "Device ID check failed: %d\n", rc); ++ return rc; ++ } ++ ++ dev_info(dev, "Probed switch chip:%s ID:0x%x firmware:%d.%d.%d\n", ++ priv->info->name, ++ priv->config.device_id, ++ priv->config.version_major, ++ priv->config.version_minor, ++ priv->config.version_revision); ++ ++ ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); ++ if (!ds) ++ return -ENOMEM; ++ ++ ds->dev = dev; ++ ds->num_ports = priv->info->num_ports; ++ ds->ops = &netc_switch_ops; ++ ds->priv = priv; ++ priv->ds = ds; ++ ++ mutex_init(&priv->mgmt_lock); ++ ++ rc = netc_parse_dt(priv); ++ if (rc < 0) { ++ dev_err(ds->dev, "Failed to parse DT: %d\n", rc); ++ return rc; ++ } ++ ++ return dsa_register_switch(priv->ds); ++} ++ ++static void netc_remove(struct spi_device *spi) ++{ ++ struct netc_private *priv = spi_get_drvdata(spi); ++ ++ if (!priv) ++ return; ++ ++ dsa_unregister_switch(priv->ds); ++} ++ ++static void netc_shutdown(struct spi_device *spi) ++{ ++ struct netc_private *priv = spi_get_drvdata(spi); ++ ++ if (!priv) ++ return; ++ ++ dsa_switch_shutdown(priv->ds); ++ ++ spi_set_drvdata(spi, NULL); ++} ++ ++const struct netc_info netc_info = { ++ .device_id = NETC_RT1180_DEVICE_ID, ++ .tag_proto = DSA_TAG_PROTO_NETC_VALUE, ++ .can_limit_mcast_flood = false, ++ .num_ports = NETC_NUM_PORTS, ++ .name = "netc", ++}; ++ ++static const struct of_device_id netc_dt_ids[] = { ++ { .compatible = "nxp,imxrt1180-netc", .data = &netc_info}, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, netc_dt_ids); ++ ++static const struct spi_device_id netc_spi_ids[] = { ++ { "imxrt1180-netc" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(spi, netc_spi_ids); ++ ++static struct spi_driver netc_driver = { ++ .driver = { ++ .name = "netc-spi", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(netc_dt_ids), ++ }, ++ .id_table = netc_spi_ids, ++ .probe = netc_probe, ++ .remove = netc_remove, ++ .shutdown = netc_shutdown, ++}; ++ ++module_spi_driver(netc_driver); ++ ++MODULE_AUTHOR("Minghuan Lian "); ++ ++MODULE_DESCRIPTION("NETC DSA Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/net/dsa/netc/netc_ptp.c b/drivers/net/dsa/netc/netc_ptp.c +new file mode 100644 +index 000000000000..de5fda25702d +--- /dev/null ++++ b/drivers/net/dsa/netc/netc_ptp.c +@@ -0,0 +1,12 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include "netc.h" ++ ++void netc_ptp_txtstamp_skb(struct dsa_switch *ds, int port, ++ struct sk_buff *skb) ++{ ++ /* To update tx timestamp in the skb */ ++} +diff --git a/drivers/net/dsa/netc/netc_spi.c b/drivers/net/dsa/netc/netc_spi.c +new file mode 100644 +index 000000000000..056501bfdd76 +--- /dev/null ++++ b/drivers/net/dsa/netc/netc_spi.c +@@ -0,0 +1,119 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include ++#include "netc.h" ++ ++int netc_xfer_cmd(const struct netc_private *priv, ++ enum netc_spi_rw_mode rw, enum netc_cmd cmd, ++ void *param, size_t param_len, ++ void *resp, size_t resp_len) ++{ ++ struct netc_cmd_hdr hdr = {0}; ++ struct spi_device *spi = priv->spidev; ++ struct spi_transfer hdr_xfer, resp_xfer; ++ int rc; ++ ++ if (!IS_ALIGNED(resp_len, NETC_SPI_MSG_WORD_BYTES)) { ++ dev_err(&spi->dev, "netc cmd %d data size should be a multiple of 4 : %ld", ++ cmd, resp_len); ++ return -EINVAL; ++ } ++ ++ if (resp_len > priv->max_xfer_len) { ++ dev_err(&spi->dev, "netc cmd %d data size is too large\n", ++ cmd); ++ return -EINVAL; ++ } ++ ++ if (param_len > NETC_SPI_MSG_PARAM_SIZE) { ++ dev_err(&spi->dev, "netc cmd %d param size is too large\n", ++ cmd); ++ return -EINVAL; ++ } ++ ++ hdr.cmd = (rw << NETC_CMD_DIR_SHIFT) | ++ ((resp_len / NETC_SPI_MSG_WORD_BYTES) << ++ NETC_CMD_LEN_SHIFT) | ++ cmd; ++ if (param) ++ memcpy(hdr.param, param, param_len); ++ ++ hdr_xfer.tx_buf = &hdr; ++ hdr_xfer.len = NETC_SPI_MSG_HEADER_SIZE; ++ ++ rc = spi_sync_transfer(spi, &hdr_xfer, 1); ++ if (rc < 0) { ++ dev_err(&spi->dev, "netc cmd %d SPI transfer failed: %d\n", ++ cmd, rc); ++ return rc; ++ } ++ ++ usleep_range(NETC_SPI_MSG_RESPONSE_TIME, ++ NETC_SPI_MSG_RESPONSE_TIME * 10); ++ ++ if (!resp) ++ return 0; ++ ++ /* Populate the transfer's data buffer */ ++ if (rw == SPI_READ) ++ resp_xfer.rx_buf = resp; ++ else ++ resp_xfer.tx_buf = resp; ++ resp_xfer.len = resp_len; ++ ++ rc = spi_sync_transfer(spi, &resp_xfer, 1); ++ if (rc < 0) { ++ dev_err(&spi->dev, "netc cmd %d SPI transfer failed: %d\n", ++ cmd, rc); ++ return rc; ++ } ++ ++ usleep_range(NETC_SPI_MSG_RESPONSE_TIME, ++ NETC_SPI_MSG_RESPONSE_TIME * 10); ++ ++ return 0; ++} ++ ++int netc_xfer_set_cmd(const struct netc_private *priv, ++ enum netc_cmd cmd, ++ void *param, size_t param_len) ++{ ++ return netc_xfer_cmd(priv, SPI_WRITE, cmd, ++ param, param_len, ++ NULL, 0); ++} ++ ++int netc_xfer_get_cmd(const struct netc_private *priv, ++ enum netc_cmd cmd, uint32_t id, ++ void *resp, size_t resp_len) ++{ ++ struct netc_cmd_read_param param; ++ ++ param.id = id; ++ ++ return netc_xfer_cmd(priv, SPI_READ, cmd, ++ ¶m, sizeof(param), ++ resp, resp_len); ++} ++ ++int netc_xfer_write_reg(const struct netc_private *priv, ++ uint32_t reg, uint32_t value) ++{ ++ struct netc_cmd_reg_cmd reg_cmd; ++ ++ reg_cmd.reg = reg; ++ reg_cmd.value = value; ++ ++ return netc_xfer_set_cmd(priv, NETC_CMD_REG_SET, ++ ®_cmd, sizeof(reg_cmd)); ++} ++ ++int netc_xfer_read_reg(const struct netc_private *priv, ++ uint32_t reg, uint32_t *value) ++{ ++ return netc_xfer_get_cmd(priv, NETC_CMD_REG_GET, reg, ++ value, sizeof(*value)); ++} +diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c +index c8b45a131d77..f84020593ff2 100644 +--- a/drivers/net/dsa/ocelot/felix.c ++++ b/drivers/net/dsa/ocelot/felix.c +@@ -1025,17 +1025,49 @@ static int felix_vlan_add(struct dsa_switch *ds, int port, + if (err) + return err; + +- return ocelot_vlan_add(ocelot, port, vlan->vid, +- flags & BRIDGE_VLAN_INFO_PVID, +- flags & BRIDGE_VLAN_INFO_UNTAGGED); ++ err = ocelot_vlan_add(ocelot, port, vlan->vid, ++ flags & BRIDGE_VLAN_INFO_PVID, ++ flags & BRIDGE_VLAN_INFO_UNTAGGED); ++ if (err) ++ return err; ++ ++ if (vlan->proto == ETH_P_8021AD) { ++ if (!ocelot->qinq_enable) { ++ ocelot->qinq_enable = true; ++ kref_init(&ocelot->qinq_refcount); ++ } else { ++ kref_get(&ocelot->qinq_refcount); ++ } ++ } ++ ++ return 0; + } + ++static void felix_vlan_qinq_release(struct kref *ref) ++{ ++ struct ocelot *ocelot; ++ ++ ocelot = container_of(ref, struct ocelot, qinq_refcount); ++ ocelot->qinq_enable = false; ++} + static int felix_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) + { + struct ocelot *ocelot = ds->priv; ++ int err; + +- return ocelot_vlan_del(ocelot, port, vlan->vid); ++ err = ocelot_vlan_del(ocelot, port, vlan->vid); ++ if (err) { ++ dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n", ++ vlan->vid, port, err); ++ return err; ++ } ++ ++ if (ocelot->qinq_enable && vlan->proto == ETH_P_8021AD) ++ kref_put(&ocelot->qinq_refcount, ++ felix_vlan_qinq_release); ++ ++ return 0; + } + + static void felix_phylink_get_caps(struct dsa_switch *ds, int port, +@@ -1083,9 +1115,13 @@ static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, + phy_interface_t interface) + { + struct ocelot *ocelot = ds->priv; ++ struct felix *felix = ocelot_to_felix(ocelot); + + ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface, + FELIX_MAC_QUIRKS); ++ ++ if (felix->info->port_preempt_reset) ++ felix->info->port_preempt_reset(ocelot, port, 0); + } + + static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, +@@ -1247,6 +1283,44 @@ static int felix_validate_phy_mode(struct felix *felix, int port, + return -EOPNOTSUPP; + } + ++static int felix_reset_preempt(struct dsa_switch *ds, int port, bool enable) ++{ ++ struct ocelot *ocelot = ds->priv; ++ struct felix *felix = ocelot_to_felix(ocelot); ++ ++ if (felix->info->port_preempt_reset) { ++ felix->info->port_preempt_reset(ocelot, port, enable); ++ ++ return 0; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++static int felix_set_preempt(struct dsa_switch *ds, int port, ++ struct ethtool_fp *fpcmd) ++{ ++ struct ocelot *ocelot = ds->priv; ++ struct felix *felix = ocelot_to_felix(ocelot); ++ ++ if (felix->info->port_set_preempt) ++ return felix->info->port_set_preempt(ocelot, port, fpcmd); ++ ++ return -EOPNOTSUPP; ++} ++ ++static int felix_get_preempt(struct dsa_switch *ds, int port, ++ struct ethtool_fp *fpcmd) ++{ ++ struct ocelot *ocelot = ds->priv; ++ struct felix *felix = ocelot_to_felix(ocelot); ++ ++ if (felix->info->port_get_preempt) ++ return felix->info->port_get_preempt(ocelot, port, fpcmd); ++ ++ return -EOPNOTSUPP; ++} ++ + static int felix_parse_ports_node(struct felix *felix, + struct device_node *ports_node, + phy_interface_t *port_phy_modes) +@@ -1549,6 +1623,97 @@ static int felix_connect_tag_protocol(struct dsa_switch *ds, + } + } + ++static int felix_qinq_port_bitmap_get(struct dsa_switch *ds, u32 *bitmap) ++{ ++ struct ocelot *ocelot = ds->priv; ++ struct ocelot_port *ocelot_port; ++ int port; ++ ++ *bitmap = 0; ++ for (port = 0; port < ds->num_ports; port++) { ++ ocelot_port = ocelot->ports[port]; ++ if (ocelot_port->qinq_mode) ++ *bitmap |= 0x01 << port; ++ } ++ ++ return 0; ++} ++ ++static int felix_qinq_port_bitmap_set(struct dsa_switch *ds, u32 bitmap) ++{ ++ struct ocelot *ocelot = ds->priv; ++ struct ocelot_port *ocelot_port; ++ int port; ++ ++ for (port = 0; port < ds->num_ports; port++) { ++ ocelot_port = ocelot->ports[port]; ++ if (bitmap & (0x01 << port)) ++ ocelot_port->qinq_mode = true; ++ else ++ ocelot_port->qinq_mode = false; ++ } ++ ++ return 0; ++} ++ ++enum felix_devlink_param_id { ++ FELIX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, ++ FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP, ++}; ++ ++static int felix_devlink_param_get(struct dsa_switch *ds, u32 id, ++ struct devlink_param_gset_ctx *ctx) ++{ ++ int err; ++ ++ switch (id) { ++ case FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP: ++ err = felix_qinq_port_bitmap_get(ds, &ctx->val.vu32); ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ return err; ++} ++ ++static int felix_devlink_param_set(struct dsa_switch *ds, u32 id, ++ struct devlink_param_gset_ctx *ctx) ++{ ++ int err; ++ ++ switch (id) { ++ case FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP: ++ err = felix_qinq_port_bitmap_set(ds, ctx->val.vu32); ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ return err; ++} ++ ++static const struct devlink_param felix_devlink_params[] = { ++ DSA_DEVLINK_PARAM_DRIVER(FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP, ++ "qinq_port_bitmap", ++ DEVLINK_PARAM_TYPE_U32, ++ BIT(DEVLINK_PARAM_CMODE_RUNTIME)), ++}; ++ ++static int felix_setup_devlink_params(struct dsa_switch *ds) ++{ ++ return dsa_devlink_params_register(ds, felix_devlink_params, ++ ARRAY_SIZE(felix_devlink_params)); ++} ++ ++static void felix_teardown_devlink_params(struct dsa_switch *ds) ++{ ++ dsa_devlink_params_unregister(ds, felix_devlink_params, ++ ARRAY_SIZE(felix_devlink_params)); ++} ++ + /* Hardware initialization done here so that we can allocate structures with + * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing + * us to allocate structures twice (leak memory) and map PCI memory twice +@@ -1601,6 +1766,10 @@ static int felix_setup(struct dsa_switch *ds) + ds->fdb_isolation = true; + ds->max_num_bridges = ds->num_ports; + ++ err = felix_setup_devlink_params(ds); ++ if (err < 0) ++ return err; ++ + return 0; + + out_deinit_ports: +@@ -1628,6 +1797,8 @@ static void felix_teardown(struct dsa_switch *ds) + felix->tag_proto_ops->teardown(ds); + rtnl_unlock(); + ++ felix_teardown_devlink_params(ds); ++ + dsa_switch_for_each_available_port(dp, ds) + ocelot_deinit_port(ocelot, dp->index); + +@@ -2080,6 +2251,9 @@ const struct dsa_switch_ops felix_switch_ops = { + .get_ethtool_stats = felix_get_ethtool_stats, + .get_sset_count = felix_get_sset_count, + .get_ts_info = felix_get_ts_info, ++ .reset_preempt = felix_reset_preempt, ++ .set_preempt = felix_set_preempt, ++ .get_preempt = felix_get_preempt, + .phylink_get_caps = felix_phylink_get_caps, + .phylink_validate = felix_phylink_validate, + .phylink_mac_select_pcs = felix_phylink_mac_select_pcs, +@@ -2135,6 +2309,8 @@ const struct dsa_switch_ops felix_switch_ops = { + .port_mrp_del_ring_role = felix_mrp_del_ring_role, + .tag_8021q_vlan_add = felix_tag_8021q_vlan_add, + .tag_8021q_vlan_del = felix_tag_8021q_vlan_del, ++ .devlink_param_get = felix_devlink_param_get, ++ .devlink_param_set = felix_devlink_param_set, + .port_get_default_prio = felix_port_get_default_prio, + .port_set_default_prio = felix_port_set_default_prio, + .port_get_dscp_prio = felix_port_get_dscp_prio, +diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h +index 0e57f9d518be..72bb1b687237 100644 +--- a/drivers/net/dsa/ocelot/felix.h ++++ b/drivers/net/dsa/ocelot/felix.h +@@ -61,6 +61,11 @@ struct felix_info { + void (*tas_guard_bands_update)(struct ocelot *ocelot, int port); + void (*port_sched_speed_set)(struct ocelot *ocelot, int port, + int speed); ++ int (*port_set_preempt)(struct ocelot *ocelot, int port, ++ struct ethtool_fp *fpcmd); ++ int (*port_get_preempt)(struct ocelot *ocelot, int port, ++ struct ethtool_fp *fpcmd); ++ void (*port_preempt_reset)(struct ocelot *ocelot, int port, bool enable); + }; + + /* Methods for initializing the hardware resources specific to a tagging +diff --git a/drivers/net/dsa/ocelot/felix_tsn.c b/drivers/net/dsa/ocelot/felix_tsn.c +index 302e21c7fddf..fd0ea4cd7d7b 100644 +--- a/drivers/net/dsa/ocelot/felix_tsn.c ++++ b/drivers/net/dsa/ocelot/felix_tsn.c +@@ -498,10 +498,12 @@ static int felix_cb_streamid_set(struct net_device *ndev, u32 index, bool enable + if (!stream) + return -EINVAL; + ++ dst_idx = stream->dst_idx; + ocelot_mact_forget(ocelot, stream->mac, stream->vid); ++ + felix_stream_table_del(index); + +- felix_streamid_force_forward_clear(ocelot, stream->dst_idx); ++ felix_streamid_force_forward_clear(ocelot, dst_idx); + + return 0; + } +@@ -1536,7 +1538,7 @@ static int felix_pcpmap_set(struct net_device *ndev, + ocelot = dp->ds->priv; + port = dp->index; + +- index = (c->pcp & GENMASK(2, 0)) * ((c->dei & BIT(0)) + 1); ++ index = (c->dei & BIT(0)) * 8 + (c->pcp & GENMASK(2, 0)); + + ocelot_rmw_ix(ocelot, + (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & (c->dpl << 3)) | +diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c +index 871a3f68b3ef..18d51bda4052 100644 +--- a/drivers/net/dsa/ocelot/felix_vsc9959.c ++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2663,6 +2664,103 @@ static const struct ocelot_ops vsc9959_ops = { + .update_stats = vsc9959_update_stats, + }; + ++static void vsc9959_port_preempt_reset(struct ocelot *ocelot, int port, bool enable) ++{ ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ ++ ocelot_port_rmwl(ocelot_port, 0, ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA | ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA, ++ DEV_MM_ENABLE_CONFIG); ++ ++ if (enable) { ++ if (ocelot_port->fp_enabled_admin) { ++ ocelot_port_rmwl(ocelot_port, ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA | ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA, ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA | ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA, ++ DEV_MM_ENABLE_CONFIG); ++ } ++ } ++} ++ ++static int vsc9959_port_set_preempt(struct ocelot *ocelot, int port, ++ struct ethtool_fp *fpcmd) ++{ ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ struct felix *felix = ocelot_to_felix(ocelot); ++ int p_queues = fpcmd->preemptible_queues_mask; ++ int mm_fragsize, val; ++ ++ if (!fpcmd->disabled && ++ (fpcmd->min_frag_size < 60 || fpcmd->min_frag_size > 252)) ++ return -EINVAL; ++ ++ mm_fragsize = DIV_ROUND_UP((fpcmd->min_frag_size + 4), 64) - 1; ++ ++ if (!fpcmd->disabled) { ++ val = DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA | ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA; ++ ocelot_port->fp_enabled_admin = 1; ++ } else { ++ val = 0; ++ ocelot_port->fp_enabled_admin = 0; ++ } ++ ++ ocelot_port_rmwl(ocelot_port, val, ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA | ++ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA, ++ DEV_MM_ENABLE_CONFIG); ++ ++ ocelot_port_rmwl(ocelot_port, ++ (fpcmd->fp_enabled ? ++ 0 : DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS), ++ DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS, ++ DEV_MM_VERIF_CONFIG); ++ ++ ocelot_rmw_rix(ocelot, ++ QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE(mm_fragsize) | ++ QSYS_PREEMPTION_CFG_P_QUEUES(p_queues), ++ QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_M | ++ QSYS_PREEMPTION_CFG_P_QUEUES_M, ++ QSYS_PREEMPTION_CFG, ++ port); ++ ++ ocelot_port->preemptable_prios = p_queues; ++ ++ if (ocelot_port->taprio && felix->info->tas_guard_bands_update) ++ felix->info->tas_guard_bands_update(ocelot, port); ++ ++ return 0; ++} ++ ++static int vsc9959_port_get_preempt(struct ocelot *ocelot, int port, ++ struct ethtool_fp *fpcmd) ++{ ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ u8 fragsize; ++ u32 val; ++ ++ fpcmd->fp_supported = 1; ++ fpcmd->supported_queues_mask = GENMASK(7, 0); ++ ++ val = ocelot_port_readl(ocelot_port, DEV_MM_STATUS); ++ val &= DEV_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS; ++ fpcmd->fp_active = (val ? 1 : 0); ++ ++ val = ocelot_port_readl(ocelot_port, DEV_MM_ENABLE_CONFIG); ++ val &= DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA; ++ fpcmd->fp_status = val; ++ ++ val = ocelot_read_rix(ocelot, QSYS_PREEMPTION_CFG, port); ++ fpcmd->preemptible_queues_mask = val & QSYS_PREEMPTION_CFG_P_QUEUES_M; ++ fragsize = QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(val); ++ fpcmd->min_frag_size = (fragsize + 1) * 64 - 4; ++ ++ return 0; ++} ++ + static const struct felix_info felix_info_vsc9959 = { + .resources = vsc9959_resources, + .num_resources = ARRAY_SIZE(vsc9959_resources), +@@ -2688,6 +2786,9 @@ static const struct felix_info felix_info_vsc9959 = { + .port_setup_tc = vsc9959_port_setup_tc, + .port_sched_speed_set = vsc9959_sched_speed_set, + .tas_guard_bands_update = vsc9959_tas_guard_bands_update, ++ .port_set_preempt = vsc9959_port_set_preempt, ++ .port_get_preempt = vsc9959_port_get_preempt, ++ .port_preempt_reset = vsc9959_port_preempt_reset, + }; + + static irqreturn_t felix_irq_handler(int irq, void *data) +diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h +index 06e0ebfe652a..0e52b6ceff78 100644 +--- a/drivers/net/dsa/sja1105/sja1105.h ++++ b/drivers/net/dsa/sja1105/sja1105.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include "sja1105_static_config.h" + +@@ -253,6 +254,7 @@ struct sja1105_private { + unsigned long bcast_egress_floods; + unsigned long hwts_tx_en; + unsigned long hwts_rx_en; ++ u32 hostprio; + const struct sja1105_info *info; + size_t max_xfer_len; + struct spi_device *spidev; +@@ -296,6 +298,7 @@ enum sja1105_reset_reason { + SJA1105_SCHEDULING, + SJA1105_BEST_EFFORT_POLICING, + SJA1105_VIRTUAL_LINKS, ++ SJA1105_VLAN_PCP_TO_TXQ_MAPPING, + }; + + int sja1105_static_config_reload(struct sja1105_private *priv, +@@ -303,6 +306,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv, + int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, + struct netlink_ext_ack *extack); + void sja1105_frame_memory_partitioning(struct sja1105_private *priv); ++int sja1105_setup_tc_mqprio(struct dsa_switch *ds, int port, ++ struct tc_mqprio_qopt_offload *mqprio); + + /* From sja1105_mdio.c */ + int sja1105_mdiobus_register(struct dsa_switch *ds); +diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c +index e3699f76f6d7..08a3e7b96254 100644 +--- a/drivers/net/dsa/sja1105/sja1105_clocking.c ++++ b/drivers/net/dsa/sja1105/sja1105_clocking.c +@@ -153,14 +153,14 @@ static int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv, + { + const struct sja1105_regs *regs = priv->info->regs; + struct sja1105_cgu_mii_ctrl mii_tx_clk; +- const int mac_clk_sources[] = { ++ static const int mac_clk_sources[] = { + CLKSRC_MII0_TX_CLK, + CLKSRC_MII1_TX_CLK, + CLKSRC_MII2_TX_CLK, + CLKSRC_MII3_TX_CLK, + CLKSRC_MII4_TX_CLK, + }; +- const int phy_clk_sources[] = { ++ static const int phy_clk_sources[] = { + CLKSRC_IDIV0, + CLKSRC_IDIV1, + CLKSRC_IDIV2, +@@ -194,7 +194,7 @@ sja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port) + const struct sja1105_regs *regs = priv->info->regs; + struct sja1105_cgu_mii_ctrl mii_rx_clk; + u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0}; +- const int clk_sources[] = { ++ static const int clk_sources[] = { + CLKSRC_MII0_RX_CLK, + CLKSRC_MII1_RX_CLK, + CLKSRC_MII2_RX_CLK, +@@ -221,7 +221,7 @@ sja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port) + const struct sja1105_regs *regs = priv->info->regs; + struct sja1105_cgu_mii_ctrl mii_ext_tx_clk; + u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0}; +- const int clk_sources[] = { ++ static const int clk_sources[] = { + CLKSRC_IDIV0, + CLKSRC_IDIV1, + CLKSRC_IDIV2, +@@ -248,7 +248,7 @@ sja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port) + const struct sja1105_regs *regs = priv->info->regs; + struct sja1105_cgu_mii_ctrl mii_ext_rx_clk; + u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0}; +- const int clk_sources[] = { ++ static const int clk_sources[] = { + CLKSRC_IDIV0, + CLKSRC_IDIV1, + CLKSRC_IDIV2, +@@ -349,8 +349,13 @@ static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv, + if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) { + clksrc = CLKSRC_PLL0; + } else { +- int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2, +- CLKSRC_IDIV3, CLKSRC_IDIV4}; ++ static const int clk_sources[] = { ++ CLKSRC_IDIV0, ++ CLKSRC_IDIV1, ++ CLKSRC_IDIV2, ++ CLKSRC_IDIV3, ++ CLKSRC_IDIV4, ++ }; + clksrc = clk_sources[port]; + } + +@@ -638,7 +643,7 @@ static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv, + const struct sja1105_regs *regs = priv->info->regs; + struct sja1105_cgu_mii_ctrl ref_clk; + u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0}; +- const int clk_sources[] = { ++ static const int clk_sources[] = { + CLKSRC_MII0_TX_CLK, + CLKSRC_MII1_TX_CLK, + CLKSRC_MII2_TX_CLK, +diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c +index f1f1368e8146..f8b220ed97ff 100644 +--- a/drivers/net/dsa/sja1105/sja1105_main.c ++++ b/drivers/net/dsa/sja1105/sja1105_main.c +@@ -863,7 +863,7 @@ static int sja1105_init_general_params(struct sja1105_private *priv) + /* Priority queue for link-local management frames + * (both ingress to and egress from CPU - PTP, STP etc) + */ +- .hostprio = 7, ++ .hostprio = priv->hostprio, + .mac_fltres1 = SJA1105_LINKLOCAL_FILTER_A, + .mac_flt1 = SJA1105_LINKLOCAL_FILTER_A_MASK, + .incl_srcpt1 = true, +@@ -1256,6 +1256,15 @@ static int sja1105_parse_dt(struct sja1105_private *priv) + return -ENODEV; + } + ++ if (of_property_read_u32(switch_node, "hostprio", &priv->hostprio) < 0) { ++ priv->hostprio = 7; ++ } else if (priv->hostprio >= SJA1105_NUM_TC) { ++ dev_err(dev, "Out of range hostprio, must be between 0 and %d\n", (SJA1105_NUM_TC - 1)); ++ return -ERANGE; ++ } ++ ++ dev_info(dev, "Configured hostprio: using queue %u\n", priv->hostprio); ++ + rc = sja1105_parse_ports_node(priv, ports_node); + of_node_put(ports_node); + +@@ -2282,6 +2291,7 @@ static const char * const sja1105_reset_reasons[] = { + [SJA1105_SCHEDULING] = "Time-aware scheduling", + [SJA1105_BEST_EFFORT_POLICING] = "Best-effort policing", + [SJA1105_VIRTUAL_LINKS] = "Virtual links", ++ SJA1105_VLAN_PCP_TO_TXQ_MAPPING] = "VLAN PCP to TX queue mapping", + }; + + /* For situations where we need to change a setting at runtime that is only +@@ -2433,6 +2443,56 @@ sja1105_get_tag_protocol(struct dsa_switch *ds, int port, + return priv->info->tag_proto; + } + ++int sja1105_setup_tc_mqprio(struct dsa_switch *ds, int port, ++ struct tc_mqprio_qopt_offload *mqprio) ++{ ++ struct sja1105_l2_forwarding_entry *l2fwd; ++ struct sja1105_private *priv = ds->priv; ++ struct sja1105_table *table; ++ int pcp, tc; ++ ++ if (mqprio->qopt.num_tc > SJA1105_MAX_NUM_PCP) { ++ dev_err(ds->dev, ++ "Only a maximum of %u traffic classes are supported by hardware\n", ++ SJA1105_MAX_NUM_PCP); ++ return -ERANGE; ++ } ++ ++ table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING]; ++ ++ l2fwd = table->entries; ++ ++ if (!mqprio->qopt.num_tc) { ++ /* Delete qdisc: reset to default 1:1 mapping. */ ++ for (pcp = 0; pcp < SJA1105_MAX_NUM_PCP; pcp++) ++ l2fwd[ds->num_ports + pcp].vlan_pmap[port] = pcp; ++ } else { ++ /* We restrict a single TXQ per traffic class ++ * The SJA1105 doesn't offer round robin among TXQs of the same priority ++ */ ++ for (tc = 0; tc < mqprio->qopt.num_tc; tc++) { ++ if (mqprio->qopt.count[tc] != 1) { ++ dev_err(ds->dev, ++ "Only a single TXQ per traffic class is supported\n"); ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ /* Use MQPRIO mapping to configure Egress PCP to HW queue mapping. */ ++ for (pcp = 0; pcp < SJA1105_MAX_NUM_PCP; pcp++) ++ l2fwd[ds->num_ports + pcp].vlan_pmap[port] = mqprio->qopt.prio_tc_map[pcp]; ++ } ++ ++ /* Although, the Egress PCP to HW queue mapping (the latter 8 entries) ++ * should be configured dynamically (once max_dynp is properly set: e.g 7), ++ * that did not work in practice. The switch (SJA1105Q) kept using ++ * the old mapping until a switch reset appears and force the reload of ++ * the static configuration. ++ * So, force a switch reset on mapping offload from here. ++ */ ++ return sja1105_static_config_reload(priv, SJA1105_VLAN_PCP_TO_TXQ_MAPPING); ++} ++ + /* The TPID setting belongs to the General Parameters table, + * which can only be partially reconfigured at runtime (and not the TPID). + * So a switch reset is required. +@@ -2834,6 +2894,8 @@ static int sja1105_port_setup_tc(struct dsa_switch *ds, int port, + return sja1105_setup_tc_taprio(ds, port, type_data); + case TC_SETUP_QDISC_CBS: + return sja1105_setup_tc_cbs(ds, port, type_data); ++ case TC_SETUP_QDISC_MQPRIO: ++ return sja1105_setup_tc_mqprio(ds, port, type_data); + default: + return -EOPNOTSUPP; + } +diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c +index e6153848a950..20a06266134e 100644 +--- a/drivers/net/dsa/sja1105/sja1105_tas.c ++++ b/drivers/net/dsa/sja1105/sja1105_tas.c +@@ -527,6 +527,8 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, + if (rc < 0) + return rc; + ++ sja1105_setup_tc_mqprio(ds, port, &admin->mqprio); ++ + return sja1105_static_config_reload(priv, SJA1105_SCHEDULING); + } + +@@ -575,6 +577,8 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, + if (rc < 0) + return rc; + ++ sja1105_setup_tc_mqprio(ds, port, &admin->mqprio); ++ + return sja1105_static_config_reload(priv, SJA1105_SCHEDULING); + } + +diff --git a/drivers/net/ethernet/alacritech/slic.h b/drivers/net/ethernet/alacritech/slic.h +index 4eecbdfff3ff..82071d0e5f7f 100644 +--- a/drivers/net/ethernet/alacritech/slic.h ++++ b/drivers/net/ethernet/alacritech/slic.h +@@ -288,13 +288,13 @@ do { \ + u64_stats_update_end(&(st)->syncp); \ + } while (0) + +-#define SLIC_GET_STATS_COUNTER(newst, st, counter) \ +-{ \ +- unsigned int start; \ ++#define SLIC_GET_STATS_COUNTER(newst, st, counter) \ ++{ \ ++ unsigned int start; \ + do { \ +- start = u64_stats_fetch_begin_irq(&(st)->syncp); \ +- newst = (st)->counter; \ +- } while (u64_stats_fetch_retry_irq(&(st)->syncp, start)); \ ++ start = u64_stats_fetch_begin(&(st)->syncp); \ ++ newst = (st)->counter; \ ++ } while (u64_stats_fetch_retry(&(st)->syncp, start)); \ + } + + struct slic_upr { +diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c +index 444ccef76da2..8da79eedc057 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c ++++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c +@@ -118,9 +118,9 @@ static void ena_safe_update_stat(u64 *src, u64 *dst, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(syncp); ++ start = u64_stats_fetch_begin(syncp); + *(dst) = *src; +- } while (u64_stats_fetch_retry_irq(syncp, start)); ++ } while (u64_stats_fetch_retry(syncp, start)); + } + + static void ena_queue_stats(struct ena_adapter *adapter, u64 **data) +diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c +index 5ce01ac72637..e8ad5ea31aff 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c ++++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c +@@ -3305,10 +3305,10 @@ static void ena_get_stats64(struct net_device *netdev, + tx_ring = &adapter->tx_ring[i]; + + do { +- start = u64_stats_fetch_begin_irq(&tx_ring->syncp); ++ start = u64_stats_fetch_begin(&tx_ring->syncp); + packets = tx_ring->tx_stats.cnt; + bytes = tx_ring->tx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&tx_ring->syncp, start)); + + stats->tx_packets += packets; + stats->tx_bytes += bytes; +@@ -3316,20 +3316,20 @@ static void ena_get_stats64(struct net_device *netdev, + rx_ring = &adapter->rx_ring[i]; + + do { +- start = u64_stats_fetch_begin_irq(&rx_ring->syncp); ++ start = u64_stats_fetch_begin(&rx_ring->syncp); + packets = rx_ring->rx_stats.cnt; + bytes = rx_ring->rx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&rx_ring->syncp, start)); + + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } + + do { +- start = u64_stats_fetch_begin_irq(&adapter->syncp); ++ start = u64_stats_fetch_begin(&adapter->syncp); + rx_drops = adapter->dev_stats.rx_drops; + tx_drops = adapter->dev_stats.tx_drops; +- } while (u64_stats_fetch_retry_irq(&adapter->syncp, start)); ++ } while (u64_stats_fetch_retry(&adapter->syncp, start)); + + stats->rx_dropped = rx_drops; + stats->tx_dropped = tx_drops; +diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c +index 77609dc0a08d..0b2a52199914 100644 +--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c ++++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + MODULE_LICENSE("GPL v2"); +diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +index 2dc8d215a591..7f933175cbda 100644 +--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c ++++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +@@ -948,7 +948,7 @@ unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data) + /* This data should mimic aq_ethtool_queue_rx_stat_names structure */ + do { + count = 0; +- start = u64_stats_fetch_begin_irq(&self->stats.rx.syncp); ++ start = u64_stats_fetch_begin(&self->stats.rx.syncp); + data[count] = self->stats.rx.packets; + data[++count] = self->stats.rx.jumbo_packets; + data[++count] = self->stats.rx.lro_packets; +@@ -965,15 +965,15 @@ unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data) + data[++count] = self->stats.rx.xdp_tx; + data[++count] = self->stats.rx.xdp_invalid; + data[++count] = self->stats.rx.xdp_redirect; +- } while (u64_stats_fetch_retry_irq(&self->stats.rx.syncp, start)); ++ } while (u64_stats_fetch_retry(&self->stats.rx.syncp, start)); + } else { + /* This data should mimic aq_ethtool_queue_tx_stat_names structure */ + do { + count = 0; +- start = u64_stats_fetch_begin_irq(&self->stats.tx.syncp); ++ start = u64_stats_fetch_begin(&self->stats.tx.syncp); + data[count] = self->stats.tx.packets; + data[++count] = self->stats.tx.queue_restarts; +- } while (u64_stats_fetch_retry_irq(&self->stats.tx.syncp, start)); ++ } while (u64_stats_fetch_retry(&self->stats.tx.syncp, start)); + } + + return ++count; +diff --git a/drivers/net/ethernet/asix/ax88796c_main.c b/drivers/net/ethernet/asix/ax88796c_main.c +index 8b7cdf015a16..21376c79f671 100644 +--- a/drivers/net/ethernet/asix/ax88796c_main.c ++++ b/drivers/net/ethernet/asix/ax88796c_main.c +@@ -662,12 +662,12 @@ static void ax88796c_get_stats64(struct net_device *ndev, + s = per_cpu_ptr(ax_local->stats, cpu); + + do { +- start = u64_stats_fetch_begin_irq(&s->syncp); ++ start = u64_stats_fetch_begin(&s->syncp); + rx_packets = u64_stats_read(&s->rx_packets); + rx_bytes = u64_stats_read(&s->rx_bytes); + tx_packets = u64_stats_read(&s->tx_packets); + tx_bytes = u64_stats_read(&s->tx_bytes); +- } while (u64_stats_fetch_retry_irq(&s->syncp, start)); ++ } while (u64_stats_fetch_retry(&s->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c +index 7f876721596c..b751dc8486dc 100644 +--- a/drivers/net/ethernet/broadcom/b44.c ++++ b/drivers/net/ethernet/broadcom/b44.c +@@ -1680,7 +1680,7 @@ static void b44_get_stats64(struct net_device *dev, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&hwstat->syncp); ++ start = u64_stats_fetch_begin(&hwstat->syncp); + + /* Convert HW stats into rtnl_link_stats64 stats. */ + nstat->rx_packets = hwstat->rx_pkts; +@@ -1714,7 +1714,7 @@ static void b44_get_stats64(struct net_device *dev, + /* Carrier lost counter seems to be broken for some devices */ + nstat->tx_carrier_errors = hwstat->tx_carrier_lost; + #endif +- } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); ++ } while (u64_stats_fetch_retry(&hwstat->syncp, start)); + + } + +@@ -2082,12 +2082,12 @@ static void b44_get_ethtool_stats(struct net_device *dev, + do { + data_src = &hwstat->tx_good_octets; + data_dst = data; +- start = u64_stats_fetch_begin_irq(&hwstat->syncp); ++ start = u64_stats_fetch_begin(&hwstat->syncp); + + for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++) + *data_dst++ = *data_src++; + +- } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); ++ } while (u64_stats_fetch_retry(&hwstat->syncp, start)); + } + + static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c +index 425d6ccd5413..f8b1adc389b3 100644 +--- a/drivers/net/ethernet/broadcom/bcmsysport.c ++++ b/drivers/net/ethernet/broadcom/bcmsysport.c +@@ -457,10 +457,10 @@ static void bcm_sysport_update_tx_stats(struct bcm_sysport_priv *priv, + for (q = 0; q < priv->netdev->num_tx_queues; q++) { + ring = &priv->tx_rings[q]; + do { +- start = u64_stats_fetch_begin_irq(&priv->syncp); ++ start = u64_stats_fetch_begin(&priv->syncp); + bytes = ring->bytes; + packets = ring->packets; +- } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); ++ } while (u64_stats_fetch_retry(&priv->syncp, start)); + + *tx_bytes += bytes; + *tx_packets += packets; +@@ -504,9 +504,9 @@ static void bcm_sysport_get_stats(struct net_device *dev, + if (s->stat_sizeof == sizeof(u64) && + s->type == BCM_SYSPORT_STAT_NETDEV64) { + do { +- start = u64_stats_fetch_begin_irq(syncp); ++ start = u64_stats_fetch_begin(syncp); + data[i] = *(u64 *)p; +- } while (u64_stats_fetch_retry_irq(syncp, start)); ++ } while (u64_stats_fetch_retry(syncp, start)); + } else + data[i] = *(u32 *)p; + j++; +@@ -1878,10 +1878,10 @@ static void bcm_sysport_get_stats64(struct net_device *dev, + &stats->tx_packets); + + do { +- start = u64_stats_fetch_begin_irq(&priv->syncp); ++ start = u64_stats_fetch_begin(&priv->syncp); + stats->rx_packets = stats64->rx_packets; + stats->rx_bytes = stats64->rx_bytes; +- } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); ++ } while (u64_stats_fetch_retry(&priv->syncp, start)); + } + + static void bcm_sysport_netif_start(struct net_device *dev) +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h +index be96f1dc0372..d4a862a9fd7d 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h +@@ -4,7 +4,7 @@ + #ifndef __CXGB4_TC_MQPRIO_H__ + #define __CXGB4_TC_MQPRIO_H__ + +-#include ++#include + + #define CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM 128 + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index fdf10318758b..5715b9ab2712 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1919,7 +1919,7 @@ static void gmac_get_stats64(struct net_device *netdev, + + /* Racing with RX NAPI */ + do { +- start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); ++ start = u64_stats_fetch_begin(&port->rx_stats_syncp); + + stats->rx_packets = port->stats.rx_packets; + stats->rx_bytes = port->stats.rx_bytes; +@@ -1931,11 +1931,11 @@ static void gmac_get_stats64(struct net_device *netdev, + stats->rx_crc_errors = port->stats.rx_crc_errors; + stats->rx_frame_errors = port->stats.rx_frame_errors; + +- } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); + + /* Racing with MIB and TX completion interrupts */ + do { +- start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); ++ start = u64_stats_fetch_begin(&port->ir_stats_syncp); + + stats->tx_errors = port->stats.tx_errors; + stats->tx_packets = port->stats.tx_packets; +@@ -1945,15 +1945,15 @@ static void gmac_get_stats64(struct net_device *netdev, + stats->rx_missed_errors = port->stats.rx_missed_errors; + stats->rx_fifo_errors = port->stats.rx_fifo_errors; + +- } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); ++ } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); + + /* Racing with hard_start_xmit */ + do { +- start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); ++ start = u64_stats_fetch_begin(&port->tx_stats_syncp); + + stats->tx_dropped = port->stats.tx_dropped; + +- } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); + + stats->rx_dropped += stats->rx_missed_errors; + } +@@ -2031,18 +2031,18 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, + /* Racing with MIB interrupt */ + do { + p = values; +- start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); ++ start = u64_stats_fetch_begin(&port->ir_stats_syncp); + + for (i = 0; i < RX_STATS_NUM; i++) + *p++ = port->hw_stats[i]; + +- } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); ++ } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); + values = p; + + /* Racing with RX NAPI */ + do { + p = values; +- start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); ++ start = u64_stats_fetch_begin(&port->rx_stats_syncp); + + for (i = 0; i < RX_STATUS_NUM; i++) + *p++ = port->rx_stats[i]; +@@ -2050,13 +2050,13 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, + *p++ = port->rx_csum_stats[i]; + *p++ = port->rx_napi_exits; + +- } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); + values = p; + + /* Racing with TX start_xmit */ + do { + p = values; +- start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); ++ start = u64_stats_fetch_begin(&port->tx_stats_syncp); + + for (i = 0; i < TX_MAX_FRAGS; i++) { + *values++ = port->tx_frag_stats[i]; +@@ -2065,7 +2065,7 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, + *values++ = port->tx_frags_linearized; + *values++ = port->tx_hw_csummed; + +- } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); ++ } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); + } + + static int gmac_get_ksettings(struct net_device *netdev, +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 77edc3d9b505..a29de29bdf23 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -389,10 +389,10 @@ static void be_get_ethtool_stats(struct net_device *netdev, + struct be_rx_stats *stats = rx_stats(rxo); + + do { +- start = u64_stats_fetch_begin_irq(&stats->sync); ++ start = u64_stats_fetch_begin(&stats->sync); + data[base] = stats->rx_bytes; + data[base + 1] = stats->rx_pkts; +- } while (u64_stats_fetch_retry_irq(&stats->sync, start)); ++ } while (u64_stats_fetch_retry(&stats->sync, start)); + + for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) { + p = (u8 *)stats + et_rx_stats[i].offset; +@@ -405,19 +405,19 @@ static void be_get_ethtool_stats(struct net_device *netdev, + struct be_tx_stats *stats = tx_stats(txo); + + do { +- start = u64_stats_fetch_begin_irq(&stats->sync_compl); ++ start = u64_stats_fetch_begin(&stats->sync_compl); + data[base] = stats->tx_compl; +- } while (u64_stats_fetch_retry_irq(&stats->sync_compl, start)); ++ } while (u64_stats_fetch_retry(&stats->sync_compl, start)); + + do { +- start = u64_stats_fetch_begin_irq(&stats->sync); ++ start = u64_stats_fetch_begin(&stats->sync); + for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) { + p = (u8 *)stats + et_tx_stats[i].offset; + data[base + i] = + (et_tx_stats[i].size == sizeof(u64)) ? + *(u64 *)p : *(u32 *)p; + } +- } while (u64_stats_fetch_retry_irq(&stats->sync, start)); ++ } while (u64_stats_fetch_retry(&stats->sync, start)); + base += ETHTOOL_TXSTATS_NUM; + } + } +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index b12152e2fca0..52d6d43e7bfe 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -665,10 +665,10 @@ static void be_get_stats64(struct net_device *netdev, + const struct be_rx_stats *rx_stats = rx_stats(rxo); + + do { +- start = u64_stats_fetch_begin_irq(&rx_stats->sync); ++ start = u64_stats_fetch_begin(&rx_stats->sync); + pkts = rx_stats(rxo)->rx_pkts; + bytes = rx_stats(rxo)->rx_bytes; +- } while (u64_stats_fetch_retry_irq(&rx_stats->sync, start)); ++ } while (u64_stats_fetch_retry(&rx_stats->sync, start)); + stats->rx_packets += pkts; + stats->rx_bytes += bytes; + stats->multicast += rx_stats(rxo)->rx_mcast_pkts; +@@ -680,10 +680,10 @@ static void be_get_stats64(struct net_device *netdev, + const struct be_tx_stats *tx_stats = tx_stats(txo); + + do { +- start = u64_stats_fetch_begin_irq(&tx_stats->sync); ++ start = u64_stats_fetch_begin(&tx_stats->sync); + pkts = tx_stats(txo)->tx_pkts; + bytes = tx_stats(txo)->tx_bytes; +- } while (u64_stats_fetch_retry_irq(&tx_stats->sync, start)); ++ } while (u64_stats_fetch_retry(&tx_stats->sync, start)); + stats->tx_packets += pkts; + stats->tx_bytes += bytes; + } +@@ -2156,16 +2156,16 @@ static int be_get_new_eqd(struct be_eq_obj *eqo) + + for_all_rx_queues_on_eq(adapter, eqo, rxo, i) { + do { +- start = u64_stats_fetch_begin_irq(&rxo->stats.sync); ++ start = u64_stats_fetch_begin(&rxo->stats.sync); + rx_pkts += rxo->stats.rx_pkts; +- } while (u64_stats_fetch_retry_irq(&rxo->stats.sync, start)); ++ } while (u64_stats_fetch_retry(&rxo->stats.sync, start)); + } + + for_all_tx_queues_on_eq(adapter, eqo, txo, i) { + do { +- start = u64_stats_fetch_begin_irq(&txo->stats.sync); ++ start = u64_stats_fetch_begin(&txo->stats.sync); + tx_pkts += txo->stats.tx_reqs; +- } while (u64_stats_fetch_retry_irq(&txo->stats.sync, start)); ++ } while (u64_stats_fetch_retry(&txo->stats.sync, start)); + } + + /* Skip, if wrapped around or first calculation */ +diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig +index 4aaada823a67..c7707f62470c 100644 +--- a/drivers/net/ethernet/freescale/Kconfig ++++ b/drivers/net/ethernet/freescale/Kconfig +@@ -35,6 +35,18 @@ config FEC + Say Y here if you want to use the built-in 10/100 Fast ethernet + controller on some Motorola ColdFire and Freescale i.MX/S32 processors. + ++config FEC_ECAT ++ tristate "FEC native dirver for FEC ethernet controller (of ColdFire and some i.MX CPUs)" ++ depends on (ARCH_MXC) ++ default ARCH_MXC if ARM ++ depends on PTP_1588_CLOCK_OPTIONAL ++ select CRC32 ++ select PHYLIB ++ imply NET_SELFTESTS ++ help ++ Say Y here if you want to use the built-in 10/100 Fast ethercat ++ controller on some Motorola ColdFire and Freescale i.MX/S32 processors. ++ + config FEC_UIO + tristate "FEC_UIO ethernet controller (i.MX 8M Mini CPU)" + default n +@@ -43,6 +55,14 @@ config FEC_UIO + Say Y here if you want to use the built-in 10/100 Fast ethernet + controller on Freescale i.MX 8M Mini processor. + ++config AVB_SUPPORT ++ bool "AVB interface support" ++ depends on FEC && ARCH_MXC ++ help ++ Say Y here if you want to enable the AVB interface in the FEC ++ driver. For the actual AVB functionality an external module is ++ still required. ++ + config FEC_MPC52xx + tristate "FEC MPC52xx driver" + depends on PPC_MPC52xx && PPC_BESTCOMM +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index 13ae9401e4c2..bd3ee981ce54 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -7,6 +7,8 @@ obj-$(CONFIG_FEC) += fec.o + fec-objs :=fec_main.o fec_ptp.o + obj-$(CONFIG_FEC_UIO) += fec_uio.o + ++obj-$(CONFIG_FEC_ECAT) += fec_ecat.o ++ + obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o + ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) + obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h +index 538d9f1587c8..a7877b6e9999 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.h ++++ b/drivers/net/ethernet/freescale/enetc/enetc.h +@@ -396,6 +396,8 @@ struct enetc_ndev_priv { + + struct work_struct tx_onestep_tstamp; + struct sk_buff_head tx_skbs; ++ ++ bool fp_enabled_admin; + }; + + /* Messaging */ +@@ -440,6 +442,7 @@ int enetc_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags); + + /* ethtool */ + void enetc_set_ethtool_ops(struct net_device *ndev); ++int enetc_pmac_reset(struct net_device *ndev, bool enable); + + /* control buffer descriptor ring (CBDR) */ + int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count, +@@ -594,11 +597,13 @@ static inline int enetc_set_psfp(struct net_device *ndev, bool en) + void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev); + void enetc_tsn_pf_deinit(struct net_device *netdev); + void enetc_pspeed_set(struct enetc_ndev_priv *priv, int speed); ++void enetc_ptp_clock_update(void); + + #else + + #define enetc_tsn_pf_init(netdev, pdev) (void)0 + #define enetc_tsn_pf_deinit(netdev) (void)0 + #define enetc_pspeed_set(priv, speed) (void)0 ++#define enetc_ptp_clock_update() (void)0 + + #endif +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +index 5ad52e8c72f6..da33d37a83c2 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +@@ -898,6 +898,56 @@ static int enetc_set_link_ksettings(struct net_device *dev, + return phylink_ethtool_ksettings_set(priv->phylink, cmd); + } + ++static void enetc_configure_port_pmac(struct enetc_hw *hw, bool enable) ++{ ++ u32 temp; ++ ++ /* Set pMAC step lock */ ++ temp = enetc_port_rd(hw, ENETC_PFPMR); ++ enetc_port_wr(hw, ENETC_PFPMR, ++ temp | ENETC_PFPMR_PMACE | ENETC_PFPMR_MWLM); ++ ++ temp = enetc_port_rd(hw, ENETC_MMCSR); ++ if (enable) ++ temp |= ENETC_MMCSR_ME; ++ else ++ temp &= (~ENETC_MMCSR_ME); ++ enetc_port_wr(hw, ENETC_MMCSR, temp); ++} ++ ++int enetc_pmac_reset(struct net_device *ndev, bool enable) ++{ ++ struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ u32 temp; ++ ++ temp = enetc_port_rd(&priv->si->hw, ENETC_PFPMR); ++ if (temp & ENETC_PFPMR_PMACE) ++ enetc_configure_port_pmac(&priv->si->hw, enable); ++ ++ return 0; ++} ++ ++static int enetc_reset_preempt(struct net_device *ndev, bool enable) ++{ ++ struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ u32 temp; ++ ++ temp = enetc_rd(&priv->si->hw, ENETC_PTGCR); ++ if (temp & ENETC_PTGCR_TGE) ++ enetc_wr(&priv->si->hw, ENETC_PTGCR, ++ temp & (~ENETC_PTGCR_TGPE)); ++ ++ if (enable) { ++ if (priv->fp_enabled_admin) { ++ enetc_configure_port_pmac(&priv->si->hw, 1); ++ } ++ } else { ++ enetc_configure_port_pmac(&priv->si->hw, 0); ++ } ++ ++ return 0; ++} ++ + static void enetc_get_channels(struct net_device *ndev, + struct ethtool_channels *chan) + { +@@ -907,6 +957,105 @@ static void enetc_get_channels(struct net_device *ndev, + chan->combined_count = priv->bdr_int_num; + } + ++static int enetc_set_preempt(struct net_device *ndev, ++ struct ethtool_fp *pt) ++{ ++ struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ u32 preempt, temp; ++ int rafs; ++ int i; ++ ++ if (!pt) ++ return -EINVAL; ++ ++ if (!pt->disabled && (pt->min_frag_size < 60 || pt->min_frag_size > 252)) ++ return -EINVAL; ++ ++ rafs = DIV_ROUND_UP((pt->min_frag_size + 4), 64) - 1; ++ ++ preempt = pt->preemptible_queues_mask; ++ ++ temp = enetc_rd(&priv->si->hw, ENETC_PTGCR); ++ if (temp & ENETC_PTGCR_TGE) ++ enetc_wr(&priv->si->hw, ENETC_PTGCR, ++ temp & (~ENETC_PTGCR_TGPE)); ++ ++ for (i = 0; i < 8; i++) { ++ /* 1 Enabled. Traffic is transmitted on the preemptive MAC. */ ++ temp = enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i)); ++ ++ if ((preempt >> i) & 0x1) ++ enetc_port_wr(&priv->si->hw, ++ ENETC_PTCFPR(i), ++ temp | ENETC_FPE); ++ else ++ enetc_port_wr(&priv->si->hw, ++ ENETC_PTCFPR(i), ++ temp & ~ENETC_FPE); ++ } ++ ++ temp = enetc_port_rd(&priv->si->hw, ENETC_MMCSR); ++ temp &= ~ENETC_MMCSR_RAFS_MASK; ++ temp |= ENETC_MMCSR_RAFS(rafs); ++ if (pt->fp_enabled) ++ temp &= ~ENETC_MMCSR_VDIS; ++ else ++ temp |= ENETC_MMCSR_VDIS; ++ enetc_port_wr(&priv->si->hw, ENETC_MMCSR, temp); ++ ++ if (pt->disabled) { ++ enetc_configure_port_pmac(&priv->si->hw, 0); ++ priv->fp_enabled_admin = 0; ++ } else { ++ enetc_configure_port_pmac(&priv->si->hw, 1); ++ priv->fp_enabled_admin = 1; ++ } ++ ++ if (pt->disabled) { ++ temp = enetc_port_rd(&priv->si->hw, ENETC_PFPMR); ++ enetc_port_wr(&priv->si->hw, ENETC_PFPMR, ++ temp & ~(ENETC_PFPMR_PMACE | ENETC_PFPMR_MWLM)); ++ } ++ ++ return 0; ++} ++ ++static int enetc_get_preempt(struct net_device *ndev, ++ struct ethtool_fp *pt) ++{ ++ struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ u32 temp; ++ int i; ++ ++ if (!pt) ++ return -EINVAL; ++ ++ temp = enetc_port_rd(&priv->si->hw, ENETC_MMCSR); ++ if (!(temp & ENETC_MMCSR_VDIS) && (ENETC_MMCSR_GET_VSTS(temp) == 3)) ++ pt->fp_active = true; ++ else if ((temp & ENETC_MMCSR_VDIS) && (temp & ENETC_MMCSR_ME)) ++ pt->fp_active = true; ++ else ++ pt->fp_active = false; ++ ++ if (temp & ENETC_MMCSR_ME) ++ pt->fp_status = true; ++ else ++ pt->fp_status = false; ++ ++ pt->preemptible_queues_mask = 0; ++ for (i = 0; i < 8; i++) ++ if (enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i)) & 0x80000000) ++ pt->preemptible_queues_mask |= 1 << i; ++ ++ pt->fp_supported = !!(priv->si->hw_features & ENETC_SI_F_QBU); ++ pt->supported_queues_mask = 0xff; ++ temp = enetc_port_rd(&priv->si->hw, ENETC_MMCSR); ++ pt->min_frag_size = (ENETC_MMCSR_GET_RAFS(temp) + 1) * 64; ++ ++ return 0; ++} ++ + static const struct ethtool_ops enetc_pf_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES | +@@ -938,6 +1087,9 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = { + .get_pauseparam = enetc_get_pauseparam, + .set_pauseparam = enetc_set_pauseparam, + .get_channels = enetc_get_channels, ++ .set_preempt = enetc_set_preempt, ++ .get_preempt = enetc_get_preempt, ++ .reset_preempt = enetc_reset_preempt, + }; + + static const struct ethtool_ops enetc_vf_ethtool_ops = { +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h +index 85db68c54e82..343a47962187 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h ++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h +@@ -223,7 +223,13 @@ enum enetc_bdr_type {TX, RX}; + #define ENETC_PSIVHFR0(n) (0x1e00 + (n) * 8) /* n = SI index */ + #define ENETC_PSIVHFR1(n) (0x1e04 + (n) * 8) /* n = SI index */ + #define ENETC_MMCSR 0x1f00 ++#define ENETC_MMCSR_VSTS GENMASK(20, 18) ++#define ENETC_MMCSR_GET_VSTS(x) (((x) & ENETC_MMCSR_VSTS) >> 18) ++#define ENETC_MMCSR_VDIS BIT(17) + #define ENETC_MMCSR_ME BIT(16) ++#define ENETC_MMCSR_RAFS_MASK GENMASK(9, 8) ++#define ENETC_MMCSR_RAFS(x) (((x) << 8) & ENETC_MMCSR_RAFS_MASK) ++#define ENETC_MMCSR_GET_RAFS(x) (((x) & ENETC_MMCSR_RAFS_MASK) >> 8) + #define ENETC_PTCMSDUR(n) (0x2020 + (n) * 4) /* n = TC index [0..7] */ + + #define ENETC_PM0_CMD_CFG 0x8008 +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c +index 3e8f2defd67f..08fe4cd64c44 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c +@@ -590,26 +590,11 @@ static void enetc_mac_enable(struct enetc_hw *hw, bool en) + enetc_port_wr(hw, ENETC_PM1_CMD_CFG, val); + } + +-static void enetc_configure_port_pmac(struct enetc_hw *hw) +-{ +- u32 temp; +- +- /* Set pMAC step lock */ +- temp = enetc_port_rd(hw, ENETC_PFPMR); +- enetc_port_wr(hw, ENETC_PFPMR, +- temp | ENETC_PFPMR_PMACE | ENETC_PFPMR_MWLM); +- +- temp = enetc_port_rd(hw, ENETC_MMCSR); +- enetc_port_wr(hw, ENETC_MMCSR, temp | ENETC_MMCSR_ME); +-} +- + static void enetc_configure_port(struct enetc_pf *pf) + { + u8 hash_key[ENETC_RSSHASH_KEY_SIZE]; + struct enetc_hw *hw = &pf->si->hw; + +- enetc_configure_port_pmac(hw); +- + enetc_configure_port_mac(hw); + + enetc_port_si_configure(pf->si); +@@ -1111,6 +1096,7 @@ static void enetc_pl_mac_link_down(struct phylink_config *config, + struct enetc_pf *pf = phylink_to_enetc_pf(config); + + enetc_mac_enable(&pf->si->hw, false); ++ enetc_pmac_reset(pf->si->ndev, 0); + } + + static const struct phylink_mac_ops enetc_mac_phylink_ops = { +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c +index 5243fc031058..9c671494cd95 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c +@@ -10,6 +10,19 @@ + int enetc_phc_index = -1; + EXPORT_SYMBOL_GPL(enetc_phc_index); + ++int ptp_enetc_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) ++{ ++ int ret; ++ ++ ret = ptp_qoriq_settime(ptp, ts); ++ if (ret) ++ return ret; ++ ++ enetc_ptp_clock_update(); ++ ++ return ret; ++} ++ + static struct ptp_clock_info enetc_ptp_caps = { + .owner = THIS_MODULE, + .name = "ENETC PTP clock", +@@ -22,7 +35,7 @@ static struct ptp_clock_info enetc_ptp_caps = { + .adjfine = ptp_qoriq_adjfine, + .adjtime = ptp_qoriq_adjtime, + .gettime64 = ptp_qoriq_gettime, +- .settime64 = ptp_qoriq_settime, ++ .settime64 = ptp_enetc_settime, + .enable = ptp_qoriq_enable, + }; + +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_tsn.c b/drivers/net/ethernet/freescale/enetc/enetc_tsn.c +index 5ff36647be84..091e12c76cfa 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_tsn.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_tsn.c +@@ -1,5 +1,5 @@ + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* Copyright 2017-2019 NXP */ ++/* Copyright 2017-2023 NXP */ + + #include "enetc.h" + +@@ -8,6 +8,13 @@ + #include + #include + ++struct netdev_list_entry { ++ struct list_head list; ++ struct net_device *dev; ++}; ++ ++static struct list_head netdev_list = {0}; ++ + static int alloc_cbdr(struct enetc_si *si, struct enetc_cbd **curr_cbd) + { + struct enetc_cbdr *ring = &si->cbd_ring; +@@ -184,17 +191,8 @@ static int enetc_qbv_set(struct net_device *ndev, + gcl_config->atc = admin_basic->gate_states; + gcl_config->acl_len = cpu_to_le16(gcl_len); + +- if (!admin_basic->base_time) { +- gcl_data->btl = +- cpu_to_le32(enetc_rd(hw, ENETC_SICTR0)); +- gcl_data->bth = +- cpu_to_le32(enetc_rd(hw, ENETC_SICTR1)); +- } else { +- gcl_data->btl = +- cpu_to_le32(lower_32_bits(admin_basic->base_time)); +- gcl_data->bth = +- cpu_to_le32(upper_32_bits(admin_basic->base_time)); +- } ++ gcl_data->btl = cpu_to_le32(lower_32_bits(admin_basic->base_time)); ++ gcl_data->bth = cpu_to_le32(upper_32_bits(admin_basic->base_time)); + + gcl_data->ct = cpu_to_le32(admin_basic->cycle_time); + gcl_data->cte = cpu_to_le32(admin_basic->cycle_time_extension); +@@ -256,8 +254,8 @@ static int enetc_qbv_get(struct net_device *ndev, + { + struct tsn_qbv_basic *admin_basic = &admin_conf->admin; + struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ u16 data_size, admin_len, oper_len, maxlen; + struct enetc_hw *hw = &priv->si->hw; +- u16 data_size, admin_len, maxlen; + struct tgs_gcl_query *gcl_query; + struct tgs_gcl_resp *gcl_data; + struct enetc_cbd *cbdr; +@@ -290,6 +288,7 @@ static int enetc_qbv_get(struct net_device *ndev, + gce = (struct gce *)(gcl_data + 1); + + gcl_query->acl_len = cpu_to_le16(maxlen); ++ gcl_query->ocl_len = cpu_to_le16(maxlen); + + dma_size = cpu_to_le16(data_size); + cbdr->length = dma_size; +@@ -312,8 +311,12 @@ static int enetc_qbv_get(struct net_device *ndev, + + /* since cbdr already passed to free, below could be get wrong */ + admin_len = le16_to_cpu(gcl_query->admin_list_len); ++ oper_len = le16_to_cpu(gcl_query->oper_list_len); + +- admin_basic->control_list_length = admin_len; ++ if (!admin_len) ++ admin_basic->control_list_length = oper_len; ++ else ++ admin_basic->control_list_length = admin_len; + + temp = ((u64)le32_to_cpu(gcl_data->abth)) << 32; + admin_basic->base_time = le32_to_cpu(gcl_data->abtl) + temp; +@@ -321,7 +324,7 @@ static int enetc_qbv_get(struct net_device *ndev, + admin_basic->cycle_time = le32_to_cpu(gcl_data->act); + admin_basic->cycle_time_extension = le32_to_cpu(gcl_data->acte); + +- admin_basic->control_list = kcalloc(admin_len, ++ admin_basic->control_list = kcalloc(admin_basic->control_list_length, + sizeof(*admin_basic->control_list), + GFP_KERNEL); + if (!admin_basic->control_list) { +@@ -330,10 +333,15 @@ static int enetc_qbv_get(struct net_device *ndev, + return -ENOMEM; + } + +- for (i = 0; i < admin_len; i++) { +- struct gce *temp_gce = gce + i; ++ for (i = 0; i < admin_basic->control_list_length; i++) { ++ struct gce *temp_gce; + struct tsn_qbv_entry *temp_entry; + ++ if (!admin_len) ++ temp_gce = gce + maxlen + i; ++ else ++ temp_gce = gce + i; ++ + temp_entry = admin_basic->control_list + i; + + temp_entry->gate_state = temp_gce->gate; +@@ -468,6 +476,120 @@ static int enetc_qbv_get_status(struct net_device *ndev, + return 0; + } + ++static int enetc_qbv_gcl_reset(struct net_device *ndev, ++ struct tsn_qbv_conf *admin_conf) ++{ ++ struct tsn_qbv_basic *admin_basic = &admin_conf->admin; ++ struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ struct enetc_hw *hw = &priv->si->hw; ++ struct tgs_gcl_conf *gcl_config; ++ struct tgs_gcl_data *gcl_data; ++ struct enetc_cbd *cbdr; ++ struct gce *gce; ++ dma_addr_t dma; ++ u16 data_size; ++ int curr_cbd; ++ u16 gcl_len; ++ u32 temp; ++ int i; ++ ++ gcl_len = admin_basic->control_list_length; ++ if (gcl_len > enetc_get_max_gcl_len(hw)) ++ return -EINVAL; ++ ++ temp = enetc_rd(hw, ENETC_PTGCR); ++ if (admin_conf->gate_enabled) { ++ enetc_wr(hw, ENETC_PTGCR, temp & ~ENETC_PTGCR_TGE); ++ usleep_range(10, 20); ++ enetc_wr(hw, ENETC_PTGCR, temp | ENETC_PTGCR_TGE); ++ } else if (!admin_conf->gate_enabled) { ++ return 0; ++ } ++ ++ /* Configure the (administrative) gate control list using the ++ * control BD descriptor. ++ */ ++ curr_cbd = alloc_cbdr(priv->si, &cbdr); ++ ++ gcl_config = &cbdr->gcl_conf; ++ ++ data_size = struct_size(gcl_data, entry, gcl_len); ++ ++ gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL); ++ if (!gcl_data) ++ return -ENOMEM; ++ ++ gce = &gcl_data->entry[0]; ++ ++ gcl_config->atc = admin_basic->gate_states; ++ gcl_config->acl_len = cpu_to_le16(gcl_len); ++ ++ gcl_data->btl = cpu_to_le32(lower_32_bits(admin_basic->base_time)); ++ gcl_data->bth = cpu_to_le32(upper_32_bits(admin_basic->base_time)); ++ ++ gcl_data->ct = cpu_to_le32(admin_basic->cycle_time); ++ gcl_data->cte = cpu_to_le32(admin_basic->cycle_time_extension); ++ ++ for (i = 0; i < gcl_len; i++) { ++ struct gce *temp_gce = gce + i; ++ struct tsn_qbv_entry *temp_entry; ++ ++ temp_entry = admin_basic->control_list + i; ++ ++ temp_gce->gate = temp_entry->gate_state; ++ temp_gce->period = cpu_to_le32(temp_entry->time_interval); ++ } ++ ++ cbdr->length = cpu_to_le16(data_size); ++ cbdr->status_flags = 0; ++ ++ dma = dma_map_single(&priv->si->pdev->dev, gcl_data, ++ data_size, DMA_TO_DEVICE); ++ if (dma_mapping_error(&priv->si->pdev->dev, dma)) { ++ netdev_err(priv->si->ndev, "DMA mapping failed!\n"); ++ kfree(gcl_data); ++ return -ENOMEM; ++ } ++ ++ cbdr->addr[0] = cpu_to_le32(lower_32_bits(dma)); ++ cbdr->addr[1] = cpu_to_le32(upper_32_bits(dma)); ++ cbdr->cmd = 0; ++ cbdr->cls = BDCR_CMD_PORT_GCL; ++ ++ /* Updated by ENETC on completion of the configuration ++ * command. A zero value indicates success. ++ */ ++ cbdr->status_flags = 0; ++ ++ xmit_cbdr(priv->si, curr_cbd); ++ ++ memset(cbdr, 0, sizeof(struct enetc_cbd)); ++ dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE); ++ kfree(gcl_data); ++ ++ return 0; ++} ++ ++static int enetc_est_reset(struct net_device *ndev) ++{ ++ struct tsn_qbv_conf admin_conf = {0}; ++ int ret; ++ ++ ret = enetc_qbv_get(ndev, &admin_conf); ++ if (ret) ++ return ret; ++ ++ return enetc_qbv_gcl_reset(ndev, &admin_conf); ++} ++ ++void enetc_ptp_clock_update() ++{ ++ struct netdev_list_entry *entry; ++ ++ list_for_each_entry(entry, &netdev_list, list) ++ enetc_est_reset(entry->dev); ++} ++ + /* CBD Class 7: Stream Identity Entry Set Descriptor - Long Format */ + static int enetc_cb_streamid_set(struct net_device *ndev, u32 index, + bool en, struct tsn_cb_streamid *streamid) +@@ -1560,6 +1682,14 @@ static int enetc_qbu_set(struct net_device *ndev, u8 ptvector) + temp & ~ENETC_FPE); + } + ++ /* Set pMAC step lock */ ++ temp = enetc_port_rd(&priv->si->hw, ENETC_PFPMR); ++ enetc_port_wr(&priv->si->hw, ENETC_PFPMR, ++ temp | ENETC_PFPMR_PMACE | ENETC_PFPMR_MWLM); ++ ++ temp = enetc_port_rd(&priv->si->hw, ENETC_MMCSR); ++ enetc_port_wr(&priv->si->hw, ENETC_MMCSR, temp | ENETC_MMCSR_ME); ++ + return 0; + } + +@@ -1922,6 +2052,33 @@ static struct tsn_ops enetc_tsn_ops_part = { + .qci_fmi_get = enetc_qci_fmi_get, + }; + ++static void enetc_tsn_netdev_list_add(struct net_device *ndev) ++{ ++ struct netdev_list_entry *entry; ++ ++ entry = kzalloc(sizeof(*entry), GFP_KERNEL); ++ if (!entry) ++ return; ++ ++ entry->dev = ndev; ++ ++ if (!netdev_list.next) ++ INIT_LIST_HEAD(&netdev_list); ++ ++ list_add_tail(&entry->list, &netdev_list); ++} ++ ++static void enetc_tsn_netdev_list_del(struct net_device *ndev) ++{ ++ struct netdev_list_entry *tmp, *n; ++ ++ list_for_each_entry_safe(tmp, n, &netdev_list, list) ++ if (tmp->dev == ndev) { ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++} ++ + void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev) + { + int port = pdev->devfn & 0x7; +@@ -1932,9 +2089,12 @@ void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev) + else + tsn_port_register(netdev, &enetc_tsn_ops_full, + (u16)pdev->bus->number); ++ ++ enetc_tsn_netdev_list_add(netdev); + } + + void enetc_tsn_pf_deinit(struct net_device *netdev) + { + tsn_port_unregister(netdev); ++ enetc_tsn_netdev_list_del(netdev); + } +diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h +index 0465d98795d7..6775eeb3c684 100644 +--- a/drivers/net/ethernet/freescale/fec.h ++++ b/drivers/net/ethernet/freescale/fec.h +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ +@@ -333,30 +334,30 @@ struct bufdesc_ex { + (IDLE_SLOPE_2 & IDLE_SLOPE_MASK)) + #define RCMR_MATCHEN (0x1 << 16) + #define RCMR_CMP_CFG(v, n) (((v) & 0x7) << (n << 2)) ++#ifdef CONFIG_AVB_SUPPORT ++#define SR_CLASS_A_PRIORITY 3 ++#define SR_CLASS_B_PRIORITY 2 ++#define RCMR_CMP_1 (RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 0) | \ ++ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 1) | \ ++ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 2) | \ ++ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 3)) ++#define RCMR_CMP_2 (RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 0) | \ ++ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 1) | \ ++ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 2) | \ ++ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 3)) ++#else + #define RCMR_CMP_1 (RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \ + RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3)) + #define RCMR_CMP_2 (RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \ + RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3)) ++#endif + #define RCMR_CMP(X) (((X) == 1) ? RCMR_CMP_1 : RCMR_CMP_2) + #define FEC_TX_BD_FTYPE(X) (((X) & 0xf) << 20) + +-/* The number of Tx and Rx buffers. These are allocated from the page +- * pool. The code may assume these are power of two, so it it best +- * to keep them that size. +- * We don't need to allocate pages for the transmitter. We just use +- * the skbuffer directly. +- */ ++#define FEC_RX_FLUSH(X) (1 << ((X) + 3)) + +-#define FEC_ENET_XDP_HEADROOM (XDP_PACKET_HEADROOM) +-#define FEC_ENET_RX_PAGES 256 +-#define FEC_ENET_RX_FRSIZE (PAGE_SIZE - FEC_ENET_XDP_HEADROOM \ +- - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +-#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) +-#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) +-#define FEC_ENET_TX_FRSIZE 2048 +-#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE) +-#define TX_RING_SIZE 512 /* Must be power of two */ +-#define TX_RING_MOD_MASK 511 /* for this to work */ ++#define FEC_TX_SCHEME_CB 0x0 /* Credit based */ ++#define FEC_TX_SCHEME_RR 0x1 /* Round-robin */ + + #define BD_ENET_RX_INT 0x00800000 + #define BD_ENET_RX_PTP ((ushort)0x0400) +@@ -401,9 +402,14 @@ struct bufdesc_ex { + #define FEC_ITR_EN (0x1 << 31) + #define FEC_ITR_ICFT(X) (((X) & 0xff) << 20) + #define FEC_ITR_ICTT(X) ((X) & 0xffff) +-#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */ + #define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */ + ++#ifdef CONFIG_AVB_SUPPORT ++#define FEC_ITR_ICFT_DEFAULT 50 /* Keep it coherent with FEC_TX_RING_SIZE/FEC_RX_RING_SIZE */ ++#else ++#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */ ++#endif ++ + #define FEC_VLAN_TAG_LEN 0x04 + #define FEC_ETHTYPE_LEN 0x02 + +@@ -556,20 +562,31 @@ struct fec_tx_buffer { + + struct fec_enet_priv_tx_q { + struct bufdesc_prop bd; +- unsigned char *tx_bounce[TX_RING_SIZE]; +- struct fec_tx_buffer tx_buf[TX_RING_SIZE]; ++ struct bufdesc *dirty_tx; ++ struct fec_tx_buffer tx_buf[FEC_TX_RING_SIZE]; ++ ++ unsigned int tx_bounce_size; + ++#ifdef CONFIG_AVB_SUPPORT ++ unsigned int tx_index; ++ unsigned char *tx_bounce[FEC_TX_RING_SIZE + 32]; ++#else ++ unsigned char *tx_bounce[FEC_TX_RING_SIZE]; ++#endif + unsigned short tx_stop_threshold; + unsigned short tx_wake_threshold; + +- struct bufdesc *dirty_tx; + char *tso_hdrs; + dma_addr_t tso_hdrs_dma; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ unsigned long tx_idle_slope; ++#endif + }; + + struct fec_enet_priv_rx_q { + struct bufdesc_prop bd; +- struct fec_enet_priv_txrx_info rx_skb_info[RX_RING_SIZE]; ++ struct fec_enet_priv_txrx_info rx_skb_info[FEC_RX_RING_SIZE]; + + /* page_pool */ + struct page_pool *page_pool; +@@ -619,6 +636,12 @@ struct fec_enet_private { + unsigned int total_tx_ring_size; + unsigned int total_rx_ring_size; + ++#ifdef CONFIG_AVB_SUPPORT ++ const struct avb_ops *avb; ++ void *avb_data; ++ unsigned int avb_enabled; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_advertising); ++#endif + struct platform_device *pdev; + + int dev_id; +@@ -650,7 +673,7 @@ struct fec_enet_private { + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_caps; + unsigned long last_overflow_check; +- spinlock_t tmreg_lock; ++ raw_spinlock_t tmreg_lock; + struct cyclecounter cc; + struct timecounter tc; + int rx_hwtstamp_filter; +@@ -658,6 +681,13 @@ struct fec_enet_private { + u32 cycle_speed; + int hwts_rx_en; + int hwts_tx_en; ++ ++ /* Transmit and receive latency, depending on link speed, for ++ * packets timestamps in ns ++ */ ++ u32 rx_tstamp_latency; ++ u32 tx_tstamp_latency; ++ + struct delayed_work time_keep; + struct regulator *reg_phy; + struct fec_stop_mode_gpr stop_gpr; +@@ -695,9 +725,35 @@ struct fec_enet_private { + /* XDP BPF Program */ + struct bpf_prog *xdp_prog; + ++ /* Configured rx/tx timestamps delays for different link speeds ++ * to compensate for FEC-PHY latency in ns ++ */ ++ u32 rx_delay_100; ++ u32 tx_delay_100; ++ u32 rx_delay_1000; ++ u32 tx_delay_1000; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ int rec_channel; ++ int rec_enable; ++#endif ++ + u64 ethtool_stats[]; + }; + ++#ifdef CONFIG_AVB_SUPPORT ++#define FEC_MAX_RATE 400 /* Mbps */ ++#define FEC_MAX_RATE_HAS_AVB 1000 /* Mbps */ ++ ++static inline int fec_max_rate(struct fec_enet_private *fep) ++{ ++ int max_rate = (fep->quirks & FEC_QUIRK_HAS_AVB) ? FEC_MAX_RATE_HAS_AVB : FEC_MAX_RATE; ++ return min(max_rate, fep->speed); ++} ++ ++#define IDLE_SLOPE_DIVISOR 512 ++#endif ++ + void fec_ptp_init(struct platform_device *pdev, int irq_idx); + void fec_ptp_stop(struct platform_device *pdev); + void fec_ptp_start_cyclecounter(struct net_device *ndev); +diff --git a/drivers/net/ethernet/freescale/fec_ecat.c b/drivers/net/ethernet/freescale/fec_ecat.c +new file mode 100644 +index 000000000000..86eb3341105b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/fec_ecat.c +@@ -0,0 +1,3008 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "fec_ecat.h" ++ ++ ++#define DRIVER_NAME "fec_ecat" ++ ++/* Pause frame feild and FIFO threshold */ ++#define FEC_ENET_FCE (1 << 5) ++#define FEC_ENET_RSEM_V 0x84 ++#define FEC_ENET_RSFL_V 16 ++#define FEC_ENET_RAEM_V 0x8 ++#define FEC_ENET_RAFL_V 0x8 ++#define FEC_ENET_OPD_V 0xFFF0 ++#define FEC_MDIO_PM_TIMEOUT 100 /* ms */ ++ ++struct fec_devinfo { ++ u32 quirks; ++}; ++ ++static const struct fec_devinfo fec_imx25_info = { ++ .quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR | ++ FEC_QUIRK_HAS_FRREG, ++}; ++ ++static const struct fec_devinfo fec_imx27_info = { ++ .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG, ++}; ++ ++static const struct fec_devinfo fec_imx28_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | ++ FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC | ++ FEC_QUIRK_HAS_FRREG | FEC_QUIRK_CLEAR_SETUP_MII | ++ FEC_QUIRK_NO_HARD_RESET, ++}; ++ ++static const struct fec_devinfo fec_imx6q_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | ++ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | ++ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 | ++ FEC_QUIRK_HAS_RACC | FEC_QUIRK_CLEAR_SETUP_MII | ++ FEC_QUIRK_HAS_PMQOS, ++}; ++ ++static const struct fec_devinfo fec_mvf600_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC, ++}; ++ ++static const struct fec_devinfo fec_imx6x_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | ++ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | ++ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | ++ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | ++ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE | ++ FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES, ++}; ++ ++static const struct fec_devinfo fec_imx6ul_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | ++ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | ++ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 | ++ FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | ++ FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII, ++}; ++ ++static const struct fec_devinfo fec_imx8mq_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | ++ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | ++ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | ++ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | ++ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE | ++ FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES | ++ FEC_QUIRK_HAS_EEE | FEC_QUIRK_WAKEUP_FROM_INT2, ++}; ++ ++static const struct fec_devinfo fec_imx8qm_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | ++ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | ++ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | ++ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | ++ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE | ++ FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES | ++ FEC_QUIRK_DELAYED_CLKS_SUPPORT, ++}; ++ ++static const struct fec_devinfo fec_s32v234_info = { ++ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | ++ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | ++ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | ++ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE, ++}; ++ ++static struct platform_device_id fec_devtype[] = { ++ { ++ /* keep it for coldfire */ ++ .name = DRIVER_NAME, ++ .driver_data = 0, ++ }, { ++ .name = "imx25-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx25_info, ++ }, { ++ .name = "imx27-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx27_info, ++ }, { ++ .name = "imx28-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx28_info, ++ }, { ++ .name = "imx6q-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx6q_info, ++ }, { ++ .name = "mvf600-fec", ++ .driver_data = (kernel_ulong_t)&fec_mvf600_info, ++ }, { ++ .name = "imx6sx-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx6x_info, ++ }, { ++ .name = "imx6ul-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx6ul_info, ++ }, { ++ .name = "imx8mq-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx8mq_info, ++ }, { ++ .name = "imx8qm-fec", ++ .driver_data = (kernel_ulong_t)&fec_imx8qm_info, ++ }, { ++ .name = "s32v234-fec", ++ .driver_data = (kernel_ulong_t)&fec_s32v234_info, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(platform, fec_devtype); ++ ++enum imx_fec_type { ++ IMX25_FEC = 1, /* runs on i.mx25/50/53 */ ++ IMX27_FEC, /* runs on i.mx27/35/51 */ ++ IMX28_FEC, ++ IMX6Q_FEC, ++ MVF600_FEC, ++ IMX6SX_FEC, ++ IMX6UL_FEC, ++ IMX8MQ_FEC, ++ IMX8QM_FEC, ++ S32V234_FEC, ++}; ++ ++static const struct of_device_id fec_dt_ids[] = { ++ { .compatible = "fsl,imx25-fec-ecat", .data = &fec_devtype[IMX25_FEC], }, ++ { .compatible = "fsl,imx27-fec-ecat", .data = &fec_devtype[IMX27_FEC], }, ++ { .compatible = "fsl,imx28-fec-ecat", .data = &fec_devtype[IMX28_FEC], }, ++ { .compatible = "fsl,imx6q-fec-ecat", .data = &fec_devtype[IMX6Q_FEC], }, ++ { .compatible = "fsl,mvf600-fec-ecat", .data = &fec_devtype[MVF600_FEC], }, ++ { .compatible = "fsl,imx6sx-fec-ecat", .data = &fec_devtype[IMX6SX_FEC], }, ++ { .compatible = "fsl,imx6ul-fec-ecat", .data = &fec_devtype[IMX6UL_FEC], }, ++ { .compatible = "fsl,imx8mq-fec-ecat", .data = &fec_devtype[IMX8MQ_FEC], }, ++ { .compatible = "fsl,imx8qm-fec-ecat", .data = &fec_devtype[IMX8QM_FEC], }, ++ { .compatible = "fsl,s32v234-fec-ecat", .data = &fec_devtype[S32V234_FEC], }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, fec_dt_ids); ++ ++static unsigned char macaddr[ETH_ALEN]; ++module_param_array(macaddr, byte, NULL, 0); ++MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); ++ ++#if defined(CONFIG_M5272) ++/* ++ * Some hardware gets it MAC address out of local flash memory. ++ * if this is non-zero then assume it is the address to get MAC from. ++ */ ++#if defined(CONFIG_NETtel) ++#define FEC_FLASHMAC 0xf0006006 ++#elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES) ++#define FEC_FLASHMAC 0xf0006000 ++#elif defined(CONFIG_CANCam) ++#define FEC_FLASHMAC 0xf0020000 ++#elif defined (CONFIG_M5272C3) ++#define FEC_FLASHMAC (0xffe04000 + 4) ++#elif defined(CONFIG_MOD5272) ++#define FEC_FLASHMAC 0xffc0406b ++#else ++#define FEC_FLASHMAC 0 ++#endif ++#endif /* CONFIG_M5272 */ ++ ++/* The FEC stores dest/src/type/vlan, data, and checksum for receive packets. ++ * ++ * 2048 byte skbufs are allocated. However, alignment requirements ++ * varies between FEC variants. Worst case is 64, so round down by 64. ++ */ ++#define PKT_MAXBUF_SIZE (round_down(2048 - 64, 64)) ++#define PKT_MINBUF_SIZE 64 ++ ++/* FEC receive acceleration */ ++#define FEC_RACC_IPDIS (1 << 1) ++#define FEC_RACC_PRODIS (1 << 2) ++#define FEC_RACC_SHIFT16 BIT(7) ++#define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS) ++ ++/* MIB Control Register */ ++#define FEC_MIB_CTRLSTAT_DISABLE BIT(31) ++ ++/* ++ * The 5270/5271/5280/5282/532x RX control register also contains maximum frame ++ * size bits. Other FEC hardware does not, so we need to take that into ++ * account when setting it. ++ */ ++#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ ++ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ ++ defined(CONFIG_ARM64) ++#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) ++#else ++#define OPT_FRAME_SIZE 0 ++#endif ++ ++/* FEC MII MMFR bits definition */ ++#define FEC_MMFR_ST (1 << 30) ++#define FEC_MMFR_ST_C45 (0) ++#define FEC_MMFR_OP_READ (2 << 28) ++#define FEC_MMFR_OP_READ_C45 (3 << 28) ++#define FEC_MMFR_OP_WRITE (1 << 28) ++#define FEC_MMFR_OP_ADDR_WRITE (0) ++#define FEC_MMFR_PA(v) ((v & 0x1f) << 23) ++#define FEC_MMFR_RA(v) ((v & 0x1f) << 18) ++#define FEC_MMFR_TA (2 << 16) ++#define FEC_MMFR_DATA(v) (v & 0xffff) ++/* FEC ECR bits definition */ ++#define FEC_ECR_MAGICEN (1 << 2) ++#define FEC_ECR_SLEEP (1 << 3) ++ ++#define FEC_MII_TIMEOUT 30000 /* us */ ++ ++/* Transmitter timeout */ ++#define TX_TIMEOUT (2 * HZ) ++ ++#define FEC_PAUSE_FLAG_AUTONEG 0x1 ++#define FEC_PAUSE_FLAG_ENABLE 0x2 ++#define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0) ++#define FEC_WOL_FLAG_ENABLE (0x1 << 1) ++#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2) ++ ++static void set_multicast_list(struct net_device *ndev); ++static int mii_cnt; ++ ++static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, ++ struct bufdesc_prop *bd) ++{ ++ return (bdp >= bd->last) ? bd->base ++ : (struct bufdesc *)(((void *)bdp) + bd->dsize); ++} ++ ++static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, ++ struct bufdesc_prop *bd) ++{ ++ return (bdp <= bd->base) ? bd->last ++ : (struct bufdesc *)(((void *)bdp) - bd->dsize); ++} ++ ++static int fec_enet_get_bd_index(struct bufdesc *bdp, ++ struct bufdesc_prop *bd) ++{ ++ return ((const char *)bdp - (const char *)bd->base) >> bd->dsize_log2; ++} ++ ++static void swap_buffer(void *bufaddr, int len) ++{ ++ int i; ++ unsigned int *buf = bufaddr; ++ ++ for (i = 0; i < len; i += 4, buf++) ++ swab32s(buf); ++} ++ ++static void swap_buffer2(void *dst_buf, void *src_buf, int len) ++{ ++ int i; ++ unsigned int *src = src_buf; ++ unsigned int *dst = dst_buf; ++ ++ for (i = 0; i < len; i += 4, src++, dst++) ++ *dst = swab32p(src); ++} ++ ++static void fec_dump(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct bufdesc *bdp; ++ struct fec_enet_priv_tx_q *txq; ++ int index = 0; ++ ++ netdev_info(ndev, "TX ring dump\n"); ++ pr_info("Nr SC addr len SKB\n"); ++ ++ txq = fep->tx_queue; ++ bdp = txq->bd.base; ++ ++ do { ++ pr_info("%3u %c%c 0x%04x 0x%08x %4u %p\n", ++ index, ++ bdp == txq->bd.cur ? 'S' : ' ', ++ bdp == txq->dirty_tx ? 'H' : ' ', ++ fec16_to_cpu(bdp->cbd_sc), ++ fec32_to_cpu(bdp->cbd_bufaddr), ++ fec16_to_cpu(bdp->cbd_datlen), ++ txq->tx_skbuff[index]); ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ index++; ++ } while (bdp != txq->bd.base); ++} ++ ++ ++static int fec_ecat_txq_submit_buff(struct fec_enet_priv_tx_q *txq, ++ void __user *buff, size_t len, struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct bufdesc *bdp, *last_bdp; ++ void *bufaddr; ++ unsigned short status; ++ unsigned short buflen; ++ unsigned int index; ++ struct sk_buff *skb; ++ ++ bdp = txq->bd.cur; ++ last_bdp = bdp; ++ status = fec16_to_cpu(bdp->cbd_sc); ++ status &= ~BD_ENET_TX_STATS; ++ ++ index = fec_enet_get_bd_index(last_bdp, &txq->bd); ++ skb = txq->tx_skbuff[index]; ++ bufaddr = skb->data; ++ buflen = len; ++ copy_from_user(skb->data, buff, len); ++ bdp->cbd_datlen = cpu_to_fec16(buflen); ++ /* Push the data cache so the CPM does not get stale memory data. */ ++ dma_sync_single_for_device(&fep->pdev->dev, ++ fec32_to_cpu(bdp->cbd_bufaddr), ++ buflen, ++ DMA_TO_DEVICE); ++ ++ status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST); ++ ++ wmb(); ++ ++ /* Send it on its way. Tell FEC it's ready, interrupt when done, ++ * it's the last BD of the frame, and to put the CRC on the end. ++ */ ++ status |= (BD_ENET_TX_READY | BD_ENET_TX_TC); ++ bdp->cbd_sc = cpu_to_fec16(status); ++ ++ /* If this was the last BD in the ring, start at the beginning again. */ ++ bdp = fec_enet_get_nextdesc(last_bdp, &txq->bd); ++ ++ wmb(); ++ txq->bd.cur = bdp; ++ ++ /* Trigger transmission start */ ++ if (!(fep->quirks & FEC_QUIRK_ERR007885) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active)) ++ writel(0, txq->bd.reg_desc_active); ++ ++ return 0; ++} ++ ++static void fec_ecat_tx_queue(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct bufdesc *bdp; ++ unsigned short status; ++ struct fec_enet_priv_tx_q *txq = fep->tx_queue; ++ int index = 0; ++ ++ /* get next bdp of dirty_tx */ ++ bdp = txq->dirty_tx; ++ ++ /* get next bdp of dirty_tx */ ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ ++ while (bdp != READ_ONCE(txq->bd.cur)) { ++ /* Order the load of bd.cur and cbd_sc */ ++ rmb(); ++ status = fec16_to_cpu(READ_ONCE(bdp->cbd_sc)); ++ if (status & BD_ENET_TX_READY) ++ break; ++ ++ /* Check for errors. */ ++ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | ++ BD_ENET_TX_RL | BD_ENET_TX_UN | ++ BD_ENET_TX_CSL)) { ++ ndev->stats.tx_errors++; ++ } else { ++ ndev->stats.tx_packets++; ++ } ++ ++ wmb(); ++ txq->dirty_tx = bdp; ++ ++ /* Update pointer to next buffer descriptor to be transmitted */ ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ } ++ ++ /* ERR006358: Keep the transmitter going */ ++ if (bdp != txq->bd.cur && ++ readl(txq->bd.reg_desc_active) == 0) ++ writel(0, txq->bd.reg_desc_active); ++} ++ ++static int fec_ecat_fast_xmit(struct net_device *ndev, void __user *buff, size_t len) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret; ++ ++ if (!mutex_trylock(&fep->fast_ndev_lock)) { ++ return -EBUSY; ++ } ++ ++ ret = fec_ecat_txq_submit_buff(fep->tx_queue, buff, len, ndev); ++ fec_ecat_tx_queue(ndev); ++ ++ mutex_unlock(&fep->fast_ndev_lock); ++ ++ return NETDEV_TX_OK; ++} ++ ++/* Init RX n TX buffer descriptors ++ */ ++static void fec_enet_bd_init(struct net_device *dev) ++{ ++ struct fec_enet_private *fep = netdev_priv(dev); ++ struct fec_enet_priv_tx_q *txq = fep->tx_queue; ++ struct fec_enet_priv_rx_q *rxq = fep->rx_queue; ++ struct bufdesc *bdp; ++ int i; ++ struct sk_buff *skb; ++ ++ /* Initialize the receive buffer descriptors. */ ++ bdp = rxq->bd.base; ++ ++ for (i = 0; i < rxq->bd.ring_size; i++) { ++ /* Initialize the BD for every fragment in the page. */ ++ if (bdp->cbd_bufaddr) ++ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY); ++ else ++ bdp->cbd_sc = cpu_to_fec16(0); ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ } ++ ++ /* Set the last buffer to wrap */ ++ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd); ++ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); ++ rxq->bd.cur = rxq->bd.base; ++ ++ /* ...and the same for transmit */ ++ bdp = txq->bd.base; ++ txq->bd.cur = bdp; ++ ++ for (i = 0; i < txq->bd.ring_size; i++) { ++ bdp->cbd_sc = cpu_to_fec16(0); ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ } ++ ++ /* Set the last buffer to wrap */ ++ bdp = fec_enet_get_prevdesc(bdp, &txq->bd); ++ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); ++ txq->dirty_tx = bdp; ++} ++ ++/* ++ * This function is called to start or restart the FEC during a link ++ * change, transmit timeout, or to reconfigure the FEC. The network ++ * packet processing for this device must be stopped before this call. ++ */ ++static void ++fec_restart(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ u32 temp_mac[2]; ++ u32 rcntl = OPT_FRAME_SIZE | 0x04; ++ u32 ecntl = FEC_ENET_ETHEREN; /* ETHEREN */ ++ ++ /* Always use disable MAC instead of MAC reset to: ++ * - Keep the ENET counter running ++ * - Avoid dead system bus for SoCs using the ENET-AXI bus ++ * and not the AHB bus, like the i.MX6SX ++ */ ++ writel(0, fep->hwp + FEC_ECNTRL); ++ ++ /* ++ * enet-mac reset will reset mac address registers too, ++ * so need to reconfigure it. ++ */ ++ memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN); ++ writel((__force u32)cpu_to_be32(temp_mac[0]), ++ fep->hwp + FEC_ADDR_LOW); ++ writel((__force u32)cpu_to_be32(temp_mac[1]), ++ fep->hwp + FEC_ADDR_HIGH); ++ ++ /* Clear any outstanding interrupt, except MDIO. */ ++ writel((0xffffffff & ~FEC_ENET_MII), fep->hwp + FEC_IEVENT); ++ ++ fec_enet_bd_init(ndev); ++ ++ writel(fep->rx_queue->bd.dma, fep->hwp + FEC_R_DES_START(0)); ++ writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_R_BUFF_SIZE(0)); ++ ++ writel(fep->tx_queue->bd.dma, fep->hwp + FEC_X_DES_START(0)); ++ ++ if (fep->quirks & FEC_QUIRK_HAS_AVB) ++ writel(FEC_RX_FLUSH(0) | FEC_TX_SCHEME_CB, ++ fep->hwp + FEC_QOS_SCHEME); ++ ++ /* Enable MII mode */ ++ if (fep->full_duplex == DUPLEX_FULL) { ++ /* FD enable */ ++ writel(0x04, fep->hwp + FEC_X_CNTRL); ++ } else { ++ /* No Rcv on Xmit */ ++ rcntl |= 0x02; ++ writel(0x0, fep->hwp + FEC_X_CNTRL); ++ } ++ ++ /* Set MII speed */ ++ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); ++ ++#if !defined(CONFIG_M5272) ++ if (fep->quirks & FEC_QUIRK_HAS_RACC) { ++ u32 val = readl(fep->hwp + FEC_RACC); ++ ++ /* align IP header */ ++ val |= FEC_RACC_SHIFT16; ++ if (fep->csum_flags & FLAG_RX_CSUM_ENABLED) ++ /* set RX checksum */ ++ val |= FEC_RACC_OPTIONS; ++ else ++ val &= ~FEC_RACC_OPTIONS; ++ writel(val, fep->hwp + FEC_RACC); ++ writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL); ++ } ++#endif ++ ++ /* ++ * The phy interface and speed need to get configured ++ * differently on enet-mac. ++ */ ++ if (fep->quirks & FEC_QUIRK_ENET_MAC) { ++ /* Enable flow control and length check */ ++ rcntl |= 0x40000000 | 0x00000020; ++ ++ /* RGMII, RMII or MII */ ++ if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII || ++ fep->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || ++ fep->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID || ++ fep->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ++ rcntl |= (1 << 6); ++ else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) ++ rcntl |= (1 << 8); ++ else ++ rcntl &= ~(1 << 8); ++ ++ /* 1G, 100M or 10M */ ++ if (ndev->phydev) { ++ if (ndev->phydev->speed == SPEED_1000) ++ ecntl |= (1 << 5); ++ else if (ndev->phydev->speed == SPEED_100) ++ rcntl &= ~(1 << 9); ++ else ++ rcntl |= (1 << 9); ++ } ++ } else { ++#ifdef FEC_MIIGSK_ENR ++ if (fep->quirks & FEC_QUIRK_USE_GASKET) { ++ u32 cfgr; ++ /* disable the gasket and wait */ ++ writel(0, fep->hwp + FEC_MIIGSK_ENR); ++ while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) ++ udelay(1); ++ ++ /* ++ * configure the gasket: ++ * RMII, 50 MHz, no loopback, no echo ++ * MII, 25 MHz, no loopback, no echo ++ */ ++ cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII) ++ ? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII; ++ if (ndev->phydev && ndev->phydev->speed == SPEED_10) ++ cfgr |= BM_MIIGSK_CFGR_FRCONT_10M; ++ writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR); ++ ++ /* re-enable the gasket */ ++ writel(2, fep->hwp + FEC_MIIGSK_ENR); ++ } ++#endif ++ } ++ ++#if !defined(CONFIG_M5272) ++ /* enable pause frame*/ ++ if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) || ++ ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) && ++ ndev->phydev && ndev->phydev->pause)) { ++ rcntl |= FEC_ENET_FCE; ++ ++ /* set FIFO threshold parameter to reduce overrun */ ++ writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM); ++ writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL); ++ writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM); ++ writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL); ++ ++ /* OPD */ ++ writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD); ++ } else { ++ rcntl &= ~FEC_ENET_FCE; ++ } ++#endif /* !defined(CONFIG_M5272) */ ++ ++ writel(rcntl, fep->hwp + FEC_R_CNTRL); ++ ++ /* Setup multicast filter. */ ++ set_multicast_list(ndev); ++#ifndef CONFIG_M5272 ++ writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); ++ writel(0, fep->hwp + FEC_HASH_TABLE_LOW); ++#endif ++ ++ if (fep->quirks & FEC_QUIRK_ENET_MAC) { ++ /* enable ENET endian swap */ ++ ecntl |= (1 << 8); ++ /* enable ENET store and forward mode */ ++ writel(1 << 8, fep->hwp + FEC_X_WMRK); ++ } ++ ++ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT && ++ fep->rgmii_txc_dly) ++ ecntl |= FEC_ENET_TXC_DLY; ++ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT && ++ fep->rgmii_rxc_dly) ++ ecntl |= FEC_ENET_RXC_DLY; ++ ++#ifndef CONFIG_M5272 ++ /* Enable the MIB statistic event counters */ ++ writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT); ++#endif ++ ++ /* And last, enable the transmit and receive processing */ ++ writel(ecntl, fep->hwp + FEC_ECNTRL); ++ writel(0, fep->rx_queue->bd.reg_desc_active); ++ ++ writel(0, fep->hwp + FEC_IMASK); ++} ++ ++static int fec_enet_ipc_handle_init(struct fec_enet_private *fep) ++{ ++ if (!(of_machine_is_compatible("fsl,imx8qm") || ++ of_machine_is_compatible("fsl,imx8qxp") || ++ of_machine_is_compatible("fsl,imx8dxl"))) ++ return 0; ++ ++ return imx_scu_get_handle(&fep->ipc_handle); ++} ++ ++static void fec_enet_ipg_stop_set(struct fec_enet_private *fep, bool enabled) ++{ ++ struct device_node *np = fep->pdev->dev.of_node; ++ u32 rsrc_id, val; ++ int idx; ++ ++ if (!np || !fep->ipc_handle) ++ return; ++ ++ idx = of_alias_get_id(np, "ethernet"); ++ if (idx < 0) ++ idx = 0; ++ rsrc_id = idx ? IMX_SC_R_ENET_1 : IMX_SC_R_ENET_0; ++ ++ val = enabled ? 1 : 0; ++ imx_sc_misc_set_control(fep->ipc_handle, rsrc_id, IMX_SC_C_IPG_STOP, val); ++} ++ ++static void fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled) ++{ ++ struct fec_platform_data *pdata = fep->pdev->dev.platform_data; ++ struct fec_stop_mode_gpr *stop_gpr = &fep->stop_gpr; ++ ++ if (stop_gpr->gpr) { ++ if (enabled) ++ regmap_update_bits(stop_gpr->gpr, stop_gpr->reg, ++ BIT(stop_gpr->bit), ++ BIT(stop_gpr->bit)); ++ else ++ regmap_update_bits(stop_gpr->gpr, stop_gpr->reg, ++ BIT(stop_gpr->bit), 0); ++ } else if (pdata && pdata->sleep_mode_enable) { ++ pdata->sleep_mode_enable(enabled); ++ } else { ++ fec_enet_ipg_stop_set(fep, enabled); ++ } ++} ++ ++static inline void fec_irqs_disable(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ writel(0, fep->hwp + FEC_IMASK); ++} ++ ++static void ++fec_stop(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); ++ ++ /* We cannot expect a graceful transmit stop without link !!! */ ++ if (fep->link) { ++ writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ ++ udelay(10); ++ if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) ++ netdev_err(ndev, "Graceful transmit stop did not complete!\n"); ++ } ++ ++ writel(0, fep->hwp + FEC_ECNTRL); ++ ++ writel(0, fep->hwp + FEC_IMASK); ++ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); ++} ++ ++ ++static void ++fec_timeout(struct net_device *ndev, unsigned int txqueue) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ fec_dump(ndev); ++ ++ ndev->stats.tx_errors++; ++ ++ schedule_work(&fep->tx_timeout_work); ++} ++ ++static void fec_enet_timeout_work(struct work_struct *work) ++{ ++ struct fec_enet_private *fep = ++ container_of(work, struct fec_enet_private, tx_timeout_work); ++ struct net_device *ndev = fep->netdev; ++ ++ if (netif_device_present(ndev) || netif_running(ndev)) { ++ mutex_lock(&fep->fast_ndev_lock); ++ ++ fec_restart(ndev); ++ mutex_unlock(&fep->fast_ndev_lock); ++ } ++} ++ ++// must be powers of 2 ++#define MAX_TX_BUF (64) ++#define MAX_RX_BUF (64) ++ ++static int fec_ecat_recv_from_queue(struct net_device *ndev, void __user *buff, size_t len, struct sockaddr __user *addr, int *addr_len) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct fec_enet_priv_rx_q *rxq = fep->rx_queue; ++ struct bufdesc *bdp; ++ unsigned short status; ++ struct sk_buff *skb = NULL; ++ ushort pkt_len; ++ __u8 *data; ++ int recv_len = 0; ++ int index = 0; ++ bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME; ++ int ret = 0; ++ ++#ifdef CONFIG_M532x ++ flush_cache_all(); ++#endif ++ ++ /* First, grab all of the stats for the incoming packet. ++ * These get messed up if we get called due to a busy condition. ++ */ ++ bdp = rxq->bd.cur; ++ ++ while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) { ++ ++ writel(FEC_ENET_RXF_GET(0), fep->hwp + FEC_IEVENT); ++ ++ /* Check for errors. */ ++ status ^= BD_ENET_RX_LAST; ++ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | ++ BD_ENET_RX_CR | BD_ENET_RX_OV | BD_ENET_RX_LAST | ++ BD_ENET_RX_CL)) { ++ ndev->stats.rx_errors++; ++ if (status & BD_ENET_RX_OV) { ++ /* FIFO overrun */ ++ ndev->stats.rx_fifo_errors++; ++ goto rx_processing_done; ++ } ++ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH ++ | BD_ENET_RX_LAST)) { ++ /* Frame too long or too short. */ ++ ndev->stats.rx_length_errors++; ++ if (status & BD_ENET_RX_LAST) ++ netdev_err(ndev, "rcv is not +last\n"); ++ } ++ if (status & BD_ENET_RX_CR) /* CRC Error */ ++ ndev->stats.rx_crc_errors++; ++ /* Report late collisions as a frame error. */ ++ if (status & (BD_ENET_RX_NO | BD_ENET_RX_CL)) ++ ndev->stats.rx_frame_errors++; ++ goto rx_processing_done; ++ } ++ ++ /* Process the incoming frame. */ ++ ndev->stats.rx_packets++; ++ pkt_len = fec16_to_cpu(bdp->cbd_datlen); ++ ndev->stats.rx_bytes += pkt_len; ++ ++ index = fec_enet_get_bd_index(bdp, &rxq->bd); ++ skb = rxq->rx_skbuff[index]; ++ ++ prefetch(skb->data - NET_IP_ALIGN); ++ dma_sync_single_for_cpu(&fep->pdev->dev, ++ fec32_to_cpu(bdp->cbd_bufaddr), ++ FEC_ENET_RX_FRSIZE - fep->rx_align, ++ DMA_FROM_DEVICE); ++ ++ pkt_len -= 6; ++ data = skb->data; ++#if !defined(CONFIG_M5272) ++ if (fep->quirks & FEC_QUIRK_HAS_RACC) ++ data += 2; ++#endif ++ if (data[12] ==0x88 && data[13] ==0xa4) { ++ len = len < pkt_len? len : pkt_len; ++ if (!need_swap) { ++ copy_to_user(buff, data, len); ++ } ++ else { ++ swap_buffer2(buff, data, len); ++ } ++ if (addr != NULL) { ++ struct sockaddr_ll *sll = (struct sockaddr_ll *)addr; ++ sll->sll_hatype = ndev->type; ++ sll->sll_ifindex = ndev->ifindex; ++ } ++ recv_len = len; ++ } ++ dma_sync_single_for_device(&fep->pdev->dev, ++ fec32_to_cpu(bdp->cbd_bufaddr), ++ FEC_ENET_RX_FRSIZE - fep->rx_align, ++ DMA_FROM_DEVICE); ++rx_processing_done: ++ /* Clear the status flags for this buffer */ ++ status &= ~BD_ENET_RX_STATS; ++ ++ /* Mark the buffer empty */ ++ status |= BD_ENET_RX_EMPTY; ++ ++ /* Make sure the updates to rest of the descriptor are ++ * performed before transferring ownership. ++ */ ++ wmb(); ++ bdp->cbd_sc = cpu_to_fec16(status); ++ ++ /* Update BD pointer to next entry */ ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ ++ /* Doing this here will keep the FEC running while we process ++ * incoming frames. On a heavily loaded network, we should be ++ * able to keep up at the expense of system resources. ++ */ ++ writel(0, rxq->bd.reg_desc_active); ++ if (recv_len) { ++ break; ++ } ++ } ++ rxq->bd.cur = bdp; ++ return recv_len; ++} ++ ++static int fec_ecat_fast_recv(struct net_device *ndev, void __user *buff, size_t len, struct sockaddr __user *addr, int *addr_len) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret; ++ ++ if (!mutex_trylock(&fep->fast_ndev_lock)) { ++ return -EBUSY; ++ } ++ ++ ret = fec_ecat_recv_from_queue(ndev, buff, len, addr, addr_len); ++ ++ mutex_unlock(&fep->fast_ndev_lock); ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------- */ ++static int fec_get_mac(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ unsigned char *iap, tmpaddr[ETH_ALEN]; ++ int ret; ++ ++ /* ++ * try to get mac address in following order: ++ * ++ * 1) module parameter via kernel command line in form ++ * fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0 ++ */ ++ iap = macaddr; ++ ++ /* ++ * 2) from device tree data ++ */ ++ if (!is_valid_ether_addr(iap)) { ++ struct device_node *np = fep->pdev->dev.of_node; ++ if (np) { ++ ret = of_get_mac_address(np, tmpaddr); ++ if (!ret) ++ iap = tmpaddr; ++ else if (ret == -EPROBE_DEFER) ++ return ret; ++ } ++ } ++ ++ /* ++ * 3) from flash or fuse (via platform data) ++ */ ++ if (!is_valid_ether_addr(iap)) { ++#ifdef CONFIG_M5272 ++ if (FEC_FLASHMAC) ++ iap = (unsigned char *)FEC_FLASHMAC; ++#else ++ struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev); ++ ++ if (pdata) ++ iap = (unsigned char *)&pdata->mac; ++#endif ++ } ++ ++ /* ++ * 4) FEC mac registers set by bootloader ++ */ ++ if (!is_valid_ether_addr(iap)) { ++ *((__be32 *) &tmpaddr[0]) = ++ cpu_to_be32(readl(fep->hwp + FEC_ADDR_LOW)); ++ *((__be16 *) &tmpaddr[4]) = ++ cpu_to_be16(readl(fep->hwp + FEC_ADDR_HIGH) >> 16); ++ iap = &tmpaddr[0]; ++ } ++ ++ /* ++ * 5) random mac address ++ */ ++ if (!is_valid_ether_addr(iap)) { ++ /* Report it and use a random ethernet address instead */ ++ dev_err(&fep->pdev->dev, "Invalid MAC address: %pM\n", iap); ++ eth_hw_addr_random(ndev); ++ dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n", ++ ndev->dev_addr); ++ return 0; ++ } ++ ++ /* Adjust MAC if using macaddr */ ++ eth_hw_addr_gen(ndev, iap, iap == macaddr ? fep->dev_id : 0); ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++/* ++ * Phy section ++ */ ++static void fec_enet_adjust_link(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct phy_device *phy_dev = ndev->phydev; ++ int status_change = 0; ++ ++ /* ++ * If the netdev is down, or is going down, we're not interested ++ * in link state events, so just mark our idea of the link as down ++ * and ignore the event. ++ */ ++ if (!netif_running(ndev) || !netif_device_present(ndev)) { ++ fep->link = 0; ++ } else if (phy_dev->link) { ++ if (!fep->link) { ++ fep->link = phy_dev->link; ++ status_change = 1; ++ } ++ ++ if (fep->full_duplex != phy_dev->duplex) { ++ fep->full_duplex = phy_dev->duplex; ++ status_change = 1; ++ } ++ ++ if (phy_dev->speed != fep->speed) { ++ fep->speed = phy_dev->speed; ++ status_change = 1; ++ } ++ ++ switch (fep->speed) { ++ case SPEED_100: ++ fep->rx_tstamp_latency = fep->rx_delay_100; ++ fep->tx_tstamp_latency = fep->tx_delay_100; ++ break; ++ case SPEED_1000: ++ fep->rx_tstamp_latency = fep->rx_delay_1000; ++ fep->tx_tstamp_latency = fep->tx_delay_1000; ++ break; ++ default: ++ fep->rx_tstamp_latency = 0; ++ fep->tx_tstamp_latency = 0; ++ } ++ ++ /* if any of the above changed restart the FEC */ ++ if (status_change) { ++ mutex_lock(&fep->fast_ndev_lock); ++ fec_restart(ndev); ++ mutex_unlock(&fep->fast_ndev_lock); ++ } ++ } else { ++ if (fep->link) { ++ mutex_lock(&fep->fast_ndev_lock); ++ fec_stop(ndev); ++ mutex_unlock(&fep->fast_ndev_lock); ++ fep->link = phy_dev->link; ++ status_change = 1; ++ } ++ } ++ ++ if (status_change) ++ phy_print_status(phy_dev); ++} ++ ++static int fec_enet_mdio_wait(struct fec_enet_private *fep) ++{ ++ uint ievent; ++ int ret; ++ ++ ret = readl_poll_timeout_atomic(fep->hwp + FEC_IEVENT, ievent, ++ ievent & FEC_ENET_MII, 2, 30000); ++ ++ if (!ret) ++ writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); ++ ++ return ret; ++} ++ ++static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) ++{ ++ struct fec_enet_private *fep = bus->priv; ++ struct device *dev = &fep->pdev->dev; ++ int ret = 0, frame_start, frame_addr, frame_op; ++ bool is_c45 = !!(regnum & MII_ADDR_C45); ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ if (is_c45) { ++ frame_start = FEC_MMFR_ST_C45; ++ ++ /* write address */ ++ frame_addr = (regnum >> 16); ++ writel(frame_start | FEC_MMFR_OP_ADDR_WRITE | ++ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(frame_addr) | ++ FEC_MMFR_TA | (regnum & 0xFFFF), ++ fep->hwp + FEC_MII_DATA); ++ ++ /* wait for end of transfer */ ++ ret = fec_enet_mdio_wait(fep); ++ if (ret) { ++ netdev_err(fep->netdev, "MDIO address write timeout\n"); ++ goto out; ++ } ++ ++ frame_op = FEC_MMFR_OP_READ_C45; ++ ++ } else { ++ /* C22 read */ ++ frame_op = FEC_MMFR_OP_READ; ++ frame_start = FEC_MMFR_ST; ++ frame_addr = regnum; ++ } ++ ++ /* start a read op */ ++ writel(frame_start | frame_op | ++ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(frame_addr) | ++ FEC_MMFR_TA, fep->hwp + FEC_MII_DATA); ++ ++ /* wait for end of transfer */ ++ ret = fec_enet_mdio_wait(fep); ++ if (ret) { ++ netdev_err(fep->netdev, "MDIO read timeout\n"); ++ goto out; ++ } ++ ++ ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); ++ ++out: ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return ret; ++} ++ ++static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, ++ u16 value) ++{ ++ struct fec_enet_private *fep = bus->priv; ++ struct device *dev = &fep->pdev->dev; ++ int ret, frame_start, frame_addr; ++ bool is_c45 = !!(regnum & MII_ADDR_C45); ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ if (is_c45) { ++ frame_start = FEC_MMFR_ST_C45; ++ ++ /* write address */ ++ frame_addr = (regnum >> 16); ++ writel(frame_start | FEC_MMFR_OP_ADDR_WRITE | ++ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(frame_addr) | ++ FEC_MMFR_TA | (regnum & 0xFFFF), ++ fep->hwp + FEC_MII_DATA); ++ ++ /* wait for end of transfer */ ++ ret = fec_enet_mdio_wait(fep); ++ if (ret) { ++ netdev_err(fep->netdev, "MDIO address write timeout\n"); ++ goto out; ++ } ++ } else { ++ /* C22 write */ ++ frame_start = FEC_MMFR_ST; ++ frame_addr = regnum; ++ } ++ ++ /* start a write op */ ++ writel(frame_start | FEC_MMFR_OP_WRITE | ++ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(frame_addr) | ++ FEC_MMFR_TA | FEC_MMFR_DATA(value), ++ fep->hwp + FEC_MII_DATA); ++ ++ /* wait for end of transfer */ ++ ret = fec_enet_mdio_wait(fep); ++ if (ret) ++ netdev_err(fep->netdev, "MDIO write timeout\n"); ++ ++out: ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return ret; ++} ++ ++static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct phy_device *phy_dev = ndev->phydev; ++ ++ if (phy_dev) { ++ phy_reset_after_clk_enable(phy_dev); ++ } else if (fep->phy_node) { ++ /* ++ * If the PHY still is not bound to the MAC, but there is ++ * OF PHY node and a matching PHY device instance already, ++ * use the OF PHY node to obtain the PHY device instance, ++ * and then use that PHY device instance when triggering ++ * the PHY reset. ++ */ ++ phy_dev = of_phy_find_device(fep->phy_node); ++ phy_reset_after_clk_enable(phy_dev); ++ put_device(&phy_dev->mdio.dev); ++ } ++} ++ ++static int fec_enet_clk_enable(struct net_device *ndev, bool enable) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret; ++ ++ if (enable) { ++ ret = clk_prepare_enable(fep->clk_enet_out); ++ if (ret) ++ return ret; ++ ++ if (fep->clk_ptp) { ++ mutex_lock(&fep->ptp_clk_mutex); ++ ret = clk_prepare_enable(fep->clk_ptp); ++ if (ret) { ++ mutex_unlock(&fep->ptp_clk_mutex); ++ goto failed_clk_ptp; ++ } else { ++ fep->ptp_clk_on = true; ++ } ++ mutex_unlock(&fep->ptp_clk_mutex); ++ } ++ ++ ret = clk_prepare_enable(fep->clk_ref); ++ if (ret) ++ goto failed_clk_ref; ++ ++ ret = clk_prepare_enable(fep->clk_2x_txclk); ++ if (ret) ++ goto failed_clk_2x_txclk; ++ ++ fec_enet_phy_reset_after_clk_enable(ndev); ++ } else { ++ clk_disable_unprepare(fep->clk_enet_out); ++ if (fep->clk_ptp) { ++ mutex_lock(&fep->ptp_clk_mutex); ++ clk_disable_unprepare(fep->clk_ptp); ++ fep->ptp_clk_on = false; ++ mutex_unlock(&fep->ptp_clk_mutex); ++ } ++ clk_disable_unprepare(fep->clk_ref); ++ clk_disable_unprepare(fep->clk_2x_txclk); ++ } ++ ++ return 0; ++ ++failed_clk_2x_txclk: ++ if (fep->clk_ref) ++ clk_disable_unprepare(fep->clk_ref); ++failed_clk_ref: ++ if (fep->clk_ptp) { ++ mutex_lock(&fep->ptp_clk_mutex); ++ clk_disable_unprepare(fep->clk_ptp); ++ fep->ptp_clk_on = false; ++ mutex_unlock(&fep->ptp_clk_mutex); ++ } ++failed_clk_ptp: ++ clk_disable_unprepare(fep->clk_enet_out); ++ ++ return ret; ++} ++ ++static int fec_enet_parse_rgmii_delay(struct fec_enet_private *fep, ++ struct device_node *np) ++{ ++ u32 rgmii_tx_delay, rgmii_rx_delay; ++ ++ /* For rgmii tx internal delay, valid values are 0ps and 2000ps */ ++ if (!of_property_read_u32(np, "tx-internal-delay-ps", &rgmii_tx_delay)) { ++ if (rgmii_tx_delay != 0 && rgmii_tx_delay != 2000) { ++ dev_err(&fep->pdev->dev, "The only allowed RGMII TX delay values are: 0ps, 2000ps"); ++ return -EINVAL; ++ } else if (rgmii_tx_delay == 2000) { ++ fep->rgmii_txc_dly = true; ++ } ++ } ++ ++ /* For rgmii rx internal delay, valid values are 0ps and 2000ps */ ++ if (!of_property_read_u32(np, "rx-internal-delay-ps", &rgmii_rx_delay)) { ++ if (rgmii_rx_delay != 0 && rgmii_rx_delay != 2000) { ++ dev_err(&fep->pdev->dev, "The only allowed RGMII RX delay values are: 0ps, 2000ps"); ++ return -EINVAL; ++ } else if (rgmii_rx_delay == 2000) { ++ fep->rgmii_rxc_dly = true; ++ } ++ } ++ ++ return 0; ++} ++ ++static int fec_restore_mii_bus(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret; ++ ++ ret = pm_runtime_get_sync(&fep->pdev->dev); ++ if (ret < 0) ++ return ret; ++ ++ writel(0xffc00000, fep->hwp + FEC_IEVENT); ++ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); ++ writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); ++ writel(FEC_ENET_ETHEREN, fep->hwp + FEC_ECNTRL); ++ ++ pm_runtime_mark_last_busy(&fep->pdev->dev); ++ pm_runtime_put_autosuspend(&fep->pdev->dev); ++ ++ return 0; ++} ++ ++static int fec_enet_mii_probe(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct phy_device *phy_dev = NULL; ++ char mdio_bus_id[MII_BUS_ID_SIZE]; ++ char phy_name[MII_BUS_ID_SIZE + 3]; ++ int phy_id; ++ int dev_id = fep->dev_id; ++ ++ if (fep->phy_node) { ++ phy_dev = of_phy_connect(ndev, fep->phy_node, ++ &fec_enet_adjust_link, 0, ++ fep->phy_interface); ++ if (!phy_dev) { ++ netdev_err(ndev, "Unable to connect to phy\n"); ++ return -ENODEV; ++ } ++ } else { ++ /* check for attached phy */ ++ for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) { ++ if (!mdiobus_is_registered_device(fep->mii_bus, phy_id)) ++ continue; ++ if (dev_id--) ++ continue; ++ strlcpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE); ++ break; ++ } ++ ++ if (phy_id >= PHY_MAX_ADDR) { ++ netdev_info(ndev, "no PHY, assuming direct connection to switch\n"); ++ strlcpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE); ++ phy_id = 0; ++ } ++ ++ snprintf(phy_name, sizeof(phy_name), ++ PHY_ID_FMT, mdio_bus_id, phy_id); ++ phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, ++ fep->phy_interface); ++ } ++ ++ if (IS_ERR(phy_dev)) { ++ netdev_err(ndev, "could not attach to PHY\n"); ++ return PTR_ERR(phy_dev); ++ } ++ ++ /* mask with MAC supported features */ ++ if (fep->quirks & FEC_QUIRK_HAS_GBIT) { ++ phy_set_max_speed(phy_dev, 1000); ++ phy_remove_link_mode(phy_dev, ++ ETHTOOL_LINK_MODE_1000baseT_Half_BIT); ++#if !defined(CONFIG_M5272) ++ phy_support_sym_pause(phy_dev); ++#endif ++ } ++ else ++ phy_set_max_speed(phy_dev, 100); ++ ++ fep->link = 0; ++ fep->full_duplex = 0; ++ ++ phy_dev->mac_managed_pm = 1; ++ ++ phy_attached_info(phy_dev); ++ ++ return 0; ++} ++ ++static int fec_enet_mii_init(struct platform_device *pdev) ++{ ++ static struct mii_bus *fec0_mii_bus; ++ static bool *fec_mii_bus_share; ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ bool suppress_preamble = false; ++ struct device_node *node; ++ int err = -ENXIO; ++ u32 mii_speed, holdtime; ++ u32 bus_freq; ++ ++ /* ++ * The i.MX28 dual fec interfaces are not equal. ++ * Here are the differences: ++ * ++ * - fec0 supports MII & RMII modes while fec1 only supports RMII ++ * - fec0 acts as the 1588 time master while fec1 is slave ++ * - external phys can only be configured by fec0 ++ * ++ * That is to say fec1 can not work independently. It only works ++ * when fec0 is working. The reason behind this design is that the ++ * second interface is added primarily for Switch mode. ++ * ++ * Because of the last point above, both phys are attached on fec0 ++ * mdio interface in board design, and need to be configured by ++ * fec0 mii_bus. ++ */ ++ if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0) { ++ /* fec1 uses fec0 mii_bus */ ++ if (mii_cnt && fec0_mii_bus) { ++ fep->mii_bus = fec0_mii_bus; ++ *fec_mii_bus_share = true; ++ mii_cnt++; ++ return 0; ++ } ++ return -ENOENT; ++ } ++ ++ bus_freq = 2500000; /* 2.5MHz by default */ ++ node = of_get_child_by_name(pdev->dev.of_node, "mdio"); ++ if (node) { ++ of_property_read_u32(node, "clock-frequency", &bus_freq); ++ suppress_preamble = of_property_read_bool(node, ++ "suppress-preamble"); ++ } ++ ++ /* ++ * Set MII speed (= clk_get_rate() / 2 * phy_speed) ++ * ++ * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while ++ * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28 ++ * Reference Manual has an error on this, and gets fixed on i.MX6Q ++ * document. ++ */ ++ mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), bus_freq * 2); ++ if (fep->quirks & FEC_QUIRK_ENET_MAC) ++ mii_speed--; ++ if (mii_speed > 63) { ++ dev_err(&pdev->dev, ++ "fec clock (%lu) too fast to get right mii speed\n", ++ clk_get_rate(fep->clk_ipg)); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ++ /* ++ * The i.MX28 and i.MX6 types have another filed in the MSCR (aka ++ * MII_SPEED) register that defines the MDIO output hold time. Earlier ++ * versions are RAZ there, so just ignore the difference and write the ++ * register always. ++ * The minimal hold time according to IEE802.3 (clause 22) is 10 ns. ++ * HOLDTIME + 1 is the number of clk cycles the fec is holding the ++ * output. ++ * The HOLDTIME bitfield takes values between 0 and 7 (inclusive). ++ * Given that ceil(clkrate / 5000000) <= 64, the calculation for ++ * holdtime cannot result in a value greater than 3. ++ */ ++ holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1; ++ ++ fep->phy_speed = mii_speed << 1 | holdtime << 8; ++ ++ if (suppress_preamble) ++ fep->phy_speed |= BIT(7); ++ ++ if (fep->quirks & FEC_QUIRK_CLEAR_SETUP_MII) { ++ /* Clear MMFR to avoid to generate MII event by writing MSCR. ++ * MII event generation condition: ++ * - writing MSCR: ++ * - mmfr[31:0]_not_zero & mscr[7:0]_is_zero & ++ * mscr_reg_data_in[7:0] != 0 ++ * - writing MMFR: ++ * - mscr[7:0]_not_zero ++ */ ++ writel(0, fep->hwp + FEC_MII_DATA); ++ } ++ ++ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); ++ ++ /* Clear any pending transaction complete indication */ ++ writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); ++ ++ fep->mii_bus = mdiobus_alloc(); ++ if (fep->mii_bus == NULL) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ fep->mii_bus->name = "fec_enet_mii_bus"; ++ fep->mii_bus->read = fec_enet_mdio_read; ++ fep->mii_bus->write = fec_enet_mdio_write; ++ snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", ++ pdev->name, fep->dev_id + 1); ++ fep->mii_bus->priv = fep; ++ fep->mii_bus->parent = &pdev->dev; ++ ++ err = of_mdiobus_register(fep->mii_bus, node); ++ if (err) ++ goto err_out_free_mdiobus; ++ of_node_put(node); ++ ++ mii_cnt++; ++ ++ /* save fec0 mii_bus */ ++ if (fep->quirks & FEC_QUIRK_SINGLE_MDIO) { ++ fec0_mii_bus = fep->mii_bus; ++ fec_mii_bus_share = &fep->mii_bus_share; ++ } ++ ++ return 0; ++ ++err_out_free_mdiobus: ++ mdiobus_free(fep->mii_bus); ++err_out: ++ of_node_put(node); ++ return err; ++} ++ ++static void fec_enet_mii_remove(struct fec_enet_private *fep) ++{ ++ if (--mii_cnt == 0) { ++ mdiobus_unregister(fep->mii_bus); ++ mdiobus_free(fep->mii_bus); ++ } ++} ++ ++static void fec_enet_get_drvinfo(struct net_device *ndev, ++ struct ethtool_drvinfo *info) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ strlcpy(info->driver, fep->pdev->dev.driver->name, ++ sizeof(info->driver)); ++ strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info)); ++} ++ ++static int fec_enet_get_regs_len(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct resource *r; ++ int s = 0; ++ ++ r = platform_get_resource(fep->pdev, IORESOURCE_MEM, 0); ++ if (r) ++ s = resource_size(r); ++ ++ return s; ++} ++ ++/* List of registers that can be safety be read to dump them with ethtool */ ++#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ ++ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ ++ defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST) ++static __u32 fec_enet_register_version = 2; ++static u32 fec_enet_register_offset[] = { ++ FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0, ++ FEC_ECNTRL, FEC_MII_DATA, FEC_MII_SPEED, FEC_MIB_CTRLSTAT, FEC_R_CNTRL, ++ FEC_X_CNTRL, FEC_ADDR_LOW, FEC_ADDR_HIGH, FEC_OPD, FEC_TXIC0, FEC_TXIC1, ++ FEC_TXIC2, FEC_RXIC0, FEC_RXIC1, FEC_RXIC2, FEC_HASH_TABLE_HIGH, ++ FEC_HASH_TABLE_LOW, FEC_GRP_HASH_TABLE_HIGH, FEC_GRP_HASH_TABLE_LOW, ++ FEC_X_WMRK, FEC_R_BOUND, FEC_R_FSTART, FEC_R_DES_START_1, ++ FEC_X_DES_START_1, FEC_R_BUFF_SIZE_1, FEC_R_DES_START_2, ++ FEC_X_DES_START_2, FEC_R_BUFF_SIZE_2, FEC_R_DES_START_0, ++ FEC_X_DES_START_0, FEC_R_BUFF_SIZE_0, FEC_R_FIFO_RSFL, FEC_R_FIFO_RSEM, ++ FEC_R_FIFO_RAEM, FEC_R_FIFO_RAFL, FEC_RACC, FEC_RCMR_1, FEC_RCMR_2, ++ FEC_DMA_CFG_1, FEC_DMA_CFG_2, FEC_R_DES_ACTIVE_1, FEC_X_DES_ACTIVE_1, ++ FEC_R_DES_ACTIVE_2, FEC_X_DES_ACTIVE_2, FEC_QOS_SCHEME, ++ RMON_T_DROP, RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT, ++ RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG, ++ RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255, ++ RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2047, ++ RMON_T_P_GTE2048, RMON_T_OCTETS, ++ IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, IEEE_T_DEF, ++ IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, IEEE_T_SQE, ++ IEEE_T_FDXFC, IEEE_T_OCTETS_OK, ++ RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN, ++ RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB, ++ RMON_R_RESVD_O, RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255, ++ RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047, ++ RMON_R_P_GTE2048, RMON_R_OCTETS, ++ IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, IEEE_R_MACERR, ++ IEEE_R_FDXFC, IEEE_R_OCTETS_OK ++}; ++#else ++static __u32 fec_enet_register_version = 1; ++static u32 fec_enet_register_offset[] = { ++ FEC_ECNTRL, FEC_IEVENT, FEC_IMASK, FEC_IVEC, FEC_R_DES_ACTIVE_0, ++ FEC_R_DES_ACTIVE_1, FEC_R_DES_ACTIVE_2, FEC_X_DES_ACTIVE_0, ++ FEC_X_DES_ACTIVE_1, FEC_X_DES_ACTIVE_2, FEC_MII_DATA, FEC_MII_SPEED, ++ FEC_R_BOUND, FEC_R_FSTART, FEC_X_WMRK, FEC_X_FSTART, FEC_R_CNTRL, ++ FEC_MAX_FRM_LEN, FEC_X_CNTRL, FEC_ADDR_LOW, FEC_ADDR_HIGH, ++ FEC_GRP_HASH_TABLE_HIGH, FEC_GRP_HASH_TABLE_LOW, FEC_R_DES_START_0, ++ FEC_R_DES_START_1, FEC_R_DES_START_2, FEC_X_DES_START_0, ++ FEC_X_DES_START_1, FEC_X_DES_START_2, FEC_R_BUFF_SIZE_0, ++ FEC_R_BUFF_SIZE_1, FEC_R_BUFF_SIZE_2 ++}; ++#endif ++ ++static void fec_enet_get_regs(struct net_device *ndev, ++ struct ethtool_regs *regs, void *regbuf) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ u32 __iomem *theregs = (u32 __iomem *)fep->hwp; ++ struct device *dev = &fep->pdev->dev; ++ u32 *buf = (u32 *)regbuf; ++ u32 i, off; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return; ++ ++ regs->version = fec_enet_register_version; ++ ++ memset(buf, 0, regs->len); ++ ++ for (i = 0; i < ARRAY_SIZE(fec_enet_register_offset); i++) { ++ off = fec_enet_register_offset[i]; ++ ++ if ((off == FEC_R_BOUND || off == FEC_R_FSTART) && ++ !(fep->quirks & FEC_QUIRK_HAS_FRREG)) ++ continue; ++ ++ off >>= 2; ++ buf[off] = readl(&theregs[off]); ++ } ++ ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++} ++ ++ ++#if !defined(CONFIG_M5272) ++ ++static void fec_enet_get_pauseparam(struct net_device *ndev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0; ++ pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0; ++ pause->rx_pause = pause->tx_pause; ++} ++ ++static int fec_enet_set_pauseparam(struct net_device *ndev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ if (!ndev->phydev) ++ return -ENODEV; ++ ++ if (pause->tx_pause != pause->rx_pause) { ++ netdev_info(ndev, ++ "hardware only support enable/disable both tx and rx"); ++ return -EINVAL; ++ } ++ ++ fep->pause_flag = 0; ++ ++ /* tx pause must be same as rx pause */ ++ fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0; ++ fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0; ++ ++ phy_set_sym_pause(ndev->phydev, pause->rx_pause, pause->tx_pause, ++ pause->autoneg); ++ ++ if (pause->autoneg) { ++ if (netif_running(ndev)) ++ fec_stop(ndev); ++ phy_start_aneg(ndev->phydev); ++ } ++ if (netif_running(ndev)) { ++ mutex_lock(&fep->fast_ndev_lock); ++ ++ netif_tx_lock_bh(ndev); ++ //netif_tx_wake_all_queues(ndev); ++ ++ mutex_unlock(&fep->fast_ndev_lock); ++ } ++ ++ return 0; ++} ++ ++static const struct fec_stat { ++ char name[ETH_GSTRING_LEN]; ++ u16 offset; ++} fec_stats[] = { ++ /* RMON TX */ ++ { "tx_dropped", RMON_T_DROP }, ++ { "tx_packets", RMON_T_PACKETS }, ++ { "tx_broadcast", RMON_T_BC_PKT }, ++ { "tx_multicast", RMON_T_MC_PKT }, ++ { "tx_crc_errors", RMON_T_CRC_ALIGN }, ++ { "tx_undersize", RMON_T_UNDERSIZE }, ++ { "tx_oversize", RMON_T_OVERSIZE }, ++ { "tx_fragment", RMON_T_FRAG }, ++ { "tx_jabber", RMON_T_JAB }, ++ { "tx_collision", RMON_T_COL }, ++ { "tx_64byte", RMON_T_P64 }, ++ { "tx_65to127byte", RMON_T_P65TO127 }, ++ { "tx_128to255byte", RMON_T_P128TO255 }, ++ { "tx_256to511byte", RMON_T_P256TO511 }, ++ { "tx_512to1023byte", RMON_T_P512TO1023 }, ++ { "tx_1024to2047byte", RMON_T_P1024TO2047 }, ++ { "tx_GTE2048byte", RMON_T_P_GTE2048 }, ++ { "tx_octets", RMON_T_OCTETS }, ++ ++ /* IEEE TX */ ++ { "IEEE_tx_drop", IEEE_T_DROP }, ++ { "IEEE_tx_frame_ok", IEEE_T_FRAME_OK }, ++ { "IEEE_tx_1col", IEEE_T_1COL }, ++ { "IEEE_tx_mcol", IEEE_T_MCOL }, ++ { "IEEE_tx_def", IEEE_T_DEF }, ++ { "IEEE_tx_lcol", IEEE_T_LCOL }, ++ { "IEEE_tx_excol", IEEE_T_EXCOL }, ++ { "IEEE_tx_macerr", IEEE_T_MACERR }, ++ { "IEEE_tx_cserr", IEEE_T_CSERR }, ++ { "IEEE_tx_sqe", IEEE_T_SQE }, ++ { "IEEE_tx_fdxfc", IEEE_T_FDXFC }, ++ { "IEEE_tx_octets_ok", IEEE_T_OCTETS_OK }, ++ ++ /* RMON RX */ ++ { "rx_packets", RMON_R_PACKETS }, ++ { "rx_broadcast", RMON_R_BC_PKT }, ++ { "rx_multicast", RMON_R_MC_PKT }, ++ { "rx_crc_errors", RMON_R_CRC_ALIGN }, ++ { "rx_undersize", RMON_R_UNDERSIZE }, ++ { "rx_oversize", RMON_R_OVERSIZE }, ++ { "rx_fragment", RMON_R_FRAG }, ++ { "rx_jabber", RMON_R_JAB }, ++ { "rx_64byte", RMON_R_P64 }, ++ { "rx_65to127byte", RMON_R_P65TO127 }, ++ { "rx_128to255byte", RMON_R_P128TO255 }, ++ { "rx_256to511byte", RMON_R_P256TO511 }, ++ { "rx_512to1023byte", RMON_R_P512TO1023 }, ++ { "rx_1024to2047byte", RMON_R_P1024TO2047 }, ++ { "rx_GTE2048byte", RMON_R_P_GTE2048 }, ++ { "rx_octets", RMON_R_OCTETS }, ++ ++ /* IEEE RX */ ++ { "IEEE_rx_drop", IEEE_R_DROP }, ++ { "IEEE_rx_frame_ok", IEEE_R_FRAME_OK }, ++ { "IEEE_rx_crc", IEEE_R_CRC }, ++ { "IEEE_rx_align", IEEE_R_ALIGN }, ++ { "IEEE_rx_macerr", IEEE_R_MACERR }, ++ { "IEEE_rx_fdxfc", IEEE_R_FDXFC }, ++ { "IEEE_rx_octets_ok", IEEE_R_OCTETS_OK }, ++}; ++ ++#define FEC_STATS_SIZE (ARRAY_SIZE(fec_stats) * sizeof(u64)) ++ ++static void fec_enet_update_ethtool_stats(struct net_device *dev) ++{ ++ struct fec_enet_private *fep = netdev_priv(dev); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(fec_stats); i++) ++ fep->ethtool_stats[i] = readl(fep->hwp + fec_stats[i].offset); ++} ++ ++static void fec_enet_get_ethtool_stats(struct net_device *dev, ++ struct ethtool_stats *stats, u64 *data) ++{ ++ struct fec_enet_private *fep = netdev_priv(dev); ++ ++ if (netif_running(dev)) ++ fec_enet_update_ethtool_stats(dev); ++ ++ memcpy(data, fep->ethtool_stats, FEC_STATS_SIZE); ++} ++ ++static void fec_enet_get_strings(struct net_device *netdev, ++ u32 stringset, u8 *data) ++{ ++ int i; ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < ARRAY_SIZE(fec_stats); i++) ++ memcpy(data + i * ETH_GSTRING_LEN, ++ fec_stats[i].name, ETH_GSTRING_LEN); ++ break; ++ case ETH_SS_TEST: ++ net_selftest_get_strings(data); ++ break; ++ } ++} ++ ++static int fec_enet_get_sset_count(struct net_device *dev, int sset) ++{ ++ switch (sset) { ++ case ETH_SS_STATS: ++ return ARRAY_SIZE(fec_stats); ++ case ETH_SS_TEST: ++ return net_selftest_get_count(); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static void fec_enet_clear_ethtool_stats(struct net_device *dev) ++{ ++ struct fec_enet_private *fep = netdev_priv(dev); ++ int i; ++ ++ /* Disable MIB statistics counters */ ++ writel(FEC_MIB_CTRLSTAT_DISABLE, fep->hwp + FEC_MIB_CTRLSTAT); ++ ++ for (i = 0; i < ARRAY_SIZE(fec_stats); i++) ++ writel(0, fep->hwp + fec_stats[i].offset); ++ ++ /* Don't disable MIB statistics counters */ ++ writel(0, fep->hwp + FEC_MIB_CTRLSTAT); ++} ++ ++#else /* !defined(CONFIG_M5272) */ ++#define FEC_STATS_SIZE 0 ++static inline void fec_enet_update_ethtool_stats(struct net_device *dev) ++{ ++} ++ ++static inline void fec_enet_clear_ethtool_stats(struct net_device *dev) ++{ ++} ++#endif /* !defined(CONFIG_M5272) */ ++ ++/* ITR clock source is enet system clock (clk_ahb). ++ * TCTT unit is cycle_ns * 64 cycle ++ * So, the ICTT value = X us / (cycle_ns * 64) ++ */ ++static int fec_enet_us_to_itr_clock(struct net_device *ndev, int us) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ return us * (fep->itr_clk_rate / 64000) / 1000; ++} ++ ++ ++/* LPI Sleep Ts count base on tx clk (clk_ref). ++ * The lpi sleep cnt value = X us / (cycle_ns). ++ */ ++static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ return us * (fep->clk_ref_rate / 1000) / 1000; ++} ++ ++static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct ethtool_eee *p = &fep->eee; ++ unsigned int sleep_cycle, wake_cycle; ++ int ret = 0; ++ ++ if (enable) { ++ ret = phy_init_eee(ndev->phydev, 0); ++ if (ret) ++ return ret; ++ ++ sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer); ++ wake_cycle = sleep_cycle; ++ } else { ++ sleep_cycle = 0; ++ wake_cycle = 0; ++ } ++ ++ p->tx_lpi_enabled = enable; ++ p->eee_enabled = enable; ++ p->eee_active = enable; ++ ++ writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP); ++ writel(wake_cycle, fep->hwp + FEC_LPI_WAKE); ++ ++ return 0; ++} ++ ++static int ++fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct ethtool_eee *p = &fep->eee; ++ ++ if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) ++ return -EOPNOTSUPP; ++ ++ if (!netif_running(ndev)) ++ return -ENETDOWN; ++ ++ edata->eee_enabled = p->eee_enabled; ++ edata->eee_active = p->eee_active; ++ edata->tx_lpi_timer = p->tx_lpi_timer; ++ edata->tx_lpi_enabled = p->tx_lpi_enabled; ++ ++ return phy_ethtool_get_eee(ndev->phydev, edata); ++} ++ ++static int ++fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct ethtool_eee *p = &fep->eee; ++ int ret = 0; ++ ++ if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) ++ return -EOPNOTSUPP; ++ ++ if (!netif_running(ndev)) ++ return -ENETDOWN; ++ ++ p->tx_lpi_timer = edata->tx_lpi_timer; ++ ++ if (!edata->eee_enabled || !edata->tx_lpi_enabled || ++ !edata->tx_lpi_timer) ++ ret = fec_enet_eee_mode_set(ndev, false); ++ else ++ ret = fec_enet_eee_mode_set(ndev, true); ++ ++ if (ret) ++ return ret; ++ ++ return phy_ethtool_set_eee(ndev->phydev, edata); ++} ++ ++static const struct ethtool_ops fec_enet_ethtool_ops = { ++ .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ++ ETHTOOL_COALESCE_MAX_FRAMES, ++ .get_drvinfo = fec_enet_get_drvinfo, ++ .get_regs_len = fec_enet_get_regs_len, ++ .get_regs = fec_enet_get_regs, ++ .nway_reset = phy_ethtool_nway_reset, ++ .get_link = ethtool_op_get_link, ++#ifndef CONFIG_M5272 ++ .get_strings = fec_enet_get_strings, ++ .get_ethtool_stats = fec_enet_get_ethtool_stats, ++ .get_sset_count = fec_enet_get_sset_count, ++#endif ++ .get_eee = fec_enet_get_eee, ++ .set_eee = fec_enet_set_eee, ++ .get_link_ksettings = phy_ethtool_get_link_ksettings, ++ .set_link_ksettings = phy_ethtool_set_link_ksettings, ++ .self_test = net_selftest, ++}; ++ ++static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct phy_device *phydev = ndev->phydev; ++ ++ if (!netif_running(ndev)) ++ return -EINVAL; ++ ++ if (!phydev) ++ return -ENODEV; ++ ++ return phy_mii_ioctl(phydev, rq, cmd); ++} ++ ++static void fec_enet_free_buffers(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ unsigned int i; ++ struct sk_buff *skb; ++ struct bufdesc *bdp; ++ struct fec_enet_priv_tx_q *txq = fep->tx_queue; ++ struct fec_enet_priv_rx_q *rxq = fep->rx_queue; ++ unsigned int q; ++ ++ bdp = rxq->bd.base; ++ for (i = 0; i < rxq->bd.ring_size; i++) { ++ skb = rxq->rx_skbuff[i]; ++ rxq->rx_skbuff[i] = NULL; ++ if (skb) { ++ dma_unmap_single(&fep->pdev->dev, ++ fec32_to_cpu(bdp->cbd_bufaddr), ++ FEC_ENET_RX_FRSIZE - fep->rx_align, ++ DMA_FROM_DEVICE); ++ dev_kfree_skb(skb); ++ } ++ } ++ ++ for (i = 0; i < txq->bd.ring_size; i++) { ++ skb = txq->tx_skbuff[i]; ++ txq->tx_skbuff[i] = NULL; ++ if (skb) { ++ dma_unmap_single(&fep->pdev->dev, ++ fec32_to_cpu(bdp->cbd_bufaddr), ++ FEC_ENET_RX_FRSIZE - fep->rx_align, ++ DMA_FROM_DEVICE); ++ dev_kfree_skb(skb); ++ } ++ } ++} ++ ++static void fec_enet_free_queue(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ if (fep->rx_queue) ++ kfree(fep->rx_queue); ++ if (fep->tx_queue) ++ kfree(fep->tx_queue); ++} ++ ++static int fec_enet_alloc_queue(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret = 0; ++ ++ fep->tx_queue = kzalloc(sizeof(*fep->tx_queue), GFP_KERNEL); ++ if (!fep->tx_queue) { ++ ret = -ENOMEM; ++ goto alloc_failed; ++ } ++ ++ fep->tx_queue->bd.ring_size = FEC_TX_RING_SIZE; ++ fep->total_tx_ring_size += fep->tx_queue->bd.ring_size; ++ ++ ++ fep->rx_queue = kzalloc(sizeof(*fep->rx_queue), GFP_KERNEL); ++ if (!fep->rx_queue) { ++ ret = -ENOMEM; ++ goto alloc_failed; ++ } ++ ++ fep->rx_queue->bd.ring_size = FEC_RX_RING_SIZE; ++ fep->total_rx_ring_size += fep->rx_queue->bd.ring_size; ++ return ret; ++ ++alloc_failed: ++ fec_enet_free_queue(ndev); ++ return ret; ++} ++ ++static int fec_enet_alloc_buffers(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ unsigned int i; ++ struct sk_buff *skb; ++ struct bufdesc *bdp; ++ int off; ++ struct fec_enet_priv_rx_q *rxq; ++ struct fec_enet_priv_tx_q *txq; ++ ++ rxq = fep->rx_queue; ++ txq = fep->tx_queue; ++ bdp = rxq->bd.base; ++ for (i = 0; i < rxq->bd.ring_size; i++) { ++ skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); ++ if (!skb) ++ goto err_alloc; ++ ++ if ((off = ((unsigned long)skb->data) & fep->rx_align) > 0) ++ skb_reserve(skb, fep->rx_align + 1 - off); ++ ++ bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE - fep->rx_align, DMA_FROM_DEVICE)); ++ if (dma_mapping_error(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr))) { ++ dev_kfree_skb(skb); ++ goto err_alloc; ++ } ++ ++ rxq->rx_skbuff[i] = skb; ++ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY); ++ ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ } ++ ++ /* Set the last buffer to wrap. */ ++ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd); ++ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); ++ ++ bdp = txq->bd.base; ++ txq->bd.cur = bdp; ++ ++ for (i = 0; i < txq->bd.ring_size; i++) { ++ bdp->cbd_sc = cpu_to_fec16(0); ++ skb = netdev_alloc_skb(ndev, FEC_ENET_TX_FRSIZE); ++ if (!skb) ++ goto err_alloc; ++ ++ if ((off = ((unsigned long)skb->data) & fep->tx_align) > 0) ++ skb_reserve(skb, fep->tx_align + 1 - off); ++ ++ bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_TX_FRSIZE - fep->tx_align, DMA_TO_DEVICE)); ++ if (dma_mapping_error(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr))) { ++ goto err_alloc; ++ } ++ txq->tx_skbuff[i] = skb; ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ } ++ ++ /* Set the last buffer to wrap. */ ++ bdp = fec_enet_get_prevdesc(bdp, &txq->bd); ++ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); ++ txq->dirty_tx = bdp; ++ return 0; ++ ++ err_alloc: ++ fec_enet_free_buffers(ndev); ++ return -ENOMEM; ++} ++ ++static int ++fec_enet_open(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret; ++ bool reset_again; ++ int i; ++ ++ ret = pm_runtime_resume_and_get(&fep->pdev->dev); ++ if (ret < 0) ++ return ret; ++ ++ pinctrl_pm_select_default_state(&fep->pdev->dev); ++ ++ /* During the first fec_enet_open call the PHY isn't probed at this ++ * point. Therefore the phy_reset_after_clk_enable() call within ++ * fec_enet_clk_enable() fails. As we need this reset in order to be ++ * sure the PHY is working correctly we check if we need to reset again ++ * later when the PHY is probed ++ */ ++ if (ndev->phydev && ndev->phydev->drv) ++ reset_again = false; ++ else ++ reset_again = true; ++ ++ /* I should reset the ring buffers here, but I don't yet know ++ * a simple way to do that. ++ */ ++ ++ ret = fec_enet_alloc_buffers(ndev); ++ if (ret) ++ goto err_enet_alloc; ++ ++ /* Init MAC prior to mii bus probe */ ++ fec_restart(ndev); ++ ++ /* Call phy_reset_after_clk_enable() again if it failed during ++ * phy_reset_after_clk_enable() before because the PHY wasn't probed. ++ */ ++ if (reset_again) ++ fec_enet_phy_reset_after_clk_enable(ndev); ++ ++ /* Probe and connect to PHY when open the interface */ ++ ret = fec_enet_mii_probe(ndev); ++ if (ret) ++ goto err_enet_mii_probe; ++ ++ if (fep->quirks & FEC_QUIRK_ERR006687) ++ imx6q_cpuidle_fec_irqs_used(); ++ if (fep->quirks & FEC_QUIRK_HAS_PMQOS) ++ cpu_latency_qos_add_request(&fep->pm_qos_req, 0); ++ ++ phy_start(ndev->phydev); ++ mutex_unlock(&fep->fast_ndev_lock); ++ return 0; ++ ++err_enet_mii_probe: ++ fec_enet_free_buffers(ndev); ++err_enet_alloc: ++ pm_runtime_mark_last_busy(&fep->pdev->dev); ++ pm_runtime_put_autosuspend(&fep->pdev->dev); ++ if (!fep->mii_bus_share) ++ pinctrl_pm_select_sleep_state(&fep->pdev->dev); ++ ++ return ret; ++} ++ ++static int ++fec_enet_close(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ phy_stop(ndev->phydev); ++ ++ if (netif_device_present(ndev)) { ++ netif_tx_disable(ndev); ++ fec_stop(ndev); ++ } ++ ++ phy_disconnect(ndev->phydev); ++ ndev->phydev = NULL; ++ ++ if (fep->quirks & FEC_QUIRK_ERR006687) ++ imx6q_cpuidle_fec_irqs_unused(); ++ ++ fec_enet_update_ethtool_stats(ndev); ++ ++ if (!fep->mii_bus_share) ++ pinctrl_pm_select_sleep_state(&fep->pdev->dev); ++ pm_runtime_mark_last_busy(&fep->pdev->dev); ++ pm_runtime_put_autosuspend(&fep->pdev->dev); ++ ++ fec_enet_free_buffers(ndev); ++ mutex_lock(&fep->fast_ndev_lock); ++ return 0; ++} ++ ++/* Set or clear the multicast filter for this adaptor. ++ * Skeleton taken from sunlance driver. ++ * The CPM Ethernet implementation allows Multicast as well as individual ++ * MAC address filtering. Some of the drivers check to make sure it is ++ * a group multicast address, and discard those that are not. I guess I ++ * will do the same for now, but just remove the test if you want ++ * individual filtering as well (do the upper net layers want or support ++ * this kind of feature?). ++ */ ++ ++#define FEC_HASH_BITS 6 /* #bits in hash */ ++ ++static void set_multicast_list(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct netdev_hw_addr *ha; ++ unsigned int crc, tmp; ++ unsigned char hash; ++ unsigned int hash_high = 0, hash_low = 0; ++ ++ if (ndev->flags & IFF_PROMISC) { ++ tmp = readl(fep->hwp + FEC_R_CNTRL); ++ tmp |= 0x8; ++ writel(tmp, fep->hwp + FEC_R_CNTRL); ++ return; ++ } ++ ++ tmp = readl(fep->hwp + FEC_R_CNTRL); ++ tmp &= ~0x8; ++ writel(tmp, fep->hwp + FEC_R_CNTRL); ++ ++ if (ndev->flags & IFF_ALLMULTI) { ++ /* Catch all multicast addresses, so set the ++ * filter to all 1's ++ */ ++ writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); ++ writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); ++ ++ return; ++ } ++ ++ /* Add the addresses in hash register */ ++ netdev_for_each_mc_addr(ha, ndev) { ++ /* calculate crc32 value of mac address */ ++ crc = ether_crc_le(ndev->addr_len, ha->addr); ++ ++ /* only upper 6 bits (FEC_HASH_BITS) are used ++ * which point to specific bit in the hash registers ++ */ ++ hash = (crc >> (32 - FEC_HASH_BITS)) & 0x3f; ++ ++ if (hash > 31) ++ hash_high |= 1 << (hash - 32); ++ else ++ hash_low |= 1 << hash; ++ } ++ ++ writel(hash_high, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); ++ writel(hash_low, fep->hwp + FEC_GRP_HASH_TABLE_LOW); ++} ++ ++/* Set a MAC change in hardware. */ ++static int ++fec_set_mac_address(struct net_device *ndev, void *p) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct sockaddr *addr = p; ++ ++ if (addr) { ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EADDRNOTAVAIL; ++ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); ++ } ++ ++ /* Add netif status check here to avoid system hang in below case: ++ * ifconfig ethx down; ifconfig ethx hw ether xx:xx:xx:xx:xx:xx; ++ * After ethx down, fec all clocks are gated off and then register ++ * access causes system hang. ++ */ ++ if (!netif_running(ndev)) ++ return 0; ++ ++ writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) | ++ (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24), ++ fep->hwp + FEC_ADDR_LOW); ++ writel((ndev->dev_addr[5] << 16) | (ndev->dev_addr[4] << 24), ++ fep->hwp + FEC_ADDR_HIGH); ++ return 0; ++} ++ ++static inline void fec_enet_set_netdev_features(struct net_device *netdev, ++ netdev_features_t features) ++{ ++ struct fec_enet_private *fep = netdev_priv(netdev); ++ netdev_features_t changed = features ^ netdev->features; ++ ++ netdev->features = features; ++ ++ /* Receive checksum has been changed */ ++ if (changed & NETIF_F_RXCSUM) { ++ if (features & NETIF_F_RXCSUM) ++ fep->csum_flags |= FLAG_RX_CSUM_ENABLED; ++ else ++ fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED; ++ } ++} ++ ++static int fec_set_features(struct net_device *netdev, ++ netdev_features_t features) ++{ ++ struct fec_enet_private *fep = netdev_priv(netdev); ++ netdev_features_t changed = features ^ netdev->features; ++ mutex_lock(&fep->fast_ndev_lock); ++ ++ if (netif_running(netdev) && changed & NETIF_F_RXCSUM) { ++ fec_stop(netdev); ++ fec_enet_set_netdev_features(netdev, features); ++ fec_restart(netdev); ++ } else { ++ fec_enet_set_netdev_features(netdev, features); ++ } ++ ++ mutex_unlock(&fep->fast_ndev_lock); ++ return 0; ++} ++ ++static netdev_tx_t ++fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ ++ return NETDEV_TX_OK; ++} ++ ++static u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb, ++ struct net_device *sb_dev) ++{ ++ return 0; ++} ++ ++static const struct net_device_ops fec_netdev_ops = { ++ .ndo_open = fec_enet_open, ++ .ndo_stop = fec_enet_close, ++ .ndo_start_xmit = fec_enet_start_xmit, ++ .ndo_select_queue = fec_enet_select_queue, ++ .ndo_fast_xmit = fec_ecat_fast_xmit, ++ .ndo_fast_recv = fec_ecat_fast_recv, ++ .ndo_set_rx_mode = set_multicast_list, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_tx_timeout = fec_timeout, ++ .ndo_set_mac_address = fec_set_mac_address, ++ .ndo_eth_ioctl = fec_enet_ioctl, ++ .ndo_set_features = fec_set_features, ++}; ++ ++static int fec_enet_init(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct bufdesc *cbd_base; ++ dma_addr_t bd_dma; ++ int bd_size; ++ unsigned int i; ++ unsigned dsize = sizeof(struct bufdesc); ++ unsigned dsize_log2 = __fls(dsize); ++ int ret; ++ unsigned char *pm = NULL; ++ ++ WARN_ON(dsize != (1 << dsize_log2)); ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ fep->rx_align = 0xf; ++ fep->tx_align = 0xf; ++#else ++ fep->rx_align = 0x3; ++ fep->tx_align = 0x3; ++#endif ++ ++ /* Check mask of the streaming and coherent API */ ++ ret = dma_set_mask_and_coherent(&fep->pdev->dev, DMA_BIT_MASK(32)); ++ if (ret < 0) { ++ dev_warn(&fep->pdev->dev, "No suitable DMA available\n"); ++ return ret; ++ } ++ ++ ret = fec_enet_alloc_queue(ndev); ++ if (ret) ++ return ret; ++ ++ bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) * dsize; ++ ++ /* Allocate memory for buffer descriptors. */ ++ cbd_base = dmam_alloc_coherent(&fep->pdev->dev, bd_size, &bd_dma, ++ GFP_KERNEL); ++ if (!cbd_base) { ++ ret = -ENOMEM; ++ goto free_queue_mem; ++ } ++ ++ /* Get the Ethernet address */ ++ ret = fec_get_mac(ndev); ++ if (ret) ++ goto free_queue_mem; ++ ++ /* make sure MAC we just acquired is programmed into the hw */ ++ fec_set_mac_address(ndev, NULL); ++ ++ /* Set receive and transmit descriptor base. */ ++ struct fec_enet_priv_rx_q *rxq = fep->rx_queue; ++ unsigned size; ++ ++ size = dsize * rxq->bd.ring_size; ++ rxq->bd.qid = i; ++ rxq->bd.base = cbd_base; ++ rxq->bd.cur = cbd_base; ++ rxq->bd.dma = bd_dma; ++ rxq->bd.dsize = dsize; ++ rxq->bd.dsize_log2 = dsize_log2; ++ rxq->bd.reg_desc_active = fep->hwp + FEC_R_DES_ACTIVE_0; ++ bd_dma += size; ++ cbd_base = (struct bufdesc *)(((void *)cbd_base) + size); ++ rxq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize); ++ ++ struct fec_enet_priv_tx_q *txq = fep->tx_queue; ++ size = dsize * txq->bd.ring_size; ++ txq->bd.qid = i; ++ txq->bd.base = cbd_base; ++ txq->bd.cur = cbd_base; ++ txq->bd.dma = bd_dma; ++ txq->bd.dsize = dsize; ++ txq->bd.dsize_log2 = dsize_log2; ++ txq->bd.reg_desc_active = fep->hwp + FEC_X_DES_ACTIVE_0; ++ bd_dma += size; ++ cbd_base = (struct bufdesc *)(((void *)cbd_base) + size); ++ txq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize); ++ ++ fep->netdev = ndev; ++ ++ /* The FEC Ethernet specific entries in the device structure */ ++ ndev->watchdog_timeo = TX_TIMEOUT; ++ ndev->netdev_ops = &fec_netdev_ops; ++ ndev->ethtool_ops = &fec_enet_ethtool_ops; ++ ++ pm = ndev->dev_addr; ++ writel(0, fep->hwp + FEC_IMASK); ++ ++ if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) { ++ fep->tx_align = 0; ++ fep->rx_align = 0x3f; ++ } ++ ++ ndev->hw_features = ndev->features; ++ ++ fec_restart(ndev); ++ ++ if (fep->quirks & FEC_QUIRK_MIB_CLEAR) ++ fec_enet_clear_ethtool_stats(ndev); ++ else ++ fec_enet_update_ethtool_stats(ndev); ++ ++ return 0; ++ ++free_queue_mem: ++ fec_enet_free_queue(ndev); ++ return ret; ++} ++ ++#ifdef CONFIG_OF ++static int fec_reset_phy(struct platform_device *pdev) ++{ ++ int err, phy_reset; ++ bool active_high = false; ++ int msec = 1, phy_post_delay = 0; ++ struct device_node *np = pdev->dev.of_node; ++ ++ if (!np) ++ return 0; ++ ++ err = of_property_read_u32(np, "phy-reset-duration", &msec); ++ /* A sane reset duration should not be longer than 1s */ ++ if (!err && msec > 1000) ++ msec = 1; ++ ++ phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); ++ if (phy_reset == -EPROBE_DEFER) ++ return phy_reset; ++ else if (!gpio_is_valid(phy_reset)) ++ return 0; ++ ++ err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay); ++ /* valid reset duration should be less than 1s */ ++ if (!err && phy_post_delay > 1000) ++ return -EINVAL; ++ ++ active_high = of_property_read_bool(np, "phy-reset-active-high"); ++ ++ err = devm_gpio_request_one(&pdev->dev, phy_reset, ++ active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, ++ "phy-reset"); ++ if (err) { ++ dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err); ++ return err; ++ } ++ ++ if (msec > 20) ++ msleep(msec); ++ else ++ usleep_range(msec * 1000, msec * 1000 + 1000); ++ ++ gpio_set_value_cansleep(phy_reset, !active_high); ++ ++ if (!phy_post_delay) ++ return 0; ++ ++ if (phy_post_delay > 20) ++ msleep(phy_post_delay); ++ else ++ usleep_range(phy_post_delay * 1000, ++ phy_post_delay * 1000 + 1000); ++ ++ return 0; ++} ++#else /* CONFIG_OF */ ++static int fec_reset_phy(struct platform_device *pdev) ++{ ++ /* ++ * In case of platform probe, the reset has been done ++ * by machine code. ++ */ ++ return 0; ++} ++#endif /* CONFIG_OF */ ++ ++static int fec_enet_init_stop_mode(struct fec_enet_private *fep, ++ struct device_node *np) ++{ ++ struct device_node *gpr_np; ++ u32 out_val[3]; ++ int ret = 0; ++ ++ gpr_np = of_parse_phandle(np, "fsl,stop-mode", 0); ++ if (!gpr_np) ++ return 0; ++ ++ ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val, ++ ARRAY_SIZE(out_val)); ++ if (ret) { ++ dev_dbg(&fep->pdev->dev, "no stop mode property\n"); ++ goto out; ++ } ++ ++ fep->stop_gpr.gpr = syscon_node_to_regmap(gpr_np); ++ if (IS_ERR(fep->stop_gpr.gpr)) { ++ dev_err(&fep->pdev->dev, "could not find gpr regmap\n"); ++ ret = PTR_ERR(fep->stop_gpr.gpr); ++ fep->stop_gpr.gpr = NULL; ++ goto out; ++ } ++ ++ fep->stop_gpr.reg = out_val[1]; ++ fep->stop_gpr.bit = out_val[2]; ++ ++out: ++ of_node_put(gpr_np); ++ ++ return ret; ++} ++ ++static int ++fec_probe(struct platform_device *pdev) ++{ ++ struct fec_enet_private *fep; ++ struct fec_platform_data *pdata; ++ phy_interface_t interface; ++ struct net_device *ndev; ++ int i, irq, ret = 0; ++ const struct of_device_id *of_id; ++ static int dev_id; ++ struct device_node *np = pdev->dev.of_node, *phy_node; ++ char irq_name[8]; ++ struct fec_devinfo *dev_info; ++ ++ /* Init network device */ ++ ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private) + ++ FEC_STATS_SIZE, 1, 1); ++ if (!ndev) ++ return -ENOMEM; ++ ndev->fast_raw_device = 1; ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ ++ /* setup board info structure */ ++ fep = netdev_priv(ndev); ++ ++ of_id = of_match_device(fec_dt_ids, &pdev->dev); ++ if (of_id) ++ pdev->id_entry = of_id->data; ++ dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data; ++ if (dev_info) ++ fep->quirks = dev_info->quirks; ++ ++ fep->netdev = ndev; ++ mutex_init(&fep->fast_ndev_lock); ++#if !defined(CONFIG_M5272) ++ /* default enable pause frame auto negotiation */ ++ if (fep->quirks & FEC_QUIRK_HAS_GBIT) ++ fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG; ++#endif ++ ++ /* Select default pin state */ ++ pinctrl_pm_select_default_state(&pdev->dev); ++ ++ fep->hwp = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(fep->hwp)) { ++ ret = PTR_ERR(fep->hwp); ++ goto failed_ioremap; ++ } ++ ++ fep->pdev = pdev; ++ fep->dev_id = dev_id++; ++ ++ platform_set_drvdata(pdev, ndev); ++ ++ if ((of_machine_is_compatible("fsl,imx6q") || ++ of_machine_is_compatible("fsl,imx6dl")) && ++ !of_property_read_bool(np, "fsl,err006687-workaround-present")) ++ fep->quirks |= FEC_QUIRK_ERR006687; ++ ++ ret = fec_enet_ipc_handle_init(fep); ++ if (ret) ++ goto failed_ipc_init; ++ ++ ret = fec_enet_init_stop_mode(fep, np); ++ if (ret) ++ goto failed_stop_mode; ++ ++ phy_node = of_parse_phandle(np, "phy-handle", 0); ++ if (!phy_node && of_phy_is_fixed_link(np)) { ++ ret = of_phy_register_fixed_link(np); ++ if (ret < 0) { ++ dev_err(&pdev->dev, ++ "broken fixed-link specification\n"); ++ goto failed_phy; ++ } ++ phy_node = of_node_get(np); ++ } ++ fep->phy_node = phy_node; ++ ++ ret = of_get_phy_mode(pdev->dev.of_node, &interface); ++ if (ret) { ++ pdata = dev_get_platdata(&pdev->dev); ++ if (pdata) ++ fep->phy_interface = pdata->phy; ++ else ++ fep->phy_interface = PHY_INTERFACE_MODE_MII; ++ } else { ++ fep->phy_interface = interface; ++ } ++ ++ ret = fec_enet_parse_rgmii_delay(fep, np); ++ if (ret) ++ goto failed_rgmii_delay; ++ ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); ++ if (IS_ERR(fep->clk_ipg)) { ++ ret = PTR_ERR(fep->clk_ipg); ++ goto failed_clk; ++ } ++ ++ fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(fep->clk_ahb)) { ++ ret = PTR_ERR(fep->clk_ahb); ++ goto failed_clk; ++ } ++ ++ fep->itr_clk_rate = clk_get_rate(fep->clk_ahb); ++ ++ /* enet_out is optional, depends on board */ ++ fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out"); ++ if (IS_ERR(fep->clk_enet_out)) ++ fep->clk_enet_out = NULL; ++ ++ fep->ptp_clk_on = false; ++ mutex_init(&fep->ptp_clk_mutex); ++ ++ /* clk_ref is optional, depends on board */ ++ fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref"); ++ if (IS_ERR(fep->clk_ref)) ++ fep->clk_ref = NULL; ++ fep->clk_ref_rate = clk_get_rate(fep->clk_ref); ++ ++ /* clk_2x_txclk is optional, depends on board */ ++ if (fep->rgmii_txc_dly || fep->rgmii_rxc_dly) { ++ fep->clk_2x_txclk = devm_clk_get(&pdev->dev, "enet_2x_txclk"); ++ if (IS_ERR(fep->clk_2x_txclk)) ++ fep->clk_2x_txclk = NULL; ++ } ++ ++ ret = fec_enet_clk_enable(ndev, true); ++ if (ret) ++ goto failed_clk; ++ ++ ret = clk_prepare_enable(fep->clk_ipg); ++ if (ret) ++ goto failed_clk_ipg; ++ ret = clk_prepare_enable(fep->clk_ahb); ++ if (ret) ++ goto failed_clk_ahb; ++ ++ fep->reg_phy = devm_regulator_get_optional(&pdev->dev, "phy"); ++ if (!IS_ERR(fep->reg_phy)) { ++ ret = regulator_enable(fep->reg_phy); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "Failed to enable phy regulator: %d\n", ret); ++ goto failed_regulator; ++ } ++ } else { ++ if (PTR_ERR(fep->reg_phy) == -EPROBE_DEFER) { ++ ret = -EPROBE_DEFER; ++ goto failed_regulator; ++ } ++ fep->reg_phy = NULL; ++ } ++ ++ if (of_property_read_u32(np, "fsl,rx-phy-delay-100-ns", &fep->rx_delay_100)) ++ fep->rx_delay_100 = 600; ++ ++ if (of_property_read_u32(np, "fsl,tx-phy-delay-100-ns", &fep->tx_delay_100)) ++ fep->tx_delay_100 = 0; ++ ++ if (of_property_read_u32(np, "fsl,rx-phy-delay-1000-ns", &fep->rx_delay_1000)) ++ fep->rx_delay_1000 = 0; ++ ++ if (of_property_read_u32(np, "fsl,tx-phy-delay-1000-ns", &fep->tx_delay_1000)) ++ fep->tx_delay_1000 = 0; ++ ++ pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT); ++ pm_runtime_use_autosuspend(&pdev->dev); ++ pm_runtime_get_noresume(&pdev->dev); ++ pm_runtime_set_active(&pdev->dev); ++ pm_runtime_enable(&pdev->dev); ++ ++ ret = fec_reset_phy(pdev); ++ if (ret) ++ goto failed_reset; ++ ++ //irq_cnt = fec_enet_get_irq_cnt(pdev); ++ ++ ret = fec_enet_init(ndev); ++ if (ret) ++ goto failed_init; ++ ++ /* board only enable one mii bus in default */ ++ if (!of_get_property(np, "fsl,mii-exclusive", NULL)) ++ fep->quirks |= FEC_QUIRK_SINGLE_MDIO; ++ ret = fec_enet_mii_init(pdev); ++ if (ret) ++ goto failed_mii_init; ++ ++ /* Carrier starts down, phylib will bring it up */ ++ netif_carrier_off(ndev); ++ pinctrl_pm_select_sleep_state(&pdev->dev); ++ ++ ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN; ++ ++ ret = register_netdev(ndev); ++ if (ret) ++ goto failed_register; ++ ++ device_init_wakeup(&ndev->dev, fep->wol_flag & ++ FEC_WOL_HAS_MAGIC_PACKET); ++ ++ ++ INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work); ++ ++ pm_runtime_mark_last_busy(&pdev->dev); ++ pm_runtime_put_autosuspend(&pdev->dev); ++ mutex_lock(&fep->fast_ndev_lock); ++ return 0; ++ ++failed_register: ++ fec_enet_mii_remove(fep); ++failed_mii_init: ++failed_irq: ++failed_init: ++ //fec_ptp_stop(pdev); ++failed_reset: ++ pm_runtime_put_noidle(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ if (fep->reg_phy) ++ regulator_disable(fep->reg_phy); ++failed_regulator: ++ clk_disable_unprepare(fep->clk_ahb); ++failed_clk_ahb: ++ clk_disable_unprepare(fep->clk_ipg); ++failed_clk_ipg: ++ fec_enet_clk_enable(ndev, false); ++failed_clk: ++ release_bus_freq(BUS_FREQ_HIGH); ++failed_rgmii_delay: ++ if (of_phy_is_fixed_link(np)) ++ of_phy_deregister_fixed_link(np); ++ of_node_put(phy_node); ++failed_stop_mode: ++failed_ipc_init: ++failed_phy: ++ dev_id--; ++failed_ioremap: ++ free_netdev(ndev); ++ ++ return ret; ++} ++ ++static int ++fec_drv_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct device_node *np = pdev->dev.of_node; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(&pdev->dev); ++ if (ret < 0) ++ return ret; ++ ++ cancel_work_sync(&fep->tx_timeout_work); ++ //fec_ptp_stop(pdev); ++ unregister_netdev(ndev); ++ fec_enet_mii_remove(fep); ++ if (fep->reg_phy) ++ regulator_disable(fep->reg_phy); ++ ++ if (of_phy_is_fixed_link(np)) ++ of_phy_deregister_fixed_link(np); ++ of_node_put(fep->phy_node); ++ ++ clk_disable_unprepare(fep->clk_ahb); ++ clk_disable_unprepare(fep->clk_ipg); ++ pm_runtime_put_noidle(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ free_netdev(ndev); ++ mutex_unlock(&fep->fast_ndev_lock); ++ return 0; ++} ++ ++static int __maybe_unused fec_suspend(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ if (netif_running(ndev)) { ++ int ret; ++ ++ phy_stop(ndev->phydev); ++ ++ netif_device_detach(ndev); ++ fec_stop(ndev); ++ fec_enet_clk_enable(ndev, false); ++ ++ fep->rpm_active = !pm_runtime_status_suspended(dev); ++ if (fep->rpm_active) { ++ ret = pm_runtime_force_suspend(dev); ++ if (ret < 0) ++ return ret; ++ } ++ } else if (fep->mii_bus_share && !ndev->phydev) { ++ pinctrl_pm_select_sleep_state(&fep->pdev->dev); ++ } ++ ++ if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) ++ regulator_disable(fep->reg_phy); ++ ++ /* SOC supply clock to phy, when clock is disabled, phy link down ++ * SOC control phy regulator, when regulator is disabled, phy link down ++ */ ++ if (fep->clk_enet_out || fep->reg_phy) ++ fep->link = 0; ++ ++ return 0; ++} ++ ++static int __maybe_unused fec_resume(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret = 0; ++ int val; ++ ++ if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) { ++ ret = regulator_enable(fep->reg_phy); ++ if (ret) ++ return ret; ++ } ++ ++ if (netif_running(ndev)) { ++ if (fep->rpm_active) ++ pm_runtime_force_resume(dev); ++ ++ ret = fec_enet_clk_enable(ndev, true); ++ if (ret) { ++ rtnl_unlock(); ++ goto failed_clk; ++ } ++ pinctrl_pm_select_default_state(&fep->pdev->dev); ++ fec_restart(ndev); ++ netif_device_attach(ndev); ++ ++ //napi_enable(&fep->napi); ++ ++ phy_init_hw(ndev->phydev); ++ phy_start(ndev->phydev); ++ } else if (fep->mii_bus_share && !ndev->phydev) { ++ pinctrl_pm_select_default_state(&fep->pdev->dev); ++ /* And then recovery mii bus */ ++ ret = fec_restore_mii_bus(ndev); ++ } ++ ++ return ret; ++ ++failed_clk: ++ if (fep->reg_phy) ++ regulator_disable(fep->reg_phy); ++ return ret; ++} ++ ++static int __maybe_unused fec_runtime_suspend(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ ++ clk_disable_unprepare(fep->clk_ahb); ++ clk_disable_unprepare(fep->clk_ipg); ++ release_bus_freq(BUS_FREQ_HIGH); ++ ++ return 0; ++} ++ ++static int __maybe_unused fec_runtime_resume(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ int ret; ++ ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ ret = clk_prepare_enable(fep->clk_ahb); ++ if (ret) ++ return ret; ++ ret = clk_prepare_enable(fep->clk_ipg); ++ if (ret) ++ goto failed_clk_ipg; ++ ++ return 0; ++ ++failed_clk_ipg: ++ clk_disable_unprepare(fep->clk_ahb); ++ release_bus_freq(BUS_FREQ_HIGH); ++ return ret; ++} ++ ++static const struct dev_pm_ops fec_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(fec_suspend, fec_resume) ++ SET_RUNTIME_PM_OPS(fec_runtime_suspend, fec_runtime_resume, NULL) ++}; ++ ++static struct platform_driver fec_ecat_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .pm = &fec_pm_ops, ++ .of_match_table = fec_dt_ids, ++ .suppress_bind_attrs = true, ++ }, ++ .id_table = fec_devtype, ++ .probe = fec_probe, ++ .remove = fec_drv_remove, ++}; ++ ++module_platform_driver(fec_ecat_driver); ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/ethernet/freescale/fec_ecat.h b/drivers/net/ethernet/freescale/fec_ecat.h +new file mode 100644 +index 000000000000..87db4c85db24 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/fec_ecat.h +@@ -0,0 +1,713 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++/****************************************************************************/ ++#ifndef FEC_ECAT_H ++#define FEC_ECAT_H ++/****************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ ++ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ ++ defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST) ++/* ++ * Just figures, Motorola would have to change the offsets for ++ * registers in the same peripheral device on different models ++ * of the ColdFire! ++ */ ++#define FEC_IEVENT 0x004 /* Interrupt event reg */ ++#define FEC_IMASK 0x008 /* Interrupt mask reg */ ++#define FEC_R_DES_ACTIVE_0 0x010 /* Receive descriptor reg */ ++#define FEC_X_DES_ACTIVE_0 0x014 /* Transmit descriptor reg */ ++#define FEC_ECNTRL 0x024 /* Ethernet control reg */ ++#define FEC_MII_DATA 0x040 /* MII manage frame reg */ ++#define FEC_MII_SPEED 0x044 /* MII speed control reg */ ++#define FEC_MIB_CTRLSTAT 0x064 /* MIB control/status reg */ ++#define FEC_R_CNTRL 0x084 /* Receive control reg */ ++#define FEC_X_CNTRL 0x0c4 /* Transmit Control reg */ ++#define FEC_ADDR_LOW 0x0e4 /* Low 32bits MAC address */ ++#define FEC_ADDR_HIGH 0x0e8 /* High 16bits MAC address */ ++#define FEC_OPD 0x0ec /* Opcode + Pause duration */ ++#define FEC_TXIC0 0x0f0 /* Tx Interrupt Coalescing for ring 0 */ ++#define FEC_TXIC1 0x0f4 /* Tx Interrupt Coalescing for ring 1 */ ++#define FEC_TXIC2 0x0f8 /* Tx Interrupt Coalescing for ring 2 */ ++#define FEC_RXIC0 0x100 /* Rx Interrupt Coalescing for ring 0 */ ++#define FEC_RXIC1 0x104 /* Rx Interrupt Coalescing for ring 1 */ ++#define FEC_RXIC2 0x108 /* Rx Interrupt Coalescing for ring 2 */ ++#define FEC_HASH_TABLE_HIGH 0x118 /* High 32bits hash table */ ++#define FEC_HASH_TABLE_LOW 0x11c /* Low 32bits hash table */ ++#define FEC_GRP_HASH_TABLE_HIGH 0x120 /* High 32bits hash table */ ++#define FEC_GRP_HASH_TABLE_LOW 0x124 /* Low 32bits hash table */ ++#define FEC_X_WMRK 0x144 /* FIFO transmit water mark */ ++#define FEC_R_BOUND 0x14c /* FIFO receive bound reg */ ++#define FEC_R_FSTART 0x150 /* FIFO receive start reg */ ++#define FEC_R_DES_START_1 0x160 /* Receive descriptor ring 1 */ ++#define FEC_X_DES_START_1 0x164 /* Transmit descriptor ring 1 */ ++#define FEC_R_BUFF_SIZE_1 0x168 /* Maximum receive buff ring1 size */ ++#define FEC_R_DES_START_2 0x16c /* Receive descriptor ring 2 */ ++#define FEC_X_DES_START_2 0x170 /* Transmit descriptor ring 2 */ ++#define FEC_R_BUFF_SIZE_2 0x174 /* Maximum receive buff ring2 size */ ++#define FEC_R_DES_START_0 0x180 /* Receive descriptor ring */ ++#define FEC_X_DES_START_0 0x184 /* Transmit descriptor ring */ ++#define FEC_R_BUFF_SIZE_0 0x188 /* Maximum receive buff size */ ++#define FEC_R_FIFO_RSFL 0x190 /* Receive FIFO section full threshold */ ++#define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */ ++#define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */ ++#define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */ ++#define FEC_FTRL 0x1b0 /* Frame truncation receive length*/ ++#define FEC_RACC 0x1c4 /* Receive Accelerator function */ ++#define FEC_RCMR_1 0x1c8 /* Receive classification match ring 1 */ ++#define FEC_RCMR_2 0x1cc /* Receive classification match ring 2 */ ++#define FEC_DMA_CFG_1 0x1d8 /* DMA class configuration for ring 1 */ ++#define FEC_DMA_CFG_2 0x1dc /* DMA class Configuration for ring 2 */ ++#define FEC_R_DES_ACTIVE_1 0x1e0 /* Rx descriptor active for ring 1 */ ++#define FEC_X_DES_ACTIVE_1 0x1e4 /* Tx descriptor active for ring 1 */ ++#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */ ++#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */ ++#define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */ ++#define FEC_LPI_SLEEP 0x1f4 /* Set IEEE802.3az LPI Sleep Ts time */ ++#define FEC_LPI_WAKE 0x1f8 /* Set IEEE802.3az LPI Wake Tw time */ ++#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */ ++#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */ ++ ++#define BM_MIIGSK_CFGR_MII 0x00 ++#define BM_MIIGSK_CFGR_RMII 0x01 ++#define BM_MIIGSK_CFGR_FRCONT_10M 0x40 ++ ++#define RMON_T_DROP 0x200 /* Count of frames not cntd correctly */ ++#define RMON_T_PACKETS 0x204 /* RMON TX packet count */ ++#define RMON_T_BC_PKT 0x208 /* RMON TX broadcast pkts */ ++#define RMON_T_MC_PKT 0x20c /* RMON TX multicast pkts */ ++#define RMON_T_CRC_ALIGN 0x210 /* RMON TX pkts with CRC align err */ ++#define RMON_T_UNDERSIZE 0x214 /* RMON TX pkts < 64 bytes, good CRC */ ++#define RMON_T_OVERSIZE 0x218 /* RMON TX pkts > MAX_FL bytes good CRC */ ++#define RMON_T_FRAG 0x21c /* RMON TX pkts < 64 bytes, bad CRC */ ++#define RMON_T_JAB 0x220 /* RMON TX pkts > MAX_FL bytes, bad CRC */ ++#define RMON_T_COL 0x224 /* RMON TX collision count */ ++#define RMON_T_P64 0x228 /* RMON TX 64 byte pkts */ ++#define RMON_T_P65TO127 0x22c /* RMON TX 65 to 127 byte pkts */ ++#define RMON_T_P128TO255 0x230 /* RMON TX 128 to 255 byte pkts */ ++#define RMON_T_P256TO511 0x234 /* RMON TX 256 to 511 byte pkts */ ++#define RMON_T_P512TO1023 0x238 /* RMON TX 512 to 1023 byte pkts */ ++#define RMON_T_P1024TO2047 0x23c /* RMON TX 1024 to 2047 byte pkts */ ++#define RMON_T_P_GTE2048 0x240 /* RMON TX pkts > 2048 bytes */ ++#define RMON_T_OCTETS 0x244 /* RMON TX octets */ ++#define IEEE_T_DROP 0x248 /* Count of frames not counted crtly */ ++#define IEEE_T_FRAME_OK 0x24c /* Frames tx'd OK */ ++#define IEEE_T_1COL 0x250 /* Frames tx'd with single collision */ ++#define IEEE_T_MCOL 0x254 /* Frames tx'd with multiple collision */ ++#define IEEE_T_DEF 0x258 /* Frames tx'd after deferral delay */ ++#define IEEE_T_LCOL 0x25c /* Frames tx'd with late collision */ ++#define IEEE_T_EXCOL 0x260 /* Frames tx'd with excesv collisions */ ++#define IEEE_T_MACERR 0x264 /* Frames tx'd with TX FIFO underrun */ ++#define IEEE_T_CSERR 0x268 /* Frames tx'd with carrier sense err */ ++#define IEEE_T_SQE 0x26c /* Frames tx'd with SQE err */ ++#define IEEE_T_FDXFC 0x270 /* Flow control pause frames tx'd */ ++#define IEEE_T_OCTETS_OK 0x274 /* Octet count for frames tx'd w/o err */ ++#define RMON_R_PACKETS 0x284 /* RMON RX packet count */ ++#define RMON_R_BC_PKT 0x288 /* RMON RX broadcast pkts */ ++#define RMON_R_MC_PKT 0x28c /* RMON RX multicast pkts */ ++#define RMON_R_CRC_ALIGN 0x290 /* RMON RX pkts with CRC alignment err */ ++#define RMON_R_UNDERSIZE 0x294 /* RMON RX pkts < 64 bytes, good CRC */ ++#define RMON_R_OVERSIZE 0x298 /* RMON RX pkts > MAX_FL bytes good CRC */ ++#define RMON_R_FRAG 0x29c /* RMON RX pkts < 64 bytes, bad CRC */ ++#define RMON_R_JAB 0x2a0 /* RMON RX pkts > MAX_FL bytes, bad CRC */ ++#define RMON_R_RESVD_O 0x2a4 /* Reserved */ ++#define RMON_R_P64 0x2a8 /* RMON RX 64 byte pkts */ ++#define RMON_R_P65TO127 0x2ac /* RMON RX 65 to 127 byte pkts */ ++#define RMON_R_P128TO255 0x2b0 /* RMON RX 128 to 255 byte pkts */ ++#define RMON_R_P256TO511 0x2b4 /* RMON RX 256 to 511 byte pkts */ ++#define RMON_R_P512TO1023 0x2b8 /* RMON RX 512 to 1023 byte pkts */ ++#define RMON_R_P1024TO2047 0x2bc /* RMON RX 1024 to 2047 byte pkts */ ++#define RMON_R_P_GTE2048 0x2c0 /* RMON RX pkts > 2048 bytes */ ++#define RMON_R_OCTETS 0x2c4 /* RMON RX octets */ ++#define IEEE_R_DROP 0x2c8 /* Count frames not counted correctly */ ++#define IEEE_R_FRAME_OK 0x2cc /* Frames rx'd OK */ ++#define IEEE_R_CRC 0x2d0 /* Frames rx'd with CRC err */ ++#define IEEE_R_ALIGN 0x2d4 /* Frames rx'd with alignment err */ ++#define IEEE_R_MACERR 0x2d8 /* Receive FIFO overflow count */ ++#define IEEE_R_FDXFC 0x2dc /* Flow control pause frames rx'd */ ++#define IEEE_R_OCTETS_OK 0x2e0 /* Octet cnt for frames rx'd w/o err */ ++ ++#else ++ ++#define FEC_ECNTRL 0x000 /* Ethernet control reg */ ++#define FEC_IEVENT 0x004 /* Interrupt even reg */ ++#define FEC_IMASK 0x008 /* Interrupt mask reg */ ++#define FEC_IVEC 0x00c /* Interrupt vec status reg */ ++#define FEC_R_DES_ACTIVE_0 0x010 /* Receive descriptor reg */ ++#define FEC_R_DES_ACTIVE_1 FEC_R_DES_ACTIVE_0 ++#define FEC_R_DES_ACTIVE_2 FEC_R_DES_ACTIVE_0 ++#define FEC_X_DES_ACTIVE_0 0x014 /* Transmit descriptor reg */ ++#define FEC_X_DES_ACTIVE_1 FEC_X_DES_ACTIVE_0 ++#define FEC_X_DES_ACTIVE_2 FEC_X_DES_ACTIVE_0 ++#define FEC_MII_DATA 0x040 /* MII manage frame reg */ ++#define FEC_MII_SPEED 0x044 /* MII speed control reg */ ++#define FEC_R_BOUND 0x08c /* FIFO receive bound reg */ ++#define FEC_R_FSTART 0x090 /* FIFO receive start reg */ ++#define FEC_X_WMRK 0x0a4 /* FIFO transmit water mark */ ++#define FEC_X_FSTART 0x0ac /* FIFO transmit start reg */ ++#define FEC_R_CNTRL 0x104 /* Receive control reg */ ++#define FEC_MAX_FRM_LEN 0x108 /* Maximum frame length reg */ ++#define FEC_X_CNTRL 0x144 /* Transmit Control reg */ ++#define FEC_ADDR_LOW 0x3c0 /* Low 32bits MAC address */ ++#define FEC_ADDR_HIGH 0x3c4 /* High 16bits MAC address */ ++#define FEC_GRP_HASH_TABLE_HIGH 0x3c8 /* High 32bits hash table */ ++#define FEC_GRP_HASH_TABLE_LOW 0x3cc /* Low 32bits hash table */ ++#define FEC_R_DES_START_0 0x3d0 /* Receive descriptor ring */ ++#define FEC_R_DES_START_1 FEC_R_DES_START_0 ++#define FEC_R_DES_START_2 FEC_R_DES_START_0 ++#define FEC_X_DES_START_0 0x3d4 /* Transmit descriptor ring */ ++#define FEC_X_DES_START_1 FEC_X_DES_START_0 ++#define FEC_X_DES_START_2 FEC_X_DES_START_0 ++#define FEC_R_BUFF_SIZE_0 0x3d8 /* Maximum receive buff size */ ++#define FEC_R_BUFF_SIZE_1 FEC_R_BUFF_SIZE_0 ++#define FEC_R_BUFF_SIZE_2 FEC_R_BUFF_SIZE_0 ++#define FEC_FIFO_RAM 0x400 /* FIFO RAM buffer */ ++/* Not existed in real chip ++ * Just for pass build. ++ */ ++#define FEC_RCMR_1 0xfff ++#define FEC_RCMR_2 0xfff ++#define FEC_DMA_CFG_1 0xfff ++#define FEC_DMA_CFG_2 0xfff ++#define FEC_TXIC0 0xfff ++#define FEC_TXIC1 0xfff ++#define FEC_TXIC2 0xfff ++#define FEC_RXIC0 0xfff ++#define FEC_RXIC1 0xfff ++#define FEC_RXIC2 0xfff ++#define FEC_LPI_SLEEP 0xfff ++#define FEC_LPI_WAKE 0xfff ++#endif /* CONFIG_M5272 */ ++ ++ ++/* ++ * Define the buffer descriptor structure. ++ * ++ * Evidently, ARM SoCs have the FEC block generated in a ++ * little endian mode so adjust endianness accordingly. ++ */ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++#define fec32_to_cpu le32_to_cpu ++#define fec16_to_cpu le16_to_cpu ++#define cpu_to_fec32 cpu_to_le32 ++#define cpu_to_fec16 cpu_to_le16 ++#define __fec32 __le32 ++#define __fec16 __le16 ++ ++struct bufdesc { ++ __fec16 cbd_datlen; /* Data length */ ++ __fec16 cbd_sc; /* Control and status info */ ++ __fec32 cbd_bufaddr; /* Buffer address */ ++}; ++#else ++#define fec32_to_cpu be32_to_cpu ++#define fec16_to_cpu be16_to_cpu ++#define cpu_to_fec32 cpu_to_be32 ++#define cpu_to_fec16 cpu_to_be16 ++#define __fec32 __be32 ++#define __fec16 __be16 ++ ++struct bufdesc { ++ __fec16 cbd_sc; /* Control and status info */ ++ __fec16 cbd_datlen; /* Data length */ ++ __fec32 cbd_bufaddr; /* Buffer address */ ++}; ++#endif ++ ++struct bufdesc_ex { ++ struct bufdesc desc; ++ __fec32 cbd_esc; ++ __fec32 cbd_prot; ++ __fec32 cbd_bdu; ++ __fec32 ts; ++ __fec16 res0[4]; ++}; ++ ++/* ++ * The following definitions courtesy of commproc.h, which where ++ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net). ++ */ ++#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ ++#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ ++#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ ++#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ ++#define BD_SC_CM ((ushort)0x0200) /* Continuous mode */ ++#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ ++#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ ++#define BD_SC_BR ((ushort)0x0020) /* Break received */ ++#define BD_SC_FR ((ushort)0x0010) /* Framing error */ ++#define BD_SC_PR ((ushort)0x0008) /* Parity error */ ++#define BD_SC_OV ((ushort)0x0002) /* Overrun */ ++#define BD_SC_CD ((ushort)0x0001) /* ?? */ ++ ++/* Buffer descriptor control/status used by Ethernet receive. ++ */ ++#define BD_ENET_RX_EMPTY ((ushort)0x8000) ++#define BD_ENET_RX_WRAP ((ushort)0x2000) ++#define BD_ENET_RX_INTR ((ushort)0x1000) ++#define BD_ENET_RX_LAST ((ushort)0x0800) ++#define BD_ENET_RX_FIRST ((ushort)0x0400) ++#define BD_ENET_RX_MISS ((ushort)0x0100) ++#define BD_ENET_RX_LG ((ushort)0x0020) ++#define BD_ENET_RX_NO ((ushort)0x0010) ++#define BD_ENET_RX_SH ((ushort)0x0008) ++#define BD_ENET_RX_CR ((ushort)0x0004) ++#define BD_ENET_RX_OV ((ushort)0x0002) ++#define BD_ENET_RX_CL ((ushort)0x0001) ++#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ ++ ++/* Enhanced buffer descriptor control/status used by Ethernet receive */ ++#define BD_ENET_RX_VLAN 0x00000004 ++ ++/* Buffer descriptor control/status used by Ethernet transmit. ++ */ ++#define BD_ENET_TX_READY ((ushort)0x8000) ++#define BD_ENET_TX_PAD ((ushort)0x4000) ++#define BD_ENET_TX_WRAP ((ushort)0x2000) ++#define BD_ENET_TX_INTR ((ushort)0x1000) ++#define BD_ENET_TX_LAST ((ushort)0x0800) ++#define BD_ENET_TX_TC ((ushort)0x0400) ++#define BD_ENET_TX_DEF ((ushort)0x0200) ++#define BD_ENET_TX_HB ((ushort)0x0100) ++#define BD_ENET_TX_LC ((ushort)0x0080) ++#define BD_ENET_TX_RL ((ushort)0x0040) ++#define BD_ENET_TX_RCMASK ((ushort)0x003c) ++#define BD_ENET_TX_UN ((ushort)0x0002) ++#define BD_ENET_TX_CSL ((ushort)0x0001) ++#define BD_ENET_TX_STATS ((ushort)0x0fff) /* All status bits */ ++ ++/* enhanced buffer descriptor control/status used by Ethernet transmit */ ++#define BD_ENET_TX_INT 0x40000000 ++#define BD_ENET_TX_TS 0x20000000 ++#define BD_ENET_TX_PINS 0x10000000 ++#define BD_ENET_TX_IINS 0x08000000 ++ ++ ++/* This device has up to three irqs on some platforms */ ++#define FEC_IRQ_NUM 3 ++ ++/* Maximum number of queues supported ++ * ENET with AVB IP can support up to 3 independent tx queues and rx queues. ++ * User can point the queue number that is less than or equal to 3. ++ */ ++#define FEC_ENET_MAX_TX_QS 3 ++#define FEC_ENET_MAX_RX_QS 3 ++ ++#define FEC_R_DES_START(X) (((X) == 1) ? FEC_R_DES_START_1 : \ ++ (((X) == 2) ? \ ++ FEC_R_DES_START_2 : FEC_R_DES_START_0)) ++#define FEC_X_DES_START(X) (((X) == 1) ? FEC_X_DES_START_1 : \ ++ (((X) == 2) ? \ ++ FEC_X_DES_START_2 : FEC_X_DES_START_0)) ++#define FEC_R_BUFF_SIZE(X) (((X) == 1) ? FEC_R_BUFF_SIZE_1 : \ ++ (((X) == 2) ? \ ++ FEC_R_BUFF_SIZE_2 : FEC_R_BUFF_SIZE_0)) ++ ++#define FEC_DMA_CFG(X) (((X) == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1) ++ ++#define DMA_CLASS_EN (1 << 16) ++#define FEC_RCMR(X) (((X) == 2) ? FEC_RCMR_2 : FEC_RCMR_1) ++#define IDLE_SLOPE_MASK 0xffff ++#define IDLE_SLOPE_1 0x200 /* BW fraction: 0.5 */ ++#define IDLE_SLOPE_2 0x200 /* BW fraction: 0.5 */ ++#define IDLE_SLOPE(X) (((X) == 1) ? \ ++ (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \ ++ (IDLE_SLOPE_2 & IDLE_SLOPE_MASK)) ++#define RCMR_MATCHEN (0x1 << 16) ++#define RCMR_CMP_CFG(v, n) (((v) & 0x7) << (n << 2)) ++#ifdef CONFIG_AVB_SUPPORT ++#define SR_CLASS_A_PRIORITY 3 ++#define SR_CLASS_B_PRIORITY 2 ++#define RCMR_CMP_1 (RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 0) | \ ++ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 1) | \ ++ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 2) | \ ++ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 3)) ++#define RCMR_CMP_2 (RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 0) | \ ++ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 1) | \ ++ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 2) | \ ++ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 3)) ++#else ++#define RCMR_CMP_1 (RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \ ++ RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3)) ++#define RCMR_CMP_2 (RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \ ++ RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3)) ++#endif ++#define RCMR_CMP(X) (((X) == 1) ? RCMR_CMP_1 : RCMR_CMP_2) ++#define FEC_TX_BD_FTYPE(X) (((X) & 0xf) << 20) ++ ++#define FEC_RX_FLUSH(X) (1 << ((X) + 3)) ++ ++#define FEC_TX_SCHEME_CB 0x0 /* Credit based */ ++#define FEC_TX_SCHEME_RR 0x1 /* Round-robin */ ++ ++#define BD_ENET_RX_INT 0x00800000 ++#define BD_ENET_RX_PTP ((ushort)0x0400) ++#define BD_ENET_RX_ICE 0x00000020 ++#define BD_ENET_RX_PCR 0x00000010 ++#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) ++#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) ++ ++/* Interrupt events/masks. */ ++#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ ++#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ ++#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ ++#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */ ++#define FEC_ENET_TXF_0 ((uint)0x08000000) /* Full frame transmitted */ ++#define FEC_ENET_TXF_1 ((uint)0x00000008) /* Full frame transmitted */ ++#define FEC_ENET_TXF_2 ((uint)0x00000080) /* Full frame transmitted */ ++#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */ ++#define FEC_ENET_RXF_0 ((uint)0x02000000) /* Full frame received */ ++#define FEC_ENET_RXF_1 ((uint)0x00000002) /* Full frame received */ ++#define FEC_ENET_RXF_2 ((uint)0x00000020) /* Full frame received */ ++#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ ++#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ ++#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ ++#define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */ ++#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2) ++#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2) ++#define FEC_ENET_RXF_GET(X) (((X) == 0) ? FEC_ENET_RXF_0 : \ ++ (((X) == 1) ? FEC_ENET_RXF_1 : \ ++ FEC_ENET_RXF_2)) ++#define FEC_ENET_TS_AVAIL ((uint)0x00010000) ++#define FEC_ENET_TS_TIMER ((uint)0x00008000) ++ ++#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF) ++#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF)) ++ ++#define FEC_ENET_ETHEREN ((uint)0x00000002) ++#define FEC_ENET_TXC_DLY ((uint)0x00010000) ++#define FEC_ENET_RXC_DLY ((uint)0x00020000) ++ ++/* ENET interrupt coalescing macro define */ ++#define FEC_ITR_CLK_SEL (0x1 << 30) ++#define FEC_ITR_EN (0x1 << 31) ++#define FEC_ITR_ICFT(X) (((X) & 0xff) << 20) ++#define FEC_ITR_ICTT(X) ((X) & 0xffff) ++#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */ ++#define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */ ++ ++#define FEC_VLAN_TAG_LEN 0x04 ++#define FEC_ETHTYPE_LEN 0x02 ++ ++/* Controller is ENET-MAC */ ++#define FEC_QUIRK_ENET_MAC (1 << 0) ++/* Controller needs driver to swap frame */ ++#define FEC_QUIRK_SWAP_FRAME (1 << 1) ++/* Controller uses gasket */ ++#define FEC_QUIRK_USE_GASKET (1 << 2) ++/* Controller has GBIT support */ ++#define FEC_QUIRK_HAS_GBIT (1 << 3) ++/* Controller has extend desc buffer */ ++#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4) ++/* Controller has hardware checksum support */ ++#define FEC_QUIRK_HAS_CSUM (1 << 5) ++/* Controller has hardware vlan support */ ++#define FEC_QUIRK_HAS_VLAN (1 << 6) ++/* ENET IP errata ERR006358 ++ * ++ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously ++ * detected as not set during a prior frame transmission, then the ++ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs ++ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in ++ * frames not being transmitted until there is a 0-to-1 transition on ++ * ENET_TDAR[TDAR]. ++ */ ++#define FEC_QUIRK_ERR006358 (1 << 7) ++/* ENET IP hw AVB ++ * ++ * i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support. ++ * - Two class indicators on receive with configurable priority ++ * - Two class indicators and line speed timer on transmit allowing ++ * implementation class credit based shapers externally ++ * - Additional DMA registers provisioned to allow managing up to 3 ++ * independent rings ++ */ ++#define FEC_QUIRK_HAS_AVB (1 << 8) ++/* There is a TDAR race condition for mutliQ when the software sets TDAR ++ * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles). ++ * This will cause the udma_tx and udma_tx_arbiter state machines to hang. ++ * The issue exist at i.MX6SX enet IP. ++ */ ++#define FEC_QUIRK_ERR007885 (1 << 9) ++/* ENET Block Guide/ Chapter for the iMX6SX (PELE) address one issue: ++ * After set ENET_ATCR[Capture], there need some time cycles before the counter ++ * value is capture in the register clock domain. ++ * The wait-time-cycles is at least 6 clock cycles of the slower clock between ++ * the register clock and the 1588 clock. The 1588 ts_clk is fixed to 25Mhz, ++ * register clock is 66Mhz, so the wait-time-cycles must be greater than 240ns ++ * (40ns * 6). ++ */ ++#define FEC_QUIRK_BUG_CAPTURE (1 << 10) ++/* Controller has only one MDIO bus */ ++#define FEC_QUIRK_SINGLE_MDIO (1 << 11) ++/* Controller supports RACC register */ ++#define FEC_QUIRK_HAS_RACC (1 << 12) ++/* Controller supports interrupt coalesc */ ++#define FEC_QUIRK_HAS_COALESCE (1 << 13) ++/* Interrupt doesn't wake CPU from deep idle */ ++#define FEC_QUIRK_ERR006687 (1 << 14) ++/* The MIB counters should be cleared and enabled during ++ * initialisation. ++ */ ++#define FEC_QUIRK_MIB_CLEAR (1 << 15) ++/* Only i.MX25/i.MX27/i.MX28 controller supports FRBR,FRSR registers, ++ * those FIFO receive registers are resolved in other platforms. ++ */ ++#define FEC_QUIRK_HAS_FRREG (1 << 16) ++ ++/* Some FEC hardware blocks need the MMFR cleared at setup time to avoid ++ * the generation of an MII event. This must be avoided in the older ++ * FEC blocks where it will stop MII events being generated. ++ */ ++#define FEC_QUIRK_CLEAR_SETUP_MII (1 << 17) ++ ++/* Some link partners do not tolerate the momentary reset of the REF_CLK ++ * frequency when the RNCTL register is cleared by hardware reset. ++ */ ++#define FEC_QUIRK_NO_HARD_RESET (1 << 18) ++ ++/* i.MX6SX ENET IP supports multiple queues (3 queues), use this quirk to ++ * represents this ENET IP. ++ */ ++#define FEC_QUIRK_HAS_MULTI_QUEUES (1 << 19) ++ ++/* i.MX8MQ ENET IP version add new feature to support IEEE 802.3az EEE ++ * standard. For the transmission, MAC supply two user registers to set ++ * Sleep (TS) and Wake (TW) time. ++ */ ++#define FEC_QUIRK_HAS_EEE (1 << 20) ++ ++/* i.MX8QM ENET IP version add new feture to generate delayed TXC/RXC ++ * as an alternative option to make sure it works well with various PHYs. ++ * For the implementation of delayed clock, ENET takes synchronized 250MHz ++ * clocks to generate 2ns delay. ++ */ ++#define FEC_QUIRK_DELAYED_CLKS_SUPPORT (1 << 21) ++ ++ ++/* i.MX8MQ SoC integration mix wakeup interrupt signal into "int2" interrupt line. */ ++#define FEC_QUIRK_WAKEUP_FROM_INT2 (1 << 22) ++ ++/* request pmqos during low power */ ++#define FEC_QUIRK_HAS_PMQOS (1 << 23) ++ ++struct bufdesc_prop { ++ int qid; ++ /* Address of Rx and Tx buffers */ ++ struct bufdesc *base; ++ struct bufdesc *last; ++ struct bufdesc *cur; ++ void __iomem *reg_desc_active; ++ dma_addr_t dma; ++ unsigned short ring_size; ++ unsigned char dsize; ++ unsigned char dsize_log2; ++}; ++ ++struct fec_enet_priv_tx_q { ++ struct bufdesc_prop bd; ++ struct bufdesc *dirty_tx; ++ struct sk_buff *tx_skbuff[FEC_TX_RING_SIZE]; ++ ++ unsigned int tx_bounce_size; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ unsigned int tx_index; ++ unsigned char *tx_bounce[FEC_TX_RING_SIZE + 32]; ++#else ++ unsigned char *tx_bounce[FEC_TX_RING_SIZE]; ++#endif ++ unsigned short tx_stop_threshold; ++ unsigned short tx_wake_threshold; ++ ++ char *tso_hdrs; ++ dma_addr_t tso_hdrs_dma; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ unsigned long tx_idle_slope; ++#endif ++}; ++ ++struct fec_enet_priv_rx_q { ++ struct bufdesc_prop bd; ++ struct sk_buff *rx_skbuff[FEC_RX_RING_SIZE]; ++}; ++ ++struct fec_stop_mode_gpr { ++ struct regmap *gpr; ++ u8 reg; ++ u8 bit; ++}; ++ ++#ifdef CONFIG_AVB_SUPPORT ++#define AVB_DMA_MAPPING 1 ++#endif ++ ++/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and ++ * tx_bd_base always point to the base of the buffer descriptors. The ++ * cur_rx and cur_tx point to the currently available buffer. ++ * The dirty_tx tracks the current buffer that is being sent by the ++ * controller. The cur_tx and dirty_tx are equal under both completely ++ * empty and completely full conditions. The empty/ready indicator in ++ * the buffer descriptor determines the actual condition. ++ */ ++struct fec_enet_private { ++ /* Hardware registers of the FEC device */ ++ void __iomem *hwp; ++ ++ struct net_device *netdev; ++ ++ struct clk *clk_ipg; ++ struct clk *clk_ahb; ++ struct clk *clk_ref; ++ struct clk *clk_enet_out; ++ struct clk *clk_ptp; ++ struct clk *clk_2x_txclk; ++ ++ bool ptp_clk_on; ++ struct mutex ptp_clk_mutex; ++ unsigned int num_tx_queues; ++ unsigned int num_rx_queues; ++ ++ /* The saved address of a sent-in-place packet/buffer, for skfree(). */ ++ struct fec_enet_priv_tx_q *tx_queue; ++ struct fec_enet_priv_rx_q *rx_queue; ++ ++ unsigned int total_tx_ring_size; ++ unsigned int total_rx_ring_size; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ const struct avb_ops *avb; ++ void *avb_data; ++ unsigned int avb_enabled; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_advertising); ++#endif ++ struct platform_device *pdev; ++ ++ int dev_id; ++ ++ /* Phylib and MDIO interface */ ++ struct mii_bus *mii_bus; ++ uint phy_speed; ++ phy_interface_t phy_interface; ++ struct device_node *phy_node; ++ bool rgmii_txc_dly; ++ bool rgmii_rxc_dly; ++ bool mii_bus_share; ++ bool rpm_active; ++ int link; ++ int full_duplex; ++ int speed; ++ int irq[FEC_IRQ_NUM]; ++ bool bufdesc_ex; ++ int pause_flag; ++ int wol_flag; ++ int wake_irq; ++ u32 quirks; ++ ++ struct napi_struct napi; ++ int csum_flags; ++ ++ struct work_struct tx_timeout_work; ++ ++ struct ptp_clock *ptp_clock; ++ struct ptp_clock_info ptp_caps; ++ unsigned long last_overflow_check; ++ raw_spinlock_t tmreg_lock; ++ struct cyclecounter cc; ++ struct timecounter tc; ++ int rx_hwtstamp_filter; ++ u32 base_incval; ++ u32 cycle_speed; ++ int hwts_rx_en; ++ int hwts_tx_en; ++ ++ /* Transmit and receive latency, depending on link speed, for ++ * packets timestamps in ns ++ */ ++ u32 rx_tstamp_latency; ++ u32 tx_tstamp_latency; ++ ++ struct delayed_work time_keep; ++ struct regulator *reg_phy; ++ struct fec_stop_mode_gpr stop_gpr; ++ struct pm_qos_request pm_qos_req; ++ ++ unsigned int tx_align; ++ unsigned int rx_align; ++ ++ /* hw interrupt coalesce */ ++ unsigned int rx_pkts_itr; ++ unsigned int rx_time_itr; ++ unsigned int tx_pkts_itr; ++ unsigned int tx_time_itr; ++ unsigned int itr_clk_rate; ++ ++ /* tx lpi eee mode */ ++ struct ethtool_eee eee; ++ unsigned int clk_ref_rate; ++ ++ u32 rx_copybreak; ++ ++ /* ptp clock period in ns*/ ++ unsigned int ptp_inc; ++ ++ /* pps */ ++ int pps_channel; ++ unsigned int reload_period; ++ int pps_enable; ++ unsigned int next_counter; ++ ++ struct mutex fast_ndev_lock; ++ struct imx_sc_ipc *ipc_handle; ++ ++ /* Configured rx/tx timestamps delays for different link speeds ++ * to compensate for FEC-PHY latency in ns ++ */ ++ u32 rx_delay_100; ++ u32 tx_delay_100; ++ u32 rx_delay_1000; ++ u32 tx_delay_1000; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ int rec_channel; ++ int rec_enable; ++#endif ++ ++ u64 ethtool_stats[]; ++}; ++ ++#ifdef CONFIG_AVB_SUPPORT ++#define FEC_MAX_RATE 400 /* Mbps */ ++#define FEC_MAX_RATE_HAS_AVB 1000 /* Mbps */ ++ ++static inline int fec_max_rate(struct fec_enet_private *fep) ++{ ++ int max_rate = (fep->quirks & FEC_QUIRK_HAS_AVB) ? FEC_MAX_RATE_HAS_AVB : FEC_MAX_RATE; ++ return min(max_rate, fep->speed); ++} ++ ++#define IDLE_SLOPE_DIVISOR 512 ++#endif ++ ++void fec_ptp_init(struct platform_device *pdev, int irq_idx); ++void fec_ptp_stop(struct platform_device *pdev); ++void fec_ptp_start_cyclecounter(struct net_device *ndev); ++void fec_ptp_disable_hwts(struct net_device *ndev); ++int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); ++int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); ++ ++/****************************************************************************/ ++#endif /* FEC_H */ +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 23f7604d9dbc..290d6cfa7fc8 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -77,17 +77,25 @@ + + static void set_multicast_list(struct net_device *ndev); + static void fec_enet_itr_coal_set(struct net_device *ndev); ++#ifndef CONFIG_AVB_SUPPORT + static int fec_enet_xdp_tx_xmit(struct net_device *ndev, + struct xdp_buff *xdp); + static int fec_enet_xdp_xmit(struct net_device *dev, + int num_frames, + struct xdp_frame **frames, + u32 flags); ++#endif + + #define DRIVER_NAME "fec" + + static const u16 fec_enet_vlan_pri_to_queue[8] = {0, 0, 1, 1, 1, 2, 2, 2}; + ++#ifdef CONFIG_AVB_SUPPORT ++/* Idle Slope values specific to AVB capable boards */ ++static const unsigned short idle_slope_values[] = {1, 2, 4, 8, 16, 32, 64, 128, ++ 256, 384, 512, 640, 768, 896, 1024, 1152, 1280, 1408, 1536}; ++#endif ++ + /* Pause frame feild and FIFO threshold */ + #define FEC_ENET_FCE (1 << 5) + #define FEC_ENET_RSEM_V 0x84 +@@ -339,6 +347,24 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); + + static int mii_cnt; + ++#ifdef CONFIG_AVB_SUPPORT ++static inline void read16(void *dst, void *src) ++{ ++#ifdef CONFIG_ARM64 ++ asm volatile ( "ldp x10, x11, [%1]\n\t" ++ "stp x10, x11, [%0]\n\t" ++ : : "r" (dst), "r" (src) : "x10", "x11", "memory"); ++#elif CONFIG_ARM ++ asm volatile ( "ldmia %1, {r5-r8}\n\t" ++ "stmia %0, {r5-r8}\n\t" ++ : : "r" (dst), "r" (src) : "r5", "r6", "r7", "r8", "memory"); ++#else ++ ((u64 *)dst)[0] = ((u64 *)src)[0]; ++ ((u64 *)dst)[1] = ((u64 *)src)[1]; ++#endif ++} ++#endif /*CONFIG_AVB_SUPPORT*/ ++ + static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, + struct bufdesc_prop *bd) + { +@@ -470,6 +496,253 @@ fec_enet_create_page_pool(struct fec_enet_private *fep, + return err; + } + ++#ifdef CONFIG_AVB_SUPPORT ++/* ++ * Sends an AVB buffer on the network. ++ */ ++int fec_enet_start_xmit_avb(void *data, struct avb_tx_desc *desc) ++{ ++ struct fec_enet_private *fep = data; ++ struct bufdesc *bdp; ++ unsigned short status; ++ unsigned int index; ++ struct bufdesc_ex *ebdp; ++ unsigned long cbd_esc; ++ unsigned short queue_id = desc->queue_id; ++ struct fec_enet_priv_tx_q *txq = fep->tx_queue[queue_id]; ++ ++ /* ring buffer base address */ ++ /* registers base address */ ++ /* current descriptor pointer */ ++ bdp = txq->bd.cur; ++ ++ if (bdp == txq->dirty_tx) ++ return -2; ++ ++ status = fec16_to_cpu(bdp->cbd_sc); ++ ++ if (status & BD_ENET_TX_READY) ++ return -2; ++ ++ /* Clear all of the status flags */ ++ status &= ~BD_ENET_TX_STATS; ++ ++ index = fec_enet_get_bd_index(bdp, &txq->bd); ++ ++ /* Save desc pointer */ ++ txq->tx_buf[index].skb = (void *)desc; ++ ++ bdp->cbd_datlen = cpu_to_fec16(desc->common.len); ++ bdp->cbd_bufaddr = cpu_to_fec32(desc->dma_addr); ++ ++ ebdp = (struct bufdesc_ex *)bdp; ++ ++ ebdp->cbd_bdu = cpu_to_fec32(0); ++ ++ if (desc->common.flags & AVB_TX_FLAG_HW_TS) ++ cbd_esc = BD_ENET_TX_TS | desc->esc; ++ else ++ cbd_esc = desc->esc; ++ ++ if (desc->common.flags & AVB_TX_FLAG_HW_CSUM) ++ cbd_esc |= BD_ENET_TX_PINS | BD_ENET_TX_IINS; ++ ++ if (fep->quirks & FEC_QUIRK_HAS_AVB) ++ cbd_esc |= FEC_TX_BD_FTYPE(txq->bd.qid); ++ ++ ebdp->cbd_esc = cpu_to_fec32(cbd_esc); ++ ++ wmb(); ++ ++ bdp->cbd_sc = cpu_to_fec16(status | (BD_ENET_TX_READY | BD_ENET_TX_LAST | BD_ENET_TX_TC)); ++ ++ /* If this was the last BD in the ring, start at the beginning again. */ ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ ++ txq->bd.cur = bdp; ++ ++ /* Trigger transmission start */ ++ if (!(fep->quirks & FEC_QUIRK_ERR006358)) ++ if (!(fep->quirks & FEC_QUIRK_ERR007885) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active)) ++ writel(0, txq->bd.reg_desc_active); ++ ++ if (bdp == txq->dirty_tx) ++ return -1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(fec_enet_start_xmit_avb); ++ ++void fec_enet_finish_xmit_avb(void *data, unsigned int queue_id) ++{ ++ struct fec_enet_private *fep = data; ++ ++ /* Trigger transmission start */ ++ if (fep->quirks & FEC_QUIRK_ERR006358) ++ if (!(fep->quirks & FEC_QUIRK_ERR007885) || ++ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active) || ++ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active) || ++ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active) || ++ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active)) ++ writel(0, fep->tx_queue[queue_id]->bd.reg_desc_active); ++} ++EXPORT_SYMBOL(fec_enet_finish_xmit_avb); ++ ++/* ++ * When AVB is enabled, it is the transmit function for the regular ++ * network traffic. It does not support any SG/TSO skb. ++ * Frames are posted to the AVB module for further scheduling. ++ */ ++static int fec_enet_start_xmit_best_effort(struct fec_enet_priv_tx_q *txq, ++ struct netdev_queue *nq, struct sk_buff *skb, struct net_device *ndev) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ void *bufaddr; ++ struct avb_tx_desc *desc; ++ int rc; ++ ++ if (fep->avb->tx_full(fep->avb_data)) { ++ netdev_err(ndev, "tx queue full!\n"); ++ return NETDEV_TX_BUSY; ++ } ++ ++ /* Protocol checksum off-load for TCP and UDP. */ ++ if (fec_enet_clear_csum(skb, ndev)) { ++ dev_kfree_skb_any(skb); ++ ndev->stats.tx_dropped++; ++ return NETDEV_TX_OK; ++ } ++ ++ if (skb_headroom(skb) < sizeof(struct avb_tx_desc)) { ++ if (pskb_expand_head(skb, sizeof(struct avb_tx_desc), 0, GFP_ATOMIC)) { ++ dev_kfree_skb_any(skb); ++ ndev->stats.tx_dropped++; ++ return NETDEV_TX_OK; ++ } ++ } ++ ++ bufaddr = skb->data; ++ desc = (struct avb_tx_desc *)(skb->data - sizeof(struct avb_tx_desc)); ++ ++ /* Set buffer length and buffer pointer */ ++ desc->common.offset = sizeof(struct avb_tx_desc); ++ desc->common.len = skb->len; ++ desc->queue_id = txq->bd.qid; ++ ++ if ((((unsigned long) bufaddr) & fep->tx_align) || ++ (fep->quirks & FEC_QUIRK_SWAP_FRAME)) { ++ memcpy(txq->tx_bounce[txq->tx_index], skb->data, skb->len); ++ bufaddr = txq->tx_bounce[txq->tx_index]; ++ ++ txq->tx_index++; ++ if (txq->tx_index >= txq->tx_bounce_size) ++ txq->tx_index = 0; ++ ++ if (fep->quirks & FEC_QUIRK_SWAP_FRAME) ++ swap_buffer(bufaddr, skb->len); ++ } ++ ++ /* Save skb pointer */ ++ desc->data = skb; ++ desc->common.flags = AVB_TX_FLAG_SKB; ++ ++ /* Push the data cache so the CPM does not get stale memory data. */ ++ desc->dma_addr = dma_map_single(&fep->pdev->dev, bufaddr, skb->len, DMA_TO_DEVICE); ++ if (dma_mapping_error(&fep->pdev->dev, desc->dma_addr)) { ++ dev_kfree_skb_any(skb); ++ if (net_ratelimit()) ++ netdev_err(ndev, "Tx DMA memory map failed\n"); ++ return NETDEV_TX_OK; ++ } ++ ++ desc->esc = 0; ++ ++ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && ++ fep->hwts_tx_en)) { ++ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; ++ desc->esc |= BD_ENET_TX_TS; ++ } ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ desc->esc |= BD_ENET_TX_PINS | BD_ENET_TX_IINS; ++ ++ skb_tx_timestamp(skb); ++ ++ if ((rc = fep->avb->tx(fep->avb_data, desc)) < 0) { ++ if (rc < -1) { ++ kfree_skb(skb); ++ ndev->stats.tx_dropped++; ++ } ++ ++ netif_tx_stop_queue(nq); ++ return NETDEV_TX_OK; ++ } ++ ++ return NETDEV_TX_OK; ++} ++ ++int fec_enet_set_idle_slope(void *data, unsigned int queue_id, ++ u32 desired_rate) ++{ ++ struct fec_enet_private *fep = data; ++ struct fec_enet_priv_tx_q *txq; ++ u64 idle_slope; ++ u32 line_rate; ++ int i; ++ ++ if (!fep) ++ return -EINVAL; ++ ++ /* Nothing to be done for non-AVB boards */ ++ if (!(fep->quirks & FEC_QUIRK_HAS_AVB)) ++ return 0; ++ ++ if ((queue_id == 0) || (queue_id >= fep->num_tx_queues)) ++ return -EINVAL; ++ ++ if ((fep->speed != SPEED_100) && (fep->speed != SPEED_1000)) ++ return -EOPNOTSUPP; ++ ++ line_rate = fep->speed * 1000000ULL; ++ if (desired_rate > line_rate) ++ return -EINVAL; ++ ++ txq = fep->tx_queue[queue_id]; ++ ++ /* ++ * Compute the desired Idle-Slope based on the desired rate and use ++ * the round up to the next integer. ++ */ ++ idle_slope = (u64)desired_rate * IDLE_SLOPE_DIVISOR + line_rate - desired_rate - 1; ++ idle_slope = div_u64(idle_slope, line_rate - desired_rate); ++ ++ for (i = 0; i < ARRAY_SIZE(idle_slope_values); i++) ++ if (idle_slope <= idle_slope_values[i]) ++ break; ++ ++ if (i >= ARRAY_SIZE(idle_slope_values)) ++ return -EINVAL; ++ /* ++ * If the desired rate is higher than the last available bandwidth ++ * threshold then we should not configure the Credit-Based shaper ++ * at all. ++ */ ++ if (idle_slope > idle_slope_values[i]) ++ return -EINVAL; ++ ++ txq->tx_idle_slope = idle_slope_values[i]; ++ writel(DMA_CLASS_EN | txq->tx_idle_slope, ++ fep->hwp + FEC_DMA_CFG(queue_id)); ++ ++ return 0; ++} ++EXPORT_SYMBOL(fec_enet_set_idle_slope); ++#endif ++ + static struct bufdesc * + fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq, + struct sk_buff *skb, +@@ -681,7 +954,12 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, + txq->bd.cur = bdp; + + /* Trigger transmission start */ +- writel(0, txq->bd.reg_desc_active); ++ if (!(fep->quirks & FEC_QUIRK_ERR007885) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active) || ++ !readl(txq->bd.reg_desc_active)) ++ writel(0, txq->bd.reg_desc_active); + + return 0; + } +@@ -898,6 +1176,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) + txq = fep->tx_queue[queue]; + nq = netdev_get_tx_queue(ndev, queue); + ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ return fec_enet_start_xmit_best_effort(txq, nq, skb, ndev); ++#endif ++ + if (skb_is_gso(skb)) + ret = fec_enet_txq_submit_tso(txq, skb, ndev); + else +@@ -922,6 +1205,9 @@ static void fec_enet_bd_init(struct net_device *dev) + struct bufdesc *bdp; + unsigned int i; + unsigned int q; ++#ifdef CONFIG_AVB_SUPPORT ++ struct sk_buff *skb; ++#endif + + for (q = 0; q < fep->num_rx_queues; q++) { + /* Initialize the receive buffer descriptors. */ +@@ -945,6 +1231,23 @@ static void fec_enet_bd_init(struct net_device *dev) + rxq->bd.cur = rxq->bd.base; + } + ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) { ++ struct avb_tx_desc *desc; ++ ++ while ((desc = fep->avb->tx_cleanup_dequeue(fep->avb_data)) != (void *) -1) { ++ ++ skb = desc->data; ++ ++ dma_unmap_single(&fep->pdev->dev, desc->bufaddr, ++ skb->len, DMA_TO_DEVICE); ++ ++ /* Free the sk buffer associated with this last transmit */ ++ dev_kfree_skb_any(skb); ++ } ++ } ++#endif ++ + for (q = 0; q < fep->num_tx_queues; q++) { + /* ...and the same for transmit */ + txq = fep->tx_queue[q]; +@@ -954,6 +1257,42 @@ static void fec_enet_bd_init(struct net_device *dev) + for (i = 0; i < txq->bd.ring_size; i++) { + /* Initialize the BD for every fragment in the page. */ + bdp->cbd_sc = cpu_to_fec16(0); ++#ifdef CONFIG_AVB_SUPPORT ++ /* AVB not compatible with XDP: all buffers are either avb descriptors or skbs. */ ++ if (txq->tx_buf[i].skb) { ++ skb = NULL; ++ if (fep->avb_enabled) { ++ struct avb_tx_desc *desc = (struct avb_tx_desc *)txq->tx_buf[i].skb; ++ ++ if (!(desc->common.flags & AVB_TX_FLAG_SKB)) { ++ fep->avb->free(fep->avb_data, &desc->common); ++ /* Avoid unmapping AVB buffers below */ ++ bdp->cbd_bufaddr = cpu_to_fec32(0); ++ } else { ++ skb = desc->data; ++ } ++ } else ++ skb = txq->tx_buf[i].skb; ++ ++ if (skb) { ++ dev_kfree_skb_any(skb); ++ } ++ ++ txq->tx_buf[i].skb = NULL; ++ } ++ ++ if (bdp->cbd_bufaddr && ++ !IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr))) ++ dma_unmap_single(&fep->pdev->dev, ++ fec32_to_cpu(bdp->cbd_bufaddr), ++ fec16_to_cpu(bdp->cbd_datlen), ++ DMA_TO_DEVICE); ++ if (txq->tx_buf[i].skb) { ++ dev_kfree_skb_any(txq->tx_buf[i].skb); ++ txq->tx_buf[i].skb = NULL; ++ } ++ ++#else + if (txq->tx_buf[i].type == FEC_TXBUF_T_SKB) { + if (bdp->cbd_bufaddr && + !IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr))) +@@ -981,7 +1320,7 @@ static void fec_enet_bd_init(struct net_device *dev) + + txq->tx_buf[i].type = FEC_TXBUF_T_SKB; + } +- ++#endif + bdp->cbd_bufaddr = cpu_to_fec32(0); + bdp = fec_enet_get_nextdesc(bdp, &txq->bd); + } +@@ -1007,6 +1346,7 @@ static void fec_enet_enable_ring(struct net_device *ndev) + struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_enet_priv_tx_q *txq; + struct fec_enet_priv_rx_q *rxq; ++ unsigned long idle_slope; + int i; + + for (i = 0; i < fep->num_rx_queues; i++) { +@@ -1025,10 +1365,25 @@ static void fec_enet_enable_ring(struct net_device *ndev) + writel(txq->bd.dma, fep->hwp + FEC_X_DES_START(i)); + + /* enable DMA1/2 */ +- if (i) +- writel(DMA_CLASS_EN | IDLE_SLOPE(i), ++ if (i) { ++#ifdef CONFIG_AVB_SUPPORT ++ idle_slope = txq->tx_idle_slope; ++#else ++ idle_slope = IDLE_SLOPE(i); ++#endif ++ ++ writel(DMA_CLASS_EN | idle_slope, + fep->hwp + FEC_DMA_CFG(i)); ++ } + } ++ ++ /* ++ * For AVB capable devices we should enable RX flushing for the ++ * best effort queue (ring 0) and also the TX credit based shaper. ++ */ ++ if (fep->quirks & FEC_QUIRK_HAS_AVB) ++ writel(FEC_RX_FLUSH(0) | FEC_TX_SCHEME_CB, ++ fep->hwp + FEC_QOS_SCHEME); + } + + /* +@@ -1044,17 +1399,12 @@ fec_restart(struct net_device *ndev) + u32 rcntl = OPT_FRAME_SIZE | 0x04; + u32 ecntl = 0x2; /* ETHEREN */ + +- /* Whack a reset. We should wait for this. +- * For i.MX6SX SOC, enet use AXI bus, we use disable MAC +- * instead of reset MAC itself. ++ /* Always use disable MAC instead of MAC reset to: ++ * - Keep the ENET counter running ++ * - Avoid dead system bus for SoCs using the ENET-AXI bus ++ * and not the AHB bus, like the i.MX6SX + */ +- if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES || +- ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) { +- writel(0, fep->hwp + FEC_ECNTRL); +- } else { +- writel(1, fep->hwp + FEC_ECNTRL); +- udelay(10); +- } ++ writel(0, fep->hwp + FEC_ECNTRL); + + /* + * enet-mac reset will reset mac address registers too, +@@ -1211,9 +1561,6 @@ fec_restart(struct net_device *ndev) + writel(ecntl, fep->hwp + FEC_ECNTRL); + fec_enet_active_rxring(ndev); + +- if (fep->bufdesc_ex) +- fec_ptp_start_cyclecounter(ndev); +- + /* Enable interrupts we wish to service */ + if (fep->link) + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); +@@ -1303,17 +1650,14 @@ fec_stop(struct net_device *ndev) + netdev_err(ndev, "Graceful transmit stop did not complete!\n"); + } + +- /* Whack a reset. We should wait for this. +- * For i.MX6SX SOC, enet use AXI bus, we use disable MAC +- * instead of reset MAC itself. +- */ + if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { +- if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) { +- writel(0, fep->hwp + FEC_ECNTRL); +- } else { +- writel(1, fep->hwp + FEC_ECNTRL); +- udelay(10); +- } ++ /* Always use disable MAC instead of MAC reset to: ++ * - Keep the ENET counter running ++ * - Avoid dead system bus for SoCs using the ENET-AXI bus ++ * and not the AHB bus, like the i.MX6SX ++ */ ++ writel(0, fep->hwp + FEC_ECNTRL); ++ + } else { + val = readl(fep->hwp + FEC_ECNTRL); + val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); +@@ -1353,7 +1697,15 @@ static void fec_enet_timeout_work(struct work_struct *work) + if (netif_device_present(ndev) || netif_running(ndev)) { + napi_disable(&fep->napi); + netif_tx_lock_bh(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->close(fep->avb_data); ++#endif + fec_restart(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep)); ++#endif + netif_tx_wake_all_queues(ndev); + netif_tx_unlock_bh(ndev); + napi_enable(&fep->napi); +@@ -1368,14 +1720,194 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts, + unsigned long flags; + u64 ns; + +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + ns = timecounter_cyc2time(&fep->tc, ts); +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + memset(hwtstamps, 0, sizeof(*hwtstamps)); + hwtstamps->hwtstamp = ns_to_ktime(ns); + } + ++#ifdef CONFIG_AVB_SUPPORT ++static int ++fec_enet_tx_queue_avb(struct net_device *ndev, u16 queue_id) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct bufdesc *bdp; ++ struct bufdesc_ex local_ebdp; ++ struct avb_tx_desc *desc; ++ unsigned short status; ++ struct fec_enet_priv_tx_q *txq; ++ struct netdev_queue *nq; ++ int index = 0; ++ int rc = 0; ++ unsigned int total_tx_packets = 0; ++ unsigned int total_tx_bytes = 0; ++ u16 tx_tstamp_latency = fep->tx_tstamp_latency; ++ ++ txq = fep->tx_queue[queue_id]; ++ nq = netdev_get_tx_queue(ndev, queue_id); ++ ++ bdp = txq->dirty_tx; ++ ++ /* get next bdp of dirty_tx */ ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ ++ while (bdp != READ_ONCE(txq->bd.cur)) { ++ /* Order the load of cur_tx and cbd_sc */ ++ rmb(); ++ ++ /* Read the first 16 bytes of the descriptor at once to avoid ++ * multiple reads of non cacheable memory from RAM */ ++ read16(&local_ebdp, bdp); ++ ++ status = fec16_to_cpu(local_ebdp.desc.cbd_sc); ++ if (status & BD_ENET_TX_READY) ++ break; ++ ++ index = fec_enet_get_bd_index(bdp, &txq->bd); ++ desc = (struct avb_tx_desc *)txq->tx_buf[index].skb; ++ ++ if (!(desc->common.flags & AVB_TX_FLAG_SKB)) { ++ if ((desc->common.flags & AVB_TX_FLAG_HW_TS)) { ++ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; ++ ++ desc->common.ts = ebdp->ts + tx_tstamp_latency; ++ ++ /* upper layer will retrieve the timestamp and free the descriptor */ ++ rc |= fep->avb->tx_ts(fep->avb_data, &desc->common); ++ } ++ else ++ fep->avb->free(fep->avb_data, &desc->common); ++ ++ total_tx_packets++; ++ total_tx_bytes += desc->datlen; ++ } else { ++ /* Backup hardware descriptor fields in software descriptor */ ++ desc->sc = status; ++ desc->datlen = fec16_to_cpu(local_ebdp.desc.cbd_datlen); ++ desc->bufaddr = fec32_to_cpu(local_ebdp.desc.cbd_bufaddr); ++ desc->common.ts = fec32_to_cpu(((struct bufdesc_ex *)bdp)->ts); ++ ++ if (fep->avb->tx_cleanup(fep->avb_data, desc) < 0) ++ BUG(); ++ } ++ ++ txq->tx_buf[index].skb = NULL; ++ bdp->cbd_bufaddr = cpu_to_fec32(0); ++ txq->dirty_tx = bdp; ++ ++ /* Update pointer to next buffer descriptor to be transmitted */ ++ bdp = fec_enet_get_nextdesc(bdp, &txq->bd); ++ } ++ ++ /* schedule tx napi, based on level of tx cleanup queue or time passed */ ++ if (fep->avb->tx_cleanup_ready(fep->avb_data) || netif_tx_queue_stopped(nq)) { ++ if (napi_schedule_prep(&fep->napi)) { ++ __napi_schedule(&fep->napi); ++ } ++ } ++ ++ /* Update stats*/ ++ ndev->stats.tx_packets += total_tx_packets; ++ ndev->stats.tx_bytes += total_tx_bytes; ++ ++ return rc; ++} ++ ++int ++fec_enet_tx_avb(void *data) ++{ ++ struct fec_enet_private *fep = data; ++ u16 queue_id; ++ int rc = 0; ++ ++ for (queue_id = 0; queue_id < fep->num_tx_queues; queue_id++) ++ rc |= fec_enet_tx_queue_avb(fep->netdev, queue_id); ++ ++ return rc; ++} ++EXPORT_SYMBOL(fec_enet_tx_avb); ++ ++static void ++fec_enet_tx_best_effort(struct net_device *ndev) ++{ ++ struct fec_enet_private *fep; ++ unsigned short status; ++ struct avb_tx_desc *desc; ++ struct sk_buff *skb; ++ struct fec_enet_priv_tx_q *txq; ++ struct netdev_queue *nq; ++ ++ fep = netdev_priv(ndev); ++ ++ while ((desc = fep->avb->tx_cleanup_dequeue(fep->avb_data)) != (void *) -1) { ++ ++ txq = fep->tx_queue[desc->queue_id]; ++ nq = netdev_get_tx_queue(ndev, desc->queue_id); ++ ++ status = desc->sc; ++ ++ /* Check for errors. */ ++ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | ++ BD_ENET_TX_RL | BD_ENET_TX_UN | ++ BD_ENET_TX_CSL)) { ++ ndev->stats.tx_errors++; ++ if (status & BD_ENET_TX_HB) /* No heartbeat */ ++ ndev->stats.tx_heartbeat_errors++; ++ if (status & BD_ENET_TX_LC) /* Late collision */ ++ ndev->stats.tx_window_errors++; ++ if (status & BD_ENET_TX_RL) /* Retrans limit */ ++ ndev->stats.tx_aborted_errors++; ++ if (status & BD_ENET_TX_UN) /* Underrun */ ++ ndev->stats.tx_fifo_errors++; ++ if (status & BD_ENET_TX_CSL) /* Carrier lost */ ++ ndev->stats.tx_carrier_errors++; ++ } else { ++ ndev->stats.tx_packets++; ++ ndev->stats.tx_bytes += desc->datlen; ++ } ++ ++ skb = desc->data; ++ ++ if (!IS_TSO_HEADER(txq, desc->bufaddr)) ++ dma_unmap_single(&fep->pdev->dev, desc->bufaddr, ++ desc->datlen, DMA_TO_DEVICE); ++ ++ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { ++ struct skb_shared_hwtstamps shhwtstamps; ++ ++ desc->common.ts += fep->tx_tstamp_latency; ++ fec_enet_hwtstamp(fep, desc->common.ts, ++ &shhwtstamps); ++ skb_tstamp_tx(skb, &shhwtstamps); ++ } ++ ++ /* Deferred means some collisions occurred during transmit, ++ * but we eventually sent the packet OK. ++ */ ++ if (status & BD_ENET_TX_DEF) ++ ndev->stats.collisions++; ++ ++ /* Free the sk buffer associated with this last transmit */ ++ dev_kfree_skb_any(skb); ++ ++ /* Make sure the update to bdp and tx_buf are performed ++ * before dirty_tx ++ */ ++ wmb(); ++ ++ //FIXME add treshold ++ if (!fep->avb->tx_full(fep->avb_data)) { ++ if (netif_tx_queue_stopped(nq)) { ++ //` netdev_info(ndev, "wake queue\n"); ++ netif_tx_wake_queue(nq); ++ } ++ } ++ } ++} ++#endif ++ + static void + fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) + { +@@ -1474,6 +2006,11 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) + struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; + + fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts), &shhwtstamps); ++ /* Adjust for TX MAC-PHY latency ++ */ ++ shhwtstamps.hwtstamp = ++ ktime_add_ns(shhwtstamps.hwtstamp, fep->tx_tstamp_latency); ++ + skb_tstamp_tx(skb, &shhwtstamps); + } + +@@ -1538,6 +2075,7 @@ static void fec_enet_update_cbd(struct fec_enet_priv_rx_q *rxq, + bdp->cbd_bufaddr = cpu_to_fec32(phys_addr); + } + ++#ifndef CONFIG_AVB_SUPPORT + static u32 + fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog, + struct xdp_buff *xdp, struct fec_enet_priv_rx_q *rxq, int index) +@@ -1572,32 +2110,302 @@ fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog, + } + break; + +- default: +- bpf_warn_invalid_xdp_action(fep->netdev, prog, act); +- fallthrough; ++ default: ++ bpf_warn_invalid_xdp_action(fep->netdev, prog, act); ++ fallthrough; ++ ++ case XDP_TX: ++ ret = fec_enet_xdp_tx_xmit(fep->netdev, xdp); ++ if (ret == FEC_ENET_XDP_CONSUMED) { ++ page = virt_to_head_page(xdp->data); ++ page_pool_put_page(rxq->page_pool, page, sync, true); ++ } else { ++ ret = FEC_ENET_XDP_TX; ++ } ++ break; ++ case XDP_ABORTED: ++ fallthrough; /* handle aborts by dropping packet */ ++ ++ case XDP_DROP: ++ rxq->stats[RX_XDP_DROP]++; ++ ret = FEC_ENET_XDP_CONSUMED; ++ page = virt_to_head_page(xdp->data); ++ page_pool_put_page(rxq->page_pool, page, sync, true); ++ break; ++ } ++ ++ return ret; ++} ++#else /* CONFIG_AVB_SUPPORT */ ++ ++static int ++fec_enet_rx_best_effort(struct net_device *ndev, int budget) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct avb_rx_desc *desc; ++ struct sk_buff *skb; ++ ushort pkt_len; ++ __u8 *data; ++ bool vlan_packet_rcvd = false; ++ u16 vlan_tag; ++ int pkt_received = 0; ++ ++ do { ++ desc = fep->avb->dequeue(fep->avb_data); ++ if (desc == (void *)-1) ++ break; ++ ++ /* Process the incoming frame. */ ++ pkt_len = desc->common.len; ++ data = (u8 *)desc + desc->common.offset; ++ ++ skb = netdev_alloc_skb(ndev, pkt_len - 4); ++ if (unlikely(!skb)) { ++ ndev->stats.rx_dropped++; ++ goto rx_processing_done; ++ } ++ else { ++ /* Make some room minus FCS */ ++ skb_put(skb, pkt_len - 4); ++ ++ /* Copy AVB buffer to skb */ ++ skb_copy_to_linear_data(skb, data, pkt_len - 4); ++ data = skb->data; ++ ++ /* Get receive timestamp from the skb */ ++ if (fep->hwts_rx_en) { ++ skb_reset_mac_header(skb); ++ fec_enet_hwtstamp(fep, desc->common.ts, ++ skb_hwtstamps(skb)); ++ } ++ ++ /* If this is a VLAN packet remove the VLAN Tag */ ++ vlan_packet_rcvd = false; ++ if (desc->common.private & BD_ENET_RX_VLAN) { ++ /* Push and remove the vlan tag */ ++ struct vlan_hdr *vlan_header = ++ (struct vlan_hdr *) (data + ETH_HLEN); ++ vlan_tag = ntohs(vlan_header->h_vlan_TCI); ++ ++ vlan_packet_rcvd = true; ++ ++ memmove(skb->data + VLAN_HLEN, data, ETH_ALEN * 2); ++ ++ skb_pull(skb, VLAN_HLEN); ++ } ++ ++ skb->protocol = eth_type_trans(skb, ndev); ++ ++ if (fep->csum_flags & FLAG_RX_CSUM_ENABLED) { ++ if (!(desc->common.private & FLAG_RX_CSUM_ERROR)) { ++ /* don't check it */ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ skb_checksum_none_assert(skb); ++ } ++ } ++ ++ /* Handle received VLAN packets */ ++ if (vlan_packet_rcvd) ++ __vlan_hwaccel_put_tag(skb, ++ htons(ETH_P_8021Q), ++ vlan_tag); ++ ++ napi_gro_receive(&fep->napi, skb); ++ } ++rx_processing_done: ++ fep->avb->free(fep->avb_data, &desc->common); ++ ++ } while (++pkt_received < budget); ++ ++ return pkt_received; ++} ++ ++static unsigned int ++fec_enet_rx_queue_avb(struct net_device *ndev, u16 queue_id) ++{ ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ struct fec_enet_priv_rx_q *rxq; ++ struct bufdesc *bdp; ++ unsigned short status; ++ ushort pkt_len; ++ __u8 *data, *new_data; ++ int index = 0; ++ struct bufdesc_ex *ebdp = NULL; ++ struct bufdesc_ex local_ebdp; ++ struct avb_rx_desc *desc; ++ unsigned int rc = 0; ++ unsigned int net_data_offset; ++ unsigned int count = 0; ++ unsigned int total_rx_packets = 0; ++ unsigned int total_rx_bytes = 0; ++ u16 rx_tstamp_latency = fep->rx_tstamp_latency; ++ bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME; ++ bool has_racc = fep->quirks & FEC_QUIRK_HAS_RACC; ++ ++ rxq = fep->rx_queue[queue_id]; ++ ++ /* First, grab all of the stats for the incoming packet. ++ * These get messed up if we get called due to a busy condition. ++ */ ++ bdp = rxq->bd.cur; ++ ++ /* 20 packets per 125us > 64 bytes packets @ 100Mbps */ ++ while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY) && (count++ < 20)) { ++ ++ writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT); ++ ++ /* Read the first 16 bytes of the descriptor at once to avoid ++ * multiple reads of non cacheable memory from RAM */ ++ read16(&local_ebdp, bdp); ++ ++ /* Check for errors. */ ++ status ^= BD_ENET_RX_LAST; ++ if (unlikely(status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | ++ BD_ENET_RX_CR | BD_ENET_RX_OV | BD_ENET_RX_LAST | ++ BD_ENET_RX_CL))) { ++ ndev->stats.rx_errors++; ++ if (status & BD_ENET_RX_OV) { ++ /* FIFO overrun */ ++ ndev->stats.rx_fifo_errors++; ++ goto rx_processing_done; ++ } ++ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH ++ | BD_ENET_RX_LAST)) { ++ /* Frame too long or too short. */ ++ ndev->stats.rx_length_errors++; ++ if (status & BD_ENET_RX_LAST) ++ netdev_err(ndev, "rcv is not +last\n"); ++ } ++ if (status & BD_ENET_RX_CR) /* CRC Error */ ++ ndev->stats.rx_crc_errors++; ++ /* Report late collisions as a frame error. */ ++ if (status & (BD_ENET_RX_NO | BD_ENET_RX_CL)) ++ ndev->stats.rx_frame_errors++; ++ goto rx_processing_done; ++ } ++ ++ new_data = fep->avb->alloc(fep->avb_data); ++ if (unlikely(!new_data)) { ++ ndev->stats.rx_dropped++; ++ goto rx_processing_done; ++ } ++ ++ /* Process the incoming frame. */ ++ total_rx_packets++; ++ pkt_len = fec16_to_cpu(local_ebdp.desc.cbd_datlen); ++ total_rx_bytes += pkt_len; ++ index = fec_enet_get_bd_index(bdp, &rxq->bd); ++ data = (__u8 *)rxq->rx_skb_info[index].skb; ++ ++ /* FIXME, skip unmap of audio data */ ++ dma_sync_single_for_cpu(&fep->pdev->dev, fec32_to_cpu(local_ebdp.desc.cbd_bufaddr), ++ L1_CACHE_ALIGN(pkt_len), DMA_FROM_DEVICE); ++ ++ desc = (struct avb_rx_desc *)data; ++ ++ net_data_offset = desc->common.offset; ++ ++#if !defined(CONFIG_M5272) ++ if (has_racc) ++ net_data_offset -= 2; ++#endif ++ prefetch(data + net_data_offset); ++ ++ if (need_swap) ++ swap_buffer(data, pkt_len); ++ ++ desc->common.len = pkt_len; ++ desc->sc = fec16_to_cpu(local_ebdp.desc.cbd_sc); ++ ++ /* Extract the enhanced buffer descriptor */ ++ ebdp = (struct bufdesc_ex *)bdp; ++ ++ desc->common.ts = ebdp->ts - rx_tstamp_latency; ++ desc->common.private = fec32_to_cpu(local_ebdp.cbd_esc); ++ ++ rc |= fep->avb->rx(fep->avb_data, desc); ++ ++ data = new_data; ++ ++ desc = (struct avb_rx_desc *)data; ++ ++ desc->common.len = 0; ++ desc->queue_id = queue_id; ++ ++ bdp->cbd_bufaddr = cpu_to_fec32((dma_addr_t)(desc->dma_addr)); ++ ++#if !defined(CONFIG_M5272) ++ if (has_racc) ++ desc->common.offset += 2; ++#endif ++ rxq->rx_skb_info[index].skb = (void *)data; ++rx_processing_done: ++ /* Clear the status flags for this buffer */ ++ status &= ~BD_ENET_RX_STATS; ++ ++ /* Mark the buffer empty */ ++ status |= BD_ENET_RX_EMPTY; ++ bdp->cbd_sc = cpu_to_fec16(status); ++ ++ ebdp = (struct bufdesc_ex *)bdp; ++ ++ ebdp->cbd_esc = cpu_to_fec32(0); ++ ebdp->cbd_prot = cpu_to_fec32(0); ++ ebdp->cbd_bdu = cpu_to_fec32(0); ++ ++ /* Update BD pointer to next entry */ ++ ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ } ++ ++ /* If the receive ring buffer can hold at least double the maximum ++ number of packets per polling period (18.2 packets @ 100Mbps), it's ++ ok to only re-enable receive after processing all current packets */ ++ ++ writel(0, rxq->bd.reg_desc_active); ++ ++ rxq->bd.cur = bdp; ++ ++ /*Update stats*/ ++ ndev->stats.rx_packets += total_rx_packets; ++ ndev->stats.rx_bytes += total_rx_bytes; ++ ++ return rc; ++} ++ ++static unsigned int ++fec_enet_rx_avb(struct net_device *ndev) ++{ ++ u16 queue_id; ++ struct fec_enet_private *fep = netdev_priv(ndev); ++ unsigned int rc = 0; ++ ++ for (queue_id = 0; queue_id < fep->num_rx_queues; queue_id++) ++ rc |= fec_enet_rx_queue_avb(ndev, queue_id); ++ ++ return rc; ++} ++ ++int fec_enet_rx_poll_avb(void *data) ++{ ++ struct fec_enet_private *fep = data; ++ struct net_device *ndev = fep->netdev; ++ unsigned int rc; + +- case XDP_TX: +- ret = fec_enet_xdp_tx_xmit(fep->netdev, xdp); +- if (ret == FEC_ENET_XDP_CONSUMED) { +- page = virt_to_head_page(xdp->data); +- page_pool_put_page(rxq->page_pool, page, sync, true); +- } else { +- ret = FEC_ENET_XDP_TX; +- } +- break; +- case XDP_ABORTED: +- fallthrough; /* handle aborts by dropping packet */ ++ rc = fec_enet_rx_avb(ndev); + +- case XDP_DROP: +- rxq->stats[RX_XDP_DROP]++; +- ret = FEC_ENET_XDP_CONSUMED; +- page = virt_to_head_page(xdp->data); +- page_pool_put_page(rxq->page_pool, page, sync, true); +- break; ++ if (rc & AVB_WAKE_NAPI) { ++ /* Best effort packets were posted, schedule napi if not scheduled yet. */ ++ if (napi_schedule_prep(&fep->napi)) ++ __napi_schedule(&fep->napi); + } + +- return ret; ++ return rc; + } ++EXPORT_SYMBOL(fec_enet_rx_poll_avb); ++ ++#endif /* CONFIG_AVB_SUPPORT */ + + /* During a receive, the bd_rx.cur points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has +@@ -1620,10 +2428,12 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) + u16 vlan_tag; + int index = 0; + bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME; ++#ifndef CONFIG_AVB_SUPPORT + struct bpf_prog *xdp_prog = READ_ONCE(fep->xdp_prog); + u32 ret, xdp_result = FEC_ENET_XDP_PASS; +- u32 data_start = FEC_ENET_XDP_HEADROOM; + struct xdp_buff xdp; ++#endif ++ u32 data_start = FEC_ENET_XDP_HEADROOM; + struct page *page; + u32 sub_len = 4; + +@@ -1646,7 +2456,9 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) + * These get messed up if we get called due to a busy condition. + */ + bdp = rxq->bd.cur; ++#ifndef CONFIG_AVB_SUPPORT + xdp_init_buff(&xdp, PAGE_SIZE, &rxq->xdp_rxq); ++#endif + + while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) { + +@@ -1696,6 +2508,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) + prefetch(page_address(page)); + fec_enet_update_cbd(rxq, bdp, index); + ++#ifndef CONFIG_AVB_SUPPORT + if (xdp_prog) { + xdp_buff_clear_frags_flag(&xdp); + /* subtract 16bit shift and FCS */ +@@ -1706,6 +2519,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) + if (ret != FEC_ENET_XDP_PASS) + goto rx_processing_done; + } ++#endif + + /* The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up +@@ -1754,10 +2568,16 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) + skb->protocol = eth_type_trans(skb, ndev); + + /* Get receive timestamp from the skb */ +- if (fep->hwts_rx_en && fep->bufdesc_ex) ++ if (fep->hwts_rx_en && fep->bufdesc_ex) { + fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts), + skb_hwtstamps(skb)); + ++ /* Adjust for RX MAC-PHY latency ++ */ ++ skb_hwtstamps(skb)->hwtstamp = ++ ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, fep->rx_tstamp_latency); ++ } ++ + if (fep->bufdesc_ex && + (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { + if (!(ebdp->cbd_esc & cpu_to_fec32(FLAG_RX_CSUM_ERROR))) { +@@ -1808,8 +2628,10 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) + } + rxq->bd.cur = bdp; + ++#ifndef CONFIG_AVB_SUPPORT + if (xdp_result & FEC_ENET_XDP_REDIR) + xdp_do_flush_map(); ++#endif + + return pkt_received; + } +@@ -1850,6 +2672,10 @@ fec_enet_interrupt(int irq, void *dev_id) + if (fec_enet_collect_events(fep) && fep->link) { + ret = IRQ_HANDLED; + ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ dev_err(&fep->pdev->dev, "Rx/Tx IRQ with AVB enabled, should not happen\n"); ++#endif + if (napi_schedule_prep(&fep->napi)) { + /* Disable interrupts */ + writel(0, fep->hwp + FEC_IMASK); +@@ -1866,10 +2692,18 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget) + struct fec_enet_private *fep = netdev_priv(ndev); + int done = 0; + +- do { +- done += fec_enet_rx(ndev, budget - done); +- fec_enet_tx(ndev); +- } while ((done < budget) && fec_enet_collect_events(fep)); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) { ++ done = fec_enet_rx_best_effort(ndev, budget); ++ fec_enet_tx_best_effort(ndev); ++ } else ++#endif ++ { ++ do { ++ done += fec_enet_rx(ndev, budget - done); ++ fec_enet_tx(ndev); ++ } while ((done < budget) && fec_enet_collect_events(fep)); ++ } + + if (done < budget) { + napi_complete_done(napi, done); +@@ -1986,11 +2820,33 @@ static void fec_enet_adjust_link(struct net_device *ndev) + status_change = 1; + } + ++ switch (fep->speed) { ++ case SPEED_100: ++ fep->rx_tstamp_latency = fep->rx_delay_100; ++ fep->tx_tstamp_latency = fep->tx_delay_100; ++ break; ++ case SPEED_1000: ++ fep->rx_tstamp_latency = fep->rx_delay_1000; ++ fep->tx_tstamp_latency = fep->tx_delay_1000; ++ break; ++ default: ++ fep->rx_tstamp_latency = 0; ++ fep->tx_tstamp_latency = 0; ++ } ++ + /* if any of the above changed restart the FEC */ + if (status_change) { + napi_disable(&fep->napi); + netif_tx_lock_bh(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->close(fep->avb_data); ++#endif + fec_restart(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep)); ++#endif + netif_tx_wake_all_queues(ndev); + netif_tx_unlock_bh(ndev); + napi_enable(&fep->napi); +@@ -1999,7 +2855,15 @@ static void fec_enet_adjust_link(struct net_device *ndev) + if (fep->link) { + napi_disable(&fep->napi); + netif_tx_lock_bh(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->close(fep->avb_data); ++#endif + fec_stop(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep)); ++#endif + netif_tx_unlock_bh(ndev); + napi_enable(&fep->napi); + fep->link = phy_dev->link; +@@ -2322,6 +3186,12 @@ static int fec_enet_mii_probe(struct net_device *ndev) + else + phy_set_max_speed(phy_dev, 100); + ++#ifdef CONFIG_AVB_SUPPORT ++ /* Restore advertising settings saved last interface close */ ++ if (!linkmode_empty(fep->phy_advertising)) ++ linkmode_copy(phy_dev->advertising, fep->phy_advertising); ++#endif ++ + fep->link = 0; + fep->full_duplex = 0; + +@@ -3252,20 +4122,86 @@ static void fec_enet_free_buffers(struct net_device *ndev) + + for (q = 0; q < fep->num_rx_queues; q++) { + rxq = fep->rx_queue[q]; +- for (i = 0; i < rxq->bd.ring_size; i++) +- page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) { ++ struct bufdesc *bdp = rxq->bd.base; ++ for (i = 0; i < rxq->bd.ring_size; i++) { ++ if (bdp->cbd_bufaddr) { ++ struct avb_rx_desc *desc; ++ ++ desc = (struct avb_rx_desc *)rxq->rx_skb_info[i].skb; ++ fep->avb->free(fep->avb_data, &desc->common); ++ bdp->cbd_bufaddr = cpu_to_fec32(0); ++ } ++ ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ } ++ } else ++#endif ++ { ++ for (i = 0; i < rxq->bd.ring_size; i++) ++ page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false); + +- for (i = 0; i < XDP_STATS_TOTAL; i++) +- rxq->stats[i] = 0; ++ for (i = 0; i < XDP_STATS_TOTAL; i++) ++ rxq->stats[i] = 0; + +- if (xdp_rxq_info_is_reg(&rxq->xdp_rxq)) +- xdp_rxq_info_unreg(&rxq->xdp_rxq); +- page_pool_destroy(rxq->page_pool); +- rxq->page_pool = NULL; ++ if (xdp_rxq_info_is_reg(&rxq->xdp_rxq)) ++ xdp_rxq_info_unreg(&rxq->xdp_rxq); ++ page_pool_destroy(rxq->page_pool); ++ rxq->page_pool = NULL; ++ } ++ } ++ ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) { ++ struct avb_rx_desc *rx_desc; ++ struct avb_tx_desc *tx_desc; ++ ++ while ((rx_desc = fep->avb->dequeue(fep->avb_data)) != (void *) -1) ++ fep->avb->free(fep->avb_data, &rx_desc->common); ++ ++ while ((tx_desc = fep->avb->tx_cleanup_dequeue(fep->avb_data)) != (void *) -1) { ++ ++ skb = tx_desc->data; ++ ++ dma_unmap_single(&fep->pdev->dev, tx_desc->bufaddr, ++ skb->len, DMA_TO_DEVICE); ++ ++ /* Free the sk buffer associated with this last transmit */ ++ dev_kfree_skb_any(skb); ++ } + } ++#endif + + for (q = 0; q < fep->num_tx_queues; q++) { + txq = fep->tx_queue[q]; ++#ifdef CONFIG_AVB_SUPPORT ++ for (i = 0; i < txq->bd.ring_size; i++) { ++ if (txq->tx_buf[i].skb) { ++ skb = NULL; ++ if (fep->avb_enabled) { ++ struct avb_tx_desc *desc = (struct avb_tx_desc *)txq->tx_buf[i].skb; ++ ++ if (!(desc->common.flags & AVB_TX_FLAG_SKB)) ++ fep->avb->free(fep->avb_data, &desc->common); ++ else ++ skb = desc->data; ++ } else { ++ skb = txq->tx_buf[i].skb; ++ } ++ ++ if (skb) ++ dev_kfree_skb(skb); ++ ++ txq->tx_buf[i].skb = NULL; ++ } ++ } ++ ++ for (i = 0; i < txq->tx_bounce_size; i++) { ++ kfree(txq->tx_bounce[i]); ++ txq->tx_bounce[i] = NULL; ++ } ++#else + for (i = 0; i < txq->bd.ring_size; i++) { + kfree(txq->tx_bounce[i]); + txq->tx_bounce[i] = NULL; +@@ -3282,6 +4218,7 @@ static void fec_enet_free_buffers(struct net_device *ndev) + txq->tx_buf[i].type = FEC_TXBUF_T_SKB; + } + } ++#endif + } + } + +@@ -3321,10 +4258,14 @@ static int fec_enet_alloc_queue(struct net_device *ndev) + } + + fep->tx_queue[i] = txq; +- txq->bd.ring_size = TX_RING_SIZE; ++ txq->bd.ring_size = FEC_TX_RING_SIZE; + fep->total_tx_ring_size += fep->tx_queue[i]->bd.ring_size; + ++#ifdef CONFIG_AVB_SUPPORT ++ txq->tx_stop_threshold = FEC_TX_RING_SIZE * 3/4; ++#else + txq->tx_stop_threshold = FEC_MAX_SKB_DESCS; ++#endif + txq->tx_wake_threshold = + (txq->bd.ring_size - txq->tx_stop_threshold) / 2; + +@@ -3346,7 +4287,7 @@ static int fec_enet_alloc_queue(struct net_device *ndev) + goto alloc_failed; + } + +- fep->rx_queue[i]->bd.ring_size = RX_RING_SIZE; ++ fep->rx_queue[i]->bd.ring_size = FEC_RX_RING_SIZE; + fep->total_rx_ring_size += fep->rx_queue[i]->bd.ring_size; + } + return ret; +@@ -3367,32 +4308,77 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue) + int i, err; + + rxq = fep->rx_queue[queue]; ++ ++#ifdef CONFIG_AVB_SUPPORT + bdp = rxq->bd.base; + +- err = fec_enet_create_page_pool(fep, rxq, rxq->bd.ring_size); +- if (err < 0) { +- netdev_err(ndev, "%s failed queue %d (%d)\n", __func__, queue, err); +- return err; ++ for (i = 0; i < rxq->bd.ring_size; i++) { ++ bdp->cbd_bufaddr = cpu_to_fec32(0); ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); + } ++#endif + +- for (i = 0; i < rxq->bd.ring_size; i++) { +- page = page_pool_dev_alloc_pages(rxq->page_pool); +- if (!page) +- goto err_alloc; ++ bdp = rxq->bd.base; ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) { ++ for (i = 0; i < rxq->bd.ring_size; i++) { ++ struct avb_rx_desc *desc; ++ void *buffer; + +- phys_addr = page_pool_get_dma_addr(page) + FEC_ENET_XDP_HEADROOM; +- bdp->cbd_bufaddr = cpu_to_fec32(phys_addr); ++ buffer = fep->avb->alloc(fep->avb_data); ++ if (!buffer) ++ goto err_alloc; + +- rxq->rx_skb_info[i].page = page; +- rxq->rx_skb_info[i].offset = FEC_ENET_XDP_HEADROOM; +- bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY); ++ desc = buffer; + +- if (fep->bufdesc_ex) { +- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; +- ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT); ++ desc->common.len = 0; ++ desc->queue_id = queue; ++ ++ rxq->rx_skb_info[i].skb = buffer; ++ bdp->cbd_bufaddr = cpu_to_fec32((dma_addr_t)(desc->dma_addr)); ++ ++#if !defined(CONFIG_M5272) ++ if (fep->quirks & FEC_QUIRK_HAS_RACC) ++ desc->common.offset += 2; ++#endif ++ ++ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY); ++ ++ if (fep->bufdesc_ex) { ++ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; ++ ebdp->cbd_esc = cpu_to_fec32(0); ++ } ++ ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ } ++ } else ++#endif ++ { ++ err = fec_enet_create_page_pool(fep, rxq, rxq->bd.ring_size); ++ if (err < 0) { ++ netdev_err(ndev, "%s failed queue %d (%d)\n", __func__, queue, err); ++ return err; + } + +- bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ for (i = 0; i < rxq->bd.ring_size; i++) { ++ page = page_pool_dev_alloc_pages(rxq->page_pool); ++ if (!page) ++ goto err_alloc; ++ ++ phys_addr = page_pool_get_dma_addr(page) + FEC_ENET_XDP_HEADROOM; ++ bdp->cbd_bufaddr = cpu_to_fec32(phys_addr); ++ ++ rxq->rx_skb_info[i].page = page; ++ rxq->rx_skb_info[i].offset = FEC_ENET_XDP_HEADROOM; ++ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY); ++ ++ if (fep->bufdesc_ex) { ++ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; ++ ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT); ++ } ++ ++ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd); ++ } + } + + /* Set the last buffer to wrap. */ +@@ -3415,17 +4401,28 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue) + + txq = fep->tx_queue[queue]; + bdp = txq->bd.base; +- for (i = 0; i < txq->bd.ring_size; i++) { ++ for (i = 0; i < txq->tx_bounce_size; i++) { + txq->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); + if (!txq->tx_bounce[i]) + goto err_alloc; ++ } ++ ++ bdp = txq->bd.base; ++ txq->bd.cur = bdp; + ++ for (i = 0; i < txq->bd.ring_size; i++) { + bdp->cbd_sc = cpu_to_fec16(0); + bdp->cbd_bufaddr = cpu_to_fec32(0); + + if (fep->bufdesc_ex) { + struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; +- ebdp->cbd_esc = cpu_to_fec32(BD_ENET_TX_INT); ++ ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ ebdp->cbd_esc = cpu_to_fec32(0); ++ else ++#endif ++ ebdp->cbd_esc = cpu_to_fec32(BD_ENET_TX_INT); + } + + bdp = fec_enet_get_nextdesc(bdp, &txq->bd); +@@ -3434,6 +4431,7 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue) + /* Set the last buffer to wrap. */ + bdp = fec_enet_get_prevdesc(bdp, &txq->bd); + bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP); ++ txq->dirty_tx = bdp; + + return 0; + +@@ -3463,15 +4461,31 @@ fec_enet_open(struct net_device *ndev) + struct fec_enet_private *fep = netdev_priv(ndev); + int ret; + bool reset_again; ++ int i; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) { ++ if (!try_module_get(fep->avb->owner)) { ++ ret = -EIO; ++ goto err_module_get; ++ } ++ for (i = 0; i < fep->num_tx_queues; i++) ++ fep->tx_queue[i]->tx_bounce_size = FEC_TX_RING_SIZE + 32; ++ } else ++#endif ++ for (i = 0; i < fep->num_tx_queues; i++) ++ fep->tx_queue[i]->tx_bounce_size = FEC_TX_RING_SIZE; + + ret = pm_runtime_resume_and_get(&fep->pdev->dev); + if (ret < 0) + return ret; + + pinctrl_pm_select_default_state(&fep->pdev->dev); ++#ifndef CONFIG_AVB_SUPPORT + ret = fec_enet_clk_enable(ndev, true); + if (ret) + goto clk_enable; ++#endif + + /* During the first fec_enet_open call the PHY isn't probed at this + * point. Therefore the phy_reset_after_clk_enable() call within +@@ -3514,6 +4528,12 @@ fec_enet_open(struct net_device *ndev) + + napi_enable(&fep->napi); + phy_start(ndev->phydev); ++ ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep)); ++#endif ++ + netif_tx_start_all_queues(ndev); + + device_set_wakeup_enable(&ndev->dev, fep->wol_flag & +@@ -3524,12 +4544,23 @@ fec_enet_open(struct net_device *ndev) + err_enet_mii_probe: + fec_enet_free_buffers(ndev); + err_enet_alloc: ++#ifndef CONFIG_AVB_SUPPORT + fec_enet_clk_enable(ndev, false); + clk_enable: ++#endif + pm_runtime_mark_last_busy(&fep->pdev->dev); + pm_runtime_put_autosuspend(&fep->pdev->dev); + if (!fep->mii_bus_share) + pinctrl_pm_select_sleep_state(&fep->pdev->dev); ++ ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ module_put(fep->avb->owner); ++#endif ++ ++#ifdef CONFIG_AVB_SUPPORT ++err_module_get: ++#endif + return ret; + } + +@@ -3543,9 +4574,20 @@ fec_enet_close(struct net_device *ndev) + if (netif_device_present(ndev)) { + napi_disable(&fep->napi); + netif_tx_disable(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->close(fep->avb_data); ++#endif + fec_stop(ndev); + } + ++#ifdef CONFIG_AVB_SUPPORT ++ /* ++ * Save advertising settings so there are not lost ++ * when opening the interface again. ++ */ ++ linkmode_copy(fep->phy_advertising, ndev->phydev->advertising); ++#endif + phy_disconnect(ndev->phydev); + ndev->phydev = NULL; + +@@ -3554,7 +4596,9 @@ fec_enet_close(struct net_device *ndev) + + fec_enet_update_ethtool_stats(ndev); + ++#ifndef CONFIG_AVB_SUPPORT + fec_enet_clk_enable(ndev, false); ++#endif + if (fep->quirks & FEC_QUIRK_HAS_PMQOS) + cpu_latency_qos_remove_request(&fep->pm_qos_req); + +@@ -3565,6 +4609,11 @@ fec_enet_close(struct net_device *ndev) + + fec_enet_free_buffers(ndev); + ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ module_put(fep->avb->owner); ++#endif ++ + return 0; + } + +@@ -3749,6 +4798,7 @@ static u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb, + return fec_enet_vlan_pri_to_queue[vlan_tag >> 13]; + } + ++#ifndef CONFIG_AVB_SUPPORT + static int fec_enet_bpf(struct net_device *dev, struct netdev_bpf *bpf) + { + struct fec_enet_private *fep = netdev_priv(dev); +@@ -3936,6 +4986,7 @@ static int fec_enet_xdp_xmit(struct net_device *dev, + + return sent_frames; + } ++#endif /* !CONFIG_AVB_SUPPORT */ + + static const struct net_device_ops fec_netdev_ops = { + .ndo_open = fec_enet_open, +@@ -3951,8 +5002,11 @@ static const struct net_device_ops fec_netdev_ops = { + .ndo_poll_controller = fec_poll_controller, + #endif + .ndo_set_features = fec_set_features, ++#ifndef CONFIG_AVB_SUPPORT ++ /* AVB support not compatible with XDP */ + .ndo_bpf = fec_enet_bpf, + .ndo_xdp_xmit = fec_enet_xdp_xmit, ++#endif + }; + + static const unsigned short offset_des_active_rxq[] = { +@@ -3963,6 +5017,196 @@ static const unsigned short offset_des_active_txq[] = { + FEC_X_DES_ACTIVE_0, FEC_X_DES_ACTIVE_1, FEC_X_DES_ACTIVE_2 + }; + ++#ifdef CONFIG_AVB_SUPPORT ++ ++static struct platform_driver fec_driver; ++ ++/* Checks if the net_device is registered by the fec */ ++static bool __is_fec_net_device(struct net_device *ndev) ++{ ++ if (!ndev) ++ return false; ++ ++ if (ndev->dev.parent->driver == &fec_driver.driver) ++ return true; ++ else ++ return false; ++} ++ ++struct device *fec_enet_avb_get_device(const char *ifname) ++{ ++ struct net_device *ndev; ++ struct fec_enet_private *fep; ++ ++ ndev = dev_get_by_name(&init_net, ifname); ++ if (!ndev) ++ goto err_dev_get; ++ ++ if (!__is_fec_net_device(ndev)) ++ goto err_ndev; ++ ++ fep = netdev_priv(ndev); ++ ++ dev_put(ndev); ++ ++ return &fep->pdev->dev; ++ ++err_ndev: ++ dev_put(ndev); ++ ++err_dev_get: ++ return NULL; ++} ++EXPORT_SYMBOL(fec_enet_avb_get_device); ++ ++int fec_enet_avb_register(const char *ifname, const struct avb_ops *avb, void *data) ++{ ++ struct net_device *ndev; ++ struct fec_enet_private *fep; ++ unsigned int up; ++ int ifindex; ++ ++ ndev = dev_get_by_name(&init_net, ifname); ++ if (!ndev) ++ goto err_dev_get; ++ ++ if (!__is_fec_net_device(ndev)) ++ goto err_ndev; ++ ++ fep = netdev_priv(ndev); ++ ++ if (fep->avb) ++ goto err_avb; ++ ++ rtnl_lock(); ++ up = ndev->flags & IFF_UP; ++ if (up) ++ dev_close(ndev); ++ ++ fep->avb = avb; ++ fep->avb_data = data; ++ fep->avb_enabled = 1; ++ ifindex = ndev->ifindex; ++ ++ if (up) { ++ /* In case of error, device is closed but avb interface is registered */ ++ dev_open(ndev, NULL); ++ } ++ ++ rtnl_unlock(); ++ ++ dev_put(ndev); ++ ++ return ifindex; ++ ++err_avb: ++err_ndev: ++ dev_put(ndev); ++ ++err_dev_get: ++ return -1; ++} ++EXPORT_SYMBOL(fec_enet_avb_register); ++ ++int fec_enet_avb_unregister(int ifindex, const struct avb_ops *avb) ++{ ++ struct net_device *ndev; ++ struct fec_enet_private *fep; ++ unsigned int up; ++ ++ ndev = dev_get_by_index(&init_net, ifindex); ++ if (!ndev) ++ goto err_dev_get; ++ ++ if (!__is_fec_net_device(ndev)) ++ goto err_ndev; ++ ++ fep = netdev_priv(ndev); ++ if (fep->avb != avb) ++ goto err_avb; ++ ++ rtnl_lock(); ++ up = ndev->flags & IFF_UP; ++ if (up) ++ dev_close(ndev); ++ ++ fep->avb = NULL; ++ fep->avb_data = NULL; ++ fep->avb_enabled = 0; ++ ++ if (up) ++ /* In case of error, device is closed but avb interface is unregistered */ ++ dev_open(ndev, NULL); ++ ++ rtnl_unlock(); ++ ++ dev_put(ndev); ++ ++ return 0; ++ ++err_avb: ++err_ndev: ++ dev_put(ndev); ++ ++err_dev_get: ++ return -1; ++} ++EXPORT_SYMBOL(fec_enet_avb_unregister); ++ ++int fec_enet_get_tx_queue_properties(int ifindex, struct tx_queue_properties *prop) ++{ ++ struct net_device *ndev; ++ struct fec_enet_private *fep; ++ ++ ndev = dev_get_by_index(&init_net, ifindex); ++ if (!ndev) ++ goto err_dev_get; ++ ++ if (!__is_fec_net_device(ndev)) ++ goto err_ndev; ++ ++ fep = netdev_priv(ndev); ++ ++ if (fep->num_tx_queues >= TX_QUEUE_PROP_MAX) ++ goto err_queues; ++ ++ if (fep->quirks & FEC_QUIRK_HAS_AVB) { ++ prop->num_queues = fep->num_tx_queues; ++ prop->queue[0].priority = 0; ++ prop->queue[0].flags = TX_QUEUE_FLAGS_STRICT_PRIORITY; ++ prop->queue[1].priority = 2; ++ prop->queue[1].flags = TX_QUEUE_FLAGS_CREDIT_SHAPER; ++ prop->queue[2].priority = 1; ++ prop->queue[2].flags = TX_QUEUE_FLAGS_CREDIT_SHAPER; ++ } else { ++ /* ++ * For now, there is no MAC non-AVB capable ++ * with more than 1 queue. ++ */ ++ if (fep->num_tx_queues == 1) { ++ prop->num_queues = fep->num_tx_queues; ++ prop->queue[0].priority = 0; ++ prop->queue[0].flags = TX_QUEUE_FLAGS_STRICT_PRIORITY; ++ } else { ++ netdev_err(ndev, "%s invalid/unknown TX queues configuration\n", __func__); ++ goto err_queues; ++ } ++ } ++ ++ dev_put(ndev); ++ ++ return 0; ++ ++err_queues: ++err_ndev: ++ dev_put(ndev); ++ ++err_dev_get: ++ return -1; ++} ++EXPORT_SYMBOL(fec_enet_get_tx_queue_properties); ++#endif ++ + /* + * XXX: We need to clean up on failure exits here. + * +@@ -4050,10 +5294,14 @@ static int fec_enet_init(struct net_device *ndev) + txq->bd.dsize_log2 = dsize_log2; + txq->bd.reg_desc_active = fep->hwp + offset_des_active_txq[i]; + bd_dma += size; ++#ifdef CONFIG_AVB_SUPPORT ++ txq->tx_idle_slope = IDLE_SLOPE(i); ++#endif + cbd_base = (struct bufdesc *)(((void *)cbd_base) + size); + txq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize); + } + ++ fep->netdev = ndev; + + /* The FEC Ethernet specific entries in the device structure */ + ndev->watchdog_timeo = TX_TIMEOUT; +@@ -4071,8 +5319,13 @@ static int fec_enet_init(struct net_device *ndev) + netif_set_tso_max_segs(ndev, FEC_MAX_TSO_SEGS); + + /* enable hw accelerator */ ++#ifdef CONFIG_AVB_SUPPORT ++ /* AVB support not compatible with SG or TSO */ ++ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM); ++#else + ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM + | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO); ++#endif + fep->csum_flags |= FLAG_RX_CSUM_ENABLED; + } + +@@ -4399,6 +5652,13 @@ fec_probe(struct platform_device *pdev) + } + + fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX; ++#ifdef CONFIG_AVB_SUPPORT ++ if (!fep->bufdesc_ex) { ++ dev_err(&pdev->dev, ++ "Error: AVB Support requires extended buffer descriptor\n"); ++ goto failed_clk; ++ } ++#endif + fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); + if (IS_ERR(fep->clk_ptp)) { + fep->clk_ptp = NULL; +@@ -4432,12 +5692,32 @@ fec_probe(struct platform_device *pdev) + fep->reg_phy = NULL; + } + ++ if (of_property_read_u32(np, "fsl,rx-phy-delay-100-ns", &fep->rx_delay_100)) ++ fep->rx_delay_100 = 0; ++ ++ if (of_property_read_u32(np, "fsl,tx-phy-delay-100-ns", &fep->tx_delay_100)) ++ fep->tx_delay_100 = 0; ++ ++ if (of_property_read_u32(np, "fsl,rx-phy-delay-1000-ns", &fep->rx_delay_1000)) ++ fep->rx_delay_1000 = 0; ++ ++ if (of_property_read_u32(np, "fsl,tx-phy-delay-1000-ns", &fep->tx_delay_1000)) ++ fep->tx_delay_1000 = 0; ++ + pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ++#ifdef CONFIG_AVB_SUPPORT ++ /* ++ * Prevent runtime pm with avb module to keep all clocks ++ * running even on link down. ++ */ ++ pm_runtime_forbid(&pdev->dev); ++#endif ++ + ret = fec_reset_phy(pdev); + if (ret) + goto failed_reset; +@@ -4480,7 +5760,9 @@ fec_probe(struct platform_device *pdev) + + /* Carrier starts down, phylib will bring it up */ + netif_carrier_off(ndev); ++#ifndef CONFIG_AVB_SUPPORT + fec_enet_clk_enable(ndev, false); ++#endif + pinctrl_pm_select_sleep_state(&pdev->dev); + + ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN; +@@ -4590,6 +5872,10 @@ static int __maybe_unused fec_suspend(struct device *dev) + netif_tx_lock_bh(ndev); + netif_device_detach(ndev); + netif_tx_unlock_bh(ndev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->close(fep->avb_data); ++#endif + fec_stop(ndev); + if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) { + fec_irqs_disable(ndev); +@@ -4674,6 +5960,10 @@ static int __maybe_unused fec_resume(struct device *dev) + napi_enable(&fep->napi); + phy_init_hw(ndev->phydev); + phy_start(ndev->phydev); ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->avb_enabled) ++ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep)); ++#endif + } else if (fep->mii_bus_share && !ndev->phydev) { + pinctrl_pm_select_default_state(&fep->pdev->dev); + /* And then recovery mii bus */ +diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c +index d15737962145..339d3f0fc3fe 100644 +--- a/drivers/net/ethernet/freescale/fec_ptp.c ++++ b/drivers/net/ethernet/freescale/fec_ptp.c +@@ -111,7 +111,14 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable) + fep->pps_channel = DEFAULT_PPS_CHANNEL; + fep->reload_period = PPS_OUPUT_RELOAD_PERIOD; + +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ ++#ifdef CONFIG_AVB_SUPPORT ++ if (fep->rec_enable && (fep->pps_channel == fep->rec_channel)) { ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ return -EBUSY; ++ } ++#endif + + if (enable) { + /* clear capture or output compare interrupt status if have. +@@ -196,7 +203,7 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable) + } + + fep->pps_enable = enable; +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + return 0; + } +@@ -207,7 +214,7 @@ static int fec_ptp_pps_perout(struct fec_enet_private *fep) + u64 curr_time; + unsigned long flags; + +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + + /* Update time counter */ + timecounter_read(&fep->tc); +@@ -230,7 +237,7 @@ static int fec_ptp_pps_perout(struct fec_enet_private *fep) + */ + if (fep->perout_stime < curr_time + 100 * NSEC_PER_MSEC) { + dev_err(&fep->pdev->dev, "Current time is too close to the start time!\n"); +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + return -1; + } + +@@ -258,7 +265,7 @@ static int fec_ptp_pps_perout(struct fec_enet_private *fep) + */ + writel(fep->next_counter, fep->hwp + FEC_TCCR(fep->pps_channel)); + fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask; +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + return 0; + } +@@ -273,6 +280,26 @@ static enum hrtimer_restart fec_ptp_pps_perout_handler(struct hrtimer *timer) + return HRTIMER_NORESTART; + } + ++#ifdef CONFIG_AVB_SUPPORT ++/** ++ * fec_timecounter_set ++ * @start_tstamp: new time in ns ++ * ++ * update the FEC timecounter structure to a new time, and make sure ++ * the HW counter matches that value. ++ */ ++static inline void fec_timecounter_set(struct fec_enet_private *fep, ++ u64 start_tstamp) ++{ ++ u32 tempval; ++ ++ tempval = start_tstamp & fep->cc.mask; ++ writel(tempval, fep->hwp + FEC_ATIME); ++ fep->tc.cycle_last = tempval; ++ fep->tc.nsec = start_tstamp; ++} ++#endif ++ + /** + * fec_ptp_read - read raw cycle counter (to be used by time counter) + * @cc: the cyclecounter structure +@@ -287,14 +314,14 @@ static u64 fec_ptp_read(const struct cyclecounter *cc) + container_of(cc, struct fec_enet_private, cc); + u32 tempval; + +- tempval = readl(fep->hwp + FEC_ATIME_CTRL); ++ tempval = readl_relaxed(fep->hwp + FEC_ATIME_CTRL); + tempval |= FEC_T_CTRL_CAPTURE; + writel(tempval, fep->hwp + FEC_ATIME_CTRL); + + if (fep->quirks & FEC_QUIRK_BUG_CAPTURE) + udelay(1); + +- return readl(fep->hwp + FEC_ATIME); ++ return readl_relaxed(fep->hwp + FEC_ATIME); + } + + /** +@@ -314,29 +341,312 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev) + inc = 1000000000 / fep->cycle_speed; + + /* grab the ptp lock */ +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + +- /* 1ns counter */ +- writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC); ++ /* 1ns counter, disable correction period */ ++ writel_relaxed(0, fep->hwp + FEC_ATIME_CORR); ++ writel_relaxed(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC); + +- /* use 31-bit timer counter */ +- writel(FEC_COUNTER_PERIOD, fep->hwp + FEC_ATIME_EVT_PERIOD); + +- writel(FEC_T_CTRL_ENABLE | FEC_T_CTRL_PERIOD_RST, ++#ifdef CONFIG_AVB_SUPPORT ++ /* use 32-bits timer counter */ ++ writel_relaxed(0, fep->hwp + FEC_ATIME_EVT_PERIOD); ++ writel_relaxed(FEC_T_CTRL_ENABLE, fep->hwp + FEC_ATIME_CTRL); ++#else ++ /* use 31-bit timer counter */ ++ writel_relaxed(FEC_COUNTER_PERIOD, fep->hwp + FEC_ATIME_EVT_PERIOD); ++ writel_relaxed(FEC_T_CTRL_ENABLE | FEC_T_CTRL_PERIOD_RST, + fep->hwp + FEC_ATIME_CTRL); ++#endif + + memset(&fep->cc, 0, sizeof(fep->cc)); + fep->cc.read = fec_ptp_read; ++#ifdef CONFIG_AVB_SUPPORT ++ fep->cc.mask = CLOCKSOURCE_MASK(32); ++#else + fep->cc.mask = CLOCKSOURCE_MASK(31); ++#endif + fep->cc.shift = 31; + fep->cc.mult = FEC_CC_MULT; + + /* reset the ns time counter */ ++#ifdef CONFIG_AVB_SUPPORT ++ fep->tc.cc = &fep->cc; ++ fec_timecounter_set(fep, 0); ++#else + timecounter_init(&fep->tc, &fep->cc, 0); ++#endif + +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + } + ++#ifdef CONFIG_AVB_SUPPORT ++/** ++ * fec_ptp_adjfreq - adjust ptp cycle frequency ++ * @ptp: the ptp clock structure ++ * @ppb: parts per billion adjustment from base ++ * ++ * Adjust the frequency of the ptp cycle counter by the ++ * indicated ppb from the base frequency. ++ * ++ * This version adjusts the HW counter. The HW implementation results in the following equation: ++ * fe * diff = ppb * (pc + 1) ++ * with: ++ * . fe : ENET ref clock frequency in Hz ++ * . diff = inc_corr - inc : difference between default increment and correction increment ++ * . ppb : parts per billion adjustment from base ++ * . pc : correction period (in number of fe clock cycles) ++ * ++ * Limitations: ++ * . only add or remove 1ns per correction period. This will limit jitter and improve short term ++ * accuracy (in particular for trigger events during clock recovery) but increase the max possible ++ * error, since the correction period will be the shortest possible and thus may not be optimal. ++ * In the case of an adjustment of about 100ppm (which should be the max if the ref clock ++ * is within the 802.1AS spec), the max error will be about 0.2ppm with a 50MHz ref clock, and ++ * 0.08ppm with a 125MHz ref clock. ++ * Long term accuracy will also be lower (20ns per 100ms @50MHz, 8ns per 100ms @125MHz), but this ++ * can be fixed by phase adjustments. ++ * . It seems not all period/correction values are valid. With a 1ns correction, all even ++ * period values return wrong timings (half the requested correction), but on the other hand odd ++ * values are not taken into account systematically by the hardware, so we choose the closest even ++ * value that matches the following equation: ++ * fe * diff = 2 * ppb * (pc + 1) ++ * . given we force abs(diff) = 1, limit max adjustment to prevent pc < 1. ++ * ++ */ ++static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) ++{ ++ struct fec_enet_private *fep = ++ container_of(ptp, struct fec_enet_private, ptp_caps); ++ unsigned long flags; ++ u32 inc, cor, pc; ++ ++ inc = fep->ptp_inc; ++ if (ppb == 0) { ++ cor = 0; ++ pc = 0; ++ } else { ++ if (ppb < 0) { ++ ppb = -ppb; ++ cor = inc - 1; ++ } ++ else ++ cor = inc + 1; ++ ++ if (ppb > fep->ptp_caps.max_adj) { ++ dev_err(&fep->pdev->dev, "ppb value %d outside accepted range (max_adj = %d)", (cor > inc) ? ppb : -ppb, ptp->max_adj); ++ return -1; ++ } ++ ++ pc = (((fep->cycle_speed / (2*ppb)) - 1) + 1) & ~ 0x1; // + 1) & ~ 0x1 returns the closest even value ++ } ++ ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ ++ writel_relaxed((cor << FEC_T_INC_CORR_OFFSET) | (inc << FEC_T_INC_OFFSET), fep->hwp + FEC_ATIME_INC); ++ writel_relaxed(pc, fep->hwp + FEC_ATIME_CORR); ++ ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ ++ return 0; ++} ++ ++/** ++ * fec_ptp_adjtime ++ * @ptp: the ptp clock structure ++ * @delta: offset to adjust the cycle counter by ++ * ++ * adjust the timer by updating the HW counter AND the timecounter structure ++ * as well. Since updating the HW register requires a read and a write, make ++ * a crude estimate of the read time and subtract it from the desired delta. ++ */ ++static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ++{ ++ struct fec_enet_private *fep = ++ container_of(ptp, struct fec_enet_private, ptp_caps); ++ unsigned long flags; ++ u64 now, then; ++ s64 real_delta; ++ ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ ++ now = timecounter_read(&fep->tc); ++ then = timecounter_read(&fep->tc); ++ ++ real_delta = delta + (then - now); ++ ++ now = timecounter_read(&fep->tc); ++ now += real_delta; ++ ++ fec_timecounter_set(fep, now); ++ ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ ++ return 0; ++} ++ ++/** ++ * fec_ptp_settime ++ * @ptp: the ptp clock structure ++ * @ts: the timespec containing the new time for the cycle counter ++ * ++ * Update the timecounter to use a new base value instead of the kernel ++ * wall timer value, and update the HW counter as well. ++ */ ++static int fec_ptp_settime(struct ptp_clock_info *ptp, ++ const struct timespec64 *ts) ++{ ++ struct fec_enet_private *fep = ++ container_of(ptp, struct fec_enet_private, ptp_caps); ++ u64 ns; ++ unsigned long flags; ++ ++ ns = ts->tv_sec * 1000000000ULL; ++ ns += ts->tv_nsec; ++ ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ fec_timecounter_set(fep, ns); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ return 0; ++} ++ ++/** ++ * fec_ptp_read ++ * @data: fec private context ptr ++ * @cnt: data pointer for counter value ++ * ++ * Returns status ++ */ ++int fec_ptp_read_cnt(void *data, u32 *cnt) ++{ ++ struct fec_enet_private *fep = data; ++ unsigned long flags; ++ ++ /* Note : it might be possible to avoid taking the lock */ ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ ++ *cnt = (u32) fec_ptp_read(&fep->cc); ++ ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL(fec_ptp_read_cnt); ++ ++/** ++ * fec_ptp_tc_start ++ * @data: fec private context ptr ++ * @id: TC register ID ++ * @ts_0: First timestamp ++ * @ts_1: Second timestamp ++ * @tcsr_val: TCSR register value ++ * ++ * Returns 0 on success, -1 if PTP counter is not ++ * enabled. ++ */ ++int fec_ptp_tc_start(void *data, u8 id, u32 ts_0, u32 ts_1, u32 tcsr_val) ++{ ++ struct fec_enet_private *fep = data; ++ unsigned long flags; ++ u32 ctrl_val; ++ int rc = 0; ++ ++ if (id > MAX_TIMER_CHANNEL) { ++ rc = -1; ++ goto exit; ++ } ++ ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ ++ /* Simple resource sharing handling with pps */ ++ if (fep->pps_enable && (fep->pps_channel == id)) { ++ rc = -1; ++ goto exit_unlock; ++ } ++ ++ ctrl_val = readl_relaxed(fep->hwp + FEC_ATIME_CTRL); ++ if (!(ctrl_val & FEC_T_CTRL_ENABLE)) { ++ rc = -1; ++ goto exit_unlock; ++ } ++ ++ writel_relaxed(ts_0, fep->hwp + FEC_TCCR(id)); ++ writel_relaxed(tcsr_val, fep->hwp + FEC_TCSR(id)); ++ writel_relaxed(ts_1, fep->hwp + FEC_TCCR(id)); ++ ++ fep->rec_enable = 1; ++ fep->rec_channel = id; ++ ++exit_unlock: ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++exit: ++ return rc; ++} ++EXPORT_SYMBOL(fec_ptp_tc_start); ++ ++/** ++ * fec_ptp_tc_stop ++ * @data: fec private context ptr ++ * @id: TC register ID ++ * ++ * Returns none ++ */ ++void fec_ptp_tc_stop(void *data, u8 id) ++{ ++ struct fec_enet_private *fep = data; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ ++ writel_relaxed(0, fep->hwp + FEC_TCCR(id)); ++ writel_relaxed(FEC_T_TF_MASK, fep->hwp + FEC_TCSR(id)); ++ ++ fep->rec_enable = 0; ++ ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++} ++EXPORT_SYMBOL(fec_ptp_tc_stop); ++ ++/** ++ * fec_ptp_tc_reload ++ * @data: fec private context ptr ++ * @id: TC register ID ++ * @ts: New timestamp to load ++ * ++ * Returns 0 if success, -1 if compare has not occured ++ * or if PTP counter is not enabled. ++ */ ++int fec_ptp_tc_reload(void *data, u8 id, u32 ts) ++{ ++ struct fec_enet_private *fep = data; ++ unsigned long flags; ++ u32 tcsr_val; ++ u32 ctrl_val; ++ int rc = 0; ++ ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); ++ ++ ctrl_val = readl_relaxed(fep->hwp + FEC_ATIME_CTRL); ++ if (!(ctrl_val & FEC_T_CTRL_ENABLE)) { ++ rc = -1; ++ goto exit; ++ } ++ ++ tcsr_val = readl_relaxed(fep->hwp + FEC_TCSR(id)); ++ if (tcsr_val & FEC_T_TF_MASK) { ++ writel_relaxed(ts, fep->hwp + FEC_TCCR(id)); ++ writel_relaxed(tcsr_val, fep->hwp + FEC_TCSR(id)); ++ } ++ else ++ rc = -1; ++ ++exit: ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ return rc; ++} ++EXPORT_SYMBOL(fec_ptp_tc_reload); ++#else /* CONFIG_AVB_SUPPORT */ ++ + /** + * fec_ptp_adjfreq - adjust ptp cycle frequency + * @ptp: the ptp clock structure +@@ -395,7 +705,7 @@ static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) + else + corr_ns = fep->ptp_inc + corr_inc; + +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + + tmp = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK; + tmp |= corr_ns << FEC_T_INC_CORR_OFFSET; +@@ -405,7 +715,7 @@ static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) + /* dummy read to update the timer. */ + timecounter_read(&fep->tc); + +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + return 0; + } +@@ -423,40 +733,9 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) + container_of(ptp, struct fec_enet_private, ptp_caps); + unsigned long flags; + +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + timecounter_adjtime(&fep->tc, delta); +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); +- +- return 0; +-} +- +-/** +- * fec_ptp_gettime +- * @ptp: the ptp clock structure +- * @ts: timespec structure to hold the current time value +- * +- * read the timecounter and return the correct value on ns, +- * after converting it into a struct timespec. +- */ +-static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +-{ +- struct fec_enet_private *adapter = +- container_of(ptp, struct fec_enet_private, ptp_caps); +- u64 ns; +- unsigned long flags; +- +- mutex_lock(&adapter->ptp_clk_mutex); +- /* Check the ptp clock */ +- if (!adapter->ptp_clk_on) { +- mutex_unlock(&adapter->ptp_clk_mutex); +- return -EINVAL; +- } +- spin_lock_irqsave(&adapter->tmreg_lock, flags); +- ns = timecounter_read(&adapter->tc); +- spin_unlock_irqrestore(&adapter->tmreg_lock, flags); +- mutex_unlock(&adapter->ptp_clk_mutex); +- +- *ts = ns_to_timespec64(ns); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + return 0; + } +@@ -492,21 +771,55 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp, + */ + counter = ns & fep->cc.mask; + +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + writel(counter, fep->hwp + FEC_ATIME); + timecounter_init(&fep->tc, &fep->cc, ns); +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + mutex_unlock(&fep->ptp_clk_mutex); + return 0; + } ++#endif /* CONFIG_AVB_SUPPORT */ ++ ++/** ++ * fec_ptp_gettime ++ * @ptp: the ptp clock structure ++ * @ts: timespec structure to hold the current time value ++ * ++ * read the timecounter and return the correct value on ns, ++ * after converting it into a struct timespec. ++ */ ++static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) ++{ ++ struct fec_enet_private *adapter = ++ container_of(ptp, struct fec_enet_private, ptp_caps); ++ u64 ns; ++ u32 remainder; ++ unsigned long flags; ++ ++ mutex_lock(&adapter->ptp_clk_mutex); ++ /* Check the ptp clock */ ++ if (!adapter->ptp_clk_on) { ++ mutex_unlock(&adapter->ptp_clk_mutex); ++ return -EINVAL; ++ } ++ raw_spin_lock_irqsave(&adapter->tmreg_lock, flags); ++ ns = timecounter_read(&adapter->tc); ++ raw_spin_unlock_irqrestore(&adapter->tmreg_lock, flags); ++ mutex_unlock(&adapter->ptp_clk_mutex); ++ ++ ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder); ++ ts->tv_nsec = remainder; ++ ++ return 0; ++} + + static int fec_ptp_pps_disable(struct fec_enet_private *fep, uint channel) + { + unsigned long flags; + +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + writel(0, fep->hwp + FEC_TCSR(channel)); +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + return 0; + } +@@ -567,10 +880,10 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, + mutex_unlock(&fep->ptp_clk_mutex); + return -EOPNOTSUPP; + } +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + /* Read current timestamp */ + curr_time = timecounter_read(&fep->tc); +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + mutex_unlock(&fep->ptp_clk_mutex); + + /* Calculate time difference */ +@@ -676,9 +989,9 @@ static void fec_time_keep(struct work_struct *work) + + mutex_lock(&fep->ptp_clk_mutex); + if (fep->ptp_clk_on) { +- spin_lock_irqsave(&fep->tmreg_lock, flags); ++ raw_spin_lock_irqsave(&fep->tmreg_lock, flags); + timecounter_read(&fep->tc); +- spin_unlock_irqrestore(&fep->tmreg_lock, flags); ++ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags); + } + mutex_unlock(&fep->ptp_clk_mutex); + +@@ -694,6 +1007,9 @@ static irqreturn_t fec_pps_interrupt(int irq, void *dev_id) + u8 channel = fep->pps_channel; + struct ptp_clock_event event; + ++ if (fep->pps_enable) ++ goto exit; ++ + val = readl(fep->hwp + FEC_TCSR(channel)); + if (val & FEC_T_TF_MASK) { + /* Write the next next compare(not the next according the spec) +@@ -713,6 +1029,7 @@ static irqreturn_t fec_pps_interrupt(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++exit: + return IRQ_NONE; + } + +@@ -736,7 +1053,18 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx) + fep->ptp_caps.owner = THIS_MODULE; + strscpy(fep->ptp_caps.name, "fec ptp", sizeof(fep->ptp_caps.name)); + ++ fep->cycle_speed = clk_get_rate(fep->clk_ptp); ++ if (!fep->cycle_speed) { ++ fep->cycle_speed = NSEC_PER_SEC; ++ dev_err(&fep->pdev->dev, "clk_ptp clock rate is zero\n"); ++ } ++ fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed; ++ ++#ifdef CONFIG_AVB_SUPPORT ++ fep->ptp_caps.max_adj = fep->cycle_speed / 2; ++#else + fep->ptp_caps.max_adj = 250000000; ++#endif + fep->ptp_caps.n_alarm = 0; + fep->ptp_caps.n_ext_ts = 0; + fep->ptp_caps.n_per_out = 1; +@@ -748,14 +1076,7 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx) + fep->ptp_caps.settime64 = fec_ptp_settime; + fep->ptp_caps.enable = fec_ptp_enable; + +- fep->cycle_speed = clk_get_rate(fep->clk_ptp); +- if (!fep->cycle_speed) { +- fep->cycle_speed = NSEC_PER_SEC; +- dev_err(&fep->pdev->dev, "clk_ptp clock rate is zero\n"); +- } +- fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed; +- +- spin_lock_init(&fep->tmreg_lock); ++ raw_spin_lock_init(&fep->tmreg_lock); + + fec_ptp_start_cyclecounter(ndev); + +diff --git a/drivers/net/ethernet/freescale/fec_uio.c b/drivers/net/ethernet/freescale/fec_uio.c +index 7e93c9966c2b..b433868d4c5a 100644 +--- a/drivers/net/ethernet/freescale/fec_uio.c ++++ b/drivers/net/ethernet/freescale/fec_uio.c +@@ -1188,8 +1188,8 @@ static int fec_enet_uio_init(struct net_device *ndev) + return ret; + } + +- tx_ring_size = RING_SIZE_TX; +- rx_ring_size = RING_SIZE_RX; ++ tx_ring_size = FEC_TX_RING_SIZE; ++ rx_ring_size = FEC_RX_RING_SIZE; + + for (i = 0; i < FEC_MAX_Q; i++) { + total_tx_ring_size += tx_ring_size; +diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c +index b2b0d3c26fcc..370fe6e965b7 100644 +--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c ++++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c +@@ -11,6 +11,7 @@ + * Modifier: Sandeep Gopalpet + * + * Copyright 2003-2006, 2008-2009, 2011 Freescale Semiconductor, Inc. ++ * Copyright 2017-2023 NXP + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -166,6 +167,32 @@ static void gfar_gdrvinfo(struct net_device *dev, + strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); + } + ++static int gfar_get_eee(struct net_device *dev, struct ethtool_eee *et_eee) ++{ ++ struct phy_device *phydev = dev->phydev; ++ ++ if (!phydev) ++ return -ENODEV; ++ ++ return phy_ethtool_get_eee(phydev, et_eee); ++} ++ ++static int gfar_set_eee(struct net_device *dev, struct ethtool_eee *et_eee) ++{ ++ struct phy_device *phydev = dev->phydev; ++ ++ if (!phydev) ++ return -ENODEV; ++ ++ if (et_eee->eee_enabled || ++ et_eee->tx_lpi_enabled || ++ et_eee->tx_lpi_timer) { ++ return -EOPNOTSUPP; ++ } ++ ++ return phy_ethtool_set_eee(phydev, et_eee); ++} ++ + /* Return the length of the register structure */ + static int gfar_reglen(struct net_device *dev) + { +@@ -1489,6 +1516,8 @@ static int gfar_get_ts_info(struct net_device *dev, + const struct ethtool_ops gfar_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, ++ .get_eee = gfar_get_eee, ++ .set_eee = gfar_set_eee, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig +index bb6693e2d702..9e219bbfd978 100644 +--- a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig +@@ -84,7 +84,7 @@ config FSL_DPAA_ETH_JUMBO_FRAME + config FSL_DPAA_TS + bool "Linux compliant timestamping" + depends on FSL_SDK_DPAA_ETH +- default n ++ default y + help + Enable Linux API compliant timestamping support. + +@@ -96,6 +96,15 @@ config FSL_DPAA_1588 + help + Enable IEEE1588 support code. + ++config FSL_DPAA_ETHERCAT ++ bool "Enable DPAA Ethercat support" ++ depends on FSL_SDK_DPAA_ETH ++ default n ++ help ++ Enable DPAA Ethercat support code, if enabling this feature, will create a new ++ QMan Portal for Ethercat port, and isolate the last cpu core for Ethercat traffic. ++ Regular ethernet traffic will NOT be in the isolated core. ++ + config FSL_DPAA_ETH_MAX_BUF_COUNT + int "Maximum number of buffers in the private bpool" + depends on FSL_SDK_DPAA_ETH +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile +index a0623b24fa1c..9f9980099aad 100644 +--- a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile +@@ -11,6 +11,9 @@ ccflags-y += -I$(NET_DPA) + obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_mac.o fsl_dpa.o + + fsl_dpa-objs += dpaa_ethtool.o dpaa_eth_sysfs.o dpaa_eth.o dpaa_eth_sg.o dpaa_eth_common.o ++ifeq ($(CONFIG_FSL_DPAA_ETHERCAT),y) ++fsl_dpa-objs += dpaa_ethercat.o ++endif + ifeq ($(CONFIG_FSL_DPAA_DBG_LOOP),y) + fsl_dpa-objs += dpaa_debugfs.o + endif +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h +index f8ab524b368c..1ccf55e475e7 100644 +--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h +@@ -1,5 +1,5 @@ + /* Copyright 2008-2012 Freescale Semiconductor Inc. +- * Copyright 2019 NXP ++ * Copyright 2019-2023 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -415,6 +415,12 @@ struct dpa_priv_s { + #ifdef CONFIG_FSL_DPAA_CEETM + bool ceetm_en; /* CEETM QoS enabled */ + #endif ++ ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++ uint16_t ethercat_channel; /* "fsl,qman-channel-id" */ ++ struct qman_portal *p; ++ void *ecdev; ++#endif + }; + + struct fm_port_fqs { +@@ -461,6 +467,11 @@ int __hot skb_to_sg_fd(struct dpa_priv_s *priv, + int __cold __attribute__((nonnull)) + _dpa_fq_free(struct device *dev, struct qman_fq *fq); + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++int dpa_unregister_ethercat(struct net_device *net_dev); ++int ec_dpaa_receive_data(void *pecdev, const void *data, size_t size); ++#endif ++ + /* Turn on HW checksum computation for this outgoing frame. + * If the current protocol is not something we support in this regard + * (or if the stack has already computed the SW checksum), we do nothing. +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c +index 8853c602d6af..641a7c0c0917 100644 +--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c +@@ -1,4 +1,5 @@ + /* Copyright 2008-2013 Freescale Semiconductor, Inc. ++ * Copyright 2019-2023 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -478,7 +479,15 @@ int __cold dpa_remove(struct platform_device *of_dev) + dpaa_eth_sysfs_remove(dev); + + dev_set_drvdata(dev, NULL); ++ ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++ if (priv->ecdev) ++ dpa_unregister_ethercat(net_dev); ++ else ++ unregister_netdev(net_dev); ++#else + unregister_netdev(net_dev); ++#endif + + err = dpa_fq_free(dev, &priv->dpa_fq_list); + +@@ -992,6 +1001,49 @@ void dpa_release_channel(void) + } + EXPORT_SYMBOL(dpa_release_channel); + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++static int ec_cpu_isolated[NR_CPUS]; ++static int __init ethercat_cpus_setup(char *str) ++{ ++ int last_idx = -1; ++ int dash_flag = 0; ++ int idx = 0; ++ int i = 0; ++ int j = 0; ++ ++ if (!str) ++ return 0; ++ ++ for (i = 0; i < strlen(str); i++) { ++ if (str[i] == ',') { ++ last_idx = -1; ++ dash_flag = 0; ++ continue; ++ } else if ((str[i] == '-') && (last_idx >= 0)) { ++ dash_flag = 1; ++ continue; ++ } ++ ++ if ((str[i] >= '0') && (str[i] <= '9')) { ++ idx = str[i] - '0'; ++ ec_cpu_isolated[idx] = 1; ++ ++ if (dash_flag) { ++ for (j = last_idx; j < idx; j++) ++ ec_cpu_isolated[j] = 1; ++ last_idx = -1; ++ dash_flag = 0; ++ } else { ++ last_idx = idx; ++ } ++ } ++ } ++ ++ return 1; ++} ++__setup("ethercat_cpus=", ethercat_cpus_setup); ++#endif ++ + void dpaa_eth_add_channel(u16 channel) + { + const cpumask_t *cpus = qman_affine_cpus(); +@@ -1000,6 +1052,10 @@ void dpaa_eth_add_channel(u16 channel) + struct qman_portal *portal; + + for_each_cpu(cpu, cpus) { ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++ if (ec_cpu_isolated[cpu]) ++ continue; ++#endif + portal = (struct qman_portal *)qman_get_affine_portal(cpu); + qman_p_static_dequeue_add(portal, pool); + } +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c +index 24704236b500..30c66abf6a8d 100644 +--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c +@@ -1,5 +1,5 @@ + /* Copyright 2012 Freescale Semiconductor Inc. +- * Copyright 2019 NXP ++ * Copyright 2019-2023 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -608,10 +608,31 @@ void __hot _dpa_rx(struct net_device *net_dev, + * which case we were in) having been removed from the pool. + */ + (*count_ptr)--; ++#ifndef CONFIG_FSL_DPAA_ETHERCAT + skb->protocol = eth_type_trans(skb, net_dev); +- ++#endif + skb_len = skb->len; + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++ if (priv->ecdev) { ++ u16 rawcpuid = 0; ++ u16 prot = 0; ++ ++ rawcpuid = (u16)raw_smp_processor_id(); ++ skb_record_rx_queue(skb, rawcpuid); ++ ++ prot = ntohs(*(u16 *)(skb->data + 12)); ++ if (prot == ETH_P_ETHERCAT) ++ ec_dpaa_receive_data(priv->ecdev, skb->data, skb->len); ++ else ++ pr_warn("invalid ethercat protocol 0x%x\n", prot); ++ ++ dev_kfree_skb(skb); ++ goto ethercat_tag; ++ } ++ skb->protocol = eth_type_trans(skb, net_dev); ++#endif ++ + #ifdef CONFIG_FSL_DPAA_DBG_LOOP + if (dpa_skb_loop(priv, skb)) { + percpu_stats->rx_packets++; +@@ -635,6 +656,9 @@ void __hot _dpa_rx(struct net_device *net_dev, + } else if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) + return; + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++ethercat_tag: ++#endif + percpu_stats->rx_packets++; + percpu_stats->rx_bytes += skb_len; + +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c +new file mode 100644 +index 000000000000..67fa72257a6f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c +@@ -0,0 +1,1217 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright 2021-2023 NXP ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* arp_hdr_len() */ ++#include /* VLAN_HLEN */ ++#include /* struct icmphdr */ ++#include /* struct iphdr */ ++#include /* struct ipv6hdr */ ++#include /* struct udphdr */ ++#include /* struct tcphdr */ ++#include /* net_ratelimit() */ ++#include /* ETH_P_IP and ETH_P_IPV6 */ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_SOC_BUS ++#include /* soc_device_match */ ++#endif ++ ++#include "fsl_fman.h" ++#include "fm_ext.h" ++#include "fm_port_ext.h" ++ ++#include "mac.h" ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++#include "dpaa_debugfs.h" ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++#define DPA_NAPI_WEIGHT 64 ++ ++/* Valid checksum indication */ ++#define DPA_CSUM_VALID 0xFFFF ++ ++#define DPA_DESCRIPTION "FSL/NXP DPAA Ethercat driver" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++MODULE_DESCRIPTION(DPA_DESCRIPTION); ++ ++static u8 debug = -1; ++ ++/* This has to work in tandem with the DPA_CS_THRESHOLD_xxx values. */ ++static u16 tx_timeout = 1000; ++ ++static const char rtx[][3] = { ++ [RX] = "RX", ++ [TX] = "TX" ++}; ++ ++/* BM */ ++ ++#define DPAA_ETH_MAX_PAD (L1_CACHE_BYTES * 8) ++ ++static u32 dpa_priv_bpid; ++static u32 dpa_priv_cpuid; ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++struct net_device *dpa_loop_netdevs[20]; ++#endif ++ ++#ifdef CONFIG_PM ++ ++static int dpaa_suspend(struct device *dev) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ int err = 0; ++ ++ net_dev = dev_get_drvdata(dev); ++ ++ if (net_dev->flags & IFF_UP) { ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ if (priv->wol & DPAA_WOL_MAGIC) { ++ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX], ++ priv->mac_dev->get_mac_handle(mac_dev), true); ++ if (err) { ++ netdev_err(net_dev, "set_wol() = %d\n", err); ++ goto set_wol_failed; ++ } ++ } ++ ++ err = fm_port_suspend(mac_dev->port_dev[RX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_suspend(RX) = %d\n", err); ++ goto rx_port_suspend_failed; ++ } ++ ++ err = fm_port_suspend(mac_dev->port_dev[TX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_suspend(TX) = %d\n", err); ++ goto tx_port_suspend_failed; ++ } ++ } ++ ++ return 0; ++ ++tx_port_suspend_failed: ++ fm_port_resume(mac_dev->port_dev[RX]); ++rx_port_suspend_failed: ++ if (priv->wol & DPAA_WOL_MAGIC) { ++ priv->mac_dev->set_wol(mac_dev->port_dev[RX], ++ priv->mac_dev->get_mac_handle(mac_dev), false); ++ } ++set_wol_failed: ++ return err; ++} ++ ++static int dpaa_resume(struct device *dev) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ int err = 0; ++ ++ net_dev = dev_get_drvdata(dev); ++ ++ if (net_dev->flags & IFF_UP) { ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ err = fm_mac_resume(mac_dev->get_mac_handle(mac_dev)); ++ if (err) { ++ netdev_err(net_dev, "fm_mac_resume = %d\n", err); ++ goto resume_failed; ++ } ++ ++ err = fm_port_resume(mac_dev->port_dev[TX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_resume(TX) = %d\n", err); ++ goto resume_failed; ++ } ++ ++ err = fm_port_resume(mac_dev->port_dev[RX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_resume(RX) = %d\n", err); ++ goto resume_failed; ++ } ++ ++ if (priv->wol & DPAA_WOL_MAGIC) { ++ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX], ++ priv->mac_dev->get_mac_handle(mac_dev), false); ++ if (err) { ++ netdev_err(net_dev, "set_wol() = %d\n", err); ++ goto resume_failed; ++ } ++ } ++ } ++ ++ return 0; ++ ++resume_failed: ++ return err; ++} ++ ++static const struct dev_pm_ops dpaa_pm_ops = { ++ .suspend = dpaa_suspend, ++ .resume = dpaa_resume, ++}; ++ ++#define DPAA_PM_OPS (&dpaa_pm_ops) ++ ++#else /* CONFIG_PM */ ++ ++#define DPAA_PM_OPS NULL ++ ++#endif /* CONFIG_PM */ ++ ++/* Checks whether the checksum field in Parse Results array is valid ++ * (equals 0xFFFF) and increments the .cse counter otherwise ++ */ ++static inline void ++dpa_csum_validation(const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd) ++{ ++ dma_addr_t addr = qm_fd_addr(fd); ++ struct dpa_bp *dpa_bp = priv->dpa_bp; ++ void *frm = phys_to_virt(addr); ++ fm_prs_result_t *parse_result; ++ ++ if (unlikely(!frm)) ++ return; ++ ++ dma_sync_single_for_cpu(dpa_bp->dev, addr, DPA_RX_PRIV_DATA_SIZE + ++ DPA_PARSE_RESULTS_SIZE, DMA_BIDIRECTIONAL); ++ ++ parse_result = (fm_prs_result_t *)(frm + DPA_RX_PRIV_DATA_SIZE); ++ ++ if (parse_result->cksum != DPA_CSUM_VALID) ++ percpu_priv->rx_errors.cse++; ++} ++ ++static void _dpa_rx_error(struct net_device *net_dev, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ /* limit common, possibly innocuous Rx FIFO Overflow errors' ++ * interference with zero-loss convergence benchmark results. ++ */ ++ if (likely(fd->status & FM_FD_STAT_ERR_PHYSICAL)) ++ pr_warn_once("fsl-dpa: non-zero error counters in fman statistics (sysfs)\n"); ++ else ++ if (netif_msg_hw(priv) && net_ratelimit()) ++ netdev_dbg(net_dev, "Err FD status = 0x%08x\n", ++ fd->status & FM_FD_STAT_RX_ERRORS); ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ if (dpaa_eth_hooks.rx_error && ++ dpaa_eth_hooks.rx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN) ++ /* it's up to the hook to perform resource cleanup */ ++ return; ++#endif ++ percpu_priv->stats.rx_errors++; ++ ++ if (fd->status & FM_PORT_FRM_ERR_DMA) ++ percpu_priv->rx_errors.dme++; ++ if (fd->status & FM_PORT_FRM_ERR_PHYSICAL) ++ percpu_priv->rx_errors.fpe++; ++ if (fd->status & FM_PORT_FRM_ERR_SIZE) ++ percpu_priv->rx_errors.fse++; ++ if (fd->status & FM_PORT_FRM_ERR_PRS_HDR_ERR) ++ percpu_priv->rx_errors.phe++; ++ if (fd->status & FM_FD_STAT_L4CV) ++ dpa_csum_validation(priv, percpu_priv, fd); ++ ++ dpa_fd_release(net_dev, fd); ++} ++ ++static void _dpa_tx_error(struct net_device *net_dev, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ struct sk_buff *skb; ++ ++ if (netif_msg_hw(priv) && net_ratelimit()) ++ netdev_warn(net_dev, "FD status = 0x%08x\n", ++ fd->status & FM_FD_STAT_TX_ERRORS); ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ if (dpaa_eth_hooks.tx_error && ++ dpaa_eth_hooks.tx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN) ++ /* now the hook must ensure proper cleanup */ ++ return; ++#endif ++ percpu_priv->stats.tx_errors++; ++ ++ /* If we intended the buffers from this frame to go into the bpools ++ * when the FMan transmit was done, we need to put it in manually. ++ */ ++ if (fd->bpid != 0xff) { ++ dpa_fd_release(net_dev, fd); ++ return; ++ } ++ ++ skb = _dpa_cleanup_tx_fd(priv, fd); ++ if (!priv->ecdev) ++ dev_kfree_skb(skb); ++} ++ ++static void __hot _dpa_tx_conf(struct net_device *net_dev, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ struct sk_buff *skb; ++ ++ /* do we need the timestamp for the error frames? */ ++ ++ if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) { ++ if (netif_msg_hw(priv) && net_ratelimit()) ++ netdev_warn(net_dev, "FD status = 0x%08x\n", ++ fd->status & FM_FD_STAT_TX_ERRORS); ++ ++ percpu_priv->stats.tx_errors++; ++ } ++ ++ /* hopefully we need not get the timestamp before the hook */ ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ if (dpaa_eth_hooks.tx_confirm && ++ dpaa_eth_hooks.tx_confirm(net_dev, fd, fqid) == DPAA_ETH_STOLEN) ++ /* it's the hook that must now perform cleanup */ ++ return; ++#endif ++ /* This might not perfectly reflect the reality, if the core dequeuing ++ * the Tx confirmation is different from the one that did the enqueue, ++ * but at least it'll show up in the total count. ++ */ ++ percpu_priv->tx_confirm++; ++ ++ skb = _dpa_cleanup_tx_fd(priv, fd); ++ if (!priv->ecdev) ++ dev_kfree_skb(skb); ++} ++ ++static enum qman_cb_dqrr_result ++priv_rx_error_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ int *count_ptr; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ count_ptr = raw_cpu_ptr(priv->percpu_count); ++ ++ if (unlikely(dpaa_eth_refill_bpools(priv->dpa_bp, count_ptr))) ++ /* Unable to refill the buffer pool due to insufficient ++ * system memory. Just release the frame back into the pool, ++ * otherwise we'll soon end up with an empty buffer pool. ++ */ ++ dpa_fd_release(net_dev, &dq->fd); ++ else ++ _dpa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++static enum qman_cb_dqrr_result __hot ++priv_rx_default_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ int *count_ptr; ++ struct dpa_bp *dpa_bp; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ dpa_bp = priv->dpa_bp; ++ ++ /* IRQ handler, non-migratable; safe to use raw_cpu_ptr here */ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ count_ptr = raw_cpu_ptr(priv->percpu_count); ++ ++ /* Vale of plenty: make sure we didn't run out of buffers */ ++ ++ if (unlikely(dpaa_eth_refill_bpools(dpa_bp, count_ptr))) ++ /* Unable to refill the buffer pool due to insufficient ++ * system memory. Just release the frame back into the pool, ++ * otherwise we'll soon end up with an empty buffer pool. ++ */ ++ dpa_fd_release(net_dev, &dq->fd); ++ else ++ _dpa_rx(net_dev, portal, priv, percpu_priv, &dq->fd, fq->fqid, ++ count_ptr); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++static enum qman_cb_dqrr_result ++priv_tx_conf_error_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ ++ _dpa_tx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++static enum qman_cb_dqrr_result __hot ++priv_tx_conf_default_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ ++ /* Non-migratable context, safe to use raw_cpu_ptr */ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ ++ _dpa_tx_conf(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++static void priv_ern(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ struct net_device *net_dev; ++ const struct dpa_priv_s *priv; ++ struct sk_buff *skb; ++ struct dpa_percpu_priv_s *percpu_priv; ++ struct qm_fd fd = msg->ern.fd; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ /* Non-migratable context, safe to use raw_cpu_ptr */ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ ++ percpu_priv->stats.tx_dropped++; ++ percpu_priv->stats.tx_fifo_errors++; ++ count_ern(percpu_priv, msg); ++ ++ /* If we intended this buffer to go into the pool ++ * when the FM was done, we need to put it in ++ * manually. ++ */ ++ if (msg->ern.fd.bpid != 0xff) { ++ dpa_fd_release(net_dev, &fd); ++ return; ++ } ++ ++ skb = _dpa_cleanup_tx_fd(priv, &fd); ++ dev_kfree_skb_any(skb); ++} ++ ++static const struct dpa_fq_cbs_t private_fq_cbs = { ++ .rx_defq = { .cb = { .dqrr = priv_rx_default_dqrr } }, ++ .tx_defq = { .cb = { .dqrr = priv_tx_conf_default_dqrr } }, ++ .rx_errq = { .cb = { .dqrr = priv_rx_error_dqrr } }, ++ .tx_errq = { .cb = { .dqrr = priv_tx_conf_error_dqrr } }, ++ .egress_ern = { .cb = { .ern = priv_ern } } ++}; ++ ++static int __cold dpa_eth_priv_start(struct net_device *net_dev) ++{ ++ int err; ++ struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ ++ err = dpa_start(net_dev); ++ ++ return err; ++} ++ ++static int __cold dpa_eth_priv_stop(struct net_device *net_dev) ++{ ++ int _errno; ++ struct dpa_priv_s *priv; ++ ++ _errno = dpa_stop(net_dev); ++ /* Allow NAPI to consume any frame still in the Rx/TxConfirm ++ * ingress queues. This is to avoid a race between the current ++ * context and ksoftirqd which could leave NAPI disabled while ++ * in fact there's still Rx traffic to be processed. ++ */ ++ usleep_range(5000, 10000); ++ ++ priv = netdev_priv(net_dev); ++ ++ return _errno; ++} ++ ++static const struct net_device_ops dpa_private_ops = { ++ .ndo_open = dpa_eth_priv_start, ++ .ndo_start_xmit = dpa_tx, ++ .ndo_stop = dpa_eth_priv_stop, ++ .ndo_tx_timeout = dpa_timeout, ++ .ndo_get_stats64 = dpa_get_stats64, ++ .ndo_set_mac_address = dpa_set_mac_address, ++ .ndo_validate_addr = eth_validate_addr, ++#ifdef CONFIG_FMAN_PFC ++ .ndo_select_queue = dpa_select_queue, ++#endif ++ .ndo_set_rx_mode = dpa_set_rx_mode, ++ .ndo_init = dpa_ndo_init, ++ .ndo_set_features = dpa_set_features, ++ .ndo_fix_features = dpa_fix_features, ++ .ndo_do_ioctl = dpa_ioctl, ++}; ++ ++typedef int (*ec_dpaa_receive_cb)(void *pecdev, const void *data, size_t size); ++typedef int (*ec_dpaa_link_cb)(void *pecdev, uint8_t link); ++typedef int (*ec_dpaa_close_cb)(void *pecdev); ++ ++static ec_dpaa_receive_cb ec_dpaa_recv_func; ++static ec_dpaa_close_cb ec_dpaa_close_func; ++static ec_dpaa_link_cb ec_dpaa_link_func; ++ ++int ec_dpaa_receive_data(void *pecdev, const void *data, size_t size) ++{ ++ int ret = 0; ++ ++ if (ec_dpaa_recv_func) ++ ret = ec_dpaa_recv_func(pecdev, data, size); ++ ++ return ret; ++} ++ ++int ec_dpaa_set_func_cb(ec_dpaa_receive_cb recv, ec_dpaa_link_cb link, ec_dpaa_close_cb close) ++{ ++ ec_dpaa_recv_func = recv; ++ ec_dpaa_link_func = link; ++ ec_dpaa_close_func = close; ++ ++ return 0; ++} ++EXPORT_SYMBOL(ec_dpaa_set_func_cb); ++ ++struct module *ec_dpaa_get_module(void) ++{ ++ struct module *m = THIS_MODULE; ++ return m; ++} ++EXPORT_SYMBOL(ec_dpaa_get_module); ++ ++#define MAX_EC_DPAA_NETDEV_CNT (16) ++static int ec_dpaa_netdev_cnt; ++static struct net_device *ec_dpaa_netdev[MAX_EC_DPAA_NETDEV_CNT]; ++ ++struct net_device *ec_dpaa_get_netdev(int idx) ++{ ++ if (idx >= MAX_EC_DPAA_NETDEV_CNT) ++ return NULL; ++ ++ if (idx >= ec_dpaa_netdev_cnt) ++ return NULL; ++ ++ return ec_dpaa_netdev[idx]; ++} ++EXPORT_SYMBOL(ec_dpaa_get_netdev); ++ ++int ec_dpaa_set_ecdev(int idx, void *ecdev) ++{ ++ struct net_device *net_dev = NULL; ++ struct dpa_priv_s *priv = NULL; ++ ++ net_dev = ec_dpaa_get_netdev(idx); ++ if (net_dev) { ++ priv = netdev_priv(net_dev); ++ priv->ecdev = ecdev; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(ec_dpaa_set_ecdev); ++ ++void *ec_dpaa_get_ecdev(int idx) ++{ ++ struct net_device *net_dev = NULL; ++ struct dpa_priv_s *priv = NULL; ++ void *ecdev = NULL; ++ ++ net_dev = ec_dpaa_get_netdev(idx); ++ if (net_dev) { ++ priv = netdev_priv(net_dev); ++ ecdev = priv->ecdev; ++ } ++ ++ return ecdev; ++} ++EXPORT_SYMBOL(ec_dpaa_get_ecdev); ++ ++void ec_dpaa_poll(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ u8 link = net_dev->phydev->state; ++ ++ qman_p_poll_dqrr(priv->p, DPA_NAPI_WEIGHT); ++ ++ if (ec_dpaa_link_func) ++ ec_dpaa_link_func(priv->ecdev, link); ++} ++EXPORT_SYMBOL(ec_dpaa_poll); ++ ++int dpa_unregister_ethercat(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ ++ if (priv->ecdev) { ++ if (ec_dpaa_close_func) ++ ec_dpaa_close_func(priv->ecdev); ++ return 0; ++ } ++ ++ return -1; ++} ++EXPORT_SYMBOL(dpa_unregister_ethercat); ++ ++static int dpa_ethercat_netdev_init(struct net_device *net_dev, ++ const u8 *mac_addr, ++ uint16_t tx_timeout) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ ++ net_dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; ++ ++ net_dev->features |= net_dev->hw_features; ++ net_dev->vlan_features = net_dev->features; ++ ++ memcpy(net_dev->perm_addr, mac_addr, net_dev->addr_len); ++ memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len); ++ ++ net_dev->ethtool_ops = &dpa_ethtool_ops; ++ ++ net_dev->needed_headroom = priv->tx_headroom; ++ net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout); ++ ++ if (ec_dpaa_netdev_cnt < MAX_EC_DPAA_NETDEV_CNT) ++ ec_dpaa_netdev[ec_dpaa_netdev_cnt++] = net_dev; ++ ++ return 0; ++} ++ ++static int dpa_private_netdev_init(struct net_device *net_dev) ++{ ++ int i; ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct dpa_percpu_priv_s *percpu_priv; ++ const u8 *mac_addr; ++ ++ /* Although we access another CPU's private data here ++ * we do it at initialization so it is safe ++ */ ++ for_each_possible_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ percpu_priv->net_dev = net_dev; ++ } ++ ++ net_dev->netdev_ops = &dpa_private_ops; ++ mac_addr = priv->mac_dev->addr; ++ ++ net_dev->mem_start = priv->mac_dev->res->start; ++ net_dev->mem_end = priv->mac_dev->res->end; ++ ++ /* Configure the maximum MTU according to the FMan's MAXFRM */ ++ net_dev->min_mtu = ETH_MIN_MTU; ++ net_dev->max_mtu = dpa_get_max_mtu(); ++ ++ net_dev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | ++ NETIF_F_LLTX); ++ ++ /* Advertise S/G and HIGHDMA support for private interfaces */ ++ net_dev->hw_features |= NETIF_F_SG | NETIF_F_HIGHDMA; ++ /* Recent kernels enable GSO automatically, if ++ * we declare NETIF_F_SG. For conformity, we'll ++ * still declare GSO explicitly. ++ */ ++ net_dev->features |= NETIF_F_GSO; ++ ++ /* Advertise GRO support */ ++ net_dev->features |= NETIF_F_GRO; ++ ++ return dpa_ethercat_netdev_init(net_dev, mac_addr, tx_timeout); ++} ++ ++static struct dpa_bp * __cold ++dpa_priv_bp_probe(struct device *dev) ++{ ++ struct dpa_bp *dpa_bp; ++ ++ dpa_bp = devm_kzalloc(dev, sizeof(*dpa_bp), GFP_KERNEL); ++ if (unlikely(!dpa_bp)) { ++ dev_err(dev, "devm_kzalloc() failed\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dpa_bp->target_count = CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT; ++ ++ dpa_bp->free_buf_cb = _dpa_bp_free_pf; ++ ++ return dpa_bp; ++} ++ ++/* Place all ingress FQs (Rx Default, Rx Error, PCD FQs) in a dedicated CGR. ++ * We won't be sending congestion notifications to FMan; for now, we just use ++ * this CGR to generate enqueue rejections to FMan in order to drop the frames ++ * before they reach our ingress queues and eat up memory. ++ */ ++static int dpaa_eth_priv_ingress_cgr_init(struct dpa_priv_s *priv) ++{ ++ struct qm_mcc_initcgr initcgr; ++ u32 cs_th; ++ int err; ++ ++ err = qman_alloc_cgrid(&priv->ingress_cgr.cgrid); ++ if (err < 0) { ++ pr_err("Error %d allocating CGR ID\n", err); ++ goto out_error; ++ } ++ ++ /* Enable CS TD, but disable Congestion State Change Notifications. */ ++ memset(&initcgr, 0, sizeof(initcgr)); ++ initcgr.we_mask = QM_CGR_WE_CS_THRES; ++ initcgr.cgr.cscn_en = QM_CGR_EN; ++ cs_th = CONFIG_FSL_DPAA_INGRESS_CS_THRESHOLD; ++ qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1); ++ ++ initcgr.we_mask |= QM_CGR_WE_CSTD_EN; ++ initcgr.cgr.cstd_en = QM_CGR_EN; ++ ++ /* This is actually a hack, because this CGR will be associated with ++ * our affine SWP. However, we'll place our ingress FQs in it. ++ */ ++ err = qman_create_cgr(&priv->ingress_cgr, QMAN_CGR_FLAG_USE_INIT, ++ &initcgr); ++ if (err < 0) { ++ pr_err("Error %d creating ingress CGR with ID %d\n", err, ++ priv->ingress_cgr.cgrid); ++ qman_release_cgrid(priv->ingress_cgr.cgrid); ++ goto out_error; ++ } ++ pr_debug("Created ingress CGR %d for netdev with hwaddr %pM\n", ++ priv->ingress_cgr.cgrid, priv->mac_dev->addr); ++ ++ /* struct qman_cgr allows special cgrid values (i.e. outside the 0..255 ++ * range), but we have no common initialization path between the ++ * different variants of the DPAA Eth driver, so we do it here rather ++ * than modifying every other variant than "private Eth". ++ */ ++ priv->use_ingress_cgr = true; ++ ++out_error: ++ return err; ++} ++ ++static void dpa_priv_bp_seed(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct dpa_bp *dpa_bp = priv->dpa_bp; ++ int i; ++ ++ /* Give each CPU an allotment of buffers */ ++ for_each_possible_cpu(i) { ++ /* Although we access another CPU's counters here ++ * we do it at boot time so it is safe ++ */ ++ int *count_ptr = per_cpu_ptr(priv->percpu_count, i); ++ ++ dpaa_eth_refill_bpools(dpa_bp, count_ptr); ++ } ++} ++ ++static const struct of_device_id dpa_match[]; ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++static int dpa_new_loop_id(void) ++{ ++ static int if_id; ++ ++ return if_id++; ++} ++#endif ++ ++extern int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp, ++ size_t count); ++ ++static inline void dpa_setup_ingress(const struct dpa_priv_s *priv, ++ struct dpa_fq *fq, ++ const struct qman_fq *template) ++{ ++ fq->fq_base = *template; ++ fq->net_dev = priv->net_dev; ++ ++ fq->flags = QMAN_FQ_FLAG_NO_ENQUEUE; ++ fq->channel = priv->channel; ++} ++ ++static inline void dpa_setup_egress(const struct dpa_priv_s *priv, ++ struct dpa_fq *fq, ++ struct fm_port *port, ++ const struct qman_fq *template) ++{ ++ fq->fq_base = *template; ++ fq->net_dev = priv->net_dev; ++ ++ if (port) { ++ fq->flags = QMAN_FQ_FLAG_TO_DCPORTAL; ++ fq->channel = (u16)fm_get_tx_port_channel(port); ++ } else { ++ fq->flags = QMAN_FQ_FLAG_NO_MODIFY; ++ } ++} ++ ++static void dpa_fq_setup_ethercat(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs, ++ struct fm_port *tx_port) ++{ ++ struct dpa_fq *fq; ++ u16 portals[NR_CPUS]; ++ int cpu, portal_cnt = 0, num_portals = 0; ++ u32 pcd_fqid, pcd_fqid_hi_prio; ++ const cpumask_t *affine_cpus = qman_affine_cpus(); ++ int egress_cnt = 0, conf_cnt = 0; ++ ++ /* Prepare for PCD FQs init */ ++ for_each_cpu(cpu, affine_cpus) ++ portals[num_portals++] = priv->ethercat_channel; ++ ++ if (num_portals == 0) ++ dev_err(priv->net_dev->dev.parent, ++ "No Qman software (affine) channels found"); ++ ++ pcd_fqid = (priv->mac_dev) ? ++ DPAA_ETH_PCD_FQ_BASE(priv->mac_dev->res->start) : 0; ++ pcd_fqid_hi_prio = (priv->mac_dev) ? ++ DPAA_ETH_PCD_FQ_HI_PRIO_BASE(priv->mac_dev->res->start) : 0; ++ ++ /* Initialize each FQ in the list */ ++ list_for_each_entry(fq, &priv->dpa_fq_list, list) { ++ switch (fq->fq_type) { ++ case FQ_TYPE_RX_DEFAULT: ++ WARN_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq); ++ break; ++ case FQ_TYPE_RX_ERROR: ++ WARN_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_errq); ++ break; ++ case FQ_TYPE_RX_PCD: ++ /* For MACless we can't have dynamic Rx queues */ ++ WARN_ON(!priv->mac_dev && !fq->fqid); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq); ++ if (!fq->fqid) ++ fq->fqid = pcd_fqid++; ++ fq->channel = portals[portal_cnt]; ++ portal_cnt = (portal_cnt + 1) % num_portals; ++ break; ++ case FQ_TYPE_RX_PCD_HI_PRIO: ++ /* For MACless we can't have dynamic Hi Pri Rx queues */ ++ WARN_ON(!priv->mac_dev && !fq->fqid); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq); ++ if (!fq->fqid) ++ fq->fqid = pcd_fqid_hi_prio++; ++ fq->channel = portals[portal_cnt]; ++ portal_cnt = (portal_cnt + 1) % num_portals; ++ break; ++ case FQ_TYPE_TX: ++ dpa_setup_egress(priv, fq, tx_port, ++ &fq_cbs->egress_ern); ++ /* If we have more Tx queues than the number of cores, ++ * just ignore the extra ones. ++ */ ++ if (egress_cnt < DPAA_ETH_TX_QUEUES) ++ priv->egress_fqs[egress_cnt++] = &fq->fq_base; ++ break; ++ case FQ_TYPE_TX_CONFIRM: ++ WARN_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq); ++ break; ++ case FQ_TYPE_TX_CONF_MQ: ++ WARN_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq); ++ priv->conf_fqs[conf_cnt++] = &fq->fq_base; ++ break; ++ case FQ_TYPE_TX_ERROR: ++ WARN_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->tx_errq); ++ break; ++ default: ++ dev_warn(priv->net_dev->dev.parent, ++ "Unknown FQ type detected!\n"); ++ break; ++ } ++ } ++ ++ /* The number of Tx queues may be smaller than the number of cores, if ++ * the Tx queue range is specified in the device tree instead of being ++ * dynamically allocated. ++ * Make sure all CPUs receive a corresponding Tx queue. ++ */ ++ while (egress_cnt < DPAA_ETH_TX_QUEUES) { ++ list_for_each_entry(fq, &priv->dpa_fq_list, list) { ++ if (fq->fq_type != FQ_TYPE_TX) ++ continue; ++ priv->egress_fqs[egress_cnt++] = &fq->fq_base; ++ if (egress_cnt == DPAA_ETH_TX_QUEUES) ++ break; ++ } ++ } ++} ++ ++static int dpaa_ethercat_probe(struct platform_device *_of_dev) ++{ ++ int err = 0, i; ++ struct device *dev; ++ struct device_node *dpa_node; ++ struct dpa_bp *dpa_bp; ++ size_t count = 1; ++ struct net_device *net_dev = NULL; ++ struct dpa_priv_s *priv = NULL; ++ struct dpa_percpu_priv_s *percpu_priv; ++ struct fm_port_fqs port_fqs; ++ struct dpa_buffer_layout_s *buf_layout = NULL; ++ struct mac_device *mac_dev; ++ u32 last_cpu = 0; ++ ++ dev = &_of_dev->dev; ++ ++ dpa_node = dev->of_node; ++ ++ if (!of_device_is_available(dpa_node)) ++ return -ENODEV; ++ ++ /* Get the buffer pools assigned to this interface; ++ * run only once the default pool probing code ++ */ ++ ++ err = of_property_read_u32(dpa_node, "fsl,bpid", &dpa_priv_bpid); ++ if (err) { ++ dev_err(dev, "Cannot find buffer pool ID in the device tree\n"); ++ return -EINVAL; ++ } ++ ++ last_cpu = qman_get_affine_last_cpu(); ++ err = of_property_read_u32(dpa_node, "fsl,cpuid", &dpa_priv_cpuid); ++ if (err) { ++ dev_warn(dev, "Cannot find cpuid in the device tree, using the last core\n"); ++ dpa_priv_cpuid = last_cpu; ++ } else if (dpa_priv_cpuid > last_cpu) { ++ dev_warn(dev, "Invalid cpuid in the device tree, using the last core\n"); ++ dpa_priv_cpuid = last_cpu; ++ } ++ ++ dpa_bp = (dpa_bpid2pool(dpa_priv_bpid)) ? : ++ dpa_priv_bp_probe(dev); ++ if (IS_ERR(dpa_bp)) ++ return PTR_ERR(dpa_bp); ++ if (dpa_bp->bpid == 0) ++ dpa_bp->bpid = dpa_priv_bpid; ++ ++ /* Allocate this early, so we can store relevant information in ++ * the private area (needed by 1588 code in dpa_mac_probe) ++ */ ++ net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA_ETH_TX_QUEUES); ++ if (!net_dev) { ++ dev_err(dev, "alloc_etherdev_mq() failed\n"); ++ goto alloc_etherdev_mq_failed; ++ } ++ ++ /* Do this here, so we can be verbose early */ ++ SET_NETDEV_DEV(net_dev, dev); ++ dev_set_drvdata(dev, net_dev); ++ ++ priv = netdev_priv(net_dev); ++ priv->net_dev = net_dev; ++ strcpy(priv->if_type, "private"); ++ ++ priv->msg_enable = netif_msg_init(debug, -1); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ priv->loop_id = dpa_new_loop_id(); ++ priv->loop_to = -1; /* disabled by default */ ++ dpa_loop_netdevs[priv->loop_id] = net_dev; ++#endif ++ ++ mac_dev = dpa_mac_probe(_of_dev); ++ if (IS_ERR(mac_dev) || !mac_dev) { ++ err = PTR_ERR(mac_dev); ++ goto mac_probe_failed; ++ } ++ ++ /* We have physical ports, so we need to establish ++ * the buffer layout. ++ */ ++ buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout), ++ GFP_KERNEL); ++ if (!buf_layout) { ++ dev_err(dev, "devm_kzalloc() failed\n"); ++ goto alloc_failed; ++ } ++ dpa_set_buffers_layout(mac_dev, buf_layout); ++ ++ /* For private ports, need to compute the size of the default ++ * buffer pool, based on FMan port buffer layout;also update ++ * the maximum buffer size for private ports if necessary ++ */ ++ dpa_bp->size = dpa_bp_size(&buf_layout[RX]); ++ ++#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME ++ /* We only want to use jumbo frame optimization if we actually have ++ * L2 MAX FRM set for jumbo frames as well. ++ */ ++ if (fm_get_max_frm() < 9600) ++ dev_warn(dev, ++ "Invalid configuration: if jumbo frames support is on, FSL_FM_MAX_FRAME_SIZE should be set to 9600\n"); ++#endif ++ ++ INIT_LIST_HEAD(&priv->dpa_fq_list); ++ ++ memset(&port_fqs, 0, sizeof(port_fqs)); ++ ++ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list, &port_fqs, true, RX); ++ if (!err) ++ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list, ++ &port_fqs, true, TX); ++ ++ if (err < 0) ++ goto fq_probe_failed; ++ ++ /* bp init */ ++ ++ err = dpa_bp_create(net_dev, dpa_bp, count); ++ ++ if (err < 0) ++ goto bp_create_failed; ++ ++ priv->mac_dev = mac_dev; ++ priv->ethercat_channel = (u16)qman_affine_channel_ethercat(dpa_priv_cpuid); ++ priv->channel = priv->ethercat_channel; ++ priv->p = qman_get_affine_portal_ethercat(dpa_priv_cpuid); ++ ++ dpa_fq_setup_ethercat(priv, &private_fq_cbs, priv->mac_dev->port_dev[TX]); ++ ++ /* Create a congestion group for this netdev, with ++ * dynamically-allocated CGR ID. ++ * Must be executed after probing the MAC, but before ++ * assigning the egress FQs to the CGRs. ++ */ ++ err = dpaa_eth_cgr_init(priv); ++ if (err < 0) { ++ dev_err(dev, "Error initializing CGR\n"); ++ goto tx_cgr_init_failed; ++ } ++ err = dpaa_eth_priv_ingress_cgr_init(priv); ++ if (err < 0) { ++ dev_err(dev, "Error initializing ingress CGR\n"); ++ goto rx_cgr_init_failed; ++ } ++ ++ /* Add the FQs to the interface, and make them active */ ++ err = dpa_fqs_init(dev, &priv->dpa_fq_list, false); ++ if (err < 0) ++ goto fq_alloc_failed; ++ ++ priv->buf_layout = buf_layout; ++ priv->tx_headroom = dpa_get_headroom(&priv->buf_layout[TX]); ++ priv->rx_headroom = dpa_get_headroom(&priv->buf_layout[RX]); ++ ++ /* All real interfaces need their ports initialized */ ++ dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs, ++ buf_layout, dev); ++ ++#ifdef CONFIG_FMAN_PFC ++ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) { ++ err = fm_port_set_pfc_priorities_mapping_to_qman_wq(mac_dev->port_dev[TX], i, i); ++ if (unlikely(err != 0)) { ++ dev_err(dev, "Error maping PFC %u to WQ %u\n", i, i); ++ goto pfc_mapping_failed; ++ } ++ } ++#endif ++ ++ priv->percpu_priv = devm_alloc_percpu(dev, *priv->percpu_priv); ++ ++ if (!priv->percpu_priv) { ++ dev_err(dev, "devm_alloc_percpu() failed\n"); ++ err = -ENOMEM; ++ goto alloc_percpu_failed; ++ } ++ ++ for_each_possible_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ memset(percpu_priv, 0, sizeof(*percpu_priv)); ++ } ++ ++ priv->percpu_count = devm_alloc_percpu(dev, *priv->percpu_count); ++ if (!priv->percpu_count) { ++ dev_err(dev, "devm_alloc_percpu() failed\n"); ++ err = -ENOMEM; ++ goto alloc_percpu_failed; ++ } ++ ++ for_each_possible_cpu(i) { ++ int *percpu_count = per_cpu_ptr(priv->percpu_count, i); ++ *percpu_count = 0; ++ } ++ ++ err = dpa_private_netdev_init(net_dev); ++ ++ dpa_priv_bp_seed(net_dev); ++ ++ if (err < 0) ++ goto netdev_init_failed; ++ ++ pr_info("Ethercat port:%02hx:%02hx:%02hx:%02hx:%02hx:%02hx bpid:%d cpu:%d\n", ++ mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2], ++ mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5], ++ dpa_priv_bpid, dpa_priv_cpuid); ++ ++#ifdef CONFIG_PM ++ device_set_wakeup_capable(dev, true); ++#endif ++ ++ pr_info("fsl_dpa: Probed interface %s\n", net_dev->name); ++ ++ return 0; ++ ++netdev_init_failed: ++ ++alloc_percpu_failed: ++#ifdef CONFIG_FMAN_PFC ++pfc_mapping_failed: ++#endif ++ dpa_fq_free(dev, &priv->dpa_fq_list); ++fq_alloc_failed: ++ qman_delete_cgr_safe(&priv->ingress_cgr); ++ qman_release_cgrid(priv->ingress_cgr.cgrid); ++rx_cgr_init_failed: ++ qman_delete_cgr_safe(&priv->cgr_data.cgr); ++ qman_release_cgrid(priv->cgr_data.cgr.cgrid); ++tx_cgr_init_failed: ++ ++ dpa_bp_free(priv); ++bp_create_failed: ++fq_probe_failed: ++alloc_failed: ++mac_probe_failed: ++ dev_set_drvdata(dev, NULL); ++ free_netdev(net_dev); ++alloc_etherdev_mq_failed: ++ if (atomic_read(&dpa_bp->refs) == 0) ++ devm_kfree(dev, dpa_bp); ++ ++ return err; ++} ++ ++static const struct of_device_id dpa_match[] = { ++ { ++ .compatible = "fsl,dpa-ethercat" ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, dpa_match); ++ ++static struct platform_driver dpa_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME "-ethercat", ++ .of_match_table = dpa_match, ++ .owner = THIS_MODULE, ++ .pm = DPAA_PM_OPS, ++ }, ++ .probe = dpaa_ethercat_probe, ++ .remove = dpa_remove ++}; ++ ++static int __init __cold dpa_ethercat_load(void) ++{ ++ int _errno; ++ ++ pr_info(DPA_DESCRIPTION "\n"); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ dpa_debugfs_module_init(); ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++ /* initialise dpaa_eth mirror values */ ++ dpa_rx_extra_headroom = fm_get_rx_extra_headroom(); ++ dpa_max_frm = fm_get_max_frm(); ++ dpa_num_cpus = num_possible_cpus(); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ memset(dpa_loop_netdevs, 0, sizeof(dpa_loop_netdevs)); ++#endif ++ ++ _errno = platform_driver_register(&dpa_driver); ++ if (unlikely(_errno < 0)) { ++ pr_err(KBUILD_MODNAME ++ ": %s:%hu:%s(): platform_driver_register() = %d\n", ++ KBUILD_BASENAME ".c", __LINE__, __func__, _errno); ++ } ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME ".c", __func__); ++ ++ return _errno; ++} ++module_init(dpa_ethercat_load); ++ ++static void __exit __cold dpa_ethercat_unload(void) ++{ ++ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", ++ KBUILD_BASENAME ".c", __func__); ++ ++ platform_driver_unregister(&dpa_driver); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ dpa_debugfs_module_exit(); ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++ /* Only one channel is used and needs to be relased after all ++ * interfaces are removed ++ */ ++ dpa_release_channel(); ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME ".c", __func__); ++} ++module_exit(dpa_ethercat_unload); +diff --git a/drivers/net/ethernet/fungible/funeth/funeth_txrx.h b/drivers/net/ethernet/fungible/funeth/funeth_txrx.h +index 671f51135c26..53b7e95213a8 100644 +--- a/drivers/net/ethernet/fungible/funeth/funeth_txrx.h ++++ b/drivers/net/ethernet/fungible/funeth/funeth_txrx.h +@@ -206,9 +206,9 @@ struct funeth_rxq { + + #define FUN_QSTAT_READ(q, seq, stats_copy) \ + do { \ +- seq = u64_stats_fetch_begin_irq(&(q)->syncp); \ ++ seq = u64_stats_fetch_begin(&(q)->syncp); \ + stats_copy = (q)->stats; \ +- } while (u64_stats_fetch_retry_irq(&(q)->syncp, (seq))) ++ } while (u64_stats_fetch_retry(&(q)->syncp, (seq))) + + #define FUN_INT_NAME_LEN (IFNAMSIZ + 16) + +diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c +index 033f17cb96be..0a5953089a24 100644 +--- a/drivers/net/ethernet/google/gve/gve_ethtool.c ++++ b/drivers/net/ethernet/google/gve/gve_ethtool.c +@@ -177,14 +177,14 @@ gve_get_ethtool_stats(struct net_device *netdev, + struct gve_rx_ring *rx = &priv->rx[ring]; + + start = +- u64_stats_fetch_begin_irq(&priv->rx[ring].statss); ++ u64_stats_fetch_begin(&priv->rx[ring].statss); + tmp_rx_pkts = rx->rpackets; + tmp_rx_bytes = rx->rbytes; + tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; + tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; + tmp_rx_desc_err_dropped_pkt = + rx->rx_desc_err_dropped_pkt; +- } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, ++ } while (u64_stats_fetch_retry(&priv->rx[ring].statss, + start)); + rx_pkts += tmp_rx_pkts; + rx_bytes += tmp_rx_bytes; +@@ -198,10 +198,10 @@ gve_get_ethtool_stats(struct net_device *netdev, + if (priv->tx) { + do { + start = +- u64_stats_fetch_begin_irq(&priv->tx[ring].statss); ++ u64_stats_fetch_begin(&priv->tx[ring].statss); + tmp_tx_pkts = priv->tx[ring].pkt_done; + tmp_tx_bytes = priv->tx[ring].bytes_done; +- } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, ++ } while (u64_stats_fetch_retry(&priv->tx[ring].statss, + start)); + tx_pkts += tmp_tx_pkts; + tx_bytes += tmp_tx_bytes; +@@ -259,13 +259,13 @@ gve_get_ethtool_stats(struct net_device *netdev, + data[i++] = rx->fill_cnt - rx->cnt; + do { + start = +- u64_stats_fetch_begin_irq(&priv->rx[ring].statss); ++ u64_stats_fetch_begin(&priv->rx[ring].statss); + tmp_rx_bytes = rx->rbytes; + tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; + tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; + tmp_rx_desc_err_dropped_pkt = + rx->rx_desc_err_dropped_pkt; +- } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, ++ } while (u64_stats_fetch_retry(&priv->rx[ring].statss, + start)); + data[i++] = tmp_rx_bytes; + data[i++] = rx->rx_cont_packet_cnt; +@@ -331,9 +331,9 @@ gve_get_ethtool_stats(struct net_device *netdev, + } + do { + start = +- u64_stats_fetch_begin_irq(&priv->tx[ring].statss); ++ u64_stats_fetch_begin(&priv->tx[ring].statss); + tmp_tx_bytes = tx->bytes_done; +- } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, ++ } while (u64_stats_fetch_retry(&priv->tx[ring].statss, + start)); + data[i++] = tmp_tx_bytes; + data[i++] = tx->wake_queue; +diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c +index 2e5e0a887270..07b2ab8d054c 100644 +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -51,10 +51,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) + for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { + do { + start = +- u64_stats_fetch_begin_irq(&priv->rx[ring].statss); ++ u64_stats_fetch_begin(&priv->rx[ring].statss); + packets = priv->rx[ring].rpackets; + bytes = priv->rx[ring].rbytes; +- } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, ++ } while (u64_stats_fetch_retry(&priv->rx[ring].statss, + start)); + s->rx_packets += packets; + s->rx_bytes += bytes; +@@ -64,10 +64,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) + for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) { + do { + start = +- u64_stats_fetch_begin_irq(&priv->tx[ring].statss); ++ u64_stats_fetch_begin(&priv->tx[ring].statss); + packets = priv->tx[ring].pkt_done; + bytes = priv->tx[ring].bytes_done; +- } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, ++ } while (u64_stats_fetch_retry(&priv->tx[ring].statss, + start)); + s->tx_packets += packets; + s->tx_bytes += bytes; +@@ -1260,9 +1260,9 @@ void gve_handle_report_stats(struct gve_priv *priv) + } + + do { +- start = u64_stats_fetch_begin_irq(&priv->tx[idx].statss); ++ start = u64_stats_fetch_begin(&priv->tx[idx].statss); + tx_bytes = priv->tx[idx].bytes_done; +- } while (u64_stats_fetch_retry_irq(&priv->tx[idx].statss, start)); ++ } while (u64_stats_fetch_retry(&priv->tx[idx].statss, start)); + stats[stats_idx++] = (struct stats) { + .stat_name = cpu_to_be32(TX_WAKE_CNT), + .value = cpu_to_be64(priv->tx[idx].wake_queue), +diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h +index c693bb701ba3..05c682f712ac 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #define HNAE3_MOD_VERSION "1.0" + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 8aae179554a8..a0aa13885475 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2496,7 +2497,7 @@ static void hns3_fetch_stats(struct rtnl_link_stats64 *stats, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + if (is_tx) { + stats->tx_bytes += ring->stats.tx_bytes; + stats->tx_packets += ring->stats.tx_pkts; +@@ -2530,7 +2531,7 @@ static void hns3_fetch_stats(struct rtnl_link_stats64 *stats, + stats->multicast += ring->stats.rx_multicast; + stats->rx_length_errors += ring->stats.err_pkt_len; + } +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + } + + static void hns3_nic_get_stats64(struct net_device *netdev, +diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c +index d649c6e323c8..ceec8be2a73b 100644 +--- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c ++++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c +@@ -74,14 +74,14 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats) + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&rxq_stats->syncp); ++ start = u64_stats_fetch_begin(&rxq_stats->syncp); + stats->pkts = rxq_stats->pkts; + stats->bytes = rxq_stats->bytes; + stats->errors = rxq_stats->csum_errors + + rxq_stats->other_errors; + stats->csum_errors = rxq_stats->csum_errors; + stats->other_errors = rxq_stats->other_errors; +- } while (u64_stats_fetch_retry_irq(&rxq_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); + } + + /** +diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c +index e91476c8ff8b..ad47ac51a139 100644 +--- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c ++++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c +@@ -99,14 +99,14 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats) + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&txq_stats->syncp); ++ start = u64_stats_fetch_begin(&txq_stats->syncp); + stats->pkts = txq_stats->pkts; + stats->bytes = txq_stats->bytes; + stats->tx_busy = txq_stats->tx_busy; + stats->tx_wake = txq_stats->tx_wake; + stats->tx_dropped = txq_stats->tx_dropped; + stats->big_frags_pkts = txq_stats->big_frags_pkts; +- } while (u64_stats_fetch_retry_irq(&txq_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); + } + + /** +diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +index 2cca9e84e31e..34ab5ff9823b 100644 +--- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c ++++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +@@ -1229,10 +1229,10 @@ static void fm10k_get_stats64(struct net_device *netdev, + continue; + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + + stats->rx_packets += packets; + stats->rx_bytes += bytes; +@@ -1245,10 +1245,10 @@ static void fm10k_get_stats64(struct net_device *netdev, + continue; + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + + stats->tx_packets += packets; + stats->tx_bytes += bytes; +diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h +index a81f918091cc..90d29a297e19 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e.h ++++ b/drivers/net/ethernet/intel/i40e/i40e.h +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +index e632041aed5f..995b2a7c8973 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +@@ -154,7 +154,7 @@ __i40e_add_ethtool_stats(u64 **data, void *pointer, + * @ring: the ring to copy + * + * Queue statistics must be copied while protected by +- * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. ++ * u64_stats_fetch_begin, so we can't directly use i40e_add_ethtool_stats. + * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the + * ring pointer is null, zero out the queue stat values and update the data + * pointer. Otherwise safely copy the stats from the ring into the supplied +@@ -172,16 +172,16 @@ i40e_add_queue_stats(u64 **data, struct i40e_ring *ring) + + /* To avoid invalid statistics values, ensure that we keep retrying + * the copy until we get a consistent value according to +- * u64_stats_fetch_retry_irq. But first, make sure our ring is ++ * u64_stats_fetch_retry. But first, make sure our ring is + * non-null before attempting to access its syncp. + */ + do { +- start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); ++ start = !ring ? 0 : u64_stats_fetch_begin(&ring->syncp); + for (i = 0; i < size; i++) { + i40e_add_one_ethtool_stat(&(*data)[i], ring, + &stats[i]); + } +- } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (ring && u64_stats_fetch_retry(&ring->syncp, start)); + + /* Once we successfully copy the stats in, update the data pointer */ + *data += size; +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 08ccf0024ce1..6b3f3727c3f1 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -419,10 +419,10 @@ static void i40e_get_netdev_stats_struct_tx(struct i40e_ring *ring, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + + stats->tx_packets += packets; + stats->tx_bytes += bytes; +@@ -472,10 +472,10 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev, + if (!ring) + continue; + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + + stats->rx_packets += packets; + stats->rx_bytes += bytes; +@@ -897,10 +897,10 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi) + continue; + + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + packets = p->stats.packets; + bytes = p->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + tx_b += bytes; + tx_p += packets; + tx_restart += p->tx_stats.restart_queue; +@@ -915,10 +915,10 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi) + continue; + + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + packets = p->stats.packets; + bytes = p->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + rx_b += bytes; + rx_p += packets; + rx_buf += p->rx_stats.alloc_buff_failed; +@@ -935,10 +935,10 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi) + continue; + + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + packets = p->stats.packets; + bytes = p->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + tx_b += bytes; + tx_p += packets; + tx_restart += p->tx_stats.restart_queue; +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 543931c06bb1..4e36fbc9d9e8 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +index fe912b1c468e..a34303ad057d 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +@@ -147,7 +147,7 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer, + * @ring: the ring to copy + * + * Queue statistics must be copied while protected by +- * u64_stats_fetch_begin_irq, so we can't directly use iavf_add_ethtool_stats. ++ * u64_stats_fetch_begin, so we can't directly use iavf_add_ethtool_stats. + * Assumes that queue stats are defined in iavf_gstrings_queue_stats. If the + * ring pointer is null, zero out the queue stat values and update the data + * pointer. Otherwise safely copy the stats from the ring into the supplied +@@ -165,14 +165,14 @@ iavf_add_queue_stats(u64 **data, struct iavf_ring *ring) + + /* To avoid invalid statistics values, ensure that we keep retrying + * the copy until we get a consistent value according to +- * u64_stats_fetch_retry_irq. But first, make sure our ring is ++ * u64_stats_fetch_retry. But first, make sure our ring is + * non-null before attempting to access its syncp. + */ + do { +- start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); ++ start = !ring ? 0 : u64_stats_fetch_begin(&ring->syncp); + for (i = 0; i < size; i++) + iavf_add_one_ethtool_stat(&(*data)[i], ring, &stats[i]); +- } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (ring && u64_stats_fetch_retry(&ring->syncp, start)); + + /* Once we successfully copy the stats in, update the data pointer */ + *data += size; +diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h +index f2be383d97df..f7ea8b0439fd 100644 +--- a/drivers/net/ethernet/intel/ice/ice.h ++++ b/drivers/net/ethernet/intel/ice/ice.h +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index 3f98781e74b2..a7d9cc1292ec 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -6407,10 +6407,10 @@ ice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(syncp); ++ start = u64_stats_fetch_begin(syncp); + *pkts = stats.pkts; + *bytes = stats.bytes; +- } while (u64_stats_fetch_retry_irq(syncp, start)); ++ } while (u64_stats_fetch_retry(syncp, start)); + } + + /** +diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c +index 96fa1c420f91..319ed601eaa1 100644 +--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c ++++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c +@@ -2316,15 +2316,15 @@ static void igb_get_ethtool_stats(struct net_device *netdev, + + ring = adapter->tx_ring[j]; + do { +- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); ++ start = u64_stats_fetch_begin(&ring->tx_syncp); + data[i] = ring->tx_stats.packets; + data[i+1] = ring->tx_stats.bytes; + data[i+2] = ring->tx_stats.restart_queue; +- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); + do { +- start = u64_stats_fetch_begin_irq(&ring->tx_syncp2); ++ start = u64_stats_fetch_begin(&ring->tx_syncp2); + restart2 = ring->tx_stats.restart_queue2; +- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start)); ++ } while (u64_stats_fetch_retry(&ring->tx_syncp2, start)); + data[i+2] += restart2; + + i += IGB_TX_QUEUE_STATS_LEN; +@@ -2332,13 +2332,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev, + for (j = 0; j < adapter->num_rx_queues; j++) { + ring = adapter->rx_ring[j]; + do { +- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); ++ start = u64_stats_fetch_begin(&ring->rx_syncp); + data[i] = ring->rx_stats.packets; + data[i+1] = ring->rx_stats.bytes; + data[i+2] = ring->rx_stats.drops; + data[i+3] = ring->rx_stats.csum_err; + data[i+4] = ring->rx_stats.alloc_failed; +- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); + i += IGB_RX_QUEUE_STATS_LEN; + } + spin_unlock(&adapter->stats64_lock); +diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c +index 45ce4ed16146..9824f7cfaca4 100644 +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -6660,10 +6660,10 @@ void igb_update_stats(struct igb_adapter *adapter) + } + + do { +- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); ++ start = u64_stats_fetch_begin(&ring->rx_syncp); + _bytes = ring->rx_stats.bytes; + _packets = ring->rx_stats.packets; +- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); + bytes += _bytes; + packets += _packets; + } +@@ -6676,10 +6676,10 @@ void igb_update_stats(struct igb_adapter *adapter) + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igb_ring *ring = adapter->tx_ring[i]; + do { +- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); ++ start = u64_stats_fetch_begin(&ring->tx_syncp); + _bytes = ring->tx_stats.bytes; + _packets = ring->tx_stats.packets; +- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); + bytes += _bytes; + packets += _packets; + } +diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c +index 511fc3f41208..2899109e6fb5 100644 +--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c ++++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c +@@ -839,15 +839,15 @@ static void igc_ethtool_get_stats(struct net_device *netdev, + + ring = adapter->tx_ring[j]; + do { +- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); ++ start = u64_stats_fetch_begin(&ring->tx_syncp); + data[i] = ring->tx_stats.packets; + data[i + 1] = ring->tx_stats.bytes; + data[i + 2] = ring->tx_stats.restart_queue; +- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); + do { +- start = u64_stats_fetch_begin_irq(&ring->tx_syncp2); ++ start = u64_stats_fetch_begin(&ring->tx_syncp2); + restart2 = ring->tx_stats.restart_queue2; +- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start)); ++ } while (u64_stats_fetch_retry(&ring->tx_syncp2, start)); + data[i + 2] += restart2; + + i += IGC_TX_QUEUE_STATS_LEN; +@@ -855,13 +855,13 @@ static void igc_ethtool_get_stats(struct net_device *netdev, + for (j = 0; j < adapter->num_rx_queues; j++) { + ring = adapter->rx_ring[j]; + do { +- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); ++ start = u64_stats_fetch_begin(&ring->rx_syncp); + data[i] = ring->rx_stats.packets; + data[i + 1] = ring->rx_stats.bytes; + data[i + 2] = ring->rx_stats.drops; + data[i + 3] = ring->rx_stats.csum_err; + data[i + 4] = ring->rx_stats.alloc_failed; +- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); + i += IGC_RX_QUEUE_STATS_LEN; + } + spin_unlock(&adapter->stats64_lock); +diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c +index 2f3947cf513b..125669a6f6bb 100644 +--- a/drivers/net/ethernet/intel/igc/igc_main.c ++++ b/drivers/net/ethernet/intel/igc/igc_main.c +@@ -4865,10 +4865,10 @@ void igc_update_stats(struct igc_adapter *adapter) + } + + do { +- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); ++ start = u64_stats_fetch_begin(&ring->rx_syncp); + _bytes = ring->rx_stats.bytes; + _packets = ring->rx_stats.packets; +- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); + bytes += _bytes; + packets += _packets; + } +@@ -4882,10 +4882,10 @@ void igc_update_stats(struct igc_adapter *adapter) + struct igc_ring *ring = adapter->tx_ring[i]; + + do { +- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); ++ start = u64_stats_fetch_begin(&ring->tx_syncp); + _bytes = ring->tx_stats.bytes; + _packets = ring->tx_stats.packets; +- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); + bytes += _bytes; + packets += _packets; + } +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +index 0051aa676e19..1c22ff2dba9b 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +@@ -1335,10 +1335,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, + } + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + data[i] = ring->stats.packets; + data[i+1] = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + i += 2; + } + for (j = 0; j < IXGBE_NUM_RX_QUEUES; j++) { +@@ -1351,10 +1351,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, + } + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + data[i] = ring->stats.packets; + data[i+1] = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + i += 2; + } + +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +index 6105419ae2d5..ec8864beb1ac 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -9051,10 +9051,10 @@ static void ixgbe_get_ring_stats64(struct rtnl_link_stats64 *stats, + + if (ring) { + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } +@@ -9074,10 +9074,10 @@ static void ixgbe_get_stats64(struct net_device *netdev, + + if (ring) { + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } +diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c +index ccfa6b91aac6..296915414a7c 100644 +--- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c ++++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c +@@ -458,10 +458,10 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, + } + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + data[i] = ring->stats.packets; + data[i + 1] = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + i += 2; + } + +@@ -475,10 +475,10 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, + } + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + data[i] = ring->stats.packets; + data[i + 1] = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + i += 2; + } + +@@ -492,10 +492,10 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, + } + + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + data[i] = ring->stats.packets; + data[i + 1] = ring->stats.bytes; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + i += 2; + } + } +diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +index e338fa572793..a9479ddf68eb 100644 +--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c ++++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +@@ -4350,10 +4350,10 @@ static void ixgbevf_get_tx_ring_stats(struct rtnl_link_stats64 *stats, + + if (ring) { + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + bytes = ring->stats.bytes; + packets = ring->stats.packets; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + stats->tx_bytes += bytes; + stats->tx_packets += packets; + } +@@ -4376,10 +4376,10 @@ static void ixgbevf_get_stats(struct net_device *netdev, + for (i = 0; i < adapter->num_rx_queues; i++) { + ring = adapter->rx_ring[i]; + do { +- start = u64_stats_fetch_begin_irq(&ring->syncp); ++ start = u64_stats_fetch_begin(&ring->syncp); + bytes = ring->stats.bytes; + packets = ring->stats.packets; +- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); ++ } while (u64_stats_fetch_retry(&ring->syncp, start)); + stats->rx_bytes += bytes; + stats->rx_packets += packets; + } +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index aca5b72cfeec..b9f742518313 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -38,7 +38,7 @@ + #include + #include + #include +-#include ++#include + #include + + /* Registers */ +@@ -813,14 +813,14 @@ mvneta_get_stats64(struct net_device *dev, + + cpu_stats = per_cpu_ptr(pp->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + rx_packets = cpu_stats->es.ps.rx_packets; + rx_bytes = cpu_stats->es.ps.rx_bytes; + rx_dropped = cpu_stats->rx_dropped; + rx_errors = cpu_stats->rx_errors; + tx_packets = cpu_stats->es.ps.tx_packets; + tx_bytes = cpu_stats->es.ps.tx_bytes; +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +@@ -4762,7 +4762,7 @@ mvneta_ethtool_update_pcpu_stats(struct mvneta_port *pp, + + stats = per_cpu_ptr(pp->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + skb_alloc_error = stats->es.skb_alloc_error; + refill_error = stats->es.refill_error; + xdp_redirect = stats->es.ps.xdp_redirect; +@@ -4772,7 +4772,7 @@ mvneta_ethtool_update_pcpu_stats(struct mvneta_port *pp, + xdp_xmit_err = stats->es.ps.xdp_xmit_err; + xdp_tx = stats->es.ps.xdp_tx; + xdp_tx_err = stats->es.ps.xdp_tx_err; +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + es->skb_alloc_error += skb_alloc_error; + es->refill_error += refill_error; +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index f936640cca4e..8c7470ab4985 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -2008,7 +2008,7 @@ mvpp2_get_xdp_stats(struct mvpp2_port *port, struct mvpp2_pcpu_stats *xdp_stats) + + cpu_stats = per_cpu_ptr(port->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + xdp_redirect = cpu_stats->xdp_redirect; + xdp_pass = cpu_stats->xdp_pass; + xdp_drop = cpu_stats->xdp_drop; +@@ -2016,7 +2016,7 @@ mvpp2_get_xdp_stats(struct mvpp2_port *port, struct mvpp2_pcpu_stats *xdp_stats) + xdp_xmit_err = cpu_stats->xdp_xmit_err; + xdp_tx = cpu_stats->xdp_tx; + xdp_tx_err = cpu_stats->xdp_tx_err; +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + xdp_stats->xdp_redirect += xdp_redirect; + xdp_stats->xdp_pass += xdp_pass; +@@ -5115,12 +5115,12 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + + cpu_stats = per_cpu_ptr(port->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + rx_packets = cpu_stats->rx_packets; + rx_bytes = cpu_stats->rx_bytes; + tx_packets = cpu_stats->tx_packets; + tx_bytes = cpu_stats->tx_bytes; +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c +index ab33ba1c3023..ff97b140886a 100644 +--- a/drivers/net/ethernet/marvell/sky2.c ++++ b/drivers/net/ethernet/marvell/sky2.c +@@ -3894,19 +3894,19 @@ static void sky2_get_stats(struct net_device *dev, + u64 _bytes, _packets; + + do { +- start = u64_stats_fetch_begin_irq(&sky2->rx_stats.syncp); ++ start = u64_stats_fetch_begin(&sky2->rx_stats.syncp); + _bytes = sky2->rx_stats.bytes; + _packets = sky2->rx_stats.packets; +- } while (u64_stats_fetch_retry_irq(&sky2->rx_stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&sky2->rx_stats.syncp, start)); + + stats->rx_packets = _packets; + stats->rx_bytes = _bytes; + + do { +- start = u64_stats_fetch_begin_irq(&sky2->tx_stats.syncp); ++ start = u64_stats_fetch_begin(&sky2->tx_stats.syncp); + _bytes = sky2->tx_stats.bytes; + _packets = sky2->tx_stats.packets; +- } while (u64_stats_fetch_retry_irq(&sky2->tx_stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&sky2->tx_stats.syncp, start)); + + stats->tx_packets = _packets; + stats->tx_bytes = _bytes; +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 0ac5ae16308f..c13cc420c64b 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -866,7 +866,7 @@ static void mtk_get_stats64(struct net_device *dev, + } + + do { +- start = u64_stats_fetch_begin_irq(&hw_stats->syncp); ++ start = u64_stats_fetch_begin(&hw_stats->syncp); + storage->rx_packets = hw_stats->rx_packets; + storage->tx_packets = hw_stats->tx_packets; + storage->rx_bytes = hw_stats->rx_bytes; +@@ -878,7 +878,7 @@ static void mtk_get_stats64(struct net_device *dev, + storage->rx_crc_errors = hw_stats->rx_fcs_errors; + storage->rx_errors = hw_stats->rx_checksum_errors; + storage->tx_aborted_errors = hw_stats->tx_skip; +- } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&hw_stats->syncp, start)); + + storage->tx_errors = dev->stats.tx_errors; + storage->rx_dropped = dev->stats.rx_dropped; +@@ -3694,13 +3694,13 @@ static void mtk_get_ethtool_stats(struct net_device *dev, + + do { + data_dst = data; +- start = u64_stats_fetch_begin_irq(&hwstats->syncp); ++ start = u64_stats_fetch_begin(&hwstats->syncp); + + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) + *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); + if (mtk_page_pool_enabled(mac->hw)) + mtk_ethtool_pp_stats(mac->hw, data_dst); +- } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); ++ } while (u64_stats_fetch_retry(&hwstats->syncp, start)); + } + + static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 4e7daa382bc0..699313b59330 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + #include + #include "eswitch.h" + #include "en.h" +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 67ecdb9e708f..8345499563a4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -827,12 +827,12 @@ mlxsw_sp_port_get_sw_stats64(const struct net_device *dev, + for_each_possible_cpu(i) { + p = per_cpu_ptr(mlxsw_sp_port->pcpu_stats, i); + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + rx_packets = p->rx_packets; + rx_bytes = p->rx_bytes; + tx_packets = p->tx_packets; + tx_bytes = p->tx_bytes; +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c b/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c +index 651d5493ae55..ee78655a1cd5 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0+ + + #include ++#include + + #include "lan966x_main.h" + +diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c +index dc2c3756e3a2..7c174cb4a8b7 100644 +--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c ++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c +@@ -5,6 +5,7 @@ + */ + + #include ++#include + + #include "sparx5_tc.h" + #include "sparx5_main.h" +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 4f4204432aaa..9cca75423933 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -316,10 +316,10 @@ static void mana_get_stats64(struct net_device *ndev, + rx_stats = &apc->rxqs[q]->stats; + + do { +- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); ++ start = u64_stats_fetch_begin(&rx_stats->syncp); + packets = rx_stats->packets; + bytes = rx_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); + + st->rx_packets += packets; + st->rx_bytes += bytes; +@@ -329,10 +329,10 @@ static void mana_get_stats64(struct net_device *ndev, + tx_stats = &apc->tx_qp[q].txq.stats; + + do { +- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); ++ start = u64_stats_fetch_begin(&tx_stats->syncp); + packets = tx_stats->packets; + bytes = tx_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); + + st->tx_packets += packets; + st->tx_bytes += bytes; +diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +index c530db76880f..96d55c91c969 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +@@ -90,13 +90,13 @@ static void mana_get_ethtool_stats(struct net_device *ndev, + rx_stats = &apc->rxqs[q]->stats; + + do { +- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); ++ start = u64_stats_fetch_begin(&rx_stats->syncp); + packets = rx_stats->packets; + bytes = rx_stats->bytes; + xdp_drop = rx_stats->xdp_drop; + xdp_tx = rx_stats->xdp_tx; + xdp_redirect = rx_stats->xdp_redirect; +- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); + + data[i++] = packets; + data[i++] = bytes; +@@ -109,11 +109,11 @@ static void mana_get_ethtool_stats(struct net_device *ndev, + tx_stats = &apc->tx_qp[q].txq.stats; + + do { +- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); ++ start = u64_stats_fetch_begin(&tx_stats->syncp); + packets = tx_stats->packets; + bytes = tx_stats->bytes; + xdp_xmit = tx_stats->xdp_xmit; +- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); + + data[i++] = packets; + data[i++] = bytes; +diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c +index aa069aa433f0..6897441e0eaf 100644 +--- a/drivers/net/ethernet/mscc/ocelot.c ++++ b/drivers/net/ethernet/mscc/ocelot.c +@@ -212,6 +212,12 @@ static void ocelot_vcap_enable(struct ocelot *ocelot, int port) + ocelot_write_gix(ocelot, ANA_PORT_VCAP_CFG_S1_ENA, + ANA_PORT_VCAP_CFG, port); + ++ /* Use key S1_5TUPLE_IP4 in second lookup. */ ++ ocelot_write_ix(ocelot, ++ ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG(2) | ++ ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG(2), ++ ANA_PORT_VCAP_S1_KEY_CFG, port, 1); ++ + ocelot_rmw_gix(ocelot, REW_PORT_CFG_ES0_EN, + REW_PORT_CFG_ES0_EN, + REW_PORT_CFG, port); +@@ -345,6 +351,8 @@ static void ocelot_port_manage_port_tag(struct ocelot *ocelot, int port) + struct ocelot_port *ocelot_port = ocelot->ports[port]; + enum ocelot_port_tag_config tag_cfg; + bool uses_native_vlan = false; ++ u32 port_tpid = 0; ++ u32 tag_tpid = 0; + + if (ocelot_port->vlan_aware) { + uses_native_vlan = ocelot_port_uses_native_vlan(ocelot, port); +@@ -355,12 +363,17 @@ static void ocelot_port_manage_port_tag(struct ocelot *ocelot, int port) + tag_cfg = OCELOT_PORT_TAG_DISABLED; + else + tag_cfg = OCELOT_PORT_TAG_TRUNK; ++ ++ if (ocelot->qinq_enable && ocelot_port->qinq_mode) ++ tag_tpid = REW_TAG_CFG_TAG_TPID_CFG(1); ++ else ++ tag_tpid = REW_TAG_CFG_TAG_TPID_CFG(0); + } else { + tag_cfg = OCELOT_PORT_TAG_DISABLED; + } + +- ocelot_rmw_gix(ocelot, REW_TAG_CFG_TAG_CFG(tag_cfg), +- REW_TAG_CFG_TAG_CFG_M, ++ ocelot_rmw_gix(ocelot, REW_TAG_CFG_TAG_CFG(tag_cfg) | tag_tpid, ++ REW_TAG_CFG_TAG_CFG_M | REW_TAG_CFG_TAG_TPID_CFG_M, + REW_TAG_CFG, port); + + if (uses_native_vlan) { +@@ -372,9 +385,16 @@ static void ocelot_port_manage_port_tag(struct ocelot *ocelot, int port) + */ + native_vlan = ocelot_port_find_native_vlan(ocelot, port); + ++ if (ocelot->qinq_enable && ocelot_port->qinq_mode) ++ port_tpid = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021AD); ++ else ++ port_tpid = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q); ++ + ocelot_rmw_gix(ocelot, +- REW_PORT_VLAN_CFG_PORT_VID(native_vlan->vid), +- REW_PORT_VLAN_CFG_PORT_VID_M, ++ REW_PORT_VLAN_CFG_PORT_VID(native_vlan->vid) | ++ port_tpid, ++ REW_PORT_VLAN_CFG_PORT_VID_M | ++ REW_PORT_VLAN_CFG_PORT_TPID_M, + REW_PORT_VLAN_CFG, port); + } + } +@@ -419,6 +439,10 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, + struct ocelot_port *ocelot_port = ocelot->ports[port]; + u16 pvid = ocelot_vlan_unaware_pvid(ocelot, ocelot_port->bridge); + u32 val = 0; ++ u32 tag_type = 0; ++ ++ if (ocelot->qinq_enable && ocelot_port->qinq_mode) ++ tag_type = ANA_PORT_VLAN_CFG_VLAN_TAG_TYPE; + + ocelot_port->pvid_vlan = pvid_vlan; + +@@ -426,8 +450,8 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, + pvid = pvid_vlan->vid; + + ocelot_rmw_gix(ocelot, +- ANA_PORT_VLAN_CFG_VLAN_VID(pvid), +- ANA_PORT_VLAN_CFG_VLAN_VID_M, ++ ANA_PORT_VLAN_CFG_VLAN_VID(pvid) | tag_type, ++ ANA_PORT_VLAN_CFG_VLAN_VID_M | tag_type, + ANA_PORT_VLAN_CFG, port); + + /* If there's no pvid, we should drop not only untagged traffic (which +@@ -585,6 +609,15 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, + ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1); + else + val = 0; ++ ++ /* if switch is enabled for QinQ, the port for LAN should set ++ * VLAN_CFG.VLAN_POP_CNT=0 && VLAN_CFG.VLAN_AWARE_ENA=0. ++ * the port for MAN should set VLAN_CFG.VLAN_POP_CNT=1 && ++ * VLAN_CFG.VLAN_AWARE_ENA=1. referring to 4.3.3 in VSC9959_1_00_TS.pdf ++ */ ++ if (ocelot->qinq_enable && !ocelot_port->qinq_mode) ++ val = 0; ++ + ocelot_rmw_gix(ocelot, val, + ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | + ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M, +@@ -1517,7 +1550,12 @@ u32 ocelot_get_bridge_fwd_mask(struct ocelot *ocelot, int src_port) + if (!ocelot_port) + continue; + +- if (ocelot_port->stp_state == BR_STATE_FORWARDING && ++ /* Keep the bridge port in forward mask if the port is forward ++ * state or force_forward mode. ++ * FRER need to set the port to force_forward mode. ++ */ ++ if ((ocelot_port->stp_state == BR_STATE_FORWARDING || ++ ocelot_port->force_forward) && + ocelot_port->bridge == bridge) + mask |= BIT(port); + } +diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c +index ee052404eb55..ee9656291fff 100644 +--- a/drivers/net/ethernet/mscc/ocelot_flower.c ++++ b/drivers/net/ethernet/mscc/ocelot_flower.c +@@ -468,20 +468,27 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, + switch (ntohs(a->vlan.proto)) { + case ETH_P_8021Q: + tpid = OCELOT_TAG_TPID_SEL_8021Q; ++ filter->action.tag_b_tpid_sel = tpid; ++ filter->action.push_inner_tag = OCELOT_ES0_TAG; ++ filter->action.tag_b_vid_sel = OCELOT_ES0_VID; ++ filter->action.tag_b_pcp_sel = OCELOT_ES0_PCP; ++ filter->action.vid_b_val = a->vlan.vid; ++ filter->action.pcp_b_val = a->vlan.prio; + break; + case ETH_P_8021AD: + tpid = OCELOT_TAG_TPID_SEL_8021AD; ++ filter->action.tag_a_tpid_sel = tpid; ++ filter->action.push_outer_tag = OCELOT_ES0_TAG; ++ filter->action.tag_a_vid_sel = OCELOT_ES0_VID; ++ filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP; ++ filter->action.vid_a_val = a->vlan.vid; ++ filter->action.pcp_a_val = a->vlan.prio; + break; + default: + NL_SET_ERR_MSG_MOD(extack, + "Cannot push custom TPID"); + return -EOPNOTSUPP; + } +- filter->action.tag_a_tpid_sel = tpid; +- filter->action.push_outer_tag = OCELOT_ES0_TAG; +- filter->action.tag_a_vid_sel = OCELOT_ES0_VID; +- filter->action.vid_a_val = a->vlan.vid; +- filter->action.pcp_a_val = a->vlan.prio; + filter->type = OCELOT_VCAP_FILTER_OFFLOAD; + break; + case FLOW_ACTION_GATE: +@@ -586,6 +593,7 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress, + BIT(FLOW_DISSECTOR_KEY_META) | + BIT(FLOW_DISSECTOR_KEY_PORTS) | + BIT(FLOW_DISSECTOR_KEY_VLAN) | ++ BIT(FLOW_DISSECTOR_KEY_CVLAN) | + BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | + BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | + BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) { +@@ -617,6 +625,18 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress, + match_protocol = false; + } + ++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) { ++ struct flow_match_vlan match; ++ ++ flow_rule_match_cvlan(rule, &match); ++ filter->key_type = OCELOT_VCAP_KEY_ANY; ++ filter->cvlan.vid.value = match.key->vlan_id; ++ filter->cvlan.vid.mask = match.mask->vlan_id; ++ filter->cvlan.pcp.value[0] = match.key->vlan_priority; ++ filter->cvlan.pcp.mask[0] = match.mask->vlan_priority; ++ match_protocol = false; ++ } ++ + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { + struct flow_match_eth_addrs match; + +diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c +index cb32234a5bf1..af69d90350e9 100644 +--- a/drivers/net/ethernet/mscc/ocelot_ptp.c ++++ b/drivers/net/ethernet/mscc/ocelot_ptp.c +@@ -532,6 +532,7 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr) + switch (cfg.tx_type) { + case HWTSTAMP_TX_ON: + ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; ++ skb_queue_purge(&ocelot_port->tx_skbs); + break; + case HWTSTAMP_TX_ONESTEP_SYNC: + /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we +diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c +index 73cdec5ca6a3..9947b634194a 100644 +--- a/drivers/net/ethernet/mscc/ocelot_vcap.c ++++ b/drivers/net/ethernet/mscc/ocelot_vcap.c +@@ -666,10 +666,11 @@ static void is1_action_set(struct ocelot *ocelot, struct vcap_data *data, + vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_VAL, a->pag_val); + } + +-static void is1_entry_set(struct ocelot *ocelot, int ix, ++static int is1_entry_set(struct ocelot *ocelot, int ix, + struct ocelot_vcap_filter *filter) + { + const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1]; ++ struct ocelot_vcap_key_vlan *ctag = &filter->cvlan; + struct ocelot_vcap_key_vlan *tag = &filter->vlan; + struct vcap_data data; + int row = ix / 2; +@@ -689,6 +690,11 @@ static void is1_entry_set(struct ocelot *ocelot, int ix, + if (filter->prio != 0) + data.tg |= data.tg_value; + ++ if (filter->lookup == 1) ++ type = IS1_TYPE_S1_5TUPLE_IP4; ++ else ++ type = IS1_TYPE_S1_NORMAL; ++ + vcap_key_set(vcap, &data, VCAP_IS1_HK_LOOKUP, filter->lookup, 0x3); + vcap_key_set(vcap, &data, VCAP_IS1_HK_IGR_PORT_MASK, 0, + ~filter->ingress_port_mask); +@@ -699,12 +705,31 @@ static void is1_entry_set(struct ocelot *ocelot, int ix, + tag->vid.value, tag->vid.mask); + vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP, + tag->pcp.value[0], tag->pcp.mask[0]); +- type = IS1_TYPE_S1_NORMAL; ++ ++ if (ctag->vid.value != 0) { ++ if (type != IS1_TYPE_S1_5TUPLE_IP4) ++ return -EOPNOTSUPP; ++ ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TPID, ++ OCELOT_VCAP_BIT_1); ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_DBL_TAGGED, ++ OCELOT_VCAP_BIT_1); ++ vcap_key_set(vcap, &data, VCAP_IS1_HK_IP4_INNER_VID, ++ ctag->vid.value, ctag->vid.mask); ++ vcap_key_set(vcap, &data, VCAP_IS1_HK_IP4_INNER_PCP, ++ ctag->pcp.value[0], ctag->pcp.mask[0]); ++ } + + switch (filter->key_type) { + case OCELOT_VCAP_KEY_ETYPE: { + struct ocelot_vcap_key_etype *etype = &filter->key.etype; + ++ if (type != IS1_TYPE_S1_NORMAL) ++ return -EOPNOTSUPP; ++ ++ if (etype->dmac.mask[0]) ++ return -EOPNOTSUPP; ++ + vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L2_SMAC, + etype->smac.value, etype->smac.mask); + vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE, +@@ -716,48 +741,103 @@ static void is1_entry_set(struct ocelot *ocelot, int ix, + struct ocelot_vcap_udp_tcp *sport = &ipv4->sport; + struct ocelot_vcap_udp_tcp *dport = &ipv4->dport; + enum ocelot_vcap_bit tcp_udp = OCELOT_VCAP_BIT_0; ++ enum ocelot_vcap_bit fragment = ipv4->fragment; ++ enum ocelot_vcap_bit options = ipv4->options; ++ enum ocelot_vcap_bit tcp = OCELOT_VCAP_BIT_0; + struct ocelot_vcap_u8 proto = ipv4->proto; + struct ocelot_vcap_ipv4 sip = ipv4->sip; ++ struct ocelot_vcap_ipv4 dip = ipv4->dip; ++ struct ocelot_vcap_u32 port; + u32 val, msk; + +- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP_SNAP, +- OCELOT_VCAP_BIT_1); +- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4, +- OCELOT_VCAP_BIT_1); +- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_ETYPE_LEN, +- OCELOT_VCAP_BIT_1); +- vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L3_IP4_SIP, +- sip.value.addr, sip.mask.addr); +- +- val = proto.value[0]; +- msk = proto.mask[0]; +- +- if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) && msk == 0xff) +- tcp_udp = OCELOT_VCAP_BIT_1; +- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP_UDP, tcp_udp); +- +- if (tcp_udp) { +- enum ocelot_vcap_bit tcp = OCELOT_VCAP_BIT_0; +- +- if (val == NEXTHDR_TCP) +- tcp = OCELOT_VCAP_BIT_1; +- +- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP, tcp); +- vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_L4_SPORT, +- sport); +- /* Overloaded field */ +- vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_ETYPE, +- dport); +- } else { +- /* IPv4 "other" frame */ +- struct ocelot_vcap_u16 etype = {0}; +- +- /* Overloaded field */ +- etype.value[0] = proto.value[0]; +- etype.mask[0] = proto.mask[0]; ++ if (type == IS1_TYPE_S1_5TUPLE_IP4) { ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4_IP4, ++ OCELOT_VCAP_BIT_1); ++ vcap_key_bit_set(vcap, &data, ++ VCAP_IS1_HK_IP4_L3_FRAGMENT, ++ fragment); ++ vcap_key_bit_set(vcap, &data, ++ VCAP_IS1_HK_IP4_L3_OPTIONS, ++ options); ++ vcap_key_bytes_set(vcap, &data, ++ VCAP_IS1_HK_IP4_L3_IP4_DIP, ++ dip.value.addr, dip.mask.addr); ++ vcap_key_bytes_set(vcap, &data, ++ VCAP_IS1_HK_IP4_L3_IP4_SIP, ++ sip.value.addr, sip.mask.addr); ++ ++ val = proto.value[0]; ++ msk = proto.mask[0]; ++ if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) && ++ msk == 0xff) { ++ tcp_udp = OCELOT_VCAP_BIT_1; ++ tcp = (val == NEXTHDR_TCP ? ++ OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0); ++ ++ vcap_key_bit_set(vcap, &data, ++ VCAP_IS1_HK_IP4_TCP_UDP, ++ tcp_udp); ++ vcap_key_bit_set(vcap, &data, ++ VCAP_IS1_HK_IP4_TCP, tcp); ++ ++ port.value[0] = sport->value & 0xFF; ++ port.value[1] = sport->value >> 8; ++ port.value[2] = dport->value & 0xFF; ++ port.value[3] = dport->value >> 8; ++ port.mask[0] = sport->mask & 0xFF; ++ port.mask[1] = sport->mask >> 8; ++ port.mask[2] = dport->mask & 0xFF; ++ port.mask[3] = dport->mask >> 8; ++ vcap_key_bytes_set(vcap, &data, ++ VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE, ++ port.value, port.mask); ++ } + +- vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE, +- etype.value, etype.mask); ++ } else if (type == IS1_TYPE_S1_NORMAL) { ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP_SNAP, ++ OCELOT_VCAP_BIT_1); ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4, ++ OCELOT_VCAP_BIT_1); ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_ETYPE_LEN, ++ OCELOT_VCAP_BIT_1); ++ vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L3_IP4_SIP, ++ sip.value.addr, sip.mask.addr); ++ ++ if (dip.mask.addr[0]) ++ return -EOPNOTSUPP; ++ ++ val = proto.value[0]; ++ msk = proto.mask[0]; ++ ++ if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) && ++ msk == 0xff) { ++ tcp_udp = OCELOT_VCAP_BIT_1; ++ tcp = (val == NEXTHDR_TCP ? ++ OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0); ++ ++ vcap_key_bit_set(vcap, &data, ++ VCAP_IS1_HK_TCP_UDP, tcp_udp); ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP, ++ tcp); ++ vcap_key_l4_port_set(vcap, &data, ++ VCAP_IS1_HK_L4_SPORT, ++ sport); ++ /* Overloaded field */ ++ vcap_key_l4_port_set(vcap, &data, ++ VCAP_IS1_HK_ETYPE, ++ dport); ++ } else if (msk == 0xff) { ++ /* IPv4 "other" frame */ ++ struct ocelot_vcap_u16 etype = {0}; ++ ++ /* Overloaded field */ ++ etype.value[0] = proto.value[0]; ++ etype.mask[0] = proto.mask[0]; ++ ++ vcap_key_bytes_set(vcap, &data, ++ VCAP_IS1_HK_ETYPE, ++ etype.value, etype.mask); ++ } + } + break; + } +@@ -775,6 +855,8 @@ static void is1_entry_set(struct ocelot *ocelot, int ix, + vcap_entry2cache(ocelot, vcap, &data); + vcap_action2cache(ocelot, vcap, &data); + vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL); ++ ++ return 0; + } + + static void es0_action_set(struct ocelot *ocelot, struct vcap_data *data, +@@ -872,15 +954,17 @@ static void vcap_entry_get(struct ocelot *ocelot, int ix, + filter->stats.pkts = cnt; + } + +-static void vcap_entry_set(struct ocelot *ocelot, int ix, +- struct ocelot_vcap_filter *filter) ++static int vcap_entry_set(struct ocelot *ocelot, int ix, ++ struct ocelot_vcap_filter *filter) + { + if (filter->block_id == VCAP_IS1) + return is1_entry_set(ocelot, ix, filter); + if (filter->block_id == VCAP_IS2) +- return is2_entry_set(ocelot, ix, filter); ++ is2_entry_set(ocelot, ix, filter); + if (filter->block_id == VCAP_ES0) +- return es0_entry_set(ocelot, ix, filter); ++ es0_entry_set(ocelot, ix, filter); ++ ++ return 0; + } + + struct vcap_policer_entry { +@@ -1214,8 +1298,7 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot, + } + + /* Now insert the new filter */ +- vcap_entry_set(ocelot, index, filter); +- return 0; ++ return vcap_entry_set(ocelot, index, filter); + } + EXPORT_SYMBOL(ocelot_vcap_filter_add); + +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +index 27f4786ace4f..a5ca5c4a7896 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +@@ -1631,21 +1631,21 @@ static void nfp_net_stat64(struct net_device *netdev, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&r_vec->rx_sync); ++ start = u64_stats_fetch_begin(&r_vec->rx_sync); + data[0] = r_vec->rx_pkts; + data[1] = r_vec->rx_bytes; + data[2] = r_vec->rx_drops; +- } while (u64_stats_fetch_retry_irq(&r_vec->rx_sync, start)); ++ } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); + stats->rx_packets += data[0]; + stats->rx_bytes += data[1]; + stats->rx_dropped += data[2]; + + do { +- start = u64_stats_fetch_begin_irq(&r_vec->tx_sync); ++ start = u64_stats_fetch_begin(&r_vec->tx_sync); + data[0] = r_vec->tx_pkts; + data[1] = r_vec->tx_bytes; + data[2] = r_vec->tx_errors; +- } while (u64_stats_fetch_retry_irq(&r_vec->tx_sync, start)); ++ } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); + stats->tx_packets += data[0]; + stats->tx_bytes += data[1]; + stats->tx_errors += data[2]; +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +index af376b900067..cc97b3d00414 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +@@ -881,7 +881,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].rx_sync); ++ start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync); + data[0] = nn->r_vecs[i].rx_pkts; + tmp[0] = nn->r_vecs[i].hw_csum_rx_ok; + tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok; +@@ -889,10 +889,10 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) + tmp[3] = nn->r_vecs[i].hw_csum_rx_error; + tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail; + tmp[5] = nn->r_vecs[i].hw_tls_rx; +- } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].rx_sync, start)); ++ } while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start)); + + do { +- start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].tx_sync); ++ start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync); + data[1] = nn->r_vecs[i].tx_pkts; + data[2] = nn->r_vecs[i].tx_busy; + tmp[6] = nn->r_vecs[i].hw_csum_tx; +@@ -902,7 +902,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) + tmp[10] = nn->r_vecs[i].hw_tls_tx; + tmp[11] = nn->r_vecs[i].tls_tx_fallback; + tmp[12] = nn->r_vecs[i].tls_tx_no_fallback; +- } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].tx_sync, start)); ++ } while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start)); + + data += NN_RVEC_PER_Q_STATS; + +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +index 8b77582bdfa0..a6b6ca1fd55e 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +@@ -134,13 +134,13 @@ nfp_repr_get_host_stats64(const struct net_device *netdev, + + repr_stats = per_cpu_ptr(repr->stats, i); + do { +- start = u64_stats_fetch_begin_irq(&repr_stats->syncp); ++ start = u64_stats_fetch_begin(&repr_stats->syncp); + tbytes = repr_stats->tx_bytes; + tpkts = repr_stats->tx_packets; + tdrops = repr_stats->tx_drops; + rbytes = repr_stats->rx_bytes; + rpkts = repr_stats->rx_packets; +- } while (u64_stats_fetch_retry_irq(&repr_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&repr_stats->syncp, start)); + + stats->tx_bytes += tbytes; + stats->tx_packets += tpkts; +diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c +index 486cbc8ab224..7a549b834e97 100644 +--- a/drivers/net/ethernet/nvidia/forcedeth.c ++++ b/drivers/net/ethernet/nvidia/forcedeth.c +@@ -1734,12 +1734,12 @@ static void nv_get_stats(int cpu, struct fe_priv *np, + u64 tx_packets, tx_bytes, tx_dropped; + + do { +- syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp); ++ syncp_start = u64_stats_fetch_begin(&np->swstats_rx_syncp); + rx_packets = src->stat_rx_packets; + rx_bytes = src->stat_rx_bytes; + rx_dropped = src->stat_rx_dropped; + rx_missed_errors = src->stat_rx_missed_errors; +- } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start)); ++ } while (u64_stats_fetch_retry(&np->swstats_rx_syncp, syncp_start)); + + storage->rx_packets += rx_packets; + storage->rx_bytes += rx_bytes; +@@ -1747,11 +1747,11 @@ static void nv_get_stats(int cpu, struct fe_priv *np, + storage->rx_missed_errors += rx_missed_errors; + + do { +- syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp); ++ syncp_start = u64_stats_fetch_begin(&np->swstats_tx_syncp); + tx_packets = src->stat_tx_packets; + tx_bytes = src->stat_tx_bytes; + tx_dropped = src->stat_tx_dropped; +- } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start)); ++ } while (u64_stats_fetch_retry(&np->swstats_tx_syncp, syncp_start)); + + storage->tx_packets += tx_packets; + storage->tx_bytes += tx_bytes; +diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +index 1b2119b1d48a..3f5e6572d20e 100644 +--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c ++++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +@@ -135,9 +135,9 @@ static void rmnet_get_stats64(struct net_device *dev, + pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu); + + do { +- start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp); ++ start = u64_stats_fetch_begin(&pcpu_ptr->syncp); + snapshot = pcpu_ptr->stats; /* struct assignment */ +- } while (u64_stats_fetch_retry_irq(&pcpu_ptr->syncp, start)); ++ } while (u64_stats_fetch_retry(&pcpu_ptr->syncp, start)); + + total_stats.rx_pkts += snapshot.rx_pkts; + total_stats.rx_bytes += snapshot.rx_bytes; +diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c +index 469e2e229c6e..9ce0e8a64ba8 100644 +--- a/drivers/net/ethernet/realtek/8139too.c ++++ b/drivers/net/ethernet/realtek/8139too.c +@@ -2532,16 +2532,16 @@ rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + netdev_stats_to_stats64(stats, &dev->stats); + + do { +- start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp); ++ start = u64_stats_fetch_begin(&tp->rx_stats.syncp); + stats->rx_packets = tp->rx_stats.packets; + stats->rx_bytes = tp->rx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&tp->rx_stats.syncp, start)); + + do { +- start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp); ++ start = u64_stats_fetch_begin(&tp->tx_stats.syncp); + stats->tx_packets = tp->tx_stats.packets; + stats->tx_bytes = tp->tx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&tp->tx_stats.syncp, start)); + } + + /* Set or clear the multicast filter for this adaptor. +diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c +index d2c6a5dfdc0e..b7e24ae92525 100644 +--- a/drivers/net/ethernet/socionext/sni_ave.c ++++ b/drivers/net/ethernet/socionext/sni_ave.c +@@ -1508,16 +1508,16 @@ static void ave_get_stats64(struct net_device *ndev, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&priv->stats_rx.syncp); ++ start = u64_stats_fetch_begin(&priv->stats_rx.syncp); + stats->rx_packets = priv->stats_rx.packets; + stats->rx_bytes = priv->stats_rx.bytes; +- } while (u64_stats_fetch_retry_irq(&priv->stats_rx.syncp, start)); ++ } while (u64_stats_fetch_retry(&priv->stats_rx.syncp, start)); + + do { +- start = u64_stats_fetch_begin_irq(&priv->stats_tx.syncp); ++ start = u64_stats_fetch_begin(&priv->stats_tx.syncp); + stats->tx_packets = priv->stats_tx.packets; + stats->tx_bytes = priv->stats_tx.bytes; +- } while (u64_stats_fetch_retry_irq(&priv->stats_tx.syncp, start)); ++ } while (u64_stats_fetch_retry(&priv->stats_tx.syncp, start)); + + stats->rx_errors = priv->stats_rx.errors; + stats->tx_errors = priv->stats_tx.errors; +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +index 84276eb681d7..7d6d6e3b1df7 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +@@ -84,22 +84,38 @@ static void dwmac4_rx_queue_enable(struct mac_device_info *hw, + } + + static void dwmac4_rx_queue_priority(struct mac_device_info *hw, +- u32 prio, u32 queue) ++ u32 prio_mask, u32 queue) + { + void __iomem *ioaddr = hw->pcsr; +- u32 base_register; +- u32 value; ++ u32 clear_mask = 0; ++ u32 ctrl2, ctrl3; ++ int i; + +- base_register = (queue < 4) ? GMAC_RXQ_CTRL2 : GMAC_RXQ_CTRL3; +- if (queue >= 4) +- queue -= 4; ++ ctrl2 = readl(ioaddr + GMAC_RXQ_CTRL2); ++ ctrl3 = readl(ioaddr + GMAC_RXQ_CTRL3); + +- value = readl(ioaddr + base_register); ++ for (i = 0; i < 4; i++) ++ clear_mask |= ((prio_mask << GMAC_RXQCTRL_PSRQX_SHIFT(i)) & ++ GMAC_RXQCTRL_PSRQX_MASK(i)); ++ ++ ctrl2 &= ~clear_mask; ++ ctrl3 &= ~clear_mask; + +- value &= ~GMAC_RXQCTRL_PSRQX_MASK(queue); +- value |= (prio << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) & ++ if (queue < 4) { ++ ctrl2 |= (prio_mask << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) & + GMAC_RXQCTRL_PSRQX_MASK(queue); +- writel(value, ioaddr + base_register); ++ ++ writel(ctrl2, ioaddr + GMAC_RXQ_CTRL2); ++ writel(ctrl3, ioaddr + GMAC_RXQ_CTRL3); ++ } else { ++ queue -= 4; ++ ++ ctrl3 |= (prio_mask << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) & ++ GMAC_RXQCTRL_PSRQX_MASK(queue); ++ ++ writel(ctrl3, ioaddr + GMAC_RXQ_CTRL3); ++ writel(ctrl2, ioaddr + GMAC_RXQ_CTRL2); ++ } + } + + static void dwmac4_tx_queue_priority(struct mac_device_info *hw, +@@ -1209,6 +1225,7 @@ const struct stmmac_ops dwmac410_ops = { + .est_configure = dwmac5_est_configure, + .est_irq_status = dwmac5_est_irq_status, + .fpe_configure = dwmac5_fpe_configure, ++ .fpe_configure_get = dwmac5_fpe_configure_get, + .fpe_send_mpacket = dwmac5_fpe_send_mpacket, + .fpe_irq_status = dwmac5_fpe_irq_status, + .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, +@@ -1261,6 +1278,7 @@ const struct stmmac_ops dwmac510_ops = { + .est_configure = dwmac5_est_configure, + .est_irq_status = dwmac5_est_irq_status, + .fpe_configure = dwmac5_fpe_configure, ++ .fpe_configure_get = dwmac5_fpe_configure_get, + .fpe_send_mpacket = dwmac5_fpe_send_mpacket, + .fpe_irq_status = dwmac5_fpe_irq_status, + .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +index e95d35f1e5a0..8633c0fa4c76 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +@@ -711,10 +711,15 @@ void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, + } + + void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, +- bool enable) ++ bool enable, struct stmmac_fpe *fpe) + { + u32 value; + ++ if (fpe) { ++ value = fpe->p_queues << MTL_FPECTRL_PEC_SHIFT | fpe->fragsize; ++ writel(value, ioaddr + MTL_FPE_CTRL_STS); ++ } ++ + if (!enable) { + value = readl(ioaddr + MAC_FPE_CTRL_STS); + +@@ -734,6 +739,18 @@ void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, + writel(value, ioaddr + MAC_FPE_CTRL_STS); + } + ++void dwmac5_fpe_configure_get(void __iomem *ioaddr, struct stmmac_fpe *fpe) ++{ ++ u32 value; ++ ++ value = readl(ioaddr + MAC_FPE_CTRL_STS); ++ fpe->enable = value & EFPE; ++ ++ value = readl(ioaddr + MTL_FPE_CTRL_STS); ++ fpe->p_queues = (value >> MTL_FPECTRL_PEC_SHIFT) & GENMASK(7, 0); ++ fpe->fragsize = value & GENMASK(1, 0); ++} ++ + int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev) + { + u32 value; +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h +index 53c138d0ff48..ead1f7d4dc19 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h +@@ -20,6 +20,9 @@ + #define SVER BIT(1) + #define EFPE BIT(0) + ++#define MTL_FPE_CTRL_STS 0x00000c90 ++#define MTL_FPECTRL_PEC_SHIFT 8 ++ + #define MAC_PPS_CONTROL 0x00000b70 + #define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1) + #define PPS_MINIDX(x) ((x) * 8) +@@ -154,7 +157,8 @@ int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, + void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, + struct stmmac_extra_stats *x, u32 txqcnt); + void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, +- bool enable); ++ bool enable, struct stmmac_fpe *fpe); ++void dwmac5_fpe_configure_get(void __iomem *ioaddr, struct stmmac_fpe *fpe); + void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, + enum stmmac_mpacket_type type); + int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev); +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +index c6c4d7948fe5..a004b2e5d2e3 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +@@ -1430,7 +1430,8 @@ static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, + } + + static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq, +- u32 num_rxq, bool enable) ++ u32 num_rxq, bool enable, ++ struct stmmac_fpe *fpe) + { + u32 value; + +diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h +index 156071275125..2cea77133e7f 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h ++++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h +@@ -279,6 +279,12 @@ struct stmmac_pps_cfg; + struct stmmac_rss; + struct stmmac_est; + ++struct stmmac_fpe { ++ u8 enable; ++ u8 p_queues; ++ u8 fragsize; ++}; ++ + /* Helpers to program the MAC core */ + struct stmmac_ops { + /* MAC core initialization */ +@@ -391,7 +397,8 @@ struct stmmac_ops { + void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev, + struct stmmac_extra_stats *x, u32 txqcnt); + void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, +- bool enable); ++ bool enable, struct stmmac_fpe *fpe); ++ void (*fpe_configure_get)(void __iomem *ioaddr, struct stmmac_fpe *fpe); + void (*fpe_send_mpacket)(void __iomem *ioaddr, + enum stmmac_mpacket_type type); + int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev); +@@ -495,6 +502,8 @@ struct stmmac_ops { + stmmac_do_void_callback(__priv, mac, est_irq_status, __args) + #define stmmac_fpe_configure(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, fpe_configure, __args) ++#define stmmac_fpe_configure_get(__priv, __args...) \ ++ stmmac_do_void_callback(__priv, mac, fpe_configure_get, __args) + #define stmmac_fpe_send_mpacket(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, fpe_send_mpacket, __args) + #define stmmac_fpe_irq_status(__priv, __args...) \ +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +index 782825822278..d07b173791e4 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +@@ -325,6 +325,7 @@ struct stmmac_priv { + /* XDP BPF Program */ + unsigned long *af_xdp_zc_qps; + struct bpf_prog *xdp_prog; ++ bool fp_enabled_admin; + }; + + enum stmmac_state { +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +index 35c8dd92d369..79988e61be69 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +@@ -19,6 +19,7 @@ + #include "stmmac.h" + #include "dwmac_dma.h" + #include "dwxgmac2.h" ++#include "common.h" + + #define REG_SPACE_SIZE 0x1060 + #define GMAC4_REG_SPACE_SIZE 0x116C +@@ -1149,6 +1150,105 @@ static int stmmac_set_tunable(struct net_device *dev, + return ret; + } + ++static int stmmac_reset_preempt(struct net_device *dev, bool enable) ++{ ++ struct stmmac_priv *priv = netdev_priv(dev); ++ struct stmmac_fpe_cfg *fpe_cfg = priv->plat->fpe_cfg; ++ bool *hs_enable = &fpe_cfg->hs_enable; ++ ++ if (enable) { ++ if (priv->fp_enabled_admin) { ++ priv->plat->fpe_cfg->enable = 1; ++ if (!*hs_enable) ++ stmmac_fpe_configure(priv, priv->ioaddr, priv->plat->tx_queues_to_use, ++ priv->plat->rx_queues_to_use, true, NULL); ++ } ++ } else { ++ priv->plat->fpe_cfg->enable = 0; ++ stmmac_fpe_configure(priv, priv->ioaddr, priv->plat->tx_queues_to_use, ++ priv->plat->rx_queues_to_use, false, NULL); ++ } ++ ++ return 0; ++} ++ ++static int stmmac_set_preempt(struct net_device *dev, struct ethtool_fp *fpcmd) ++{ ++ struct stmmac_priv *priv = netdev_priv(dev); ++ struct stmmac_fpe fpe; ++ ++ if (!priv->dma_cap.fpesel) ++ return -EOPNOTSUPP; ++ ++ if (!fpcmd->disabled && ++ (fpcmd->min_frag_size < 60 || fpcmd->min_frag_size > 252)) ++ return -EINVAL; ++ ++ fpe.p_queues = fpcmd->preemptible_queues_mask; ++ fpe.fragsize = DIV_ROUND_UP((fpcmd->min_frag_size + 4), 64) - 1; ++ ++ if (priv->plat->fpe_cfg->lo_fpe_state == FPE_STATE_ON) ++ fpe.enable = 1; ++ else ++ fpe.enable = fpcmd->fp_enabled ? 0 : 1; ++ ++ /* To support preemption MAC should have more than 1 TX queue with at ++ * least 1 Queue designated as Express Queue. Queue 0 is always used as ++ * preemption queue when preemption MAC is enabled. ++ */ ++ if (fpe.p_queues >= (GENMASK(priv->plat->tx_queues_to_use - 1, 0) - 1)) { ++ netdev_err(priv->dev, ++ "Preemptable queue mask 0x%x not supported.", ++ fpe.p_queues); ++ return -EINVAL; ++ } ++ ++ if (fpcmd->disabled) { ++ fpe.enable = 0; ++ priv->plat->fpe_cfg->enable = 0; ++ priv->fp_enabled_admin = 0; ++ } else { ++ priv->plat->fpe_cfg->enable = 1; ++ priv->fp_enabled_admin = 1; ++ } ++ stmmac_fpe_configure(priv, priv->ioaddr, priv->plat->tx_queues_to_use, ++ priv->plat->rx_queues_to_use, fpe.enable, &fpe); ++ ++ stmmac_fpe_handshake(priv, fpcmd->fp_enabled); ++ ++ return 0; ++} ++ ++static int stmmac_get_preempt(struct net_device *dev, struct ethtool_fp *fpcmd) ++{ ++ struct stmmac_priv *priv = netdev_priv(dev); ++ struct stmmac_fpe fpe; ++ int ret; ++ ++ ret = stmmac_fpe_configure_get(priv, priv->ioaddr, &fpe); ++ if (ret) { ++ fpcmd->fp_supported = 0; ++ fpcmd->supported_queues_mask = 0; ++ fpcmd->preemptible_queues_mask = 0; ++ fpcmd->min_frag_size = 0; ++ ++ return 0; ++ } ++ ++ fpcmd->fp_supported = 1; ++ fpcmd->fp_status = priv->plat->fpe_cfg->enable; ++ fpcmd->fp_active = fpe.enable; ++ fpcmd->supported_queues_mask = GENMASK(priv->plat->tx_queues_to_use - 1, ++ 0); ++ fpcmd->preemptible_queues_mask = fpe.p_queues; ++ /* Queue 0 is always preemption when preemption is active. */ ++ if (fpcmd->fp_active) ++ fpcmd->preemptible_queues_mask |= 1; ++ fpcmd->min_frag_size = (fpe.fragsize + 1) * 64 - 4; ++ ++ return 0; ++} ++ + static const struct ethtool_ops stmmac_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, +@@ -1188,6 +1288,9 @@ static const struct ethtool_ops stmmac_ethtool_ops = { + .set_tunable = stmmac_set_tunable, + .get_link_ksettings = stmmac_ethtool_get_link_ksettings, + .set_link_ksettings = stmmac_ethtool_set_link_ksettings, ++ .set_preempt = stmmac_set_preempt, ++ .get_preempt = stmmac_get_preempt, ++ .reset_preempt = stmmac_reset_preempt, + }; + + void stmmac_set_ethtool_ops(struct net_device *netdev) +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 72c0b874acee..63a0738ebdf2 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -956,11 +956,17 @@ static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up) + enum stmmac_fpe_state *lp_state = &fpe_cfg->lp_fpe_state; + bool *hs_enable = &fpe_cfg->hs_enable; + +- if (is_up && *hs_enable) { +- stmmac_fpe_send_mpacket(priv, priv->ioaddr, MPACKET_VERIFY); ++ if (is_up) { ++ if (*hs_enable) ++ stmmac_fpe_send_mpacket(priv, priv->ioaddr, MPACKET_VERIFY); + } else { + *lo_state = FPE_STATE_OFF; + *lp_state = FPE_STATE_OFF; ++ priv->plat->fpe_cfg->enable = false; ++ stmmac_fpe_configure(priv, priv->ioaddr, ++ priv->plat->tx_queues_to_use, ++ priv->plat->rx_queues_to_use, ++ false, NULL); + } + } + +@@ -2433,12 +2439,14 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) + /* We are sharing with slow path and stop XSK TX desc submission when + * available TX ring is less than threshold. + */ +- if (unlikely(stmmac_tx_avail(priv, queue) < STMMAC_TX_XSK_AVAIL) || +- !netif_carrier_ok(priv->dev)) { ++ if (unlikely(stmmac_tx_avail(priv, queue) < STMMAC_TX_XSK_AVAIL)) { + work_done = false; + break; + } + ++ if (!netif_carrier_ok(priv->dev)) ++ break; ++ + if (!xsk_tx_peek_desc(pool, &xdp_desc)) + break; + +@@ -6775,7 +6783,9 @@ static const struct net_device_ops stmmac_netdev_ops = { + .ndo_fix_features = stmmac_fix_features, + .ndo_set_features = stmmac_set_features, + .ndo_set_rx_mode = stmmac_set_rx_mode, ++#ifndef CONFIG_NET_SCH_MULTIQ + .ndo_tx_timeout = stmmac_tx_timeout, ++#endif + .ndo_eth_ioctl = stmmac_ioctl, + .ndo_setup_tc = stmmac_setup_tc, + .ndo_select_queue = stmmac_select_queue, +@@ -6928,6 +6938,7 @@ static void stmmac_napi_add(struct net_device *dev) + { + struct stmmac_priv *priv = netdev_priv(dev); + u32 queue, maxq; ++ char name[NAPINAMSIZ]; + + maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use); + +@@ -6939,16 +6950,22 @@ static void stmmac_napi_add(struct net_device *dev) + spin_lock_init(&ch->lock); + + if (queue < priv->plat->rx_queues_to_use) { +- netif_napi_add(dev, &ch->rx_napi, stmmac_napi_poll_rx); ++ snprintf(name, NAPINAMSIZ, "rx-%d", queue); ++ netif_napi_add_named(dev, &ch->rx_napi, stmmac_napi_poll_rx, ++ NAPI_POLL_WEIGHT, name); + } + if (queue < priv->plat->tx_queues_to_use) { +- netif_napi_add_tx(dev, &ch->tx_napi, +- stmmac_napi_poll_tx); ++ snprintf(name, NAPINAMSIZ, "tx-%d", queue); ++ netif_napi_add_tx_named(dev, &ch->tx_napi, ++ stmmac_napi_poll_tx, ++ NAPI_POLL_WEIGHT, name); + } + if (queue < priv->plat->rx_queues_to_use && + queue < priv->plat->tx_queues_to_use) { +- netif_napi_add(dev, &ch->rxtx_napi, +- stmmac_napi_poll_rxtx); ++ snprintf(name, NAPINAMSIZ, "zc-%d", queue); ++ netif_napi_add_named(dev, &ch->rxtx_napi, ++ stmmac_napi_poll_rxtx, ++ NAPI_POLL_WEIGHT, name); + } + } + } +@@ -7025,7 +7042,6 @@ static void stmmac_fpe_lp_task(struct work_struct *work) + enum stmmac_fpe_state *lo_state = &fpe_cfg->lo_fpe_state; + enum stmmac_fpe_state *lp_state = &fpe_cfg->lp_fpe_state; + bool *hs_enable = &fpe_cfg->hs_enable; +- bool *enable = &fpe_cfg->enable; + int retries = 20; + + while (retries-- > 0) { +@@ -7038,7 +7054,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work) + stmmac_fpe_configure(priv, priv->ioaddr, + priv->plat->tx_queues_to_use, + priv->plat->rx_queues_to_use, +- *enable); ++ true, NULL); + + netdev_info(priv->dev, "configured FPE\n"); + +@@ -7481,7 +7497,7 @@ int stmmac_suspend(struct device *dev) + /* Disable FPE */ + stmmac_fpe_configure(priv, priv->ioaddr, + priv->plat->tx_queues_to_use, +- priv->plat->rx_queues_to_use, false); ++ priv->plat->rx_queues_to_use, false, NULL); + + stmmac_fpe_handshake(priv, false); + stmmac_fpe_stop_wq(priv); +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +index 773e415cc2de..7c1759d99952 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +@@ -922,7 +922,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv, + struct plat_stmmacenet_data *plat = priv->plat; + struct timespec64 time, current_time, qopt_time; + ktime_t current_time_ns; +- bool fpe = false; ++ struct stmmac_fpe fpe; + int i, ret = 0; + u64 ctr; + +@@ -988,6 +988,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv, + priv->plat->est->enable = qopt->enable; + mutex_unlock(&priv->plat->est->lock); + ++ stmmac_fpe_configure_get(priv, priv->ioaddr, &fpe); ++ + for (i = 0; i < size; i++) { + s64 delta_ns = qopt->entries[i].interval; + u32 gates = qopt->entries[i].gate_mask; +@@ -999,16 +1001,18 @@ static int tc_setup_taprio(struct stmmac_priv *priv, + + switch (qopt->entries[i].command) { + case TC_TAPRIO_CMD_SET_GATES: +- if (fpe) ++ if (fpe.enable) + return -EINVAL; + break; + case TC_TAPRIO_CMD_SET_AND_HOLD: ++ if (!fpe.enable) ++ return -EINVAL; + gates |= BIT(0); +- fpe = true; + break; + case TC_TAPRIO_CMD_SET_AND_RELEASE: ++ if (!fpe.enable) ++ return -EINVAL; + gates &= ~BIT(0); +- fpe = true; + break; + default: + return -EOPNOTSUPP; +@@ -1035,16 +1039,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv, + priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC); + priv->plat->est->ctr[1] = (u32)ctr; + +- if (fpe && !priv->dma_cap.fpesel) { +- mutex_unlock(&priv->plat->est->lock); +- return -EOPNOTSUPP; +- } +- +- /* Actual FPE register configuration will be done after FPE handshake +- * is success. +- */ +- priv->plat->fpe_cfg->enable = fpe; +- + ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, + priv->plat->clk_ptp_rate); + mutex_unlock(&priv->plat->est->lock); +@@ -1055,11 +1049,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv, + + netdev_info(priv->dev, "configured EST\n"); + +- if (fpe) { +- stmmac_fpe_handshake(priv, true); +- netdev_info(priv->dev, "start FPE handshake\n"); +- } +- + return 0; + + disable: +@@ -1071,16 +1060,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv, + mutex_unlock(&priv->plat->est->lock); + } + +- priv->plat->fpe_cfg->enable = false; +- stmmac_fpe_configure(priv, priv->ioaddr, +- priv->plat->tx_queues_to_use, +- priv->plat->rx_queues_to_use, +- false); +- netdev_info(priv->dev, "disabled FPE\n"); +- +- stmmac_fpe_handshake(priv, false); +- netdev_info(priv->dev, "stop FPE handshake\n"); +- + return ret; + } + +diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +index 25466cbdc16b..450c20d65d19 100644 +--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c ++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +@@ -1376,12 +1376,12 @@ static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev, + + cpu_stats = per_cpu_ptr(ndev_priv->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + rx_packets = cpu_stats->rx_packets; + rx_bytes = cpu_stats->rx_bytes; + tx_packets = cpu_stats->tx_packets; + tx_bytes = cpu_stats->tx_bytes; +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c +index 758295c898ac..e966dd47e2db 100644 +--- a/drivers/net/ethernet/ti/cpsw_priv.c ++++ b/drivers/net/ethernet/ti/cpsw_priv.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "cpsw.h" + #include "cpts.h" +diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c +index 9eb9eaff4dc9..1bb596a9d8a2 100644 +--- a/drivers/net/ethernet/ti/netcp_core.c ++++ b/drivers/net/ethernet/ti/netcp_core.c +@@ -1916,16 +1916,16 @@ netcp_get_stats(struct net_device *ndev, struct rtnl_link_stats64 *stats) + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&p->syncp_rx); ++ start = u64_stats_fetch_begin(&p->syncp_rx); + rxpackets = p->rx_packets; + rxbytes = p->rx_bytes; +- } while (u64_stats_fetch_retry_irq(&p->syncp_rx, start)); ++ } while (u64_stats_fetch_retry(&p->syncp_rx, start)); + + do { +- start = u64_stats_fetch_begin_irq(&p->syncp_tx); ++ start = u64_stats_fetch_begin(&p->syncp_tx); + txpackets = p->tx_packets; + txbytes = p->tx_bytes; +- } while (u64_stats_fetch_retry_irq(&p->syncp_tx, start)); ++ } while (u64_stats_fetch_retry(&p->syncp_tx, start)); + + stats->rx_packets = rxpackets; + stats->rx_bytes = rxbytes; +diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c +index 0fb15a17b547..d716e6fe26e1 100644 +--- a/drivers/net/ethernet/via/via-rhine.c ++++ b/drivers/net/ethernet/via/via-rhine.c +@@ -2217,16 +2217,16 @@ rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + netdev_stats_to_stats64(stats, &dev->stats); + + do { +- start = u64_stats_fetch_begin_irq(&rp->rx_stats.syncp); ++ start = u64_stats_fetch_begin(&rp->rx_stats.syncp); + stats->rx_packets = rp->rx_stats.packets; + stats->rx_bytes = rp->rx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&rp->rx_stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&rp->rx_stats.syncp, start)); + + do { +- start = u64_stats_fetch_begin_irq(&rp->tx_stats.syncp); ++ start = u64_stats_fetch_begin(&rp->tx_stats.syncp); + stats->tx_packets = rp->tx_stats.packets; + stats->tx_bytes = rp->tx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&rp->tx_stats.syncp, start)); + } + + static void rhine_set_rx_mode(struct net_device *dev) +diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +index 420a73203ca1..ffc943a12762 100644 +--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c ++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +@@ -1305,16 +1305,16 @@ axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + netdev_stats_to_stats64(stats, &dev->stats); + + do { +- start = u64_stats_fetch_begin_irq(&lp->rx_stat_sync); ++ start = u64_stats_fetch_begin(&lp->rx_stat_sync); + stats->rx_packets = u64_stats_read(&lp->rx_packets); + stats->rx_bytes = u64_stats_read(&lp->rx_bytes); +- } while (u64_stats_fetch_retry_irq(&lp->rx_stat_sync, start)); ++ } while (u64_stats_fetch_retry(&lp->rx_stat_sync, start)); + + do { +- start = u64_stats_fetch_begin_irq(&lp->tx_stat_sync); ++ start = u64_stats_fetch_begin(&lp->tx_stat_sync); + stats->tx_packets = u64_stats_read(&lp->tx_packets); + stats->tx_bytes = u64_stats_read(&lp->tx_bytes); +- } while (u64_stats_fetch_retry_irq(&lp->tx_stat_sync, start)); ++ } while (u64_stats_fetch_retry(&lp->tx_stat_sync, start)); + } + + static const struct net_device_ops axienet_netdev_ops = { +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index 89eb4f179a3c..f9b219e6cd58 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -1264,12 +1264,12 @@ static void netvsc_get_vf_stats(struct net_device *net, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + rx_packets = stats->rx_packets; + tx_packets = stats->tx_packets; + rx_bytes = stats->rx_bytes; + tx_bytes = stats->tx_bytes; +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + tot->rx_packets += rx_packets; + tot->tx_packets += tx_packets; +@@ -1294,12 +1294,12 @@ static void netvsc_get_pcpu_stats(struct net_device *net, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + this_tot->vf_rx_packets = stats->rx_packets; + this_tot->vf_tx_packets = stats->tx_packets; + this_tot->vf_rx_bytes = stats->rx_bytes; + this_tot->vf_tx_bytes = stats->tx_bytes; +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + this_tot->rx_packets = this_tot->vf_rx_packets; + this_tot->tx_packets = this_tot->vf_tx_packets; + this_tot->rx_bytes = this_tot->vf_rx_bytes; +@@ -1318,20 +1318,20 @@ static void netvsc_get_pcpu_stats(struct net_device *net, + + tx_stats = &nvchan->tx_stats; + do { +- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); ++ start = u64_stats_fetch_begin(&tx_stats->syncp); + packets = tx_stats->packets; + bytes = tx_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); + + this_tot->tx_bytes += bytes; + this_tot->tx_packets += packets; + + rx_stats = &nvchan->rx_stats; + do { +- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); ++ start = u64_stats_fetch_begin(&rx_stats->syncp); + packets = rx_stats->packets; + bytes = rx_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); + + this_tot->rx_bytes += bytes; + this_tot->rx_packets += packets; +@@ -1370,21 +1370,21 @@ static void netvsc_get_stats64(struct net_device *net, + + tx_stats = &nvchan->tx_stats; + do { +- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); ++ start = u64_stats_fetch_begin(&tx_stats->syncp); + packets = tx_stats->packets; + bytes = tx_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); + + t->tx_bytes += bytes; + t->tx_packets += packets; + + rx_stats = &nvchan->rx_stats; + do { +- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); ++ start = u64_stats_fetch_begin(&rx_stats->syncp); + packets = rx_stats->packets; + bytes = rx_stats->bytes; + multicast = rx_stats->multicast + rx_stats->broadcast; +- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); + + t->rx_bytes += bytes; + t->rx_packets += packets; +@@ -1527,24 +1527,24 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, + tx_stats = &nvdev->chan_table[j].tx_stats; + + do { +- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); ++ start = u64_stats_fetch_begin(&tx_stats->syncp); + packets = tx_stats->packets; + bytes = tx_stats->bytes; + xdp_xmit = tx_stats->xdp_xmit; +- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); + data[i++] = packets; + data[i++] = bytes; + data[i++] = xdp_xmit; + + rx_stats = &nvdev->chan_table[j].rx_stats; + do { +- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); ++ start = u64_stats_fetch_begin(&rx_stats->syncp); + packets = rx_stats->packets; + bytes = rx_stats->bytes; + xdp_drop = rx_stats->xdp_drop; + xdp_redirect = rx_stats->xdp_redirect; + xdp_tx = rx_stats->xdp_tx; +- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); + data[i++] = packets; + data[i++] = bytes; + data[i++] = xdp_drop; +diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c +index 1c64d5347b8e..78253ad57b2e 100644 +--- a/drivers/net/ifb.c ++++ b/drivers/net/ifb.c +@@ -162,18 +162,18 @@ static void ifb_stats64(struct net_device *dev, + + for (i = 0; i < dev->num_tx_queues; i++,txp++) { + do { +- start = u64_stats_fetch_begin_irq(&txp->rx_stats.sync); ++ start = u64_stats_fetch_begin(&txp->rx_stats.sync); + packets = txp->rx_stats.packets; + bytes = txp->rx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&txp->rx_stats.sync, start)); ++ } while (u64_stats_fetch_retry(&txp->rx_stats.sync, start)); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + + do { +- start = u64_stats_fetch_begin_irq(&txp->tx_stats.sync); ++ start = u64_stats_fetch_begin(&txp->tx_stats.sync); + packets = txp->tx_stats.packets; + bytes = txp->tx_stats.bytes; +- } while (u64_stats_fetch_retry_irq(&txp->tx_stats.sync, start)); ++ } while (u64_stats_fetch_retry(&txp->tx_stats.sync, start)); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } +@@ -245,12 +245,12 @@ static void ifb_fill_stats_data(u64 **data, + int j; + + do { +- start = u64_stats_fetch_begin_irq(&q_stats->sync); ++ start = u64_stats_fetch_begin(&q_stats->sync); + for (j = 0; j < IFB_Q_STATS_LEN; j++) { + offset = ifb_q_stats_desc[j].offset; + (*data)[j] = *(u64 *)(stats_base + offset); + } +- } while (u64_stats_fetch_retry_irq(&q_stats->sync, start)); ++ } while (u64_stats_fetch_retry(&q_stats->sync, start)); + + *data += IFB_Q_STATS_LEN; + } +diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c +index cd16bc8bf154..1b55928e89b8 100644 +--- a/drivers/net/ipvlan/ipvlan_main.c ++++ b/drivers/net/ipvlan/ipvlan_main.c +@@ -301,13 +301,13 @@ static void ipvlan_get_stats64(struct net_device *dev, + for_each_possible_cpu(idx) { + pcptr = per_cpu_ptr(ipvlan->pcpu_stats, idx); + do { +- strt= u64_stats_fetch_begin_irq(&pcptr->syncp); ++ strt = u64_stats_fetch_begin(&pcptr->syncp); + rx_pkts = u64_stats_read(&pcptr->rx_pkts); + rx_bytes = u64_stats_read(&pcptr->rx_bytes); + rx_mcast = u64_stats_read(&pcptr->rx_mcast); + tx_pkts = u64_stats_read(&pcptr->tx_pkts); + tx_bytes = u64_stats_read(&pcptr->tx_bytes); +- } while (u64_stats_fetch_retry_irq(&pcptr->syncp, ++ } while (u64_stats_fetch_retry(&pcptr->syncp, + strt)); + + s->rx_packets += rx_pkts; +diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c +index 2e9742952c4e..f6d53e63ef4e 100644 +--- a/drivers/net/loopback.c ++++ b/drivers/net/loopback.c +@@ -106,10 +106,10 @@ void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes) + + lb_stats = per_cpu_ptr(dev->lstats, i); + do { +- start = u64_stats_fetch_begin_irq(&lb_stats->syncp); ++ start = u64_stats_fetch_begin(&lb_stats->syncp); + tpackets = u64_stats_read(&lb_stats->packets); + tbytes = u64_stats_read(&lb_stats->bytes); +- } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&lb_stats->syncp, start)); + *bytes += tbytes; + *packets += tpackets; + } +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index 578f470e9fad..2de422ab3e6a 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -2800,9 +2800,9 @@ static void get_rx_sc_stats(struct net_device *dev, + + stats = per_cpu_ptr(rx_sc->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + memcpy(&tmp, &stats->stats, sizeof(tmp)); +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + sum->InOctetsValidated += tmp.InOctetsValidated; + sum->InOctetsDecrypted += tmp.InOctetsDecrypted; +@@ -2881,9 +2881,9 @@ static void get_tx_sc_stats(struct net_device *dev, + + stats = per_cpu_ptr(macsec_priv(dev)->secy.tx_sc.stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + memcpy(&tmp, &stats->stats, sizeof(tmp)); +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + sum->OutPktsProtected += tmp.OutPktsProtected; + sum->OutPktsEncrypted += tmp.OutPktsEncrypted; +@@ -2937,9 +2937,9 @@ static void get_secy_stats(struct net_device *dev, struct macsec_dev_stats *sum) + + stats = per_cpu_ptr(macsec_priv(dev)->stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + memcpy(&tmp, &stats->stats, sizeof(tmp)); +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + sum->OutPktsUntagged += tmp.OutPktsUntagged; + sum->InPktsUntagged += tmp.InPktsUntagged; +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index b8cc55b2d721..99a971929c8e 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -948,13 +948,13 @@ static void macvlan_dev_get_stats64(struct net_device *dev, + for_each_possible_cpu(i) { + p = per_cpu_ptr(vlan->pcpu_stats, i); + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + rx_packets = u64_stats_read(&p->rx_packets); + rx_bytes = u64_stats_read(&p->rx_bytes); + rx_multicast = u64_stats_read(&p->rx_multicast); + tx_packets = u64_stats_read(&p->tx_packets); + tx_bytes = u64_stats_read(&p->tx_bytes); +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +diff --git a/drivers/net/mhi_net.c b/drivers/net/mhi_net.c +index 0b9d37979133..3d322ac4f6a5 100644 +--- a/drivers/net/mhi_net.c ++++ b/drivers/net/mhi_net.c +@@ -104,19 +104,19 @@ static void mhi_ndo_get_stats64(struct net_device *ndev, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&mhi_netdev->stats.rx_syncp); ++ start = u64_stats_fetch_begin(&mhi_netdev->stats.rx_syncp); + stats->rx_packets = u64_stats_read(&mhi_netdev->stats.rx_packets); + stats->rx_bytes = u64_stats_read(&mhi_netdev->stats.rx_bytes); + stats->rx_errors = u64_stats_read(&mhi_netdev->stats.rx_errors); +- } while (u64_stats_fetch_retry_irq(&mhi_netdev->stats.rx_syncp, start)); ++ } while (u64_stats_fetch_retry(&mhi_netdev->stats.rx_syncp, start)); + + do { +- start = u64_stats_fetch_begin_irq(&mhi_netdev->stats.tx_syncp); ++ start = u64_stats_fetch_begin(&mhi_netdev->stats.tx_syncp); + stats->tx_packets = u64_stats_read(&mhi_netdev->stats.tx_packets); + stats->tx_bytes = u64_stats_read(&mhi_netdev->stats.tx_bytes); + stats->tx_errors = u64_stats_read(&mhi_netdev->stats.tx_errors); + stats->tx_dropped = u64_stats_read(&mhi_netdev->stats.tx_dropped); +- } while (u64_stats_fetch_retry_irq(&mhi_netdev->stats.tx_syncp, start)); ++ } while (u64_stats_fetch_retry(&mhi_netdev->stats.tx_syncp, start)); + } + + static const struct net_device_ops mhi_netdev_ops = { +diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c +index 9a1a5b203624..e470e3398abc 100644 +--- a/drivers/net/netdevsim/netdev.c ++++ b/drivers/net/netdevsim/netdev.c +@@ -67,10 +67,10 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&ns->syncp); ++ start = u64_stats_fetch_begin(&ns->syncp); + stats->tx_bytes = ns->tx_bytes; + stats->tx_packets = ns->tx_packets; +- } while (u64_stats_fetch_retry_irq(&ns->syncp, start)); ++ } while (u64_stats_fetch_retry(&ns->syncp, start)); + } + + static int +diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c +index 95f07cf7b37c..1c72733f6824 100644 +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -36,7 +36,8 @@ + #include + #include + +-#define PHY_STATE_TIME HZ ++#define PHY_STATE_TIME HZ ++#define PHY_STATE_TIME_MS 100 + + #define PHY_STATE_STR(_state) \ + case PHY_##_state: \ +@@ -1281,7 +1282,7 @@ void phy_state_machine(struct work_struct *work) + */ + mutex_lock(&phydev->lock); + if (phy_polling_mode(phydev) && phy_is_started(phydev)) +- phy_queue_state_machine(phydev, PHY_STATE_TIME); ++ phy_queue_state_machine(phydev, (PHY_STATE_TIME_MS * HZ) / 1000); + mutex_unlock(&phydev->lock); + } + +diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c +index 921ca59822b0..382756c3fb83 100644 +--- a/drivers/net/team/team.c ++++ b/drivers/net/team/team.c +@@ -1866,13 +1866,13 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + for_each_possible_cpu(i) { + p = per_cpu_ptr(team->pcpu_stats, i); + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + rx_packets = u64_stats_read(&p->rx_packets); + rx_bytes = u64_stats_read(&p->rx_bytes); + rx_multicast = u64_stats_read(&p->rx_multicast); + tx_packets = u64_stats_read(&p->tx_packets); + tx_bytes = u64_stats_read(&p->tx_bytes); +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c +index b095a4b4957b..18d99fda997c 100644 +--- a/drivers/net/team/team_mode_loadbalance.c ++++ b/drivers/net/team/team_mode_loadbalance.c +@@ -466,9 +466,9 @@ static void __lb_one_cpu_stats_add(struct lb_stats *acc_stats, + struct lb_stats tmp; + + do { +- start = u64_stats_fetch_begin_irq(syncp); ++ start = u64_stats_fetch_begin(syncp); + tmp.tx_bytes = cpu_stats->tx_bytes; +- } while (u64_stats_fetch_retry_irq(syncp, start)); ++ } while (u64_stats_fetch_retry(syncp, start)); + acc_stats->tx_bytes += tmp.tx_bytes; + } + +diff --git a/drivers/net/veth.c b/drivers/net/veth.c +index 36c5a41f84e4..605f511a886c 100644 +--- a/drivers/net/veth.c ++++ b/drivers/net/veth.c +@@ -182,12 +182,12 @@ static void veth_get_ethtool_stats(struct net_device *dev, + size_t offset; + + do { +- start = u64_stats_fetch_begin_irq(&rq_stats->syncp); ++ start = u64_stats_fetch_begin(&rq_stats->syncp); + for (j = 0; j < VETH_RQ_STATS_LEN; j++) { + offset = veth_rq_stats_desc[j].offset; + data[idx + j] = *(u64 *)(stats_base + offset); + } +- } while (u64_stats_fetch_retry_irq(&rq_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rq_stats->syncp, start)); + idx += VETH_RQ_STATS_LEN; + } + +@@ -203,12 +203,12 @@ static void veth_get_ethtool_stats(struct net_device *dev, + + tx_idx += (i % dev->real_num_tx_queues) * VETH_TQ_STATS_LEN; + do { +- start = u64_stats_fetch_begin_irq(&rq_stats->syncp); ++ start = u64_stats_fetch_begin(&rq_stats->syncp); + for (j = 0; j < VETH_TQ_STATS_LEN; j++) { + offset = veth_tq_stats_desc[j].offset; + data[tx_idx + j] += *(u64 *)(base + offset); + } +- } while (u64_stats_fetch_retry_irq(&rq_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rq_stats->syncp, start)); + } + } + +@@ -381,13 +381,13 @@ static void veth_stats_rx(struct veth_stats *result, struct net_device *dev) + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + peer_tq_xdp_xmit_err = stats->vs.peer_tq_xdp_xmit_err; + xdp_tx_err = stats->vs.xdp_tx_err; + packets = stats->vs.xdp_packets; + bytes = stats->vs.xdp_bytes; + drops = stats->vs.rx_drops; +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + result->peer_tq_xdp_xmit_err += peer_tq_xdp_xmit_err; + result->xdp_tx_err += xdp_tx_err; + result->xdp_packets += packets; +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 21d3461fb5d1..666622ae4b9d 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -2107,18 +2107,18 @@ static void virtnet_stats(struct net_device *dev, + struct send_queue *sq = &vi->sq[i]; + + do { +- start = u64_stats_fetch_begin_irq(&sq->stats.syncp); ++ start = u64_stats_fetch_begin(&sq->stats.syncp); + tpackets = sq->stats.packets; + tbytes = sq->stats.bytes; + terrors = sq->stats.tx_timeouts; +- } while (u64_stats_fetch_retry_irq(&sq->stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); + + do { +- start = u64_stats_fetch_begin_irq(&rq->stats.syncp); ++ start = u64_stats_fetch_begin(&rq->stats.syncp); + rpackets = rq->stats.packets; + rbytes = rq->stats.bytes; + rdrops = rq->stats.drops; +- } while (u64_stats_fetch_retry_irq(&rq->stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&rq->stats.syncp, start)); + + tot->rx_packets += rpackets; + tot->tx_packets += tpackets; +@@ -2726,12 +2726,12 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, + + stats_base = (u8 *)&rq->stats; + do { +- start = u64_stats_fetch_begin_irq(&rq->stats.syncp); ++ start = u64_stats_fetch_begin(&rq->stats.syncp); + for (j = 0; j < VIRTNET_RQ_STATS_LEN; j++) { + offset = virtnet_rq_stats_desc[j].offset; + data[idx + j] = *(u64 *)(stats_base + offset); + } +- } while (u64_stats_fetch_retry_irq(&rq->stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&rq->stats.syncp, start)); + idx += VIRTNET_RQ_STATS_LEN; + } + +@@ -2740,12 +2740,12 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, + + stats_base = (u8 *)&sq->stats; + do { +- start = u64_stats_fetch_begin_irq(&sq->stats.syncp); ++ start = u64_stats_fetch_begin(&sq->stats.syncp); + for (j = 0; j < VIRTNET_SQ_STATS_LEN; j++) { + offset = virtnet_sq_stats_desc[j].offset; + data[idx + j] = *(u64 *)(stats_base + offset); + } +- } while (u64_stats_fetch_retry_irq(&sq->stats.syncp, start)); ++ } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); + idx += VIRTNET_SQ_STATS_LEN; + } + } +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index f6dcec66f0a4..bdb3a76a352e 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -159,13 +159,13 @@ static void vrf_get_stats64(struct net_device *dev, + + dstats = per_cpu_ptr(dev->dstats, i); + do { +- start = u64_stats_fetch_begin_irq(&dstats->syncp); ++ start = u64_stats_fetch_begin(&dstats->syncp); + tbytes = dstats->tx_bytes; + tpkts = dstats->tx_pkts; + tdrops = dstats->tx_drps; + rbytes = dstats->rx_bytes; + rpkts = dstats->rx_pkts; +- } while (u64_stats_fetch_retry_irq(&dstats->syncp, start)); ++ } while (u64_stats_fetch_retry(&dstats->syncp, start)); + stats->tx_bytes += tbytes; + stats->tx_packets += tpkts; + stats->tx_dropped += tdrops; +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index c5cf55030158..c3ff30ab782e 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -129,9 +129,9 @@ static void vxlan_vnifilter_stats_get(const struct vxlan_vni_node *vninode, + + pstats = per_cpu_ptr(vninode->stats, i); + do { +- start = u64_stats_fetch_begin_irq(&pstats->syncp); ++ start = u64_stats_fetch_begin(&pstats->syncp); + memcpy(&temp, &pstats->stats, sizeof(temp)); +- } while (u64_stats_fetch_retry_irq(&pstats->syncp, start)); ++ } while (u64_stats_fetch_retry(&pstats->syncp, start)); + + dest->rx_packets += temp.rx_packets; + dest->rx_bytes += temp.rx_bytes; +diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c +index ef70bb7c88ad..3f72ae943b29 100644 +--- a/drivers/net/wwan/mhi_wwan_mbim.c ++++ b/drivers/net/wwan/mhi_wwan_mbim.c +@@ -456,19 +456,19 @@ static void mhi_mbim_ndo_get_stats64(struct net_device *ndev, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&link->rx_syncp); ++ start = u64_stats_fetch_begin(&link->rx_syncp); + stats->rx_packets = u64_stats_read(&link->rx_packets); + stats->rx_bytes = u64_stats_read(&link->rx_bytes); + stats->rx_errors = u64_stats_read(&link->rx_errors); +- } while (u64_stats_fetch_retry_irq(&link->rx_syncp, start)); ++ } while (u64_stats_fetch_retry(&link->rx_syncp, start)); + + do { +- start = u64_stats_fetch_begin_irq(&link->tx_syncp); ++ start = u64_stats_fetch_begin(&link->tx_syncp); + stats->tx_packets = u64_stats_read(&link->tx_packets); + stats->tx_bytes = u64_stats_read(&link->tx_bytes); + stats->tx_errors = u64_stats_read(&link->tx_errors); + stats->tx_dropped = u64_stats_read(&link->tx_dropped); +- } while (u64_stats_fetch_retry_irq(&link->tx_syncp, start)); ++ } while (u64_stats_fetch_retry(&link->tx_syncp, start)); + } + + static void mhi_mbim_ul_callback(struct mhi_device *mhi_dev, +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index dc404e05970c..14aec417fa06 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -1392,16 +1392,16 @@ static void xennet_get_stats64(struct net_device *dev, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); ++ start = u64_stats_fetch_begin(&tx_stats->syncp); + tx_packets = tx_stats->packets; + tx_bytes = tx_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); + + do { +- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); ++ start = u64_stats_fetch_begin(&rx_stats->syncp); + rx_packets = rx_stats->packets; + rx_bytes = rx_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); + + tot->rx_packets += rx_packets; + tot->tx_packets += tx_packets; +diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig +index 288c6f1c6979..64d3846b93be 100644 +--- a/drivers/nfc/Kconfig ++++ b/drivers/nfc/Kconfig +@@ -60,6 +60,7 @@ config NFC_VIRTUAL_NCI + + If unsure, say N. + ++source "drivers/nfc/pn5xx/Kconfig" + source "drivers/nfc/fdp/Kconfig" + source "drivers/nfc/pn544/Kconfig" + source "drivers/nfc/pn533/Kconfig" +diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile +index 7b1bfde1d971..62d495c57a15 100644 +--- a/drivers/nfc/Makefile ++++ b/drivers/nfc/Makefile +@@ -3,6 +3,7 @@ + # Makefile for nfc devices + # + ++obj-$(CONFIG_NFC_NXP_PN5XX) += pn5xx/ + obj-$(CONFIG_NFC_FDP) += fdp/ + obj-$(CONFIG_NFC_PN544) += pn544/ + obj-$(CONFIG_NFC_MICROREAD) += microread/ +diff --git a/drivers/nfc/pn5xx/Kconfig b/drivers/nfc/pn5xx/Kconfig +new file mode 100644 +index 000000000000..10db8c403866 +--- /dev/null ++++ b/drivers/nfc/pn5xx/Kconfig +@@ -0,0 +1,12 @@ ++config NFC_NXP_PN5XX ++ tristate "NXP PN5XX based driver" ++ depends on I2C ++ select CRC_CCITT ++ help ++ NXP PN5XX driver based on I2C. ++ This is a driver to provides I2C access to PN5xx and PN7120 NFC ++ Controller devices ++ ++ To compile this driver as a module, choose m here. The module will ++ be called pn5xx_i2c. ++ Say N if unsure. +diff --git a/drivers/nfc/pn5xx/Makefile b/drivers/nfc/pn5xx/Makefile +new file mode 100644 +index 000000000000..b31bbb51423a +--- /dev/null ++++ b/drivers/nfc/pn5xx/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# Makefile for PN5xx NFC driver ++# ++ ++obj-$(CONFIG_NFC_NXP_PN5XX) += pn5xx_i2c.o +diff --git a/drivers/nfc/pn5xx/README.md b/drivers/nfc/pn5xx/README.md +new file mode 100644 +index 000000000000..c0c8d5c73757 +--- /dev/null ++++ b/drivers/nfc/pn5xx/README.md +@@ -0,0 +1,2 @@ ++# nxp-pn5xx ++NXP's NFC Open Source Kernel mode driver +diff --git a/drivers/nfc/pn5xx/pn5xx_i2c.c b/drivers/nfc/pn5xx/pn5xx_i2c.c +new file mode 100644 +index 000000000000..3511f1441cf6 +--- /dev/null ++++ b/drivers/nfc/pn5xx/pn5xx_i2c.c +@@ -0,0 +1,672 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2010 Trusted Logic S.A. ++ * Copyright 2015,2019-2023 NXP ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pn5xx_i2c.h" ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define MAX_BUFFER_SIZE 512 ++ ++#define MODE_OFF 0 ++#define MODE_RUN 1 ++#define MODE_FW 2 ++ ++/* pn7120, pn548, pn547 and pn544 are supported */ ++#define CHIP "pn544" ++#define DRIVER_CARD "PN54x NFC" ++#define DRIVER_DESC "NFC driver for PN54x Family" ++ ++#ifndef CONFIG_OF ++#define CONFIG_OF ++#endif ++ ++struct pn54x_dev { ++ wait_queue_head_t read_wq; ++ struct mutex read_mutex; ++ struct i2c_client *client; ++ struct miscdevice pn54x_device; ++ int ven_gpio; ++ int firm_gpio; ++ int irq_gpio; ++ int clkreq_gpio; ++ struct regulator *pvdd_reg; ++ struct regulator *vbat_reg; ++ struct regulator *pmuvcc_reg; ++ struct regulator *sevdd_reg; ++ bool irq_enabled; ++ spinlock_t irq_enabled_lock; ++}; ++ ++static struct task_struct *test_task; ++/* Interrupt control and handler */ ++static void pn54x_disable_irq(struct pn54x_dev *pn54x_dev) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pn54x_dev->irq_enabled_lock, flags); ++ if (pn54x_dev->irq_enabled) { ++ disable_irq_nosync(pn54x_dev->client->irq); ++ pn54x_dev->irq_enabled = false; ++ } ++ spin_unlock_irqrestore(&pn54x_dev->irq_enabled_lock, flags); ++} ++ ++static irqreturn_t pn54x_dev_irq_handler(int irq, void *dev_id) ++{ ++ struct pn54x_dev *pn54x_dev = dev_id; ++ ++ pn54x_disable_irq(pn54x_dev); ++ ++ /* Wake up waiting readers */ ++ wake_up(&pn54x_dev->read_wq); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct pn54x_dev *gpn54x_dev = NULL; ++static int pn54x_dev_loop_handler(void *data) ++{ ++ struct pn54x_dev *pn54x_dev = (struct pn54x_dev *)gpn54x_dev; ++ ++ printk("In pn54x_dev_loop_handler...%x \n", data); ++ while (1) { ++ /* Wake up waiting readers */ ++ wake_up(&pn54x_dev->read_wq); ++ msleep(200); ++ } ++ ++ return 0; ++} ++ ++/* private functions */ ++static int pn544_enable(struct pn54x_dev *dev, int mode) ++{ ++ int r; ++ ++ /* ++ * turn on the regulators ++ * -- if the regulators were specified, they're required ++ */ ++ if (dev->pvdd_reg != NULL) { ++ r = regulator_enable(dev->pvdd_reg); ++ if (r < 0) { ++ pr_err("%s: not able to enable pvdd\n", __func__); ++ return r; ++ } ++ } ++ if (dev->vbat_reg != NULL) { ++ r = regulator_enable(dev->vbat_reg); ++ if (r < 0) { ++ pr_err("%s: not able to enable vbat\n", __func__); ++ goto enable_exit0; ++ } ++ } ++ if (dev->pmuvcc_reg != NULL) { ++ r = regulator_enable(dev->pmuvcc_reg); ++ if (r < 0) { ++ pr_err("%s: not able to enable pmuvcc\n", __func__); ++ goto enable_exit1; ++ } ++ } ++ if (dev->sevdd_reg != NULL) { ++ r = regulator_enable(dev->sevdd_reg); ++ if (r < 0) { ++ pr_err("%s: not able to enable sevdd\n", __func__); ++ goto enable_exit2; ++ } ++ } ++ ++ if (MODE_RUN == mode) { ++ printk("%s power on\n", __func__); ++ if (gpio_is_valid(dev->firm_gpio)) ++ gpio_set_value_cansleep(dev->firm_gpio, 0); ++ msleep(100); ++ } else if (MODE_FW == mode) { ++ /* power on with firmware download (requires hw reset) */ ++ pr_info("%s power on with firmware\n", __func__); ++ msleep(20); ++ if (gpio_is_valid(dev->firm_gpio)) { ++ gpio_set_value(dev->firm_gpio, 1); ++ } else { ++ pr_err("%s Unused Firm GPIO %d\n", __func__, mode); ++ return GPIO_UNUSED; ++ } ++ msleep(20); ++ msleep(100); ++ msleep(20); ++ } else { ++ pr_err("%s bad arg %d\n", __func__, mode); ++ return -EINVAL; ++ } ++ ++ return 0; ++ ++enable_exit2: ++ if (dev->pmuvcc_reg) ++ regulator_disable(dev->pmuvcc_reg); ++enable_exit1: ++ if (dev->vbat_reg) ++ regulator_disable(dev->vbat_reg); ++enable_exit0: ++ if (dev->pvdd_reg) ++ regulator_disable(dev->pvdd_reg); ++ ++ return r; ++} ++ ++static void pn544_disable(struct pn54x_dev *dev) ++{ ++ /* power off */ ++ printk("%s power off\n", __func__); ++ if (gpio_is_valid(dev->firm_gpio)) ++ gpio_set_value_cansleep(dev->firm_gpio, 0); ++ msleep(100); ++ ++ if (dev->sevdd_reg) ++ regulator_disable(dev->sevdd_reg); ++ if (dev->pmuvcc_reg) ++ regulator_disable(dev->pmuvcc_reg); ++ if (dev->vbat_reg) ++ regulator_disable(dev->vbat_reg); ++ if (dev->pvdd_reg) ++ regulator_disable(dev->pvdd_reg); ++} ++ ++/* driver functions */ ++static ssize_t pn54x_dev_read(struct file *filp, char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ struct pn54x_dev *pn54x_dev = filp->private_data; ++ char tmp[MAX_BUFFER_SIZE]; ++ int ret; ++ ++ if (count > MAX_BUFFER_SIZE) ++ count = MAX_BUFFER_SIZE; ++ ++ mutex_lock(&pn54x_dev->read_mutex); ++ ++ /* Read data */ ++ ret = i2c_master_recv(pn54x_dev->client, tmp, count); ++ ++ mutex_unlock(&pn54x_dev->read_mutex); ++ ++ /* ++ * pn54x seems to be slow in handling I2C read requests ++ * so add 1ms delay after recv operation ++ */ ++ udelay(1000); ++ ++ if (ret < 0) ++ return ret; ++ ++ if (ret > count) { ++ pr_err("%s: received too many bytes from i2c (%d)\n", ++ __func__, ret); ++ return -EIO; ++ } ++ if (copy_to_user(buf, tmp, ret)) { ++ pr_err("%s : failed to copy to user space\n", __func__); ++ return -EFAULT; ++ } ++ return ret; ++ ++fail: ++ mutex_unlock(&pn54x_dev->read_mutex); ++ return ret; ++} ++ ++static ssize_t pn54x_dev_write(struct file *filp, const char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ struct pn54x_dev *pn54x_dev; ++ char tmp[MAX_BUFFER_SIZE]; ++ int ret; ++ ++ pn54x_dev = filp->private_data; ++ ++ if (count > MAX_BUFFER_SIZE) ++ count = MAX_BUFFER_SIZE; ++ ++ if (copy_from_user(tmp, buf, count)) { ++ pr_err("%s : failed to copy from user space\n", __func__); ++ return -EFAULT; ++ } ++ ++ pr_debug("%s : writing %zu bytes.\n", __func__, count); ++ /* Write data */ ++ ret = i2c_master_send(pn54x_dev->client, tmp, count); ++ if (ret != count) { ++ pr_err("%s : i2c_master_send returned %d\n", __func__, ret); ++ pr_err("I2C addr is 0x%02X, name is %s\n", ++ pn54x_dev->client->addr, pn54x_dev->client->name); ++ ret = -EIO; ++ } ++ ++ /* ++ * pn54x seems to be slow in handling I2C write requests ++ * so add 1ms delay after I2C send oparation ++ */ ++ udelay(1000); ++ ++ return ret; ++} ++ ++static int pn54x_dev_open(struct inode *inode, struct file *filp) ++{ ++ struct pn54x_dev *pn54x_dev = container_of(filp->private_data, ++ struct pn54x_dev, ++ pn54x_device); ++ ++ filp->private_data = pn54x_dev; ++ ++ pr_info("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); ++ ++ return 0; ++} ++ ++static int pn54x_dev_release(struct inode *inode, struct file *filp) ++{ ++ pr_info("%s : closing %d,%d\n", __func__, imajor(inode), iminor(inode)); ++ ++ return 0; ++} ++ ++static long pn54x_dev_ioctl(struct file *filp, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct pn54x_dev *pn54x_dev = filp->private_data; ++ ++ pr_info("%s, cmd=%d, arg=%lu\n", __func__, cmd, arg); ++ switch (cmd) { ++ case PN544_SET_PWR: ++ if (arg == 2) { ++ /* power on w/FW */ ++ if (pn544_enable(pn54x_dev, arg) == GPIO_UNUSED) ++ return GPIO_UNUSED; ++ } else if (arg == 1) { ++ /* power on */ ++ pn544_enable(pn54x_dev, arg); ++ } else if (arg == 0) { ++ /* power off */ ++ pn544_disable(pn54x_dev); ++ } else { ++ pr_err("%s bad SET_PWR arg %lu\n", __func__, arg); ++ return -EINVAL; ++ } ++ break; ++ case PN54X_CLK_REQ: ++ if (arg == 1) { ++ if (gpio_is_valid(pn54x_dev->clkreq_gpio)) { ++ gpio_set_value(pn54x_dev->clkreq_gpio, 1); ++ } else { ++ pr_err("%s Unused Clkreq GPIO %lu\n", ++ __func__, arg); ++ return GPIO_UNUSED; ++ } ++ } else if (arg == 0) { ++ if (gpio_is_valid(pn54x_dev->clkreq_gpio)) { ++ gpio_set_value(pn54x_dev->clkreq_gpio, 0); ++ } else { ++ pr_err("%s Unused Clkreq GPIO %lu\n", ++ __func__, arg); ++ return GPIO_UNUSED; ++ } ++ } else { ++ pr_err("%s bad CLK_REQ arg %lu\n", __func__, arg); ++ return -EINVAL; ++ } ++ break; ++ default: ++ pr_err("%s bad ioctl %u\n", __func__, cmd); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct file_operations pn54x_dev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = pn54x_dev_read, ++ .write = pn54x_dev_write, ++ .open = pn54x_dev_open, ++ .release = pn54x_dev_release, ++ .unlocked_ioctl = pn54x_dev_ioctl, ++}; ++ ++/* Handlers for alternative sources of platform_data */ ++#ifdef CONFIG_OF ++/* Translate OpenFirmware node properties into platform_data */ ++static int pn54x_get_pdata(struct device *dev, ++ struct pn544_i2c_platform_data *pdata) ++{ ++ struct device_node *node; ++ u32 flags; ++ int val; ++ ++ /* make sure there is actually a device tree node */ ++ node = dev->of_node; ++ if (!node) ++ return -ENODEV; ++ ++ memset(pdata, 0, sizeof(*pdata)); ++ ++ /* ++ * read the dev tree data ++ * firm pin - controls firmware download - OPTIONAL ++ */ ++ val = of_get_named_gpio_flags(node, "firmware-gpios", 0, &flags); ++ if (val >= 0) { ++ pdata->firm_gpio = val; ++ } else { ++ pdata->firm_gpio = GPIO_UNUSED; ++ dev_warn(dev, "FIRM GPIO error getting from OF node\n"); ++ } ++ ++ /* clkreq pin - controls the clock to the PN547 - OPTIONAL */ ++ val = of_get_named_gpio_flags(node, "nxp,pn54x-clkreq", 0, &flags); ++ if (val >= 0) { ++ pdata->clkreq_gpio = val; ++ } else { ++ pdata->clkreq_gpio = GPIO_UNUSED; ++ dev_warn(dev, ++ "CLKREQ GPIO error getting from OF node\n"); ++ } ++ ++ /* ++ * handle the regulator lines - these are optional ++ * PVdd - pad Vdd (544, 547) ++ * Vbat - Battery (544, 547) ++ * PMUVcc - UICC Power (544, 547) ++ * SEVdd - SE Power (544) ++ * ++ * Will attempt to load a matching Regulator Resource for each ++ * If no resource is provided, then the input will not be controlled ++ * Example: if only PVdd is provided, it is the only one that will be ++ * turned on/off. ++ */ ++ pdata->pvdd_reg = regulator_get(dev, "nxp,pn54x-pvdd"); ++ if (IS_ERR(pdata->pvdd_reg)) { ++ pr_err("%s: could not get nxp,pn54x-pvdd, rc=%ld\n", ++ __func__, PTR_ERR(pdata->pvdd_reg)); ++ pdata->pvdd_reg = NULL; ++ } ++ ++ pdata->vbat_reg = regulator_get(dev, "nxp,pn54x-vbat"); ++ if (IS_ERR(pdata->vbat_reg)) { ++ pr_err("%s: could not get nxp,pn54x-vbat, rc=%ld\n", ++ __func__, PTR_ERR(pdata->vbat_reg)); ++ pdata->vbat_reg = NULL; ++ } ++ ++ pdata->pmuvcc_reg = regulator_get(dev, "nxp,pn54x-pmuvcc"); ++ if (IS_ERR(pdata->pmuvcc_reg)) { ++ pr_err("%s: could not get nxp,pn54x-pmuvcc, rc=%ld\n", ++ __func__, PTR_ERR(pdata->pmuvcc_reg)); ++ pdata->pmuvcc_reg = NULL; ++ } ++ ++ pdata->sevdd_reg = regulator_get(dev, "nxp,pn54x-sevdd"); ++ if (IS_ERR(pdata->sevdd_reg)) { ++ pr_err("%s: could not get nxp,pn54x-sevdd, rc=%ld\n", ++ __func__, PTR_ERR(pdata->sevdd_reg)); ++ pdata->sevdd_reg = NULL; ++ } ++ ++ return 0; ++} ++#else ++static int pn54x_get_pdata(struct device *dev, ++ struct pn544_i2c_platform_data *pdata) ++{ ++ pdata = dev->platform_data; ++ return 0; ++} ++#endif ++ ++/* pn54x_probe */ ++#ifdef KERNEL_3_4_AND_OLDER ++static int __devinit pn54x_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++#else ++static int pn54x_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++#endif ++{ ++ int ret; ++ /* gpio values, from board file or DT */ ++ struct pn544_i2c_platform_data *pdata; ++ struct pn544_i2c_platform_data tmp_pdata; ++ /* internal device specific data */ ++ struct pn54x_dev *pn54x_dev; ++ ++ pr_info("%s\n", __func__); ++ ++ /* ++ * ---- retrieve the platform data ---- ++ * If the dev.platform_data is NULL, then ++ * attempt to read from the device tree ++ */ ++ if (!client->dev.platform_data) { ++ ret = pn54x_get_pdata(&(client->dev), &tmp_pdata); ++ if (ret) ++ return ret; ++ ++ pdata = &tmp_pdata; ++ } else { ++ pdata = client->dev.platform_data; ++ } ++ ++ if (pdata == NULL) { ++ pr_err("%s : nfc probe fail\n", __func__); ++ return -ENODEV; ++ } ++ ++ /* validate the the adapter has basic I2C functionality */ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ pr_err("%s : need I2C_FUNC_I2C\n", __func__); ++ return -ENODEV; ++ } ++ ++ if (gpio_is_valid(pdata->firm_gpio)) { ++ pr_info("%s: request firm_gpio %d\n", ++ __func__, pdata->firm_gpio); ++ ret = gpio_request(pdata->firm_gpio, "nfc_firm"); ++ if (ret) { ++ pr_err("%s :not able to get GPIO firm_gpio\n", ++ __func__); ++ goto err_firm; ++ } ++ } ++ ++ if (gpio_is_valid(pdata->clkreq_gpio)) { ++ pr_info("%s: request clkreq_gpio %d\n", ++ __func__, pdata->clkreq_gpio); ++ ret = gpio_request(pdata->clkreq_gpio, "nfc_clkreq"); ++ if (ret) { ++ pr_err("%s :not able to get GPIO clkreq_gpio\n", ++ __func__); ++ goto err_clkreq; ++ } ++ } ++ ++ /* allocate the pn54x driver information structure */ ++ pn54x_dev = kzalloc(sizeof(*pn54x_dev), GFP_KERNEL); ++ if (pn54x_dev == NULL) { ++ dev_err(&client->dev, ++ "failed to allocate memory for module data\n"); ++ ret = -ENOMEM; ++ goto err_exit; ++ } ++ ++ /* store the platform data in the driver info struct */ ++ pn54x_dev->firm_gpio = pdata->firm_gpio; ++ pn54x_dev->clkreq_gpio = pdata->clkreq_gpio; ++ pn54x_dev->pvdd_reg = pdata->pvdd_reg; ++ pn54x_dev->vbat_reg = pdata->vbat_reg; ++ pn54x_dev->pmuvcc_reg = pdata->pmuvcc_reg; ++ pn54x_dev->sevdd_reg = pdata->sevdd_reg; ++ ++ pn54x_dev->client = client; ++ ++ if (gpio_is_valid(pn54x_dev->firm_gpio)) { ++ ret = gpio_direction_output(pn54x_dev->firm_gpio, 0); ++ if (ret < 0) { ++ pr_err("%s : not able to set firm_gpio as output\n", ++ __func__); ++ goto err_exit; ++ } ++ } ++ ++ if (gpio_is_valid(pn54x_dev->clkreq_gpio)) { ++ ret = gpio_direction_output(pn54x_dev->clkreq_gpio, 0); ++ if (ret < 0) { ++ pr_err("%s : not able to set clkreq_gpio as output\n", ++ __func__); ++ goto err_exit; ++ } ++ } ++ ++ /* init mutex and queues */ ++ init_waitqueue_head(&pn54x_dev->read_wq); ++ mutex_init(&pn54x_dev->read_mutex); ++ spin_lock_init(&pn54x_dev->irq_enabled_lock); ++ ++ /* register as a misc device - character based with one entry point */ ++ pn54x_dev->pn54x_device.minor = MISC_DYNAMIC_MINOR; ++ pn54x_dev->pn54x_device.name = CHIP; ++ pn54x_dev->pn54x_device.fops = &pn54x_dev_fops; ++ ret = misc_register(&pn54x_dev->pn54x_device); ++ if (ret) { ++ pr_err("%s : misc_register failed\n", __FILE__); ++ goto err_misc_register; ++ } ++ ++ /* ++ * request irq. the irq is set whenever the chip has data available ++ * for reading. it is cleared when all data has been read. ++ */ ++ i2c_set_clientdata(client, pn54x_dev); ++ ++ return 0; ++ ++err_request_irq_failed: ++ misc_deregister(&pn54x_dev->pn54x_device); ++err_misc_register: ++err_exit: ++ if (gpio_is_valid(pdata->clkreq_gpio)) ++ gpio_free(pdata->clkreq_gpio); ++err_clkreq: ++ if (gpio_is_valid(pdata->firm_gpio)) ++ gpio_free(pdata->firm_gpio); ++err_firm: ++err_ven: ++ return ret; ++} ++ ++#ifdef KERNEL_3_4_AND_OLDER ++static int __devexit pn54x_remove(struct i2c_client *client) ++#else ++static void pn54x_remove(struct i2c_client *client) ++#endif ++{ ++ struct pn54x_dev *pn54x_dev; ++ ++ pr_info("%s\n", __func__); ++ ++ pn54x_dev = i2c_get_clientdata(client); ++ free_irq(client->irq, pn54x_dev); ++ misc_deregister(&pn54x_dev->pn54x_device); ++ mutex_destroy(&pn54x_dev->read_mutex); ++ if (gpio_is_valid(pn54x_dev->firm_gpio)) ++ gpio_free(pn54x_dev->firm_gpio); ++ if (gpio_is_valid(pn54x_dev->clkreq_gpio)) ++ gpio_free(pn54x_dev->clkreq_gpio); ++ regulator_put(pn54x_dev->pvdd_reg); ++ regulator_put(pn54x_dev->vbat_reg); ++ regulator_put(pn54x_dev->pmuvcc_reg); ++ regulator_put(pn54x_dev->sevdd_reg); ++ ++ kfree(pn54x_dev); ++ ++#ifdef KERNEL_3_4_AND_OLDER ++ return 0; ++#else ++ return; ++#endif ++} ++ ++#ifdef CONFIG_OF ++static struct of_device_id pn54x_dt_match[] = { ++ { .compatible = "nxp,pn547", }, ++ { .compatible = "nxp,pn544", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, pn54x_dt_match); ++#endif ++ ++static const struct i2c_device_id pn54x_id[] = { ++ { "pn547", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(i2c, pn54x_id); ++ ++static struct i2c_driver pn54x_driver = { ++ .id_table = pn54x_id, ++ .probe = pn54x_probe, ++#ifdef KERNEL_3_4_AND_OLDER ++ .remove = __devexit_p(pn54x_remove), ++#else ++ .remove = pn54x_remove, ++#endif ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "pn544", ++ .of_match_table = pn54x_dt_match, ++ }, ++}; ++ ++/* module load/unload record keeping */ ++static int __init pn54x_dev_init(void) ++{ ++ pr_info("%s\n", __func__); ++ return i2c_add_driver(&pn54x_driver); ++} ++ ++static void __exit pn54x_dev_exit(void) ++{ ++ pr_info("%s\n", __func__); ++ i2c_del_driver(&pn54x_driver); ++} ++ ++module_init(pn54x_dev_init); ++module_exit(pn54x_dev_exit); ++ ++MODULE_AUTHOR("Sylvain Fonteneau"); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/nfc/pn5xx/pn5xx_i2c.h b/drivers/nfc/pn5xx/pn5xx_i2c.h +new file mode 100644 +index 000000000000..4b53655007e0 +--- /dev/null ++++ b/drivers/nfc/pn5xx/pn5xx_i2c.h +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2010 Trusted Logic S.A. ++ * Copyright 2015,2019-2023 NXP ++ * ++ */ ++ ++#define PN544_MAGIC 0xE9 ++ ++/* ++ * PN544 power control via ioctl ++ * PN544_SET_PWR(0): power off ++ * PN544_SET_PWR(1): power on ++ * PN544_SET_PWR(2): reset and power on with firmware download enabled ++ */ ++ ++#define PWR_OFF 0 ++#define PWR_ON 1 ++#define PWR_FW 2 ++ ++#define CLK_OFF 0 ++#define CLK_ON 1 ++ ++#define GPIO_UNUSED -1 ++ ++#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, unsigned int) ++#define PN54X_CLK_REQ _IOW(PN544_MAGIC, 0x02, unsigned int) ++ ++struct pn544_i2c_platform_data { ++ unsigned int irq_gpio; ++ unsigned int ven_gpio; ++ unsigned int firm_gpio; ++ unsigned int clkreq_gpio; ++ struct regulator *pvdd_reg; ++ struct regulator *vbat_reg; ++ struct regulator *pmuvcc_reg; ++ struct regulator *sevdd_reg; ++}; +diff --git a/drivers/nfc/pn5xx/sample_devicetree.txt b/drivers/nfc/pn5xx/sample_devicetree.txt +new file mode 100644 +index 000000000000..0e81959052fc +--- /dev/null ++++ b/drivers/nfc/pn5xx/sample_devicetree.txt +@@ -0,0 +1,17 @@ ++Example: ++ ++&i2c{ ++ ++ status = "okay"; ++ ++ pn547: pn547@29 { ++ ++ compatible = "nxp,pn547"; ++ ++ reg = <0x29>; ++ clock-frequency = <400000>; ++ ++ interrupt-gpios = <&gpio2 17 0>; ++ enable-gpios = <&gpio4 21 0>; ++ }; ++}; +diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig +index afba55506632..968ddd1fac18 100644 +--- a/drivers/rpmsg/Kconfig ++++ b/drivers/rpmsg/Kconfig +@@ -81,10 +81,17 @@ config RPMSG_VIRTIO + select RPMSG_NS + select VIRTIO + ++config RPMSG_PERF ++ tristate "RPMSG performance test driver" ++ depends on RPMSG ++ default m ++ help ++ Say Y here to enable the RPMSG performance test driver. ++ + config HAVE_IMX_RPMSG + bool "IMX RPMSG driver on the AMP SOCs" + default y +- depends on IMX_MBOX ++ depends on IMX_MBOX || GENERIC_SOFTWARE_MAILBOX + select RPMSG_VIRTIO + help + Say y here to enable support for the iMX Rpmsg Driver providing +@@ -118,4 +125,11 @@ config IMX_RPMSG_TTY + executed by the command "echo > ", thus + remote M core would receive the string. + ++config RPMSG_8M_BUF ++ bool "RPMSG 8M bytes buffer support" ++ default n ++ depends on HAVE_IMX_RPMSG ++ help ++ Say y here to enable support for 8M bytes Vring buffer for rpmsg. ++ + endmenu +diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile +index 7c4ee52e92c4..f64fa4d0ada2 100644 +--- a/drivers/rpmsg/Makefile ++++ b/drivers/rpmsg/Makefile +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_RPMSG) += rpmsg_core.o + obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o ++obj-$(CONFIG_RPMSG_PERF) += rpmsg_perf.o + obj-$(CONFIG_RPMSG_CTRL) += rpmsg_ctrl.o + obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o + obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o +diff --git a/drivers/rpmsg/imx_rpmsg.c b/drivers/rpmsg/imx_rpmsg.c +index 8d4ecd7360fd..b4277d5cfe37 100644 +--- a/drivers/rpmsg/imx_rpmsg.c ++++ b/drivers/rpmsg/imx_rpmsg.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * Copyright 2019 NXP ++ * Copyright 2019,2023 NXP + */ + + #include +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -163,8 +164,12 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, + return ERR_PTR(-ENOMEM); + + /* ioremap'ing normal memory, so we cast away sparse's complaints */ +- rpvq->addr = (__force void *) ioremap(virdev->vring[index], +- RPMSG_RING_SIZE); ++ if (of_dma_is_coherent(dev->of_node)) ++ rpvq->addr = (__force void *)ioremap_cache(virdev->vring[index], ++ RPMSG_RING_SIZE); ++ else ++ rpvq->addr = (__force void *)ioremap(virdev->vring[index], ++ RPMSG_RING_SIZE); + if (!rpvq->addr) { + err = -ENOMEM; + goto free_rpvq; +@@ -466,6 +471,13 @@ static int imx_rpmsg_rxdb_channel_init(struct imx_rpmsg_vproc *rpdev) + return ret; + } + ++static int imx_rpmsg_rxdb_channel_deinit(struct imx_rpmsg_vproc *rpdev) ++{ ++ mbox_free_channel(rpdev->rxdb_ch); ++ ++ return 0; ++} ++ + static void imx_rpmsg_rx_callback(struct mbox_client *c, void *msg) + { + int buf_space; +@@ -531,6 +543,14 @@ static int imx_rpmsg_xtr_channel_init(struct imx_rpmsg_vproc *rpdev) + return ret; + } + ++static int imx_rpmsg_xtr_channel_deinit(struct imx_rpmsg_vproc *rpdev) ++{ ++ mbox_free_channel(rpdev->tx_ch); ++ mbox_free_channel(rpdev->rx_ch); ++ ++ return 0; ++} ++ + static int imx_rpmsg_probe(struct platform_device *pdev) + { + int j, ret = 0; +@@ -653,6 +673,36 @@ static int imx_rpmsg_probe(struct platform_device *pdev) + return ret; + } + ++static int imx_rpmsg_remove(struct platform_device *pdev) ++{ ++ struct imx_rpmsg_vproc *rpdev = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int i; ++ ++#ifdef CONFIG_IMX_SCU ++ if (rpdev->variant == IMX8QXP || rpdev->variant == IMX8QM) { ++ imx_scu_irq_unregister_notifier(&rpdev->proc_nb); ++ imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, ++ BIT(rpdev->mub_partition), false); ++ } ++#endif ++ imx_rpmsg_rxdb_channel_deinit(rpdev); ++ ++ for (i = 0; i < rpdev->vdev_nums; i++) { ++ unregister_virtio_device(&rpdev->ivdev[i]->vdev); ++ kfree(rpdev->ivdev[i]); ++ } ++ ++ if (rpdev->flags & SPECIFIC_DMA_POOL) ++ of_reserved_mem_device_release(dev); ++ ++ imx_rpmsg_xtr_channel_deinit(rpdev); ++ ++ cancel_delayed_work_sync(&rpdev->rpmsg_work); ++ ++ return 0; ++} ++ + static struct platform_driver imx_rpmsg_driver = { + .driver = { + .owner = THIS_MODULE, +@@ -660,6 +710,7 @@ static struct platform_driver imx_rpmsg_driver = { + .of_match_table = imx_rpmsg_dt_ids, + }, + .probe = imx_rpmsg_probe, ++ .remove = imx_rpmsg_remove, + }; + + static int __init imx_rpmsg_init(void) +diff --git a/drivers/rpmsg/imx_rpmsg_tty.c b/drivers/rpmsg/imx_rpmsg_tty.c +index 6114c686c388..ab3e64cc1a06 100644 +--- a/drivers/rpmsg/imx_rpmsg_tty.c ++++ b/drivers/rpmsg/imx_rpmsg_tty.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + /* +- * Copyright 2019 NXP ++ * Copyright 2019,2023 NXP + */ + + #include +@@ -13,8 +13,24 @@ + #include + #include + ++#ifdef CONFIG_RPMSG_8M_BUF ++struct rpmsg_hdr { ++ __rpmsg32 src; ++ __rpmsg32 dst; ++ __rpmsg32 reserved; ++ __rpmsg16 len; ++ __rpmsg16 flags; ++ u8 data[]; ++} __packed; ++ ++#define MAX_RPMSG_BUF_SIZE (512 * 2) ++/* this needs to be less then (RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) */ ++#define RPMSG_MAX_SIZE (MAX_RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) ++#else + /* this needs to be less then (RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) */ + #define RPMSG_MAX_SIZE 256 ++#endif ++ + #define MSG "hello world!" + + /* +diff --git a/drivers/rpmsg/rpmsg_perf.c b/drivers/rpmsg/rpmsg_perf.c +new file mode 100644 +index 000000000000..f58b15b2ea8d +--- /dev/null ++++ b/drivers/rpmsg/rpmsg_perf.c +@@ -0,0 +1,545 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rpmsg_internal.h" ++ ++#define RPMSG_PERF_AS_SENDER_IOCTL _IO(0xb5, 0x5) ++#define RPMSG_PERF_AS_RECEIVER_IOCTL _IO(0xb5, 0x6) ++#define RPMSG_PERF_AS_RECEIVER_END_ACK_IOCTL _IO(0xb5, 0x7) ++#define RPMSG_PERF_GET_RUNNING_STA_IOCTL _IO(0xb5, 0x8) ++ ++#define RPMSG_DEV_MAX (MINORMASK + 1) ++ ++static dev_t rpmsg_major; ++ ++static DEFINE_IDA(rpmsg_perf_minor_ida); ++ ++#define dev_to_eptdev(dev) container_of(dev, struct rpmsg_eptdev, dev) ++#define cdev_to_eptdev(i_cdev) container_of(i_cdev, struct rpmsg_eptdev, cdev) ++ ++struct packet_header { ++ uint32_t preamble; ++ bool no_copy; ++ uint32_t packet_size; ++ uint32_t packet_cnt; ++ uint32_t test_time; /* unit: second */ ++}; ++ ++enum { ++ RPMSG_PERF_PREAMBLE_SENDER_START = 0xBECAACEA, ++ RPMSG_PERF_PREAMBLE_SENDER_END = 0xBECAACEB, ++ RPMSG_PERF_PREAMBLE_SENDER_END_ACK = 0xBECAACEC, ++ RPMSG_PERF_PREAMBLE_RECEIVER_START = 0xBECAACED, ++ RPMSG_PERF_PREAMBLE_RECEIVER_END = 0xBECAACEE, ++ RPMSG_PERF_PREAMBLE_RECEIVER_END_ACK = 0xBECAACEF, ++}; ++ ++enum dev_state { ++ RPMSG_DEV_IDLE, ++ RPMSG_DEV_SENDING, ++ RPMSG_DEV_RECEIVING, ++}; ++ ++struct test_statistic { ++ uint32_t recv_packet_cnt; ++ uint32_t send_packet_cnt; ++ uint32_t packet_size; ++ uint32_t test_time; ++}; ++ ++/** ++ * struct rpmsg_eptdev - endpoint device context ++ * @dev: endpoint device ++ * @cdev: cdev for the endpoint device ++ * @rpdev: underlaying rpmsg device ++ * @chinfo: info used to open the endpoint ++ * @ept_lock: synchronization of @ept modifications ++ * @ept: rpmsg endpoint reference, when open ++ * @default_ept: set to channel default endpoint if the default endpoint should be re-used ++ * on device open to prevent endpoint address update. ++ */ ++struct rpmsg_eptdev { ++ struct device dev; ++ struct cdev cdev; ++ ++ struct rpmsg_device *rpdev; ++ struct rpmsg_channel_info chinfo; ++ ++ struct mutex ept_lock; ++ struct rpmsg_endpoint *ept; ++ struct rpmsg_endpoint *default_ept; ++ ++ enum dev_state state; ++ struct test_statistic statistic; ++ ++ struct packet_header param; ++}; ++ ++static int rpmsg_perf_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, ++ void *priv, u32 addr) ++{ ++ struct packet_header *hdr = (struct packet_header *)buf; ++ struct rpmsg_eptdev *eptdev = priv; ++ struct test_statistic *statistic = &eptdev->statistic; ++ uint32_t rate; ++ ++ switch (hdr->preamble) { ++ case RPMSG_PERF_PREAMBLE_SENDER_END_ACK: ++ if (eptdev->state == RPMSG_DEV_SENDING) { ++ eptdev->state = RPMSG_DEV_IDLE; ++ rate = statistic->send_packet_cnt / ++ statistic->test_time / 1000; ++ pr_info("packet size: %u, sent packets: %u, time: %u s, rate: %u kpps\n", ++ statistic->packet_size, ++ statistic->send_packet_cnt, ++ statistic->test_time, rate); ++ statistic->packet_size = 0; ++ statistic->send_packet_cnt = 0; ++ } ++ break; ++ default: ++ break; ++ } ++ statistic->recv_packet_cnt++; ++ ++ return 0; ++} ++ ++static int rpmsg_perf_eptdev_open(struct inode *inode, struct file *filp) ++{ ++ struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); ++ struct rpmsg_endpoint *ept; ++ struct rpmsg_device *rpdev = eptdev->rpdev; ++ struct device *dev = &eptdev->dev; ++ ++ mutex_lock(&eptdev->ept_lock); ++ if (eptdev->ept) { ++ mutex_unlock(&eptdev->ept_lock); ++ return -EBUSY; ++ } ++ ++ get_device(dev); ++ ++ /* ++ * If the default_ept is set, the rpmsg device default endpoint is used. ++ * Else a new endpoint is created on open that will be destroyed on release. ++ */ ++ if (eptdev->default_ept) ++ ept = eptdev->default_ept; ++ else ++ ept = rpmsg_create_ept(rpdev, rpmsg_perf_ept_cb, eptdev, eptdev->chinfo); ++ ++ if (!ept) { ++ dev_err(dev, "failed to open %s\n", eptdev->chinfo.name); ++ put_device(dev); ++ mutex_unlock(&eptdev->ept_lock); ++ return -EINVAL; ++ } ++ ++ eptdev->ept = ept; ++ filp->private_data = eptdev; ++ mutex_unlock(&eptdev->ept_lock); ++ ++ return 0; ++} ++ ++static int rpmsg_perf_eptdev_release(struct inode *inode, struct file *filp) ++{ ++ struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); ++ struct device *dev = &eptdev->dev; ++ ++ /* Close the endpoint, if it's not already destroyed by the parent */ ++ mutex_lock(&eptdev->ept_lock); ++ if (eptdev->ept) { ++ if (!eptdev->default_ept) ++ rpmsg_destroy_ept(eptdev->ept); ++ eptdev->ept = NULL; ++ } ++ mutex_unlock(&eptdev->ept_lock); ++ ++ put_device(dev); ++ ++ return 0; ++} ++ ++static int rpmsg_perf_sender_thread(void *p) ++{ ++ struct rpmsg_eptdev *eptdev = (struct rpmsg_eptdev *)p; ++ struct packet_header hdr = eptdev->param; ++ unsigned long timeout; ++ uint8_t *data; ++ uint32_t packet_len; ++ int ret; ++ ++ hdr.preamble = RPMSG_PERF_PREAMBLE_SENDER_START; ++ packet_len = hdr.packet_size; ++ eptdev->statistic.send_packet_cnt = 0; ++ ++ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr), eptdev->chinfo.dst); ++ if (ret) { ++ pr_err("failed to send packet header\n"); ++ return ret; ++ } ++ ++ /* Prepare data packets */ ++ data = kmalloc(packet_len, GFP_KERNEL); ++ if (data == NULL) { ++ pr_err("allocate data buffer failure\n"); ++ return -ENOMEM; ++ } ++ memset(data, 0, packet_len); ++ ++ udelay(100); ++ timeout = jiffies + msecs_to_jiffies(hdr.test_time * 1000); ++ ++ do { ++ do { ++ ret = rpmsg_trysendto(eptdev->ept, data, packet_len, ++ eptdev->chinfo.dst); ++ } while (ret != 0); ++ eptdev->statistic.send_packet_cnt++; ++ } while (time_before(jiffies, timeout)); ++ ++ memset(&hdr, 0, sizeof(hdr)); ++ hdr.preamble = RPMSG_PERF_PREAMBLE_SENDER_END; ++ ++ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr), eptdev->chinfo.dst); ++ if (ret) { ++ pr_err("failed to send RPMSG_PERF_PREAMBLE_SENDER_END packet\n"); ++ } ++ ++ kfree(data); ++ ++ return ret; ++} ++ ++static long rpmsg_perf_eptdev_ioctl(struct file *fp, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct rpmsg_eptdev *eptdev = fp->private_data; ++ struct test_statistic *statistic = &eptdev->statistic; ++ struct task_struct *sender_thread_h; ++ struct packet_header hdr = {0}; ++ uint32_t packet_cnt; ++ uint32_t rate; ++ uint32_t status; ++ long ret; ++ ++ switch (cmd) { ++ case RPMSG_PERF_GET_RUNNING_STA_IOCTL: ++ status = eptdev->state; ++ if (copy_to_user((char __user *)arg, &status, sizeof(status))) { ++ pr_err("copy_to_user() failed\n"); ++ return -EFAULT; ++ } ++ break; ++ case RPMSG_PERF_AS_SENDER_IOCTL: ++ if (eptdev->state != RPMSG_DEV_IDLE) ++ return -EINVAL; ++ ++ eptdev->state = RPMSG_DEV_SENDING; ++ ret = copy_from_user((void *)&hdr, (const void __user *)arg, ++ sizeof(struct packet_header)); ++ if (ret) { ++ pr_err("copy_from_user() failed\n"); ++ return -EFAULT; ++ } ++ ++ eptdev->param.no_copy = hdr.no_copy; ++ eptdev->param.packet_size = hdr.packet_size; ++ eptdev->param.test_time = hdr.test_time; ++ statistic->packet_size = hdr.packet_size; ++ statistic->test_time = hdr.test_time; ++ ++ sender_thread_h = kthread_run(rpmsg_perf_sender_thread, ++ eptdev, "rpmsg_sender"); ++ if (IS_ERR(sender_thread_h)) { ++ pr_err("failed to create sender thread\n"); ++ return -EFAULT; ++ } ++ break; ++ case RPMSG_PERF_AS_RECEIVER_IOCTL: ++ if (eptdev->state != RPMSG_DEV_IDLE) ++ return -EINVAL; ++ ++ eptdev->state = RPMSG_DEV_RECEIVING; ++ ret = copy_from_user((void *)&hdr, (const void __user *)arg, ++ sizeof(struct packet_header)); ++ if (ret) { ++ pr_err("copy_from_user() failed\n"); ++ return -EFAULT; ++ } ++ hdr.preamble = RPMSG_PERF_PREAMBLE_RECEIVER_START; ++ statistic->test_time = hdr.test_time; ++ statistic->packet_size = hdr.packet_size; ++ statistic->recv_packet_cnt = 0; ++ ++ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr), ++ eptdev->chinfo.dst); ++ if (ret) ++ pr_err("failed to send RPMSG_PERF_PREAMBLE_RECEIVER_START packet\n"); ++ break; ++ case RPMSG_PERF_AS_RECEIVER_END_ACK_IOCTL: ++ if (eptdev->state != RPMSG_DEV_RECEIVING) ++ return -EINVAL; ++ ++ packet_cnt = statistic->recv_packet_cnt - 1; ++ rate = packet_cnt / statistic->test_time / 1000; ++ pr_info("packet size: %u, received packets: %u, time: %u s, rate: %u kpps\n", ++ statistic->packet_size, packet_cnt, ++ statistic->test_time, rate); ++ ++ hdr.preamble = RPMSG_PERF_PREAMBLE_RECEIVER_END_ACK; ++ hdr.packet_cnt = packet_cnt; ++ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr), ++ eptdev->chinfo.dst); ++ if (ret) { ++ pr_err("failed to send RPMSG_PERF_PREAMBLE_RECEIVER_END_ACK packet\n"); ++ return ret; ++ } ++ eptdev->state = RPMSG_DEV_IDLE; ++ statistic->test_time = 0; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const struct file_operations rpmsg_perf_eptdev_fops = { ++ .owner = THIS_MODULE, ++ .open = rpmsg_perf_eptdev_open, ++ .release = rpmsg_perf_eptdev_release, ++ .unlocked_ioctl = rpmsg_perf_eptdev_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, ++}; ++ ++static ssize_t name_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%s\n", eptdev->chinfo.name); ++} ++static DEVICE_ATTR_RO(name); ++ ++static ssize_t src_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", eptdev->chinfo.src); ++} ++static DEVICE_ATTR_RO(src); ++ ++static ssize_t dst_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", eptdev->chinfo.dst); ++} ++static DEVICE_ATTR_RO(dst); ++ ++static struct attribute *rpmsg_perf_eptdev_attrs[] = { ++ &dev_attr_name.attr, ++ &dev_attr_src.attr, ++ &dev_attr_dst.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(rpmsg_perf_eptdev); ++ ++static void rpmsg_eptdev_release_device(struct device *dev) ++{ ++ struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev); ++ ++ ida_simple_remove(&rpmsg_perf_minor_ida, MINOR(eptdev->dev.devt)); ++ kfree(eptdev); ++} ++ ++static struct rpmsg_eptdev *rpmsg_perf_eptdev_alloc(struct rpmsg_device *rpdev, ++ struct device *parent) ++{ ++ struct rpmsg_eptdev *eptdev; ++ struct device *dev; ++ ++ eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL); ++ if (!eptdev) ++ return ERR_PTR(-ENOMEM); ++ ++ eptdev->state = RPMSG_DEV_IDLE; ++ ++ dev = &eptdev->dev; ++ eptdev->rpdev = rpdev; ++ ++ mutex_init(&eptdev->ept_lock); ++ ++ device_initialize(dev); ++ dev->class = rpmsg_class; ++ dev->parent = parent; ++ dev->groups = rpmsg_perf_eptdev_groups; ++ dev_set_drvdata(dev, eptdev); ++ ++ cdev_init(&eptdev->cdev, &rpmsg_perf_eptdev_fops); ++ eptdev->cdev.owner = THIS_MODULE; ++ ++ return eptdev; ++} ++ ++static int rpmsg_perf_eptdev_add(struct rpmsg_eptdev *eptdev, ++ struct rpmsg_channel_info chinfo) ++{ ++ struct device *dev = &eptdev->dev; ++ int dst = eptdev->rpdev->dst; ++ int ret; ++ ++ eptdev->chinfo = chinfo; ++ ++ ret = ida_simple_get(&rpmsg_perf_minor_ida, 0, ++ RPMSG_DEV_MAX, GFP_KERNEL); ++ if (ret < 0) ++ goto free_eptdev; ++ dev->devt = MKDEV(MAJOR(rpmsg_major), ret); ++ ++ dev->id = dst; ++ dev_set_name(dev, "rpmsg-perf%d", dst); ++ ++ ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); ++ if (ret) ++ goto free_minor_ida; ++ ++ /* We can now rely on the release function for cleanup */ ++ dev->release = rpmsg_eptdev_release_device; ++ ++ return ret; ++ ++free_minor_ida: ++ ida_simple_remove(&rpmsg_perf_minor_ida, MINOR(dev->devt)); ++free_eptdev: ++ put_device(dev); ++ kfree(eptdev); ++ ++ return ret; ++} ++ ++static int rpmsg_perf_probe(struct rpmsg_device *rpdev) ++{ ++ struct rpmsg_channel_info chinfo; ++ struct rpmsg_eptdev *eptdev; ++ struct device *dev = &rpdev->dev; ++ ++ memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); ++ chinfo.src = rpdev->src; ++ chinfo.dst = rpdev->dst; ++ ++ eptdev = rpmsg_perf_eptdev_alloc(rpdev, dev); ++ if (IS_ERR(eptdev)) ++ return PTR_ERR(eptdev); ++ ++ /* Set the default_ept to the rpmsg device endpoint */ ++ eptdev->default_ept = rpdev->ept; ++ ++ /* ++ * The rpmsg_perf_ept_cb uses *priv parameter to get its ++ * rpmsg_eptdev context. Stored it in default_ept *priv field. ++ */ ++ eptdev->default_ept->priv = eptdev; ++ ++ return rpmsg_perf_eptdev_add(eptdev, chinfo); ++} ++ ++static int rpmsg_perf_eptdev_chrdev_destroy(struct device *dev, void *data) ++{ ++ struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev); ++ ++ mutex_lock(&eptdev->ept_lock); ++ if (eptdev->ept) { ++ /* The default endpoint is released by the rpmsg core */ ++ if (!eptdev->default_ept) ++ rpmsg_destroy_ept(eptdev->ept); ++ eptdev->ept = NULL; ++ } ++ mutex_unlock(&eptdev->ept_lock); ++ ++ cdev_device_del(&eptdev->cdev, &eptdev->dev); ++ put_device(&eptdev->dev); ++ ++ return 0; ++} ++ ++static void rpmsg_perf_remove(struct rpmsg_device *rpdev) ++{ ++ int ret; ++ ++ ret = device_for_each_child(&rpdev->dev, NULL, ++ rpmsg_perf_eptdev_chrdev_destroy); ++ if (ret) ++ dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret); ++} ++ ++static struct rpmsg_device_id rpmsg_perf_id_table[] = { ++ { .name = "rpmsg-perf" }, ++ { }, ++}; ++ ++static struct rpmsg_driver rpmsg_perf_driver = { ++ .probe = rpmsg_perf_probe, ++ .remove = rpmsg_perf_remove, ++ .callback = rpmsg_perf_ept_cb, ++ .id_table = rpmsg_perf_id_table, ++ .drv.name = "rpmsg_perf", ++}; ++ ++static int rpmsg_perf_init(void) ++{ ++ int ret; ++ ++ ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_perf"); ++ if (ret < 0) { ++ pr_err("failed to allocate char dev region\n"); ++ return ret; ++ } ++ ++ ret = register_rpmsg_driver(&rpmsg_perf_driver); ++ if (ret < 0) { ++ pr_err("rpmsg: failed to register rpmsg raw driver\n"); ++ goto free_region; ++ } ++ ++ return 0; ++ ++free_region: ++ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX); ++ ++ return ret; ++} ++postcore_initcall(rpmsg_perf_init); ++ ++static void rpmsg_perf_exit(void) ++{ ++ unregister_rpmsg_driver(&rpmsg_perf_driver); ++ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX); ++} ++module_exit(rpmsg_perf_exit); ++ ++MODULE_ALIAS("rpmsg:rpmsg_perf"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c +index 905ac7910c98..d9f341bfd299 100644 +--- a/drivers/rpmsg/virtio_rpmsg_bus.c ++++ b/drivers/rpmsg/virtio_rpmsg_bus.c +@@ -127,8 +127,13 @@ struct virtio_rpmsg_channel { + * can change this without changing anything in the firmware of the remote + * processor. + */ ++#ifdef CONFIG_RPMSG_8M_BUF ++#define MAX_RPMSG_NUM_BUFS (1024 * 8) ++#define MAX_RPMSG_BUF_SIZE (512 * 2) ++#else + #define MAX_RPMSG_NUM_BUFS (512) + #define MAX_RPMSG_BUF_SIZE (512) ++#endif + + /* + * Local addresses are dynamically allocated on-demand. +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 36d99d7a183c..cd0e5bdd37f6 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1850,6 +1850,7 @@ config RTC_DRV_IMX_SC + config RTC_DRV_IMX_RPMSG + tristate "NXP RPMSG RTC support" + depends on OF ++ depends on RPMSG + help + If you say yes here you get support for the NXP RPMSG + RTC module. +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index 151fef199c38..825412e799cd 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -127,10 +127,10 @@ do { \ + unsigned int start; \ + pcpu_stats = per_cpu_ptr(in, i); \ + do { \ +- start = u64_stats_fetch_begin_irq( \ ++ start = u64_stats_fetch_begin( \ + &pcpu_stats->syncp); \ + inc = u64_stats_read(&pcpu_stats->field); \ +- } while (u64_stats_fetch_retry_irq( \ ++ } while (u64_stats_fetch_retry( \ + &pcpu_stats->syncp, start)); \ + ret += inc; \ + } \ +diff --git a/drivers/staging/fsl_qbman/qman_driver.c b/drivers/staging/fsl_qbman/qman_driver.c +index 14671df9e4ce..135235595521 100644 +--- a/drivers/staging/fsl_qbman/qman_driver.c ++++ b/drivers/staging/fsl_qbman/qman_driver.c +@@ -1,4 +1,5 @@ + /* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright 2019-2023 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -722,6 +723,50 @@ static int qman_online_cpu(unsigned int cpu) + + #endif /* CONFIG_HOTPLUG_CPU */ + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++__init void qman_ethercat_portal_init(int cpu) ++{ ++ struct qm_portal_config *pcfg; ++ struct qman_portal *p; ++ ++ pcfg = get_pcfg(&unused_pcfgs); ++ if (pcfg) { ++ pcfg->public_cfg.cpu = cpu; ++ pcfg->public_cfg.is_shared = 0; ++ ++ pcfg->iommu_domain = NULL; ++ portal_set_cpu(pcfg, pcfg->public_cfg.cpu); ++ p = qman_create_affine_portal_ethercat(pcfg, NULL, cpu); ++ if (p) { ++ pr_info("Qman portal %sinitialised, cpu %d\n", ++ pcfg->public_cfg.is_shared ? "(shared) " : "", ++ pcfg->public_cfg.cpu); ++ } else { ++ pr_crit("Qman portal failure on cpu %d\n", ++ pcfg->public_cfg.cpu); ++ } ++ return; ++ } ++} ++ ++static u32 qman_affine_last_cpu; ++ ++u32 qman_get_affine_last_cpu(void) ++{ ++ return qman_affine_last_cpu; ++} ++ ++__init void qman_ethercat_portal_init_on_cpu(void) ++{ ++ int cpu = 0; ++ ++ for_each_online_cpu(cpu) { ++ qman_affine_last_cpu = cpu; ++ qman_ethercat_portal_init(cpu); ++ } ++} ++#endif ++ + __init int qman_init(void) + { + struct cpumask slave_cpus; +@@ -877,6 +922,11 @@ __init int qman_init(void) + return ret; + } + #endif ++ ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++ qman_ethercat_portal_init_on_cpu(); ++#endif ++ + return 0; + } + +diff --git a/drivers/staging/fsl_qbman/qman_high.c b/drivers/staging/fsl_qbman/qman_high.c +index 961177fa681e..15a38ed75a2b 100644 +--- a/drivers/staging/fsl_qbman/qman_high.c ++++ b/drivers/staging/fsl_qbman/qman_high.c +@@ -1,4 +1,5 @@ + /* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright 2019-2023 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -776,6 +777,29 @@ struct qman_portal *qman_create_portal( + return NULL; + } + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++static struct qman_portal ethercat_portal[NR_CPUS]; ++static u16 ethercat_channel[NR_CPUS]; ++static DEFINE_SPINLOCK(ethercat_mask_lock); ++ ++struct qman_portal *qman_create_affine_portal_ethercat ++ (const struct qm_portal_config *config, ++ const struct qman_cgrs *cgrs, int cpu) ++{ ++ struct qman_portal *res; ++ struct qman_portal *portal = NULL; ++ ++ portal = ðercat_portal[cpu]; ++ res = qman_create_portal(portal, config, cgrs); ++ if (res) { ++ spin_lock(ðercat_mask_lock); ++ ethercat_channel[cpu] = config->public_cfg.channel; ++ spin_unlock(ðercat_mask_lock); ++ } ++ return res; ++} ++#endif ++ + struct qman_portal *qman_create_affine_portal( + const struct qm_portal_config *config, + const struct qman_cgrs *cgrs) +@@ -1412,6 +1436,20 @@ void *qman_get_affine_portal(int cpu) + } + EXPORT_SYMBOL(qman_get_affine_portal); + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++u16 qman_affine_channel_ethercat(int cpu) ++{ ++ return ethercat_channel[cpu]; ++} ++EXPORT_SYMBOL(qman_affine_channel_ethercat); ++ ++void *qman_get_affine_portal_ethercat(int cpu) ++{ ++ return ðercat_portal[cpu]; ++} ++EXPORT_SYMBOL(qman_get_affine_portal_ethercat); ++#endif ++ + int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit) + { + int ret; +diff --git a/drivers/staging/fsl_qbman/qman_private.h b/drivers/staging/fsl_qbman/qman_private.h +index 4ba7bd5b0bb2..47a06dc35e5a 100644 +--- a/drivers/staging/fsl_qbman/qman_private.h ++++ b/drivers/staging/fsl_qbman/qman_private.h +@@ -1,4 +1,5 @@ + /* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright 2019-2023 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -232,6 +233,11 @@ struct qman_portal *qman_create_portal( + const struct qm_portal_config *config, + const struct qman_cgrs *cgrs); + ++#ifdef CONFIG_FSL_DPAA_ETHERCAT ++struct qman_portal *qman_create_affine_portal_ethercat ++ (const struct qm_portal_config *config, ++ const struct qman_cgrs *cgrs, int cpu); ++#endif + struct qman_portal *qman_create_affine_portal( + const struct qm_portal_config *config, + const struct qman_cgrs *cgrs); +diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig +index cc30ff93e2e4..ccfbd6187e4a 100644 +--- a/drivers/tty/Kconfig ++++ b/drivers/tty/Kconfig +@@ -382,4 +382,6 @@ config RPMSG_TTY + + endif # TTY + ++ ++ + source "drivers/tty/serdev/Kconfig" +diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c +index 29db413bbc03..a5d44406b566 100644 +--- a/drivers/tty/rpmsg_tty.c ++++ b/drivers/tty/rpmsg_tty.c +@@ -1,13 +1,14 @@ + // SPDX-License-Identifier: GPL-2.0 + /* + * Copyright (C) 2021 STMicroelectronics - All Rights Reserved ++ * Copyright 2023 NXP + * + * The rpmsg tty driver implements serial communication on the RPMsg bus to makes + * possible for user-space programs to send and receive rpmsg messages as a standard + * tty protocol. + * +- * The remote processor can instantiate a new tty by requesting a "rpmsg-tty" RPMsg service. +- * The "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet. ++ * The remote processor can instantiate a new tty by requesting a "srtm-uart-channel" or "rpmsg-tty" RPMsg service. ++ * The "srtm-uart-channel" or "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet. + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -17,6 +18,43 @@ + #include + #include + #include ++#include ++#include ++ ++/* ++ * The srtm (simplified real time message) protocol for uart: ++ * ++ * +---------------+-------------------------------+ ++ * | Byte Offset | Content | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 0 | Category | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 1 ~ 2 | Version | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 3 | Type | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 4 | Command | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 5 | Priority | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 6 | Reserved1 | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 7 | Reserved2 | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 8 | Reserved3 | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 9 | Reserved4 | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 10 | UART BUS ID | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 11 | reserved/ret code | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 12 ~ 13 | Flags | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * | 14 ~ 495 | Data | ++ * +---------------+---+---+---+---+---+---+---+---+ ++ * UART BUS ID: real uart instance, such as: the soc has UART0(UART BUS ID = 0), UART1(UART BUS ID = 1), UART2(UART BUS ID = 2), ... , UARTx(UART BUS ID = x) ++ */ + + #define RPMSG_TTY_NAME "ttyRPMSG" + #define MAX_TTY_RPMSG 32 +@@ -29,18 +67,72 @@ static struct tty_driver *rpmsg_tty_driver; + struct rpmsg_tty_port { + struct tty_port port; /* TTY port data */ + int id; /* TTY rpmsg index */ ++ int bus_id; /* used for srtm uart protocol, which real uart will be used, such as, uart0, uart1, uart2, uart3... */ ++ int flags; /* used for srtm uart protocol */ ++ u16 srtm_uart_msg_data_max_sz; /* used for srtm uart protocol */ ++ bool use_srtm_uart_protocol; /* used for srtm uart protocol */ + struct rpmsg_device *rpdev; /* rpmsg device */ + }; + ++struct srtm_uart_msg_header { ++ struct imx_srtm_head common; ++ u8 bus_id; /* The bus_id is used when send data from acore to mcore; The bus_id is useless when acore received data that from mcore*/ ++ union { ++ u8 reserved; /* used in request packet */ ++ u8 retCode; /* used in response packet */ ++ }; ++ u16 flags; ++} __packed __aligned[1]; ++ ++struct srtm_uart_msg { ++ struct srtm_uart_msg_header header; ++ /* srtm uart Payload Start */ ++ u8 data[1]; ++} __packed __aligned(1); ++ ++struct imx_srtm_uart_data_structure ++{ ++ bool use_srtm_uart_protocol; ++}; ++ ++const static struct imx_srtm_uart_data_structure imx_srtm_uart_data = { ++ .use_srtm_uart_protocol = true, ++}; ++ ++const static struct imx_srtm_uart_data_structure rpmsg_tty_data = { ++ .use_srtm_uart_protocol = false, ++}; ++ + static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src) + { + struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); ++ struct srtm_uart_msg *msg = (struct srtm_uart_msg *)data; + int copied; ++ u8 *payload = data; ++ int payload_len = len; + +- if (!len) ++ if (!payload_len) + return -EINVAL; +- copied = tty_insert_flip_string(&cport->port, data, len); +- if (copied != len) ++ if (cport->use_srtm_uart_protocol) { ++ if (payload_len < (sizeof(struct srtm_uart_msg))) ++ return -EINVAL; ++ payload_len -= (sizeof(struct srtm_uart_msg) - 1); /* 1: msg->data[0] */ ++ ++ if (msg->header.common.type != IMX_SRTM_TYPE_RESPONSE && msg->header.common.type != IMX_SRTM_TYPE_NOTIFY) { ++ return -EINVAL; ++ } ++ ++ if (payload_len > cport->srtm_uart_msg_data_max_sz) { ++ dev_err(&rpdev->dev, ++ "%s failed: data length greater than %d, len=%d\n", ++ __func__, cport->srtm_uart_msg_data_max_sz, payload_len); ++ return -EINVAL; ++ } ++ payload = &msg->data[0]; ++ } ++ ++ copied = tty_insert_flip_string(&cport->port, payload, payload_len); ++ if (copied != payload_len) + dev_err_ratelimited(&rpdev->dev, "Trunc buffer: available space is %d\n", copied); + tty_flip_buffer_push(&cport->port); + +@@ -77,27 +169,52 @@ static int rpmsg_tty_write(struct tty_struct *tty, const u8 *buf, int len) + { + struct rpmsg_tty_port *cport = tty->driver_data; + struct rpmsg_device *rpdev; +- int msg_max_size, msg_size; ++ int msg_max_size, msg_size = -1; ++ struct srtm_uart_msg *msg = NULL; + int ret; ++ void *data = NULL; ++ int data_len = 0; + + rpdev = cport->rpdev; + +- msg_max_size = rpmsg_get_mtu(rpdev->ept); ++ msg_max_size = cport->use_srtm_uart_protocol ? (cport->srtm_uart_msg_data_max_sz) : (rpmsg_get_mtu(rpdev->ept)); + if (msg_max_size < 0) + return msg_max_size; + + msg_size = min(len, msg_max_size); +- ++ if (cport->use_srtm_uart_protocol) { ++ data_len = msg_size + sizeof(struct srtm_uart_msg) - 1; /* srtm uart msg header + data len */ ++ msg = kmalloc(data_len, GFP_KERNEL); ++ if (!msg) ++ return -ENOMEM; ++ ++ memset(msg, 0, data_len); ++ msg->header.common.cate = IMX_SRTM_CATEGORY_UART; ++ msg->header.common.major = IMX_SRTM_VER_UART; ++ msg->header.common.minor = IMX_SRTM_VER_UART >> 8; ++ msg->header.common.type = IMX_SRTM_TYPE_NOTIFY; ++ msg->header.common.cmd = IMX_SRTM_UART_COMMAND_SEND; ++ msg->header.common.reserved[0] = IMX_SRTM_UART_PRIORITY; ++ msg->header.bus_id = cport->bus_id & 0xFF; ++ msg->header.flags = cport->flags & 0xFFFF; ++ memcpy(&msg->data[0], buf, msg_size); ++ data = (void *)msg; ++ } else { ++ data = (void *)buf; ++ data_len = msg_size; ++ } + /* + * Use rpmsg_trysend instead of rpmsg_send to send the message so the caller is not + * hung until a rpmsg buffer is available. In such case rpmsg_trysend returns -ENOMEM. + */ +- ret = rpmsg_trysend(rpdev->ept, (void *)buf, msg_size); ++ ret = rpmsg_trysend(rpdev->ept, data, data_len); + if (ret) { + dev_dbg_ratelimited(&rpdev->dev, "rpmsg_send failed: %d\n", ret); +- return ret; ++ msg_size = ret; + } + ++ kfree(msg); ++ + return msg_size; + } + +@@ -105,8 +222,10 @@ static unsigned int rpmsg_tty_write_room(struct tty_struct *tty) + { + struct rpmsg_tty_port *cport = tty->driver_data; + int size; ++ struct rpmsg_device *rpdev; + +- size = rpmsg_get_mtu(cport->rpdev->ept); ++ rpdev = cport->rpdev; ++ size = cport->use_srtm_uart_protocol ? (cport->srtm_uart_msg_data_max_sz) : (rpmsg_get_mtu(rpdev->ept)); + if (size < 0) + return 0; + +@@ -172,7 +291,12 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev) + struct rpmsg_tty_port *cport; + struct device *dev = &rpdev->dev; + struct device *tty_dev; ++ struct device_node *np; ++ struct imx_srtm_uart_data_structure *srtm_uart_data = NULL; ++ struct srtm_uart_msg *msg = NULL; + int ret; ++ int data_len = 0; ++ char buf[64]; + + cport = rpmsg_tty_alloc_cport(); + if (IS_ERR(cport)) +@@ -181,6 +305,23 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev) + tty_port_init(&cport->port); + cport->port.ops = &rpmsg_tty_port_ops; + ++ cport->rpdev = rpdev; ++ ++ srtm_uart_data = (struct imx_srtm_uart_data_structure *)rpdev->id.driver_data; ++ if (srtm_uart_data && srtm_uart_data->use_srtm_uart_protocol == true) { ++ cport->bus_id = 0xFF; /* mcore directly print the data that received from acore */ ++ cport->use_srtm_uart_protocol = true; ++ snprintf(buf, sizeof(buf), "uart-rpbus-%d", cport->id); ++ np = of_find_node_by_name(NULL, buf); ++ if (np && of_device_is_compatible(np, "fsl,uart-rpbus") && of_device_is_available(np)) { ++ of_property_read_u32(np, "bus_id", &cport->bus_id); /* mcore will use the id as uart instance, then write data to the real uart instance */ ++ of_property_read_u32(np, "flags", &cport->flags); ++ } ++ cport->srtm_uart_msg_data_max_sz = rpmsg_get_mtu(rpdev->ept) - (sizeof(struct srtm_uart_msg) - 1); /* 1: data[1] of struct srtm_uart_msg */ ++ } else { ++ cport->use_srtm_uart_protocol = false; ++ } ++ + tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver, + cport->id, dev); + if (IS_ERR(tty_dev)) { +@@ -189,9 +330,28 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev) + return ret; + } + +- cport->rpdev = rpdev; +- +- dev_set_drvdata(dev, cport); ++ dev_set_drvdata(dev, (void *)cport); ++ ++ /* Say hello to remote to acknowleage each other */ ++ if (cport->use_srtm_uart_protocol) { ++ data_len = sizeof(struct srtm_uart_msg); /* srtm uart msg header */ ++ msg = kmalloc(data_len, GFP_KERNEL); ++ if (!msg) ++ return -ENOMEM; ++ ++ memset(msg, 0, data_len); ++ msg->header.common.cate = IMX_SRTM_CATEGORY_UART; ++ msg->header.common.major = IMX_SRTM_VER_UART; ++ msg->header.common.minor = IMX_SRTM_VER_UART >> 8; ++ msg->header.common.type = IMX_SRTM_TYPE_NOTIFY; ++ msg->header.common.cmd = IMX_SRTM_UART_COMMAND_HELLO; ++ msg->header.common.reserved[0] = IMX_SRTM_UART_PRIORITY; ++ msg->header.bus_id = cport->bus_id & 0xFF; ++ msg->header.flags = cport->flags & 0xFFFF; ++ ++ rpmsg_send(rpdev->ept, (void *)msg, data_len); ++ kfree(msg); ++ } + + dev_dbg(dev, "New channel: 0x%x -> 0x%x: " RPMSG_TTY_NAME "%d\n", + rpdev->src, rpdev->dst, cport->id); +@@ -214,7 +374,8 @@ static void rpmsg_tty_remove(struct rpmsg_device *rpdev) + } + + static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = { +- { .name = "rpmsg-tty" }, ++ { .name = "srtm-uart-channel", .driver_data = (kernel_ulong_t)&imx_srtm_uart_data, }, ++ { .name = "rpmsg-tty", .driver_data = (kernel_ulong_t)&rpmsg_tty_data, }, + { }, + }; + MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table); +@@ -283,5 +444,6 @@ module_init(rpmsg_tty_init); + module_exit(rpmsg_tty_exit); + + MODULE_AUTHOR("Arnaud Pouliquen "); ++MODULE_AUTHOR("Biwen Li "); + MODULE_DESCRIPTION("remote processor messaging tty driver"); + MODULE_LICENSE("GPL v2"); +diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h +index eeb7b43ebe53..b17715d340c3 100644 +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -176,12 +176,49 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value) + up->dl_write(up, value); + } + ++static inline int serial8250_in_IER(struct uart_8250_port *up) ++{ ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ bool is_console; ++ int ier; ++ ++ is_console = uart_console(port); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(flags); ++ ++ ier = serial_in(up, UART_IER); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(flags); ++ ++ return ier; ++} ++ ++static inline void serial8250_set_IER(struct uart_8250_port *up, int ier) ++{ ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ bool is_console; ++ ++ is_console = uart_console(port); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(flags); ++ ++ serial_out(up, UART_IER, ier); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(flags); ++} ++ + static inline bool serial8250_set_THRI(struct uart_8250_port *up) + { + if (up->ier & UART_IER_THRI) + return false; + up->ier |= UART_IER_THRI; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + return true; + } + +@@ -190,7 +227,7 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up) + if (!(up->ier & UART_IER_THRI)) + return false; + up->ier &= ~UART_IER_THRI; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + return true; + } + +diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c +index 9d2a7856784f..7cc6b527c088 100644 +--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c ++++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c +@@ -278,7 +278,7 @@ static void __aspeed_vuart_set_throttle(struct uart_8250_port *up, + up->ier &= ~irqs; + if (!throttle) + up->ier |= irqs; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + } + static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle) + { +diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c +index ffc7f67e27e3..8b211e668bc0 100644 +--- a/drivers/tty/serial/8250/8250_bcm7271.c ++++ b/drivers/tty/serial/8250/8250_bcm7271.c +@@ -609,7 +609,7 @@ static int brcmuart_startup(struct uart_port *port) + * will handle this. + */ + up->ier &= ~UART_IER_RDI; +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + + priv->tx_running = false; + priv->dma.rx_dma = NULL; +@@ -775,10 +775,12 @@ static int brcmuart_handle_irq(struct uart_port *p) + unsigned int iir = serial_port_in(p, UART_IIR); + struct brcmuart_priv *priv = p->private_data; + struct uart_8250_port *up = up_to_u8250p(p); ++ unsigned long cs_flags; + unsigned int status; + unsigned long flags; + unsigned int ier; + unsigned int mcr; ++ bool is_console; + int handled = 0; + + /* +@@ -789,6 +791,10 @@ static int brcmuart_handle_irq(struct uart_port *p) + spin_lock_irqsave(&p->lock, flags); + status = serial_port_in(p, UART_LSR); + if ((status & UART_LSR_DR) == 0) { ++ is_console = uart_console(p); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(cs_flags); + + ier = serial_port_in(p, UART_IER); + /* +@@ -809,6 +815,9 @@ static int brcmuart_handle_irq(struct uart_port *p) + serial_port_in(p, UART_RX); + } + ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(cs_flags); ++ + handled = 1; + } + spin_unlock_irqrestore(&p->lock, flags); +@@ -823,8 +832,10 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) + struct brcmuart_priv *priv = container_of(t, struct brcmuart_priv, hrt); + struct uart_port *p = priv->up; + struct uart_8250_port *up = up_to_u8250p(p); ++ unsigned long cs_flags; + unsigned int status; + unsigned long flags; ++ bool is_console; + + if (priv->shutdown) + return HRTIMER_NORESTART; +@@ -846,12 +857,20 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) + /* re-enable receive unless upper layer has disabled it */ + if ((up->ier & (UART_IER_RLSI | UART_IER_RDI)) == + (UART_IER_RLSI | UART_IER_RDI)) { ++ is_console = uart_console(p); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(cs_flags); ++ + status = serial_port_in(p, UART_IER); + status |= (UART_IER_RLSI | UART_IER_RDI); + serial_port_out(p, UART_IER, status); + status = serial_port_in(p, UART_MCR); + status |= UART_MCR_RTS; + serial_port_out(p, UART_MCR, status); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(cs_flags); + } + spin_unlock_irqrestore(&p->lock, flags); + return HRTIMER_NORESTART; +diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c +index 81a5dab1a828..536f639ff56c 100644 +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -255,8 +255,11 @@ static void serial8250_timeout(struct timer_list *t) + static void serial8250_backup_timeout(struct timer_list *t) + { + struct uart_8250_port *up = from_timer(up, t, timer); ++ struct uart_port *port = &up->port; + unsigned int iir, ier = 0, lsr; ++ unsigned long cs_flags; + unsigned long flags; ++ bool is_console; + + spin_lock_irqsave(&up->port.lock, flags); + +@@ -265,8 +268,16 @@ static void serial8250_backup_timeout(struct timer_list *t) + * based handler. + */ + if (up->port.irq) { ++ is_console = uart_console(port); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(cs_flags); ++ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(cs_flags); + } + + iir = serial_in(up, UART_IIR); +@@ -289,7 +300,7 @@ static void serial8250_backup_timeout(struct timer_list *t) + serial8250_tx_chars(up); + + if (up->port.irq) +- serial_out(up, UART_IER, ier); ++ serial8250_set_IER(up, ier); + + spin_unlock_irqrestore(&up->port.lock, flags); + +@@ -575,6 +586,14 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) + + #ifdef CONFIG_SERIAL_8250_CONSOLE + ++static void univ8250_console_write_atomic(struct console *co, const char *s, ++ unsigned int count) ++{ ++ struct uart_8250_port *up = &serial8250_ports[co->index]; ++ ++ serial8250_console_write_atomic(up, s, count); ++} ++ + static void univ8250_console_write(struct console *co, const char *s, + unsigned int count) + { +@@ -668,6 +687,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, + + static struct console univ8250_console = { + .name = "ttyS", ++ .write_atomic = univ8250_console_write_atomic, + .write = univ8250_console_write, + .device = uart_console_device, + .setup = univ8250_console_setup, +@@ -961,7 +981,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work) + spin_lock_irqsave(&port->lock, flags); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + up->port.read_status_mask |= UART_LSR_DR; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + spin_unlock_irqrestore(&port->lock, flags); + } + +diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c +index b406cba10b0e..246c32c75a4c 100644 +--- a/drivers/tty/serial/8250/8250_exar.c ++++ b/drivers/tty/serial/8250/8250_exar.c +@@ -189,6 +189,8 @@ static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud, + + static int xr17v35x_startup(struct uart_port *port) + { ++ struct uart_8250_port *up = up_to_u8250p(port); ++ + /* + * First enable access to IER [7:5], ISR [5:4], FCR [5:4], + * MCR [7:5] and MSR [7:0] +@@ -199,7 +201,7 @@ static int xr17v35x_startup(struct uart_port *port) + * Make sure all interrups are masked until initialization is + * complete and the FIFOs are cleared + */ +- serial_port_out(port, UART_IER, 0); ++ serial8250_set_IER(up, 0); + + return serial8250_do_startup(port); + } +diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c +index 8adfaa183f77..eaf148245a10 100644 +--- a/drivers/tty/serial/8250/8250_fsl.c ++++ b/drivers/tty/serial/8250/8250_fsl.c +@@ -58,7 +58,8 @@ int fsl8250_handle_irq(struct uart_port *port) + if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) { + unsigned long delay; + +- up->ier = port->serial_in(port, UART_IER); ++ up->ier = serial8250_in_IER(up); ++ + if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { + port->ops->stop_rx(port); + } else { +diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c +index 2b2f5d8d24b9..2b78e6c394fb 100644 +--- a/drivers/tty/serial/8250/8250_ingenic.c ++++ b/drivers/tty/serial/8250/8250_ingenic.c +@@ -146,6 +146,7 @@ OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart", + + static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) + { ++ struct uart_8250_port *up = up_to_u8250p(p); + int ier; + + switch (offset) { +@@ -167,7 +168,7 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) + * If we have enabled modem status IRQs we should enable + * modem mode. + */ +- ier = p->serial_in(p, UART_IER); ++ ier = serial8250_in_IER(up); + + if (ier & UART_IER_MSI) + value |= UART_MCR_MDCE | UART_MCR_FCM; +diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c +index fb1d5ec0940e..3e7203909d6a 100644 +--- a/drivers/tty/serial/8250/8250_mtk.c ++++ b/drivers/tty/serial/8250/8250_mtk.c +@@ -222,12 +222,40 @@ static void mtk8250_shutdown(struct uart_port *port) + + static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) + { +- serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask)); ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ bool is_console; ++ int ier; ++ ++ is_console = uart_console(port); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(flags); ++ ++ ier = serial_in(up, UART_IER); ++ serial_out(up, UART_IER, ier & (~mask)); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(flags); + } + + static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask) + { +- serial_out(up, UART_IER, serial_in(up, UART_IER) | mask); ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ bool is_console; ++ int ier; ++ ++ is_console = uart_console(port); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(flags); ++ ++ ier = serial_in(up, UART_IER); ++ serial_out(up, UART_IER, ier | mask); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(flags); + } + + static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) +diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c +index adc85e250822..92a8441ba756 100644 +--- a/drivers/tty/serial/8250/8250_omap.c ++++ b/drivers/tty/serial/8250/8250_omap.c +@@ -328,7 +328,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) + /* drop TCR + TLR access, we setup XON/XOFF later */ + serial8250_out_MCR(up, mcr); + +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_dl_write(up, priv->quot); +@@ -518,7 +518,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, + serial_out(up, UART_EFR, efr | UART_EFR_ECB); + serial_out(up, UART_LCR, 0); + +- serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); ++ serial8250_set_IER(up, (state != 0) ? UART_IERX_SLEEP : 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, efr); + serial_out(up, UART_LCR, 0); +@@ -641,7 +641,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id) + + /* Synchronize UART_IER access against the console. */ + spin_lock(&port->lock); +- up->ier = port->serial_in(port, UART_IER); ++ up->ier = serial8250_in_IER(up); + if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { + port->ops->stop_rx(port); + } else { +@@ -701,7 +701,7 @@ static int omap_8250_startup(struct uart_port *port) + goto err; + + up->ier = UART_IER_RLSI | UART_IER_RDI; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + + #ifdef CONFIG_PM + up->capabilities |= UART_CAP_RPM; +@@ -742,7 +742,7 @@ static void omap_8250_shutdown(struct uart_port *port) + serial_out(up, UART_OMAP_EFR2, 0x0); + + up->ier = 0; +- serial_out(up, UART_IER, 0); ++ serial8250_set_IER(up, 0); + + if (up->dma) + serial8250_release_dma(up); +@@ -790,7 +790,7 @@ static void omap_8250_unthrottle(struct uart_port *port) + up->dma->rx_dma(up); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + port->read_status_mask |= UART_LSR_DR; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + spin_unlock_irqrestore(&port->lock, flags); + + pm_runtime_mark_last_busy(port->dev); +@@ -881,7 +881,7 @@ static void __dma_rx_complete(void *param) + __dma_rx_do_complete(p); + if (!priv->throttled) { + p->ier |= UART_IER_RLSI | UART_IER_RDI; +- serial_out(p, UART_IER, p->ier); ++ serial8250_set_IER(p, p->ier); + if (!(priv->habit & UART_HAS_EFR2)) + omap_8250_rx_dma(p); + } +@@ -938,7 +938,7 @@ static int omap_8250_rx_dma(struct uart_8250_port *p) + * callback to run. + */ + p->ier &= ~(UART_IER_RLSI | UART_IER_RDI); +- serial_out(p, UART_IER, p->ier); ++ serial8250_set_IER(p, p->ier); + } + goto out; + } +@@ -1151,12 +1151,12 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, + * periodic timeouts, re-enable interrupts. + */ + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + omap_8250_rx_dma_flush(up); + serial_in(up, UART_IIR); + serial_out(up, UART_OMAP_EFR2, 0x0); + up->ier |= UART_IER_RLSI | UART_IER_RDI; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + } + } + +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index 38760bd6e0c2..b3719e8258f7 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -744,7 +744,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); + } +- serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); ++ serial8250_set_IER(p, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, efr); +@@ -755,12 +755,29 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) + serial8250_rpm_put(p); + } + +-static void serial8250_clear_IER(struct uart_8250_port *up) ++static unsigned int serial8250_clear_IER(struct uart_8250_port *up) + { ++ struct uart_port *port = &up->port; ++ unsigned int clearval = 0; ++ unsigned long flags; ++ bool is_console; ++ unsigned int prior; ++ ++ is_console = uart_console(port); ++ + if (up->capabilities & UART_CAP_UUE) +- serial_out(up, UART_IER, UART_IER_UUE); +- else +- serial_out(up, UART_IER, 0); ++ clearval = UART_IER_UUE; ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(flags); ++ ++ prior = serial_in(up, UART_IER); ++ serial_out(up, UART_IER, clearval); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(flags); ++ ++ return prior; + } + + #ifdef CONFIG_SERIAL_8250_RSA +@@ -1026,8 +1043,11 @@ static int broken_efr(struct uart_8250_port *up) + */ + static void autoconfig_16550a(struct uart_8250_port *up) + { ++ struct uart_port *port = &up->port; + unsigned char status1, status2; + unsigned int iersave; ++ unsigned long flags; ++ bool is_console; + + up->port.type = PORT_16550A; + up->capabilities |= UART_CAP_FIFO; +@@ -1139,6 +1159,11 @@ static void autoconfig_16550a(struct uart_8250_port *up) + return; + } + ++ is_console = uart_console(port); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(flags); ++ + /* + * Try writing and reading the UART_IER_UUE bit (b6). + * If it works, this is probably one of the Xscale platform's +@@ -1174,6 +1199,9 @@ static void autoconfig_16550a(struct uart_8250_port *up) + } + serial_out(up, UART_IER, iersave); + ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(flags); ++ + /* + * We distinguish between 16550A and U6 16550A by counting + * how many bytes are in the FIFO. +@@ -1196,8 +1224,10 @@ static void autoconfig(struct uart_8250_port *up) + unsigned char status1, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + struct uart_port *port = &up->port; ++ unsigned long cs_flags; + unsigned long flags; + unsigned int old_capabilities; ++ bool is_console; + + if (!port->iobase && !port->mapbase && !port->membase) + return; +@@ -1215,6 +1245,11 @@ static void autoconfig(struct uart_8250_port *up) + up->bugs = 0; + + if (!(port->flags & UPF_BUGGY_UART)) { ++ is_console = uart_console(port); ++ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(cs_flags); ++ + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. +@@ -1244,6 +1279,10 @@ static void autoconfig(struct uart_8250_port *up) + #endif + scratch3 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, scratch); ++ ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(cs_flags); ++ + if (scratch2 != 0 || scratch3 != 0x0F) { + /* + * We failed; there's nothing here +@@ -1367,7 +1406,9 @@ static void autoconfig_irq(struct uart_8250_port *up) + unsigned char save_mcr, save_ier; + unsigned char save_ICP = 0; + unsigned int ICP = 0; ++ unsigned long flags; + unsigned long irqs; ++ bool is_console; + int irq; + + if (port->flags & UPF_FOURPORT) { +@@ -1377,8 +1418,12 @@ static void autoconfig_irq(struct uart_8250_port *up) + inb_p(ICP); + } + +- if (uart_console(port)) ++ is_console = uart_console(port); ++ ++ if (is_console) { + console_lock(); ++ printk_cpu_sync_get_irqsave(flags); ++ } + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); +@@ -1410,8 +1455,10 @@ static void autoconfig_irq(struct uart_8250_port *up) + if (port->flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); + +- if (uart_console(port)) ++ if (is_console) { ++ printk_cpu_sync_put_irqrestore(flags); + console_unlock(); ++ } + + port->irq = (irq > 0) ? irq : 0; + } +@@ -1424,7 +1471,7 @@ static void serial8250_stop_rx(struct uart_port *port) + + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + up->port.read_status_mask &= ~UART_LSR_DR; +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + + serial8250_rpm_put(up); + } +@@ -1454,7 +1501,7 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p) + serial8250_clear_and_reinit_fifos(p); + + p->ier |= UART_IER_RLSI | UART_IER_RDI; +- serial_port_out(&p->port, UART_IER, p->ier); ++ serial8250_set_IER(p, p->ier); + } + } + EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); +@@ -1703,7 +1750,7 @@ static void serial8250_disable_ms(struct uart_port *port) + mctrl_gpio_disable_ms(up->gpios); + + up->ier &= ~UART_IER_MSI; +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + } + + static void serial8250_enable_ms(struct uart_port *port) +@@ -1719,7 +1766,7 @@ static void serial8250_enable_ms(struct uart_port *port) + up->ier |= UART_IER_MSI; + + serial8250_rpm_get(up); +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + serial8250_rpm_put(up); + } + +@@ -2171,8 +2218,7 @@ static void serial8250_put_poll_char(struct uart_port *port, + /* + * First save the IER then disable the interrupts + */ +- ier = serial_port_in(port, UART_IER); +- serial8250_clear_IER(up); ++ ier = serial8250_clear_IER(up); + + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); + /* +@@ -2185,7 +2231,7 @@ static void serial8250_put_poll_char(struct uart_port *port, + * and restore the IER + */ + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); +- serial_port_out(port, UART_IER, ier); ++ serial8250_set_IER(up, ier); + serial8250_rpm_put(up); + } + +@@ -2194,8 +2240,10 @@ static void serial8250_put_poll_char(struct uart_port *port, + int serial8250_do_startup(struct uart_port *port) + { + struct uart_8250_port *up = up_to_u8250p(port); ++ unsigned long cs_flags; + unsigned long flags; + unsigned char iir; ++ bool is_console; + int retval; + u16 lsr; + +@@ -2216,7 +2264,7 @@ int serial8250_do_startup(struct uart_port *port) + up->acr = 0; + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); +- serial_port_out(port, UART_IER, 0); ++ serial8250_set_IER(up, 0); + serial_port_out(port, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); +@@ -2226,7 +2274,7 @@ int serial8250_do_startup(struct uart_port *port) + + if (port->type == PORT_DA830) { + /* Reset the port */ +- serial_port_out(port, UART_IER, 0); ++ serial8250_set_IER(up, 0); + serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); + mdelay(10); + +@@ -2325,6 +2373,8 @@ int serial8250_do_startup(struct uart_port *port) + if (retval) + goto out; + ++ is_console = uart_console(port); ++ + if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { + unsigned char iir1; + +@@ -2341,6 +2391,9 @@ int serial8250_do_startup(struct uart_port *port) + */ + spin_lock_irqsave(&port->lock, flags); + ++ if (is_console) ++ printk_cpu_sync_get_irqsave(cs_flags); ++ + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ +@@ -2351,6 +2404,9 @@ int serial8250_do_startup(struct uart_port *port) + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(cs_flags); ++ + spin_unlock_irqrestore(&port->lock, flags); + + if (port->irqflags & IRQF_SHARED) +@@ -2405,10 +2461,14 @@ int serial8250_do_startup(struct uart_port *port) + * Do a quick test to see if we receive an interrupt when we enable + * the TX irq. + */ ++ if (is_console) ++ printk_cpu_sync_get_irqsave(cs_flags); + serial_port_out(port, UART_IER, UART_IER_THRI); + lsr = serial_port_in(port, UART_LSR); + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); ++ if (is_console) ++ printk_cpu_sync_put_irqrestore(cs_flags); + + if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + if (!(up->bugs & UART_BUG_TXEN)) { +@@ -2440,7 +2500,7 @@ int serial8250_do_startup(struct uart_port *port) + if (up->dma) { + const char *msg = NULL; + +- if (uart_console(port)) ++ if (is_console) + msg = "forbid DMA for kernel console"; + else if (serial8250_request_dma(up)) + msg = "failed to request DMA"; +@@ -2491,7 +2551,7 @@ void serial8250_do_shutdown(struct uart_port *port) + */ + spin_lock_irqsave(&port->lock, flags); + up->ier = 0; +- serial_port_out(port, UART_IER, 0); ++ serial8250_set_IER(up, 0); + spin_unlock_irqrestore(&port->lock, flags); + + synchronize_irq(port->irq); +@@ -2853,7 +2913,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + if (up->capabilities & UART_CAP_RTOIE) + up->ier |= UART_IER_RTOIE; + +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + + if (up->capabilities & UART_CAP_EFR) { + unsigned char efr = 0; +@@ -3318,7 +3378,7 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults); + + #ifdef CONFIG_SERIAL_8250_CONSOLE + +-static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) ++static void serial8250_console_putchar_locked(struct uart_port *port, unsigned char ch) + { + struct uart_8250_port *up = up_to_u8250p(port); + +@@ -3326,6 +3386,18 @@ static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) + serial_port_out(port, UART_TX, ch); + } + ++static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) ++{ ++ struct uart_8250_port *up = up_to_u8250p(port); ++ unsigned long flags; ++ ++ wait_for_xmitr(up, UART_LSR_THRE); ++ ++ printk_cpu_sync_get_irqsave(flags); ++ serial8250_console_putchar_locked(port, ch); ++ printk_cpu_sync_put_irqrestore(flags); ++} ++ + /* + * Restore serial console when h/w power-off detected + */ +@@ -3352,6 +3424,32 @@ static void serial8250_console_restore(struct uart_8250_port *up) + serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); + } + ++void serial8250_console_write_atomic(struct uart_8250_port *up, ++ const char *s, unsigned int count) ++{ ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ unsigned int ier; ++ ++ printk_cpu_sync_get_irqsave(flags); ++ ++ touch_nmi_watchdog(); ++ ++ ier = serial8250_clear_IER(up); ++ ++ if (atomic_fetch_inc(&up->console_printing)) { ++ uart_console_write(port, "\n", 1, ++ serial8250_console_putchar_locked); ++ } ++ uart_console_write(port, s, count, serial8250_console_putchar_locked); ++ atomic_dec(&up->console_printing); ++ ++ wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); ++ serial8250_set_IER(up, ier); ++ ++ printk_cpu_sync_put_irqrestore(flags); ++} ++ + /* + * Print a string to the serial port using the device FIFO + * +@@ -3397,20 +3495,15 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int ier, use_fifo; +- int locked = 1; + + touch_nmi_watchdog(); + +- if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); +- else +- spin_lock_irqsave(&port->lock, flags); ++ spin_lock_irqsave(&port->lock, flags); + + /* + * First save the IER then disable the interrupts + */ +- ier = serial_port_in(port, UART_IER); +- serial8250_clear_IER(up); ++ ier = serial8250_clear_IER(up); + + /* check scratch reg to see if port powered off during system sleep */ + if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { +@@ -3444,10 +3537,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + */ + !(up->port.flags & UPF_CONS_FLOW); + ++ atomic_inc(&up->console_printing); + if (likely(use_fifo)) + serial8250_console_fifo_write(up, s, count); + else + uart_console_write(port, s, count, serial8250_console_putchar); ++ atomic_dec(&up->console_printing); + + /* + * Finally, wait for transmitter to become empty +@@ -3460,8 +3555,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + if (em485->tx_stopped) + up->rs485_stop_tx(up); + } +- +- serial_port_out(port, UART_IER, ier); ++ serial8250_set_IER(up, ier); + + /* + * The receive handling will happen properly because the +@@ -3473,8 +3567,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + if (up->msr_saved_flags) + serial8250_modem_status(up); + +- if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ spin_unlock_irqrestore(&port->lock, flags); + } + + static unsigned int probe_baud(struct uart_port *port) +@@ -3494,6 +3587,7 @@ static unsigned int probe_baud(struct uart_port *port) + + int serial8250_console_setup(struct uart_port *port, char *options, bool probe) + { ++ struct uart_8250_port *up = up_to_u8250p(port); + int baud = 9600; + int bits = 8; + int parity = 'n'; +@@ -3503,6 +3597,8 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) + if (!port->iobase && !port->membase) + return -ENODEV; + ++ atomic_set(&up->console_printing, 0); ++ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else if (probe) +diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig +index 583a340f9934..1f31320820a6 100644 +--- a/drivers/tty/serial/8250/Kconfig ++++ b/drivers/tty/serial/8250/Kconfig +@@ -9,6 +9,7 @@ config SERIAL_8250 + depends on !S390 + select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB ++ select HAVE_ATOMIC_CONSOLE + help + This selects whether you want to include the driver for the standard + serial ports. The standard answer is Y. People who might say N +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 0a1cc36f93aa..51a8176050f8 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2320,18 +2320,24 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + { + struct uart_amba_port *uap = amba_ports[co->index]; + unsigned int old_cr = 0, new_cr; +- unsigned long flags; ++ unsigned long flags = 0; + int locked = 1; + + clk_enable(uap->clk); + +- local_irq_save(flags); ++ /* ++ * local_irq_save(flags); ++ * ++ * This local_irq_save() is nonsense. If we come in via sysrq ++ * handling then interrupts are already disabled. Aside of ++ * that the port.sysrq check is racy on SMP regardless. ++ */ + if (uap->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&uap->port.lock); ++ locked = spin_trylock_irqsave(&uap->port.lock, flags); + else +- spin_lock(&uap->port.lock); ++ spin_lock_irqsave(&uap->port.lock, flags); + + /* + * First save the CR then disable the interrupts +@@ -2357,8 +2363,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + pl011_write(old_cr, uap, REG_CR); + + if (locked) +- spin_unlock(&uap->port.lock); +- local_irq_restore(flags); ++ spin_unlock_irqrestore(&uap->port.lock, flags); + + clk_disable(uap->clk); + } +diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c +index 7d0d2718ef59..aa216fdbcb1d 100644 +--- a/drivers/tty/serial/omap-serial.c ++++ b/drivers/tty/serial/omap-serial.c +@@ -1241,13 +1241,10 @@ serial_omap_console_write(struct console *co, const char *s, + unsigned int ier; + int locked = 1; + +- local_irq_save(flags); +- if (up->port.sysrq) +- locked = 0; +- else if (oops_in_progress) +- locked = spin_trylock(&up->port.lock); ++ if (up->port.sysrq || oops_in_progress) ++ locked = spin_trylock_irqsave(&up->port.lock, flags); + else +- spin_lock(&up->port.lock); ++ spin_lock_irqsave(&up->port.lock, flags); + + /* + * First save the IER then disable the interrupts +@@ -1274,8 +1271,7 @@ serial_omap_console_write(struct console *co, const char *s, + check_modem_status(up); + + if (locked) +- spin_unlock(&up->port.lock); +- local_irq_restore(flags); ++ spin_unlock_irqrestore(&up->port.lock, flags); + } + + static int __init +diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c +index d2b2720db6ca..18e623325887 100644 +--- a/drivers/tty/sysrq.c ++++ b/drivers/tty/sysrq.c +@@ -581,6 +581,7 @@ void __handle_sysrq(int key, bool check_mask) + + rcu_sysrq_start(); + rcu_read_lock(); ++ printk_prefer_direct_enter(); + /* + * Raise the apparent loglevel to maximum so that the sysrq header + * is shown to provide the user with positive feedback. We do not +@@ -622,6 +623,7 @@ void __handle_sysrq(int key, bool check_mask) + pr_cont("\n"); + console_loglevel = orig_log_level; + } ++ printk_prefer_direct_exit(); + rcu_read_unlock(); + rcu_sysrq_end(); + +diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h +index 4e0e50e7ac15..173e979b84a9 100644 +--- a/drivers/vdpa/vdpa_user/iova_domain.h ++++ b/drivers/vdpa/vdpa_user/iova_domain.h +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + + #define IOVA_START_PFN 1 + +diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig +index 106b47ab9f4f..d0b8375d10ec 100644 +--- a/drivers/virtio/Kconfig ++++ b/drivers/virtio/Kconfig +@@ -145,6 +145,14 @@ config VIRTIO_INPUT + + If unsure, say M. + ++config VIRTIO_TRANS ++ tristate "VirtIO transfer test driver" ++ depends on VIRTIO ++ help ++ This driver is for VirtIO transfer performance test ++ between front-end and back-end driver. ++ If unsure, say N. ++ + config VIRTIO_MMIO + tristate "Platform bus driver for memory mapped virtio devices" + depends on HAS_IOMEM && HAS_DMA +diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile +index 7960f6493913..bdf34908610c 100644 +--- a/drivers/virtio/Makefile ++++ b/drivers/virtio/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o + obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o + obj-$(CONFIG_VIRTIO_MEM) += virtio_mem.o + obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) += virtio_dma_buf.o ++obj-$(CONFIG_VIRTIO_TRANS) += virtio_trans.o +diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c +index dec3cba88458..c65a22c6631d 100644 +--- a/drivers/virtio/virtio_mmio.c ++++ b/drivers/virtio/virtio_mmio.c +@@ -3,6 +3,7 @@ + * Virtio memory mapped device driver + * + * Copyright 2011-2014, ARM Ltd. ++ * Copyright 2022-2023 NXP + * + * This module allows virtio devices to be used over a virtual, memory mapped + * platform device. +@@ -60,7 +61,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -69,7 +72,7 @@ + #include + #include + #include +- ++#include + + + /* The alignment to use between consumer and producer parts of vring. +@@ -81,6 +84,13 @@ + #define to_virtio_mmio_device(_plat_dev) \ + container_of(_plat_dev, struct virtio_mmio_device, vdev) + ++struct virtio_mmio_wr_op { ++ uint64_t phy_base; ++ uint32_t offset; ++ uint32_t value; ++ uint8_t len; ++}; ++ + struct virtio_mmio_device { + struct virtio_device vdev; + struct platform_device *pdev; +@@ -91,6 +101,16 @@ struct virtio_mmio_device { + /* a list of queues so we can dispatch IRQs */ + spinlock_t lock; + struct list_head virtqueues; ++ ++ /* Hypervisor_less virtio */ ++ bool is_hypervisor_less; ++ phys_addr_t phys; ++ struct virtio_mmio_wr_op *wr_ops; ++ dma_addr_t wr_ops_phys; ++ struct mbox_client mbox_wr_cl; ++ struct mbox_client mbox_irq_cl; ++ struct mbox_chan *mmio_wr_ch; ++ struct mbox_chan *mmio_irq_ch; + }; + + struct virtio_mmio_vq_info { +@@ -101,7 +121,72 @@ struct virtio_mmio_vq_info { + struct list_head node; + }; + ++static void vmd_write(struct virtio_mmio_device *vm_dev, u32 val, u32 off, u8 len) ++{ ++ void __iomem *addr = vm_dev->base + off; ++ struct virtio_mmio_wr_op *wr_ops = vm_dev->wr_ops; ++ int timeout; ++ int ret; ++ ++ switch (len) { ++ case 1: ++ writeb(val, addr); ++ break; ++ case 2: ++ writew(val, addr); ++ break; ++ case 4: ++ writel(val, addr); ++ break; ++ default: ++ return; ++ } ++ ++ if (vm_dev->is_hypervisor_less) { ++ ++ timeout = 1000000; ++ writel(0, vm_dev->base + VIRTIO_MMIO_WD_STATUS); ++ ++ wr_ops->phy_base = (uint64_t)vm_dev->phys; ++ wr_ops->offset = off; ++ wr_ops->value = val; ++ wr_ops->len = len; ++ ++ ret = mbox_send_message(vm_dev->mmio_wr_ch, &vm_dev->wr_ops_phys); ++ if (ret < 0) ++ dev_err(&vm_dev->vdev.dev, "mmio write error: base: %llx offset: %x, val: %x, len: %d\n", ++ wr_ops->phy_base, wr_ops->offset, ++ wr_ops->value, wr_ops->len); ++ ++ /* Unnecessary to sync for virtqueue notification */ ++ if (off == VIRTIO_MMIO_QUEUE_NOTIFY) ++ return; ++ ++ /* poll backend write operation complete */ ++ while (timeout-- && !readl(vm_dev->base + VIRTIO_MMIO_WD_STATUS)) ++ udelay(1); ++ ++ if (timeout < 0) ++ dev_err(&vm_dev->vdev.dev, "mmio write timeout: base: %llx offset: %x, val: %x, len: %d\n", ++ wr_ops->phy_base, wr_ops->offset, ++ wr_ops->value, wr_ops->len); ++ } ++} ++ ++static void vmd_writel(struct virtio_mmio_device *vm_dev, u32 val, u32 off) ++{ ++ vmd_write(vm_dev, val, off, 4); ++} ++ ++static void vmd_writew(struct virtio_mmio_device *vm_dev, u32 val, u32 off) ++{ ++ vmd_write(vm_dev, val, off, 2); ++} + ++static void vmd_writeb(struct virtio_mmio_device *vm_dev, u32 val, u32 off) ++{ ++ vmd_write(vm_dev, val, off, 1); ++} + + /* Configuration interface */ + +@@ -110,11 +195,11 @@ static u64 vm_get_features(struct virtio_device *vdev) + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); + u64 features; + +- writel(1, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL); ++ vmd_writel(vm_dev, 1, VIRTIO_MMIO_DEVICE_FEATURES_SEL); + features = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES); + features <<= 32; + +- writel(0, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL); ++ vmd_writel(vm_dev, 0, VIRTIO_MMIO_DEVICE_FEATURES_SEL); + features |= readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES); + + return features; +@@ -134,13 +219,13 @@ static int vm_finalize_features(struct virtio_device *vdev) + return -EINVAL; + } + +- writel(1, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL); +- writel((u32)(vdev->features >> 32), +- vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES); ++ vmd_writel(vm_dev, 1, VIRTIO_MMIO_DRIVER_FEATURES_SEL); ++ vmd_writel(vm_dev, (u32)(vdev->features >> 32), ++ VIRTIO_MMIO_DRIVER_FEATURES); + +- writel(0, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL); +- writel((u32)vdev->features, +- vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES); ++ vmd_writel(vm_dev, 0, VIRTIO_MMIO_DRIVER_FEATURES_SEL); ++ vmd_writel(vm_dev, (u32)vdev->features, ++ VIRTIO_MMIO_DRIVER_FEATURES); + + return 0; + } +@@ -191,17 +276,13 @@ static void vm_set(struct virtio_device *vdev, unsigned int offset, + const void *buf, unsigned int len) + { + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); +- void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG; ++ u32 base = VIRTIO_MMIO_CONFIG; + u8 b; + __le16 w; + __le32 l; + + if (vm_dev->version == 1) { +- const u8 *ptr = buf; +- int i; +- +- for (i = 0; i < len; i++) +- writeb(ptr[i], base + offset + i); ++ vmd_writel(vm_dev, *(u32 *)buf, base + offset); + + return; + } +@@ -209,21 +290,21 @@ static void vm_set(struct virtio_device *vdev, unsigned int offset, + switch (len) { + case 1: + memcpy(&b, buf, sizeof b); +- writeb(b, base + offset); ++ vmd_writeb(vm_dev, b, base + offset); + break; + case 2: + memcpy(&w, buf, sizeof w); +- writew(le16_to_cpu(w), base + offset); ++ vmd_writew(vm_dev, le16_to_cpu(w), base + offset); + break; + case 4: + memcpy(&l, buf, sizeof l); +- writel(le32_to_cpu(l), base + offset); ++ vmd_writel(vm_dev, le32_to_cpu(l), base + offset); + break; + case 8: + memcpy(&l, buf, sizeof l); +- writel(le32_to_cpu(l), base + offset); ++ vmd_writel(vm_dev, le32_to_cpu(l), base + offset); + memcpy(&l, buf + sizeof l, sizeof l); +- writel(le32_to_cpu(l), base + offset + sizeof l); ++ vmd_writel(vm_dev, le32_to_cpu(l), base + offset + sizeof l); + break; + default: + BUG(); +@@ -259,7 +340,7 @@ static void vm_set_status(struct virtio_device *vdev, u8 status) + * that the cache coherent memory writes have completed + * before writing to the MMIO region. + */ +- writel(status, vm_dev->base + VIRTIO_MMIO_STATUS); ++ vmd_writel(vm_dev, status, VIRTIO_MMIO_STATUS); + } + + static void vm_reset(struct virtio_device *vdev) +@@ -267,7 +348,7 @@ static void vm_reset(struct virtio_device *vdev) + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); + + /* 0 status means a reset. */ +- writel(0, vm_dev->base + VIRTIO_MMIO_STATUS); ++ vmd_writel(vm_dev, 0, VIRTIO_MMIO_STATUS); + } + + +@@ -281,10 +362,40 @@ static bool vm_notify(struct virtqueue *vq) + + /* We write the queue's selector into the notification register to + * signal the other end */ +- writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY); ++ vmd_writel(vm_dev, vq->index, VIRTIO_MMIO_QUEUE_NOTIFY); + return true; + } + ++/* Notify all virtqueues on an interrupt. */ ++static void virtio_mmio_irq_callback(struct mbox_client *c, void *msg) ++{ ++ struct virtio_mmio_device *vm_dev = container_of(c, ++ struct virtio_mmio_device, mbox_irq_cl); ++ struct virtio_mmio_vq_info *info; ++ unsigned long status; ++ unsigned long flags; ++ ++ /* Read and acknowledge interrupts */ ++ status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS); ++ ++ /* ++ * For Hypervisor-less virtio, write ACK without notification, since ++ * in mailbox RX channel callback function sometimes the timeout occur ++ * calling the vmd_writel(). ++ */ ++ writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK); ++ ++ if (unlikely(status & VIRTIO_MMIO_INT_CONFIG)) ++ virtio_config_changed(&vm_dev->vdev); ++ ++ if (likely(status & VIRTIO_MMIO_INT_VRING)) { ++ spin_lock_irqsave(&vm_dev->lock, flags); ++ list_for_each_entry(info, &vm_dev->virtqueues, node) ++ vring_interrupt(0, info->vq); ++ spin_unlock_irqrestore(&vm_dev->lock, flags); ++ } ++} ++ + /* Notify all virtqueues on an interrupt. */ + static irqreturn_t vm_interrupt(int irq, void *opaque) + { +@@ -296,7 +407,7 @@ static irqreturn_t vm_interrupt(int irq, void *opaque) + + /* Read and acknowledge interrupts */ + status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS); +- writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK); ++ vmd_writel(vm_dev, status, VIRTIO_MMIO_INTERRUPT_ACK); + + if (unlikely(status & VIRTIO_MMIO_INT_CONFIG)) { + virtio_config_changed(&vm_dev->vdev); +@@ -327,11 +438,11 @@ static void vm_del_vq(struct virtqueue *vq) + spin_unlock_irqrestore(&vm_dev->lock, flags); + + /* Select and deactivate the queue */ +- writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); ++ vmd_writel(vm_dev, index, VIRTIO_MMIO_QUEUE_SEL); + if (vm_dev->version == 1) { +- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); ++ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_PFN); + } else { +- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); ++ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_READY); + WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY)); + } + +@@ -348,7 +459,10 @@ static void vm_del_vqs(struct virtio_device *vdev) + list_for_each_entry_safe(vq, n, &vdev->vqs, list) + vm_del_vq(vq); + +- free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev); ++ if (vm_dev->is_hypervisor_less) ++ mbox_free_channel(vm_dev->mmio_irq_ch); ++ else ++ free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev); + } + + static void vm_synchronize_cbs(struct virtio_device *vdev) +@@ -373,7 +487,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in + return NULL; + + /* Select the queue we're interested in */ +- writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); ++ vmd_writel(vm_dev, index, VIRTIO_MMIO_QUEUE_SEL); + + /* Queue shouldn't already be set up. */ + if (readl(vm_dev->base + (vm_dev->version == 1 ? +@@ -406,7 +520,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in + vq->num_max = num; + + /* Activate the queue */ +- writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); ++ vmd_writel(vm_dev, virtqueue_get_vring_size(vq), VIRTIO_MMIO_QUEUE_NUM); + if (vm_dev->version == 1) { + u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT; + +@@ -423,27 +537,27 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in + goto error_bad_pfn; + } + +- writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); +- writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); ++ vmd_writel(vm_dev, PAGE_SIZE, VIRTIO_MMIO_QUEUE_ALIGN); ++ vmd_writel(vm_dev, q_pfn, VIRTIO_MMIO_QUEUE_PFN); + } else { + u64 addr; + + addr = virtqueue_get_desc_addr(vq); +- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW); +- writel((u32)(addr >> 32), +- vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH); ++ vmd_writel(vm_dev, (u32)addr, VIRTIO_MMIO_QUEUE_DESC_LOW); ++ vmd_writel(vm_dev, (u32)(addr >> 32), ++ VIRTIO_MMIO_QUEUE_DESC_HIGH); + + addr = virtqueue_get_avail_addr(vq); +- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW); +- writel((u32)(addr >> 32), +- vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH); ++ vmd_writel(vm_dev, (u32)addr, VIRTIO_MMIO_QUEUE_AVAIL_LOW); ++ vmd_writel(vm_dev, (u32)(addr >> 32), ++ VIRTIO_MMIO_QUEUE_AVAIL_HIGH); + + addr = virtqueue_get_used_addr(vq); +- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW); +- writel((u32)(addr >> 32), +- vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH); ++ vmd_writel(vm_dev, (u32)addr, VIRTIO_MMIO_QUEUE_USED_LOW); ++ vmd_writel(vm_dev, (u32)(addr >> 32), ++ VIRTIO_MMIO_QUEUE_USED_HIGH); + +- writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); ++ vmd_writel(vm_dev, 1, VIRTIO_MMIO_QUEUE_READY); + } + + vq->priv = info; +@@ -459,9 +573,9 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in + vring_del_virtqueue(vq); + error_new_virtqueue: + if (vm_dev->version == 1) { +- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); ++ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_PFN); + } else { +- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); ++ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_READY); + WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY)); + } + kfree(info); +@@ -470,6 +584,28 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in + return ERR_PTR(err); + } + ++static int virtio_mmio_irq_channel_init(struct virtio_mmio_device *vm_dev) ++{ ++ struct platform_device *pdev = vm_dev->pdev; ++ struct device *dev = &pdev->dev; ++ struct mbox_client *cl; ++ int ret = 0; ++ ++ cl = &vm_dev->mbox_irq_cl; ++ cl->dev = dev; ++ cl->rx_callback = virtio_mmio_irq_callback; ++ ++ vm_dev->mmio_irq_ch = mbox_request_channel_byname(cl, "mmioirq"); ++ if (IS_ERR(vm_dev->mmio_irq_ch)) { ++ ret = PTR_ERR(vm_dev->mmio_irq_ch); ++ dev_err(cl->dev, "failed to request mbox irq chan, ret %d\n", ++ ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ + static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs, + struct virtqueue *vqs[], + vq_callback_t *callbacks[], +@@ -478,16 +614,24 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs, + struct irq_affinity *desc) + { + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); +- int irq = platform_get_irq(vm_dev->pdev, 0); ++ int irq; + int i, err, queue_idx = 0; + +- if (irq < 0) +- return irq; ++ if (vm_dev->is_hypervisor_less) { ++ err = virtio_mmio_irq_channel_init(vm_dev); ++ if (err) ++ return err; ++ } else { ++ irq = platform_get_irq(vm_dev->pdev, 0); ++ if (irq < 0) ++ return irq; + +- err = request_irq(irq, vm_interrupt, IRQF_SHARED, +- dev_name(&vdev->dev), vm_dev); +- if (err) +- return err; ++ err = request_irq(irq, vm_interrupt, IRQF_SHARED, ++ dev_name(&vdev->dev), vm_dev); ++ ++ if (err) ++ return err; ++ } + + if (of_property_read_bool(vm_dev->pdev->dev.of_node, "wakeup-source")) + enable_irq_wake(irq); +@@ -523,7 +667,7 @@ static bool vm_get_shm_region(struct virtio_device *vdev, + u64 len, addr; + + /* Select the region we're interested in */ +- writel(id, vm_dev->base + VIRTIO_MMIO_SHM_SEL); ++ vmd_writel(vm_dev, id, VIRTIO_MMIO_SHM_SEL); + + /* Read the region size */ + len = (u64) readl(vm_dev->base + VIRTIO_MMIO_SHM_LEN_LOW); +@@ -594,6 +738,27 @@ static void virtio_mmio_release_dev(struct device *_d) + kfree(vm_dev); + } + ++static int virtio_mmio_mbox_channel_init(struct virtio_mmio_device *vm_dev) ++{ ++ struct platform_device *pdev = vm_dev->pdev; ++ struct device *dev = &pdev->dev; ++ struct mbox_client *cl; ++ int ret = 0; ++ ++ cl = &vm_dev->mbox_wr_cl; ++ cl->dev = dev; ++ ++ vm_dev->mmio_wr_ch = mbox_request_channel_byname(cl, "mmiowr"); ++ if (IS_ERR(vm_dev->mmio_wr_ch)) { ++ ret = PTR_ERR(vm_dev->mmio_wr_ch); ++ dev_err(cl->dev, "failed to request mbox chan mmio, ret %d\n", ++ ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ + /* Platform device */ + + static int virtio_mmio_probe(struct platform_device *pdev) +@@ -601,11 +766,19 @@ static int virtio_mmio_probe(struct platform_device *pdev) + struct virtio_mmio_device *vm_dev; + unsigned long magic; + int rc; ++ struct resource *res; + + vm_dev = kzalloc(sizeof(*vm_dev), GFP_KERNEL); + if (!vm_dev) + return -ENOMEM; + ++ if (of_property_read_bool(pdev->dev.of_node, "hypervisor_less")) { ++ vm_dev->is_hypervisor_less = true; ++ rc = of_reserved_mem_device_init(&pdev->dev); ++ if (rc) ++ dev_info(&pdev->dev, "Device specific DMA pool is not available\n"); ++ } ++ + vm_dev->vdev.dev.parent = &pdev->dev; + vm_dev->vdev.dev.release = virtio_mmio_release_dev; + vm_dev->vdev.config = &virtio_mmio_config_ops; +@@ -613,15 +786,19 @@ static int virtio_mmio_probe(struct platform_device *pdev) + INIT_LIST_HEAD(&vm_dev->virtqueues); + spin_lock_init(&vm_dev->lock); + +- vm_dev->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(vm_dev->base)) +- return PTR_ERR(vm_dev->base); ++ vm_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); ++ ++ if (IS_ERR(vm_dev->base)) { ++ rc = PTR_ERR(vm_dev->base); ++ goto err; ++ } + + /* Check magic value */ + magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE); + if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) { + dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic); +- return -ENODEV; ++ rc = -ENODEV; ++ goto err; + } + + /* Check device version */ +@@ -629,7 +806,8 @@ static int virtio_mmio_probe(struct platform_device *pdev) + if (vm_dev->version < 1 || vm_dev->version > 2) { + dev_err(&pdev->dev, "Version %ld not supported!\n", + vm_dev->version); +- return -ENXIO; ++ rc = -ENXIO; ++ goto err; + } + + vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID); +@@ -638,12 +816,25 @@ static int virtio_mmio_probe(struct platform_device *pdev) + * virtio-mmio device with an ID 0 is a (dummy) placeholder + * with no function. End probing now with no error reported. + */ +- return -ENODEV; ++ rc = -ENODEV; ++ goto err; + } + vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID); + ++ if (vm_dev->is_hypervisor_less) { ++ vm_dev->phys = res->start; ++ ++ vm_dev->wr_ops = vm_dev->base + VIRTIO_MMIO_RW_OPS_MEM_OFFSET; ++ vm_dev->wr_ops_phys = res->start + VIRTIO_MMIO_RW_OPS_MEM_OFFSET; ++ ++ /* Initialize mailbox mmio channel. */ ++ rc = virtio_mmio_mbox_channel_init(vm_dev); ++ if (rc) ++ goto err; ++ } ++ + if (vm_dev->version == 1) { +- writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); ++ vmd_writel(vm_dev, PAGE_SIZE, VIRTIO_MMIO_GUEST_PAGE_SIZE); + + rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + /* +@@ -668,11 +859,20 @@ static int virtio_mmio_probe(struct platform_device *pdev) + put_device(&vm_dev->vdev.dev); + + return rc; ++ ++err: ++ if (vm_dev->is_hypervisor_less) ++ of_reserved_mem_device_release(&pdev->dev); ++ ++ return rc; + } + + static int virtio_mmio_remove(struct platform_device *pdev) + { + struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev); ++ ++ if (vm_dev->is_hypervisor_less) ++ mbox_free_channel(vm_dev->mmio_wr_ch); + unregister_virtio_device(&vm_dev->vdev); + + return 0; +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index 7d320f799ca1..dae64a48bf9e 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -572,8 +572,6 @@ static inline int virtqueue_add_split(struct virtqueue *_vq, + /* FIXME: for historical reasons, we force a notify here if + * there are outgoing parts to the buffer. Presumably the + * host should service the ring ASAP. */ +- if (out_sgs) +- vq->notify(&vq->vq); + if (indirect) + kfree(desc); + END_USE(vq); +diff --git a/drivers/virtio/virtio_trans.c b/drivers/virtio/virtio_trans.c +new file mode 100644 +index 000000000000..4fe106af4162 +--- /dev/null ++++ b/drivers/virtio/virtio_trans.c +@@ -0,0 +1,793 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright 2022-2023 NXP ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_TEST_LEN 2048 ++#define VT_TIMES 1000 ++#define INDIRECT_NUM 1 ++#define WAIT_TO_MS 2000 ++ ++#define VT_TXRX_BIT (1 << 0) ++#define VT_B_COPY_BIT (1 << 1) ++#define VT_F_COPY_BIT (1 << 2) ++#define VT_B_MODE_BIT (1 << 3) ++#define VT_F_MODE_BIT (1 << 4) ++ ++static u32 poll_delay = 10; ++ ++struct virtio_trans { ++ /* The virtio device we're associated with */ ++ struct virtio_device *vdev; ++ struct device *dev; ++ wait_queue_head_t waitqueue; ++ struct work_struct config_work; ++ ++ struct virtqueue *tx_vq, *rx_vq; ++ void *tx_buf, *rx_buf; ++ spinlock_t txvq_lock; ++ spinlock_t rxvq_lock; ++ struct scatterlist *tx_sgl; ++ struct scatterlist *rx_sgl; ++ size_t tx_vring_size; ++ size_t rx_vring_size; ++ ++ bool vt_running; ++ u32 regression; ++ size_t pkt_size; ++ bool tx; ++ bool do_copy; ++ bool poll_mode; ++ bool back_poll_mode; ++ void *data_buf; ++}; ++ ++static void tx_intr(struct virtqueue *vq) ++{ ++ struct virtio_trans *vt = vq->vdev->priv; ++ ++ if (vt->poll_mode) ++ return; ++ ++ if (!vt->vt_running) ++ return; ++ ++ if (!vt->tx) ++ return; ++ ++ wake_up_interruptible(&vt->waitqueue); ++} ++ ++static void virttrans_init_sg(struct scatterlist *sg, size_t sg_num, void *base, size_t len) ++{ ++ int i; ++ ++ sg_init_table(sg, sg_num); ++ if (likely(is_vmalloc_addr(base))) ++ for (i = 0; i < sg_num; i++) ++ sg_set_page(&sg[i], vmalloc_to_page(base + i * len), len, ++ offset_in_page(base)); ++ else ++ for (i = 0; i < sg_num; i++) ++ sg_set_buf(&sg[i], base + i * len, len); ++} ++ ++/* call this func with lock */ ++static void virttrans_queue_txbuf(struct virtio_trans *vt, ++ struct scatterlist *sg, ++ void *buf, size_t pkt_size) ++{ ++ if (vt->do_copy) ++ memcpy(buf, vt->data_buf, pkt_size); ++ virtqueue_add_outbuf(vt->tx_vq, sg, INDIRECT_NUM, buf, GFP_ATOMIC); ++} ++ ++static void virttrans_reclaim_txvq(struct virtio_trans *vt) ++{ ++ void *buf; ++ u32 len; ++ ++ spin_lock(&vt->txvq_lock); ++ while ((buf = virtqueue_get_buf(vt->tx_vq, &len)) != NULL) ++ ; ++ spin_unlock(&vt->txvq_lock); ++ ++} ++ ++static void virttrans_fill_txvq(struct virtio_trans *vt, size_t pkt_size) ++{ ++ int i; ++ ++ spin_lock(&vt->txvq_lock); ++ for (i = 0; i < vt->tx_vring_size; i++) { ++ virttrans_init_sg(&vt->tx_sgl[i * INDIRECT_NUM], INDIRECT_NUM, ++ vt->tx_buf + i * MAX_TEST_LEN * INDIRECT_NUM, ++ pkt_size); ++ virttrans_queue_txbuf(vt, &vt->tx_sgl[i * INDIRECT_NUM], ++ vt->tx_buf + i * MAX_TEST_LEN * ++ INDIRECT_NUM, pkt_size); ++ } ++ spin_unlock(&vt->txvq_lock); ++} ++ ++static void *vt_get_tx_buf(struct virtio_trans *vt) ++{ ++ void *buf; ++ int len; ++ ++ spin_lock(&vt->txvq_lock); ++ buf = virtqueue_get_buf(vt->tx_vq, &len); ++ spin_unlock(&vt->txvq_lock); ++ ++ return buf; ++} ++static int tx_pkts(struct virtio_trans *vt, size_t pkt_size, u32 times) ++{ ++ ++ ktime_t start_time, stop_time; ++ u32 cnt = times; ++ u64 time_period; ++ u32 tx_count; ++ int err; ++ int i; ++ u64 idx = 0; ++ void *buf; ++ ++ if (pkt_size > MAX_TEST_LEN) { ++ dev_err(vt->dev, "pkt_size must be less than 0x%x\n", ++ MAX_TEST_LEN); ++ return -EINVAL; ++ } ++ ++ start_time = ktime_get(); ++ ++ while (vt->vt_running && cnt > 0) { ++ buf = vt_get_tx_buf(vt); ++ while (!buf) { ++ if (!vt->back_poll_mode) ++ virtqueue_kick(vt->tx_vq); ++ ++ if (vt->poll_mode) { ++ udelay(poll_delay); ++ buf = vt_get_tx_buf(vt); ++ continue; ++ } ++ ++ err = wait_event_interruptible_timeout(vt->waitqueue, ++ (buf = vt_get_tx_buf(vt)), ++ msecs_to_jiffies(WAIT_TO_MS)); ++ if (err == -ERESTARTSYS) { ++ dev_info(vt->dev, "%s: interrupt the waiting for tx buffer by signal\n", ++ __func__); ++ goto out; ++ } ++ } ++ ++ spin_lock(&vt->txvq_lock); ++ virttrans_queue_txbuf(vt, &vt->tx_sgl[idx % vt->tx_vring_size], ++ buf, vt->pkt_size); ++ idx++; ++ spin_unlock(&vt->txvq_lock); ++ ++ cnt -= INDIRECT_NUM; ++ } ++ ++out: ++ i = 100; ++ while (i--) { ++ virtqueue_kick(vt->tx_vq); ++ virtio_cread_le(vt->vdev, struct virtio_trans_config, ++ tx_count, &tx_count); ++ if (tx_count >= times - cnt) ++ break; ++ mdelay(10); ++ } ++ ++ if (i < 0) ++ dev_err(vt->dev, "Wait backend completion timeout\n"); ++ ++ stop_time = ktime_get(); ++ time_period = ktime_us_delta(stop_time, start_time); ++ ++ pr_info("tx_test: pkt_size (%zu B), pkt_cnt (%d), period (%llu us)\n", ++ pkt_size, times - cnt, time_period); ++ ++ return err; ++} ++ ++/* call this func with lock */ ++static void virttrans_queue_rxbuf(struct virtio_trans *vt, ++ struct scatterlist *sg, ++ void *buf, size_t pkt_size) ++{ ++ if (vt->do_copy) ++ memcpy(vt->data_buf, buf, pkt_size); ++ virtqueue_add_inbuf(vt->rx_vq, sg, INDIRECT_NUM, buf, GFP_ATOMIC); ++} ++ ++static void virttrans_reclaim_rxvq(struct virtio_trans *vt) ++{ ++ void *buf; ++ u32 len; ++ ++ spin_lock(&vt->rxvq_lock); ++ while ((buf = virtqueue_get_buf(vt->rx_vq, &len)) != NULL) ++ ; ++ spin_unlock(&vt->rxvq_lock); ++ ++} ++ ++static void virttrans_fill_rxvq(struct virtio_trans *vt, size_t pkt_size) ++{ ++ int i; ++ ++ spin_lock(&vt->rxvq_lock); ++ for (i = 0; i < vt->rx_vring_size; i++) { ++ virttrans_init_sg(&vt->rx_sgl[i * INDIRECT_NUM], INDIRECT_NUM, ++ vt->rx_buf + i * MAX_TEST_LEN * INDIRECT_NUM, ++ pkt_size); ++ virttrans_queue_rxbuf(vt, &vt->rx_sgl[i * INDIRECT_NUM], ++ vt->rx_buf + i * MAX_TEST_LEN * ++ INDIRECT_NUM, pkt_size); ++ } ++ spin_unlock(&vt->rxvq_lock); ++} ++ ++static void rx_intr(struct virtqueue *vq) ++{ ++ struct virtio_trans *vt = vq->vdev->priv; ++ ++ if (vt->poll_mode) ++ return; ++ ++ if (!vt->vt_running) ++ return; ++ ++ if (vt->tx) ++ return; ++ ++ wake_up_interruptible(&vt->waitqueue); ++} ++ ++static void *vt_get_rx_buf(struct virtio_trans *vt) ++{ ++ void *buf; ++ int len; ++ ++ spin_lock(&vt->rxvq_lock); ++ buf = virtqueue_get_buf(vt->rx_vq, &len); ++ spin_unlock(&vt->rxvq_lock); ++ ++ return buf; ++} ++ ++static int rx_pkts(struct virtio_trans *vt, size_t pkt_size, u32 times) ++{ ++ ++ ktime_t start_time, stop_time; ++ u32 cnt = times; ++ u64 time_period; ++ int err; ++ void *buf; ++ u64 idx = 0; ++ ++ if (pkt_size > MAX_TEST_LEN) { ++ dev_err(vt->dev, "pkt_size must be less than 0x%x\n", ++ MAX_TEST_LEN); ++ return -EINVAL; ++ } ++ ++ start_time = ktime_get(); ++ while (vt->vt_running && cnt > 0) { ++ buf = vt_get_rx_buf(vt); ++ while (!buf) { ++ if (!vt->back_poll_mode) ++ virtqueue_kick(vt->rx_vq); ++ ++ if (vt->poll_mode) { ++ udelay(poll_delay); ++ buf = vt_get_rx_buf(vt); ++ continue; ++ } ++ ++ err = wait_event_interruptible_timeout(vt->waitqueue, ++ (buf = vt_get_rx_buf(vt)), ++ msecs_to_jiffies(WAIT_TO_MS)); ++ if (err == -ERESTARTSYS) { ++ dev_info(vt->dev, "%s: interrupt the waiting for rx buffer by signal\n", ++ __func__); ++ goto out; ++ } ++ } ++ ++ spin_lock(&vt->rxvq_lock); ++ virttrans_queue_rxbuf(vt, &vt->rx_sgl[idx % vt->rx_vring_size], ++ buf, vt->pkt_size); ++ idx++; ++ spin_unlock(&vt->rxvq_lock); ++ ++ cnt -= INDIRECT_NUM; ++ } ++ ++out: ++ stop_time = ktime_get(); ++ time_period = ktime_us_delta(stop_time, start_time); ++ ++ pr_info("rx_test: pkt_size (%zu B), pkt_cnt (%d), period (%llu us)\n", ++ pkt_size, times - cnt, time_period); ++ ++ return 0; ++} ++ ++static ssize_t vt_control_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ u32 control; ++ ++ virtio_cread_le(vt->vdev, struct virtio_trans_config, control, ++ &control); ++ ++ return sprintf(buf, "0: stop\n1: start\ncontrol = %u\n", control); ++} ++ ++static ssize_t vt_control_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t cnt) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ u32 control; ++ unsigned long val; ++ ++ if (kstrtoul(buf, 0, &val) < 0 || (val > 1)) { ++ dev_err(vt->dev, "Invalid param\n"); ++ pr_info("0: stop\n"); ++ pr_info("1: start\n"); ++ return -EINVAL; ++ } ++ ++ virtio_cread_le(vt->vdev, struct virtio_trans_config, control, ++ &control); ++ ++ if (!val) { ++ control &= ~VT_CTRL_START; ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control, ++ &control); ++ vt->vt_running = 0; ++ if (!vt->tx) ++ virttrans_reclaim_rxvq(vt); ++ else ++ virttrans_reclaim_txvq(vt); ++ ++ vt->regression = 0; ++ return cnt; ++ } ++ ++ if (vt->vt_running) { ++ dev_err(vt->dev, "Try again after this test completed\n"); ++ return -EAGAIN; ++ } ++ ++ vt->vt_running = 1; ++ control |= VT_CTRL_START; ++ ++ if (!vt->tx) { ++ virttrans_fill_rxvq(vt, vt->pkt_size); ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control, ++ &control); ++ rx_pkts(vt, vt->pkt_size, vt->regression); ++ } else { ++ virttrans_fill_txvq(vt, vt->pkt_size); ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control, ++ &control); ++ tx_pkts(vt, vt->pkt_size, vt->regression); ++ } ++ ++ control &= ~VT_CTRL_START; ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control, ++ &control); ++ ++ vt->vt_running = 0; ++ vt->regression = 0; ++ ++ return cnt; ++} ++ ++static ssize_t vt_config_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t cnt) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ u32 config; ++ unsigned long val; ++ ++ if (vt->vt_running) { ++ dev_err(dev, "Try again after this test completed\n"); ++ return -EAGAIN; ++ } ++ ++ if (kstrtoul(buf, 0, &val) < 0 || (val & ~0x1f)) { ++ dev_err(dev, "Invalid param\n"); ++ pr_info("bit[0]:\n"); ++ pr_info("\t0: TX\n"); ++ pr_info("\t1: RX\n"); ++ pr_info("bit[1]:\n"); ++ pr_info("\t0: Backend do NOT copy buffer\n"); ++ pr_info("\t1: Backend do copy buffer\n"); ++ pr_info("bit[2]:\n"); ++ pr_info("\t0: Frontend do NOT copy buffer\n"); ++ pr_info("\t1: Frontend do copy buffer\n"); ++ pr_info("bit[3]:\n"); ++ pr_info("\t0: Backend interrupt mode\n"); ++ pr_info("\t1: Backend polling mode\n"); ++ pr_info("bit[4]:\n"); ++ pr_info("\t0: Frontend interrupt mode\n"); ++ pr_info("\t1: Frontend polling mode\n"); ++ return -EINVAL; ++ } ++ ++ if (!vt->pkt_size) ++ vt->pkt_size = 64; ++ ++ if (!vt->regression) { ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, ++ regression, &vt->regression); ++ vt->regression = VT_TIMES; ++ } ++ ++ virtio_cread_le(vt->vdev, struct virtio_trans_config, config, &config); ++ ++ config &= ~(VT_CFG_TX | VT_CFG_RX | VT_CFG_COPY | ++ VT_CFG_B_POLL | VT_CFG_F_POLL); ++ vt->do_copy = false; ++ vt->back_poll_mode = false; ++ vt->poll_mode = false; ++ ++ if (val & VT_TXRX_BIT) { ++ vt->tx = false; ++ config |= VT_CFG_RX; ++ } else { ++ vt->tx = true; ++ config |= VT_CFG_TX; ++ } ++ ++ if (val & VT_B_COPY_BIT) ++ config |= VT_CFG_COPY; ++ ++ if (val & VT_F_COPY_BIT) ++ vt->do_copy = true; ++ ++ if (val & VT_B_MODE_BIT) { ++ vt->back_poll_mode = true; ++ config |= VT_CFG_B_POLL; ++ } ++ ++ if (val & VT_F_MODE_BIT) { ++ vt->poll_mode = true; ++ config |= VT_CFG_F_POLL; ++ } ++ ++ pr_info("*********************************************************\n"); ++ pr_info("Front-end: %s mode\n", vt->poll_mode ? "poll" : "interrupt"); ++ pr_info("Back-end: %s mode\n", vt->back_poll_mode ? "poll" : "interrupt"); ++ pr_info("Front-end: do %scopy buffer\n", vt->do_copy ? "" : "NOT "); ++ pr_info("Back-end: do %scopy buffer\n", (config & VT_CFG_COPY) ? "" : "NOT"); ++ ++ pr_info("\tTest case: %s\n\tpkt_size: <%zu>\n\tregress times: <%d>\n\n", ++ vt->tx ? "TX" : "RX", vt->pkt_size, vt->regression); ++ ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, config, &config); ++ ++ return cnt; ++} ++static ssize_t vt_config_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ u32 config; ++ ++ virtio_cread_le(vt->vdev, struct virtio_trans_config, config, &config); ++ ++ return sprintf(buf, "0x%x\n", config); ++} ++ ++static ssize_t vt_pkt_size_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t cnt) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ u32 val; ++ ++ if (vt->vt_running) { ++ dev_err(dev, "Try again after this test completed\n"); ++ return -EAGAIN; ++ } ++ ++ if (kstrtou32(buf, 0, &val) < 0 || (val > MAX_TEST_LEN)) { ++ dev_err(dev, "pkt_size must be less then 0x%x\n", MAX_TEST_LEN); ++ return -EINVAL; ++ } ++ ++ vt->pkt_size = val; ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, pkt_size, &val); ++ ++ dev_dbg(dev, "Update pkt_size to %u\n", val); ++ ++ return cnt; ++} ++static ssize_t vt_pkt_size_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%ld\n", vt->pkt_size); ++} ++ ++static ssize_t vt_regression_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t cnt) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ u32 val; ++ ++ if (vt->vt_running) { ++ dev_err(dev, "Try again after this test completed\n"); ++ return -EAGAIN; ++ } ++ ++ if (kstrtou32(buf, 0, &val) < 0 || val <= 0) { ++ dev_err(dev, "Invalid regression\n"); ++ return -EINVAL; ++ } ++ ++ vt->regression = val; ++ ++ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, regression, ++ &val); ++ dev_dbg(dev, "Update regression to %u\n", val); ++ ++ return cnt; ++} ++static ssize_t vt_regression_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct virtio_trans *vt = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", vt->regression); ++} ++ ++static DEVICE_ATTR_RW(vt_control); ++static DEVICE_ATTR_RW(vt_config); ++static DEVICE_ATTR_RW(vt_pkt_size); ++static DEVICE_ATTR_RW(vt_regression); ++ ++static struct attribute *sysfs_entries[] = { ++ &dev_attr_vt_config.attr, ++ &dev_attr_vt_control.attr, ++ &dev_attr_vt_pkt_size.attr, ++ &dev_attr_vt_regression.attr, ++ NULL ++}; ++ ++static const struct attribute_group vt_attribute_group = { ++ .name = NULL, /* put in device directory */ ++ .attrs = sysfs_entries, ++}; ++ ++static void config_intr(struct virtio_device *vdev) ++{ ++ struct virtio_trans *vt = vdev->priv; ++ ++ schedule_work(&vt->config_work); ++} ++ ++static void config_work_handler(struct work_struct *work) ++{ ++ /* handle the config change */ ++} ++ ++static int virttrans_init_vqs(struct virtio_trans *vt) ++{ ++ struct virtqueue *vqs[2]; ++ vq_callback_t *cbs[] = { tx_intr, rx_intr}; ++ static const char * const names[] = { "tx", "rx" }; ++ int err; ++ ++ err = virtio_find_vqs(vt->vdev, 2, vqs, cbs, names, NULL); ++ if (err) { ++ dev_err(vt->dev, "Failed to find vqs\n"); ++ return err; ++ } ++ vt->tx_vq = vqs[0]; ++ vt->rx_vq = vqs[1]; ++ ++ return 0; ++} ++ ++static int virttrans_probe(struct virtio_device *vdev) ++{ ++ struct virtio_trans *vt; ++ int err; ++ dma_addr_t tx_buf_dma; ++ ++ vt = kzalloc(sizeof(*vt), GFP_KERNEL); ++ if (!vt) ++ return -ENOMEM; ++ ++ vdev->priv = vt; ++ vt->vdev = vdev; ++ vt->dev = &vdev->dev; ++ vt->pkt_size = 64; ++ vt->regression = VT_TIMES; ++ ++ dev_set_drvdata(vt->dev, vt); ++ ++ err = virttrans_init_vqs(vt); ++ if (err) { ++ dev_err(vt->dev, "Failed to init virtqueues\n"); ++ goto err_init_vq; ++ } ++ ++ vt->tx_vring_size = virtqueue_get_vring_size(vt->tx_vq); ++ vt->rx_vring_size = virtqueue_get_vring_size(vt->rx_vq); ++ ++ vt->data_buf = kzalloc(MAX_TEST_LEN, GFP_KERNEL); ++ if (!vt->data_buf) { ++ err = -ENOMEM; ++ dev_err(vt->dev, "Failed to alloc data buffer\n"); ++ goto alloc_data_buf; ++ } ++ ++ memset(vt->data_buf, 0xa5, MAX_TEST_LEN); ++ ++ vt->tx_sgl = kzalloc(INDIRECT_NUM * (vt->rx_vring_size + ++ vt->tx_vring_size) * sizeof(struct scatterlist), ++ GFP_KERNEL); ++ ++ if (!vt->tx_sgl) { ++ err = -ENOMEM; ++ dev_err(vt->dev, "Failed to alloc SG descriptors\n"); ++ goto alloc_sgl; ++ } ++ ++ vt->rx_sgl = vt->tx_sgl + INDIRECT_NUM * vt->tx_vring_size; ++ ++ vt->tx_buf = dma_alloc_coherent(vdev->dev.parent, MAX_TEST_LEN * ++ INDIRECT_NUM * (vt->rx_vring_size + ++ vt->tx_vring_size), &tx_buf_dma, ++ GFP_KERNEL); ++ if (!vt->tx_buf) { ++ err = -ENOMEM; ++ dev_err(vt->dev, "Failed to alloc Vring buffers\n"); ++ goto alloc_buf; ++ } ++ ++ vt->rx_buf = vt->tx_buf + ++ MAX_TEST_LEN * INDIRECT_NUM * vt->tx_vring_size; ++ ++ spin_lock_init(&vt->txvq_lock); ++ spin_lock_init(&vt->rxvq_lock); ++ init_waitqueue_head(&vt->waitqueue); ++ INIT_WORK(&vt->config_work, &config_work_handler); ++ ++ err = sysfs_create_group(&vt->dev->kobj, &vt_attribute_group); ++ if (err) { ++ dev_err(vt->dev, "Failed to create sysfs device attributes\n"); ++ goto sysfs; ++ } else { ++ /* ++ * Generate a udev event so that appropriate ++ * symlinks can be created based on udev ++ * rules. ++ */ ++ kobject_uevent(&vt->dev->kobj, KOBJ_CHANGE); ++ } ++ ++ virtio_device_ready(vt->vdev); ++ ++ return 0; ++ ++sysfs: ++ dma_free_coherent(vdev->dev.parent, MAX_TEST_LEN * INDIRECT_NUM * ++ (vt->rx_vring_size + vt->tx_vring_size), ++ vt->tx_buf, tx_buf_dma); ++alloc_buf: ++ kfree(vt->tx_sgl); ++alloc_sgl: ++ kfree(vt->data_buf); ++alloc_data_buf: ++ /* TODO: vtrans_deinit_vq(); */ ++err_init_vq: ++ kfree(vt); ++ ++ return err; ++} ++ ++static void virttrans_remove(struct virtio_device *vdev) ++{ ++ struct virtio_trans *vt = vdev->priv; ++ void *buf; ++ ++ virtio_break_device(vdev); ++ flush_work(&vt->config_work); ++ vdev->config->reset(vdev); ++ cancel_work_sync(&vt->config_work); ++ ++ sysfs_remove_group(&vt->dev->kobj, &vt_attribute_group); ++ ++ while ((buf = virtqueue_detach_unused_buf(vt->tx_vq)) != NULL) ++ kfree(buf); ++ vdev->config->del_vqs(vdev); ++ ++ kfree(vt); ++} ++ ++static const struct virtio_device_id id_table[] = { ++ { VIRTIO_ID_TRANS, VIRTIO_DEV_ANY_ID }, ++ { 0 }, ++}; ++ ++static const unsigned int features[] = { ++ /* none */ ++}; ++ ++ ++static struct virtio_driver virtio_transfer = { ++ .feature_table = features, ++ .feature_table_size = ARRAY_SIZE(features), ++ .driver.name = KBUILD_MODNAME, ++ .driver.owner = THIS_MODULE, ++ .id_table = id_table, ++ .probe = virttrans_probe, ++ .remove = virttrans_remove, ++ .config_changed = config_intr, ++}; ++ ++static int __init virtio_transfer_init(void) ++{ ++ int err; ++ ++ err = register_virtio_driver(&virtio_transfer); ++ if (err < 0) { ++ pr_err("Failed to register virtio driver\n"); ++ return err; ++ } ++ return 0; ++} ++ ++static void __exit virtio_transfer_exit(void) ++{ ++ unregister_virtio_driver(&virtio_transfer); ++} ++ ++module_init(virtio_transfer_init); ++module_exit(virtio_transfer_exit); ++ ++MODULE_DEVICE_TABLE(virtio, id_table); ++MODULE_DESCRIPTION("VirtIO transfer test driver"); ++MODULE_LICENSE("GPL"); +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0008-net-add-RT-NXP-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0008-net-add-RT-NXP-support.patch new file mode 100644 index 000000000..814a6ea9d --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0008-net-add-RT-NXP-support.patch @@ -0,0 +1,1486 @@ +From 05d5158bf43c26c1bc70017da27b125cd8d7cb31 Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Mon, 26 Feb 2024 09:25:16 +0100 +Subject: [PATCH 08/10] net: add RT NXP support + +Signed-off-by: Mike Engel +--- + net/8021q/vlan_dev.c | 4 +- + net/bridge/br_multicast.c | 4 +- + net/bridge/br_switchdev.c | 24 +++++ + net/bridge/br_vlan.c | 4 +- + net/core/dev.c | 64 ++++++++--- + net/core/drop_monitor.c | 8 +- + net/core/gen_stats.c | 16 +-- + net/core/skbuff.c | 7 +- + net/devlink/leftover.c | 4 +- + net/dsa/Kconfig | 6 ++ + net/dsa/Makefile | 1 + + net/dsa/slave.c | 53 ++++++++- + net/dsa/tag_netc.c | 168 +++++++++++++++++++++++++++++ + net/dsa/tag_sja1105.c | 5 +- + net/ethtool/Makefile | 2 +- + net/ethtool/ioctl.c | 55 ++++++++++ + net/ethtool/netlink.c | 17 +++ + net/ethtool/netlink.h | 3 + + net/ethtool/preempt.c | 191 +++++++++++++++++++++++++++++++++ + net/ipv4/af_inet.c | 4 +- + net/ipv6/seg6_local.c | 4 +- + net/mac80211/sta_info.c | 8 +- + net/mpls/af_mpls.c | 4 +- + net/netfilter/ipvs/ip_vs_ctl.c | 4 +- + net/netfilter/nf_tables_api.c | 4 +- + net/openvswitch/datapath.c | 4 +- + net/openvswitch/flow_table.c | 9 +- + net/packet/af_packet.c | 9 +- + net/sched/sch_cbs.c | 5 + + net/sched/sch_taprio.c | 20 ++++ + net/socket.c | 27 +++++ + net/tsn/genl_tsn.c | 13 ++- + 32 files changed, 679 insertions(+), 72 deletions(-) + create mode 100644 net/dsa/tag_netc.c + create mode 100644 net/ethtool/preempt.c + +diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c +index d3e511e1eba8..0fa52bcc296b 100644 +--- a/net/8021q/vlan_dev.c ++++ b/net/8021q/vlan_dev.c +@@ -712,13 +712,13 @@ static void vlan_dev_get_stats64(struct net_device *dev, + + p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + rxpackets = u64_stats_read(&p->rx_packets); + rxbytes = u64_stats_read(&p->rx_bytes); + rxmulticast = u64_stats_read(&p->rx_multicast); + txpackets = u64_stats_read(&p->tx_packets); + txbytes = u64_stats_read(&p->tx_bytes); +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + + stats->rx_packets += rxpackets; + stats->rx_bytes += rxbytes; +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c +index db4f2641d1cd..7e2a9fb5786c 100644 +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -4899,9 +4899,9 @@ void br_multicast_get_stats(const struct net_bridge *br, + unsigned int start; + + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + memcpy(&temp, &cpu_stats->mstats, sizeof(temp)); +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + mcast_stats_add_dir(tdst.igmp_v1queries, temp.igmp_v1queries); + mcast_stats_add_dir(tdst.igmp_v2queries, temp.igmp_v2queries); +diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c +index 4b3982c368b3..7e6fbd0962f6 100644 +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -171,6 +171,26 @@ br_switchdev_fdb_notify(struct net_bridge *br, + } + } + ++static u16 br_switchdev_get_bridge_vlan_proto(const struct net_device *dev) ++{ ++ const struct net_device *br = NULL; ++ u16 vlan_proto = ETH_P_8021Q; ++ struct net_bridge_port *p; ++ ++ if (netif_is_bridge_master(dev)) { ++ br = dev; ++ } else { ++ p = br_port_get_rtnl_rcu(dev); ++ if (p) ++ br = p->br->dev; ++ } ++ ++ if (br) ++ br_vlan_get_proto(br, &vlan_proto); ++ ++ return vlan_proto; ++} ++ + int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags, + bool changed, struct netlink_ext_ack *extack) + { +@@ -182,6 +202,8 @@ int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags, + .changed = changed, + }; + ++ v.proto = br_switchdev_get_bridge_vlan_proto(dev); ++ + return switchdev_port_obj_add(dev, &v.obj, extack); + } + +@@ -193,6 +215,8 @@ int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid) + .vid = vid, + }; + ++ v.proto = br_switchdev_get_bridge_vlan_proto(dev); ++ + return switchdev_port_obj_del(dev, &v.obj); + } + +diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c +index 9ffd40b8270c..bc75fa1e4666 100644 +--- a/net/bridge/br_vlan.c ++++ b/net/bridge/br_vlan.c +@@ -1389,12 +1389,12 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v, + + cpu_stats = per_cpu_ptr(v->stats, i); + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + rxpackets = u64_stats_read(&cpu_stats->rx_packets); + rxbytes = u64_stats_read(&cpu_stats->rx_bytes); + txbytes = u64_stats_read(&cpu_stats->tx_bytes); + txpackets = u64_stats_read(&cpu_stats->tx_packets); +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + u64_stats_add(&stats->rx_packets, rxpackets); + u64_stats_add(&stats->rx_bytes, rxbytes); +diff --git a/net/core/dev.c b/net/core/dev.c +index a2e3c6470ab3..bd2ab2988ca5 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -1385,8 +1385,8 @@ static int napi_kthread_create(struct napi_struct *n) + * TASK_INTERRUPTIBLE mode to avoid the blocked task + * warning and work with loadavg. + */ +- n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d", +- n->dev->name, n->napi_id); ++ n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%s", ++ n->dev->name, n->name); + if (IS_ERR(n->thread)) { + err = PTR_ERR(n->thread); + pr_err("kthread_run failed with err %d\n", err); +@@ -4589,15 +4589,6 @@ static void rps_trigger_softirq(void *data) + + #endif /* CONFIG_RPS */ + +-/* Called from hardirq (IPI) context */ +-static void trigger_rx_softirq(void *data) +-{ +- struct softnet_data *sd = data; +- +- __raise_softirq_irqoff(NET_RX_SOFTIRQ); +- smp_store_release(&sd->defer_ipi_scheduled, 0); +-} +- + /* + * Check if this softnet_data structure is another cpu one + * If yes, queue it to our IPI list and return 1 +@@ -6369,8 +6360,9 @@ int dev_set_threaded(struct net_device *dev, bool threaded) + } + EXPORT_SYMBOL(dev_set_threaded); + +-void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, +- int (*poll)(struct napi_struct *, int), int weight) ++void netif_napi_add_named(struct net_device *dev, struct napi_struct *napi, ++ int (*poll)(struct napi_struct *, int), int weight, ++ const char *name) + { + if (WARN_ON(test_and_set_bit(NAPI_STATE_LISTED, &napi->state))) + return; +@@ -6397,6 +6389,12 @@ void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, + list_add_rcu(&napi->dev_list, &dev->napi_list); + napi_hash_add(napi); + napi_get_frags_check(napi); ++ ++ if (name) ++ strncpy(napi->name, name, NAPINAMSIZ); ++ else ++ snprintf(napi->name, NAPINAMSIZ, "%d", napi->napi_id); ++ + /* Create kthread for this napi if dev->threaded is set. + * Clear dev->threaded if kthread creation failed so that + * threaded mode will not be enabled in napi_enable(). +@@ -6404,6 +6402,13 @@ void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, + if (dev->threaded && napi_kthread_create(napi)) + dev->threaded = 0; + } ++EXPORT_SYMBOL(netif_napi_add_named); ++ ++void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, ++ int (*poll)(struct napi_struct *, int), int weight) ++{ ++ netif_napi_add_named(dev, napi, poll, weight, NULL); ++} + EXPORT_SYMBOL(netif_napi_add_weight); + + void napi_disable(struct napi_struct *n) +@@ -6655,6 +6660,30 @@ static void skb_defer_free_flush(struct softnet_data *sd) + } + } + ++#ifndef CONFIG_PREEMPT_RT ++/* Called from hardirq (IPI) context */ ++static void trigger_rx_softirq(void *data) ++{ ++ struct softnet_data *sd = data; ++ ++ __raise_softirq_irqoff(NET_RX_SOFTIRQ); ++ smp_store_release(&sd->defer_ipi_scheduled, 0); ++} ++ ++#else ++ ++static void trigger_rx_softirq(struct work_struct *defer_work) ++{ ++ struct softnet_data *sd; ++ ++ sd = container_of(defer_work, struct softnet_data, defer_work); ++ smp_store_release(&sd->defer_ipi_scheduled, 0); ++ local_bh_disable(); ++ skb_defer_free_flush(sd); ++ local_bh_enable(); ++} ++#endif ++ + static __latent_entropy void net_rx_action(struct softirq_action *h) + { + struct softnet_data *sd = this_cpu_ptr(&softnet_data); +@@ -10476,12 +10505,12 @@ void dev_fetch_sw_netstats(struct rtnl_link_stats64 *s, + + stats = per_cpu_ptr(netstats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + rx_packets = u64_stats_read(&stats->rx_packets); + rx_bytes = u64_stats_read(&stats->rx_bytes); + tx_packets = u64_stats_read(&stats->tx_packets); + tx_bytes = u64_stats_read(&stats->tx_bytes); +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + s->rx_packets += rx_packets; + s->rx_bytes += rx_bytes; +@@ -10607,6 +10636,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, + dev_mc_init(dev); + dev_uc_init(dev); + ++ dev->fast_raw_device = 0; + dev_net_set(dev, &init_net); + + dev->gso_max_size = GSO_LEGACY_MAX_SIZE; +@@ -11396,7 +11426,11 @@ static int __init net_dev_init(void) + INIT_CSD(&sd->csd, rps_trigger_softirq, sd); + sd->cpu = i; + #endif ++#ifndef CONFIG_PREEMPT_RT + INIT_CSD(&sd->defer_csd, trigger_rx_softirq, sd); ++#else ++ INIT_WORK(&sd->defer_work, trigger_rx_softirq); ++#endif + spin_lock_init(&sd->defer_lock); + + init_gro_hash(&sd->backlog); +diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c +index f084a4a6b7ab..11aa6e8a3098 100644 +--- a/net/core/drop_monitor.c ++++ b/net/core/drop_monitor.c +@@ -1432,9 +1432,9 @@ static void net_dm_stats_read(struct net_dm_stats *stats) + u64 dropped; + + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + dropped = u64_stats_read(&cpu_stats->dropped); +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + u64_stats_add(&stats->dropped, dropped); + } +@@ -1476,9 +1476,9 @@ static void net_dm_hw_stats_read(struct net_dm_stats *stats) + u64 dropped; + + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + dropped = u64_stats_read(&cpu_stats->dropped); +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + u64_stats_add(&stats->dropped, dropped); + } +diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c +index c8d137ef5980..b71ccaec0991 100644 +--- a/net/core/gen_stats.c ++++ b/net/core/gen_stats.c +@@ -135,10 +135,10 @@ static void gnet_stats_add_basic_cpu(struct gnet_stats_basic_sync *bstats, + u64 bytes, packets; + + do { +- start = u64_stats_fetch_begin_irq(&bcpu->syncp); ++ start = u64_stats_fetch_begin(&bcpu->syncp); + bytes = u64_stats_read(&bcpu->bytes); + packets = u64_stats_read(&bcpu->packets); +- } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); ++ } while (u64_stats_fetch_retry(&bcpu->syncp, start)); + + t_bytes += bytes; + t_packets += packets; +@@ -162,10 +162,10 @@ void gnet_stats_add_basic(struct gnet_stats_basic_sync *bstats, + } + do { + if (running) +- start = u64_stats_fetch_begin_irq(&b->syncp); ++ start = u64_stats_fetch_begin(&b->syncp); + bytes = u64_stats_read(&b->bytes); + packets = u64_stats_read(&b->packets); +- } while (running && u64_stats_fetch_retry_irq(&b->syncp, start)); ++ } while (running && u64_stats_fetch_retry(&b->syncp, start)); + + _bstats_update(bstats, bytes, packets); + } +@@ -187,10 +187,10 @@ static void gnet_stats_read_basic(u64 *ret_bytes, u64 *ret_packets, + u64 bytes, packets; + + do { +- start = u64_stats_fetch_begin_irq(&bcpu->syncp); ++ start = u64_stats_fetch_begin(&bcpu->syncp); + bytes = u64_stats_read(&bcpu->bytes); + packets = u64_stats_read(&bcpu->packets); +- } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); ++ } while (u64_stats_fetch_retry(&bcpu->syncp, start)); + + t_bytes += bytes; + t_packets += packets; +@@ -201,10 +201,10 @@ static void gnet_stats_read_basic(u64 *ret_bytes, u64 *ret_packets, + } + do { + if (running) +- start = u64_stats_fetch_begin_irq(&b->syncp); ++ start = u64_stats_fetch_begin(&b->syncp); + *ret_bytes = u64_stats_read(&b->bytes); + *ret_packets = u64_stats_read(&b->packets); +- } while (running && u64_stats_fetch_retry_irq(&b->syncp, start)); ++ } while (running && u64_stats_fetch_retry(&b->syncp, start)); + } + + static int +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index bacc7b486a7f..1339c79171a7 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6705,6 +6705,11 @@ nodefer: __kfree_skb(skb); + /* Make sure to trigger NET_RX_SOFTIRQ on the remote CPU + * if we are unlucky enough (this seems very unlikely). + */ +- if (unlikely(kick) && !cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) ++ if (unlikely(kick) && !cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) { ++#ifndef CONFIG_PREEMPT_RT + smp_call_function_single_async(cpu, &sd->defer_csd); ++#else ++ schedule_work_on(cpu, &sd->defer_work); ++#endif ++ } + } +diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c +index 032c7af065cd..94e8cc3de330 100644 +--- a/net/devlink/leftover.c ++++ b/net/devlink/leftover.c +@@ -8307,10 +8307,10 @@ static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats, + + cpu_stats = per_cpu_ptr(trap_stats, i); + do { +- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ start = u64_stats_fetch_begin(&cpu_stats->syncp); + rx_packets = u64_stats_read(&cpu_stats->rx_packets); + rx_bytes = u64_stats_read(&cpu_stats->rx_bytes); +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); + + u64_stats_add(&stats->rx_packets, rx_packets); + u64_stats_add(&stats->rx_bytes, rx_bytes); +diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig +index 3eef72ce99a4..0feef61007ef 100644 +--- a/net/dsa/Kconfig ++++ b/net/dsa/Kconfig +@@ -166,4 +166,10 @@ config NET_DSA_TAG_XRS700X + Say Y or M if you want to enable support for tagging frames for + Arrow SpeedChips XRS700x switches that use a single byte tag trailer. + ++config NET_DSA_TAG_NETC ++ tristate "Tag driver for NETC family of switches, using VLAN" ++ help ++ Say Y or M if you want to enable support for tagging frames with a ++ NXP NETC switch family. The custom 802.1Q VLAN header is available. ++ + endif +diff --git a/net/dsa/Makefile b/net/dsa/Makefile +index bf57ef3bce2a..640101b28f33 100644 +--- a/net/dsa/Makefile ++++ b/net/dsa/Makefile +@@ -29,3 +29,4 @@ obj-$(CONFIG_NET_DSA_TAG_RZN1_A5PSW) += tag_rzn1_a5psw.o + obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o + obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o + obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o ++obj-$(CONFIG_NET_DSA_TAG_NETC) += tag_netc.o +\ No newline at end of file +diff --git a/net/dsa/slave.c b/net/dsa/slave.c +index 5fe075bf479e..637568fcedac 100644 +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -976,12 +976,12 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev, + + s = per_cpu_ptr(dev->tstats, i); + do { +- start = u64_stats_fetch_begin_irq(&s->syncp); ++ start = u64_stats_fetch_begin(&s->syncp); + tx_packets = u64_stats_read(&s->tx_packets); + tx_bytes = u64_stats_read(&s->tx_bytes); + rx_packets = u64_stats_read(&s->rx_packets); + rx_bytes = u64_stats_read(&s->rx_bytes); +- } while (u64_stats_fetch_retry_irq(&s->syncp, start)); ++ } while (u64_stats_fetch_retry(&s->syncp, start)); + data[0] += tx_packets; + data[1] += tx_bytes; + data[2] += rx_packets; +@@ -1610,6 +1610,41 @@ static int dsa_slave_get_ts_info(struct net_device *dev, + return ds->ops->get_ts_info(ds, p->dp->index, ts); + } + ++static int dsa_slave_reset_preempt(struct net_device *dev, bool enable) ++{ ++ struct dsa_slave_priv *p = netdev_priv(dev); ++ struct dsa_switch *ds = p->dp->ds; ++ ++ if (!ds->ops->reset_preempt) ++ return -EOPNOTSUPP; ++ ++ return ds->ops->reset_preempt(ds, p->dp->index, enable); ++} ++ ++static int dsa_slave_set_preempt(struct net_device *dev, ++ struct ethtool_fp *fpcmd) ++{ ++ struct dsa_slave_priv *p = netdev_priv(dev); ++ struct dsa_switch *ds = p->dp->ds; ++ ++ if (!ds->ops->set_preempt) ++ return -EOPNOTSUPP; ++ ++ return ds->ops->set_preempt(ds, p->dp->index, fpcmd); ++} ++ ++static int dsa_slave_get_preempt(struct net_device *dev, ++ struct ethtool_fp *fpcmd) ++{ ++ struct dsa_slave_priv *p = netdev_priv(dev); ++ struct dsa_switch *ds = p->dp->ds; ++ ++ if (!ds->ops->get_preempt) ++ return -EOPNOTSUPP; ++ ++ return ds->ops->get_preempt(ds, p->dp->index, fpcmd); ++} ++ + static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, + u16 vid) + { +@@ -1619,6 +1654,7 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, + .vid = vid, + /* This API only allows programming tagged, non-PVID VIDs */ + .flags = 0, ++ .proto = ntohs(proto), + }; + struct netlink_ext_ack extack = {0}; + int ret; +@@ -1632,6 +1668,7 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, + } + + /* And CPU port... */ ++ vlan.proto = ETH_P_8021Q; + ret = dsa_port_host_vlan_add(dp, &vlan, &extack); + if (ret) { + if (extack._msg) +@@ -1651,6 +1688,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, + .vid = vid, + /* This API only allows programming tagged, non-PVID VIDs */ + .flags = 0, ++ .proto = ntohs(proto), + }; + int err; + +@@ -2159,6 +2197,9 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { + .set_rxnfc = dsa_slave_set_rxnfc, + .get_ts_info = dsa_slave_get_ts_info, + .self_test = dsa_slave_net_selftest, ++ .set_preempt = dsa_slave_set_preempt, ++ .get_preempt = dsa_slave_get_preempt, ++ .reset_preempt = dsa_slave_reset_preempt, + }; + + static const struct dcbnl_rtnl_ops __maybe_unused dsa_slave_dcbnl_ops = { +@@ -2770,7 +2811,9 @@ dsa_slave_check_8021q_upper(struct net_device *dev, + struct net_device *br = dsa_port_bridge_dev_get(dp); + struct bridge_vlan_info br_info; + struct netlink_ext_ack *extack; ++ bool update_proto = false; + int err = NOTIFY_DONE; ++ u16 br_proto, proto; + u16 vid; + + if (!br || !br_vlan_enabled(br)) +@@ -2778,13 +2821,17 @@ dsa_slave_check_8021q_upper(struct net_device *dev, + + extack = netdev_notifier_info_to_extack(&info->info); + vid = vlan_dev_vlan_id(info->upper_dev); ++ proto = vlan_dev_vlan_proto(info->upper_dev); ++ err = br_vlan_get_proto(br, &br_proto); ++ if (err == 0 && br_proto != proto) ++ update_proto = true; + + /* br_vlan_get_info() returns -EINVAL or -ENOENT if the + * device, respectively the VID is not found, returning + * 0 means success, which is a failure for us here. + */ + err = br_vlan_get_info(br, vid, &br_info); +- if (err == 0) { ++ if (err == 0 && !update_proto) { + NL_SET_ERR_MSG_MOD(extack, + "This VLAN is already configured by the bridge"); + return notifier_from_errno(-EBUSY); +diff --git a/net/dsa/tag_netc.c b/net/dsa/tag_netc.c +new file mode 100644 +index 000000000000..84bf6e02cf12 +--- /dev/null ++++ b/net/dsa/tag_netc.c +@@ -0,0 +1,168 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2023 NXP ++ */ ++ ++#include ++#include ++#include ++#include "dsa_priv.h" ++ ++struct netc_tagger_private { ++ struct netc_tagger_data data; /* Must be first */ ++ struct kthread_worker *xmit_worker; ++}; ++ ++/* Similar to is_link_local_ether_addr(hdr->h_dest) but also covers PTP */ ++static inline bool netc_is_link_local(const struct sk_buff *skb) ++{ ++ const struct ethhdr *hdr = eth_hdr(skb); ++ u64 dmac = ether_addr_to_u64(hdr->h_dest); ++ ++ if (ntohs(hdr->h_proto) == ETH_P_NETC_META) ++ return false; ++ ++ if ((dmac & NETC_LINKLOCAL_FILTER_A_MASK) == ++ NETC_LINKLOCAL_FILTER_A) ++ return true; ++ ++ return false; ++} ++ ++static struct sk_buff *netc_defer_xmit(struct dsa_port *dp, ++ struct sk_buff *skb) ++{ ++ struct netc_tagger_private *priv = dp->ds->tagger_data; ++ struct netc_tagger_data *data = &priv->data; ++ void (*xmit_work_fn)(struct kthread_work *work); ++ struct netc_deferred_xmit_work *xmit_work; ++ struct kthread_worker *xmit_worker; ++ ++ xmit_work_fn = data->xmit_work_fn; ++ xmit_worker = priv->xmit_worker; ++ ++ if (!xmit_work_fn || !xmit_worker) ++ return NULL; ++ ++ /* PTP over IP packets need UDP checksumming. We may have inherited ++ * NETIF_F_HW_CSUM from the DSA master, but these packets are not sent ++ * through the DSA master, so calculate the checksum here. ++ */ ++ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) ++ return NULL; ++ ++ xmit_work = kzalloc(sizeof(*xmit_work), GFP_ATOMIC); ++ if (!xmit_work) ++ return NULL; ++ ++ /* Calls felix_port_deferred_xmit in felix.c */ ++ kthread_init_work(&xmit_work->work, xmit_work_fn); ++ /* Increase refcount so the kfree_skb in dsa_slave_xmit ++ * won't really free the packet. ++ */ ++ xmit_work->dp = dp; ++ xmit_work->skb = skb_get(skb); ++ ++ kthread_queue_work(xmit_worker, &xmit_work->work); ++ ++ return NULL; ++} ++ ++static struct sk_buff *netc_xmit(struct sk_buff *skb, ++ struct net_device *netdev) ++{ ++ struct dsa_port *dp = dsa_slave_to_port(netdev); ++ u16 queue_mapping = skb_get_queue_mapping(skb); ++ u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); ++ u16 tx_vid = dsa_tag_8021q_standalone_vid(dp); ++ ++ if (unlikely(netc_is_link_local(skb))) ++ return netc_defer_xmit(dp, skb); ++ ++ return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q, ++ ((pcp << VLAN_PRIO_SHIFT) | tx_vid)); ++} ++ ++static struct sk_buff *netc_rcv(struct sk_buff *skb, ++ struct net_device *netdev) ++{ ++ int src_port = -1, switch_id = -1, vid = -1; ++ struct ethhdr *hdr; ++ bool is_link_local; ++ ++ hdr = eth_hdr(skb); ++ is_link_local = netc_is_link_local(skb); ++ ++ if (is_link_local) { ++ /* Management traffic path. Switch embeds the switch ID and ++ * port ID into bytes of the destination MAC, courtesy of ++ * the incl_srcpt options. ++ */ ++ src_port = hdr->h_dest[3]; ++ switch_id = hdr->h_dest[4]; ++ } ++ ++ if (skb_vlan_tag_present(skb)) ++ /* Normal traffic path. */ ++ dsa_8021q_rcv(skb, &src_port, &switch_id, &vid); ++ else ++ return NULL; ++ ++ skb->dev = dsa_master_find_slave(netdev, switch_id, src_port); ++ if (!skb->dev) { ++ netdev_warn(netdev, "Couldn't decode source port switch-%d port- %d\n", ++ switch_id, src_port); ++ return NULL; ++ } ++ ++ if (!is_link_local) ++ dsa_default_offload_fwd_mark(skb); ++ ++ return skb; ++} ++ ++static void netc_disconnect(struct dsa_switch *ds) ++{ ++ struct netc_tagger_private *priv = ds->tagger_data; ++ ++ kthread_destroy_worker(priv->xmit_worker); ++ kfree(priv); ++ ds->tagger_data = NULL; ++} ++ ++static int netc_connect(struct dsa_switch *ds) ++{ ++ struct netc_tagger_private *priv; ++ int err; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->xmit_worker = kthread_create_worker(0, "netc_xmit"); ++ if (IS_ERR(priv->xmit_worker)) { ++ err = PTR_ERR(priv->xmit_worker); ++ kfree(priv); ++ return err; ++ } ++ ++ ds->tagger_data = priv; ++ ++ return 0; ++} ++ ++static const struct dsa_device_ops netc_netdev_ops = { ++ .name = "netc-8021q", ++ .proto = DSA_TAG_PROTO_NETC, ++ .xmit = netc_xmit, ++ .rcv = netc_rcv, ++ .connect = netc_connect, ++ .disconnect = netc_disconnect, ++ .needed_headroom = VLAN_HLEN, ++ .promisc_on_master = true, ++}; ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_NETC); ++ ++module_dsa_tag_driver(netc_netdev_ops); +diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c +index 143348962a21..b472d6b2870e 100644 +--- a/net/dsa/tag_sja1105.c ++++ b/net/dsa/tag_sja1105.c +@@ -262,9 +262,8 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + struct dsa_port *dp = dsa_slave_to_port(netdev); +- u16 queue_mapping = skb_get_queue_mapping(skb); +- u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); + u16 tx_vid = dsa_tag_8021q_standalone_vid(dp); ++ u8 pcp = skb->priority; + + if (skb->offload_fwd_mark) + return sja1105_imprecise_xmit(skb, netdev); +@@ -474,7 +473,7 @@ static bool sja1110_skb_has_inband_control_extension(const struct sk_buff *skb) + static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port, + int *switch_id, int *vbid, u16 *vid) + { +- struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)skb_mac_header(skb); ++ struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); + u16 vlan_tci; + + if (skb_vlan_tag_present(skb)) +diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile +index 72ab0944262a..194eeedf7581 100644 +--- a/net/ethtool/Makefile ++++ b/net/ethtool/Makefile +@@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ + linkstate.o debug.o wol.o features.o privflags.o rings.o \ + channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ + tunnels.o fec.o eeprom.o stats.o phc_vclocks.o module.o \ +- pse-pd.o ++ pse-pd.o preempt.o +diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c +index e31d1247b9f0..a7b4a749fcb3 100644 +--- a/net/ethtool/ioctl.c ++++ b/net/ethtool/ioctl.c +@@ -2713,6 +2713,49 @@ static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr) + return dev->ethtool_ops->set_fecparam(dev, &fecparam); + } + ++static int ethtool_get_preempt(struct net_device *dev, void __user *useraddr) ++{ ++ struct ethtool_fp fpparam = { .cmd = ETHTOOL_GFP }; ++ int rc; ++ ++ if (!dev->ethtool_ops->get_preempt) ++ return -EOPNOTSUPP; ++ ++ rc = dev->ethtool_ops->get_preempt(dev, &fpparam); ++ if (rc) ++ return rc; ++ ++ if (copy_to_user(useraddr, &fpparam, sizeof(fpparam))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ethtool_set_preempt(struct net_device *dev, void __user *useraddr) ++{ ++ struct ethtool_fp fpparam; ++ ++ if (!dev->ethtool_ops->set_preempt) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&fpparam, useraddr, sizeof(fpparam))) ++ return -EFAULT; ++ ++ return dev->ethtool_ops->set_preempt(dev, &fpparam); ++} ++ ++static int ethtool_reset_preempt(struct net_device *dev, void __user *useraddr) ++{ ++ struct ethtool_fp fpparam; ++ ++ if (!dev->ethtool_ops->reset_preempt) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&fpparam, useraddr, sizeof(fpparam))) ++ return -EFAULT; ++ ++ return dev->ethtool_ops->reset_preempt(dev, fpparam.fp_enabled); ++} ++ + /* The main entry point in this file. Called from net/core/dev_ioctl.c */ + + static int +@@ -2772,6 +2815,9 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr, + case ETHTOOL_PHY_GTUNABLE: + case ETHTOOL_GLINKSETTINGS: + case ETHTOOL_GFECPARAM: ++ case ETHTOOL_GFP: ++ case ETHTOOL_SFP: ++ case ETHTOOL_RFP: + break; + default: + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) +@@ -2999,6 +3045,15 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr, + case ETHTOOL_SFECPARAM: + rc = ethtool_set_fecparam(dev, useraddr); + break; ++ case ETHTOOL_GFP: ++ rc = ethtool_get_preempt(dev, useraddr); ++ break; ++ case ETHTOOL_SFP: ++ rc = ethtool_set_preempt(dev, useraddr); ++ break; ++ case ETHTOOL_RFP: ++ rc = ethtool_reset_preempt(dev, useraddr); ++ break; + default: + rc = -EOPNOTSUPP; + } +diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c +index 1a4c11356c96..3e0ed6cf7cce 100644 +--- a/net/ethtool/netlink.c ++++ b/net/ethtool/netlink.c +@@ -287,6 +287,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { + [ETHTOOL_MSG_PHC_VCLOCKS_GET] = ðnl_phc_vclocks_request_ops, + [ETHTOOL_MSG_MODULE_GET] = ðnl_module_request_ops, + [ETHTOOL_MSG_PSE_GET] = ðnl_pse_request_ops, ++ [ETHTOOL_MSG_PREEMPT_GET] = ðnl_preempt_request_ops, + }; + + static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) +@@ -602,6 +603,7 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = { + [ETHTOOL_MSG_EEE_NTF] = ðnl_eee_request_ops, + [ETHTOOL_MSG_FEC_NTF] = ðnl_fec_request_ops, + [ETHTOOL_MSG_MODULE_NTF] = ðnl_module_request_ops, ++ [ETHTOOL_MSG_PREEMPT_NTF] = ðnl_preempt_request_ops, + }; + + /* default notification handler */ +@@ -695,6 +697,7 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = { + [ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify, + [ETHTOOL_MSG_FEC_NTF] = ethnl_default_notify, + [ETHTOOL_MSG_MODULE_NTF] = ethnl_default_notify, ++ [ETHTOOL_MSG_PREEMPT_NTF] = ethnl_default_notify, + }; + + void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data) +@@ -1040,6 +1043,20 @@ static const struct genl_ops ethtool_genl_ops[] = { + .policy = ethnl_pse_set_policy, + .maxattr = ARRAY_SIZE(ethnl_pse_set_policy) - 1, + }, ++ { ++ .cmd = ETHTOOL_MSG_PREEMPT_GET, ++ .doit = ethnl_default_doit, ++ .start = ethnl_default_start, ++ .dumpit = ethnl_default_dumpit, ++ .done = ethnl_default_done, ++ .policy = preempt_get_policy, ++ .maxattr = ETHTOOL_A_PREEMPT_MAX, ++ }, ++ { ++ .cmd = ETHTOOL_MSG_PREEMPT_SET, ++ .flags = GENL_UNS_ADMIN_PERM, ++ .doit = ethnl_set_preempt, ++ }, + }; + + static const struct genl_multicast_group ethtool_nl_mcgrps[] = { +diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h +index 1bfd374f9718..4fd801446147 100644 +--- a/net/ethtool/netlink.h ++++ b/net/ethtool/netlink.h +@@ -346,6 +346,7 @@ extern const struct ethnl_request_ops ethnl_stats_request_ops; + extern const struct ethnl_request_ops ethnl_phc_vclocks_request_ops; + extern const struct ethnl_request_ops ethnl_module_request_ops; + extern const struct ethnl_request_ops ethnl_pse_request_ops; ++extern const struct ethnl_request_ops ethnl_preempt_request_ops; + + extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; + extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; +@@ -386,6 +387,7 @@ extern const struct nla_policy ethnl_module_get_policy[ETHTOOL_A_MODULE_HEADER + + extern const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MODE_POLICY + 1]; + extern const struct nla_policy ethnl_pse_get_policy[ETHTOOL_A_PSE_HEADER + 1]; + extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1]; ++extern const struct nla_policy preempt_get_policy[ETHTOOL_A_PREEMPT_MAX + 1]; + + int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); + int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); +@@ -406,6 +408,7 @@ int ethnl_tunnel_info_dumpit(struct sk_buff *skb, struct netlink_callback *cb); + int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info); + int ethnl_set_module(struct sk_buff *skb, struct genl_info *info); + int ethnl_set_pse(struct sk_buff *skb, struct genl_info *info); ++int ethnl_set_preempt(struct sk_buff *skb, struct genl_info *info); + + extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; + extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN]; +diff --git a/net/ethtool/preempt.c b/net/ethtool/preempt.c +new file mode 100644 +index 000000000000..2d98942002e4 +--- /dev/null ++++ b/net/ethtool/preempt.c +@@ -0,0 +1,191 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include "netlink.h" ++#include "common.h" ++ ++struct preempt_req_info { ++ struct ethnl_req_info base; ++}; ++ ++struct preempt_reply_data { ++ struct ethnl_reply_data base; ++ struct ethtool_fp fp; ++}; ++ ++#define PREEMPT_REPDATA(__reply_base) \ ++ container_of(__reply_base, struct preempt_reply_data, base) ++ ++const struct nla_policy preempt_get_policy[ETHTOOL_A_PREEMPT_MAX + 1] = { ++ [ETHTOOL_A_PREEMPT_UNSPEC] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_HEADER] = { .type = NLA_NESTED }, ++ [ETHTOOL_A_PREEMPT_SUPPORTED] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_STATUS] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_ACTIVE] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE] = { .type = NLA_REJECT }, ++}; ++ ++static int preempt_prepare_data(const struct ethnl_req_info *req_base, ++ struct ethnl_reply_data *reply_base, ++ struct genl_info *info) ++{ ++ struct preempt_reply_data *data = PREEMPT_REPDATA(reply_base); ++ struct net_device *dev = reply_base->dev; ++ int ret; ++ ++ if (!dev->ethtool_ops->get_preempt) ++ return -EOPNOTSUPP; ++ ++ ret = ethnl_ops_begin(dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = dev->ethtool_ops->get_preempt(dev, &data->fp); ++ ethnl_ops_complete(dev); ++ ++ return ret; ++} ++ ++static int preempt_reply_size(const struct ethnl_req_info *req_base, ++ const struct ethnl_reply_data *reply_base) ++{ ++ int len = 0; ++ ++ len += nla_total_size(sizeof(u8)); /* _PREEMPT_SUPPORTED */ ++ len += nla_total_size(sizeof(u8)); /* _PREEMPT_STATUS */ ++ len += nla_total_size(sizeof(u8)); /* _PREEMPT_ACTIVE */ ++ len += nla_total_size(sizeof(u32)); /* _PREEMPT_QUEUES_SUPPORTED */ ++ len += nla_total_size(sizeof(u32)); /* _PREEMPT_QUEUES_PREEMPTIBLE */ ++ len += nla_total_size(sizeof(u32)); /* _PREEMPT_MIN_FRAG_SIZE */ ++ ++ return len; ++} ++ ++static int preempt_fill_reply(struct sk_buff *skb, ++ const struct ethnl_req_info *req_base, ++ const struct ethnl_reply_data *reply_base) ++{ ++ const struct preempt_reply_data *data = PREEMPT_REPDATA(reply_base); ++ const struct ethtool_fp *preempt = &data->fp; ++ ++ if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED, ++ preempt->supported_queues_mask)) ++ return -EMSGSIZE; ++ ++ if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE, ++ preempt->preemptible_queues_mask)) ++ return -EMSGSIZE; ++ ++ if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_STATUS, preempt->fp_status)) ++ return -EMSGSIZE; ++ ++ if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_ACTIVE, preempt->fp_active)) ++ return -EMSGSIZE; ++ ++ if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_SUPPORTED, ++ preempt->fp_supported)) ++ return -EMSGSIZE; ++ ++ if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE, ++ preempt->min_frag_size)) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++ ++const struct ethnl_request_ops ethnl_preempt_request_ops = { ++ .request_cmd = ETHTOOL_MSG_PREEMPT_GET, ++ .reply_cmd = ETHTOOL_MSG_PREEMPT_GET_REPLY, ++ .hdr_attr = ETHTOOL_A_PREEMPT_HEADER, ++ .req_info_size = sizeof(struct preempt_req_info), ++ .reply_data_size = sizeof(struct preempt_reply_data), ++ ++ .prepare_data = preempt_prepare_data, ++ .reply_size = preempt_reply_size, ++ .fill_reply = preempt_fill_reply, ++}; ++ ++static const struct nla_policy ++preempt_set_policy[ETHTOOL_A_PREEMPT_MAX + 1] = { ++ [ETHTOOL_A_PREEMPT_UNSPEC] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_HEADER] = { .type = NLA_NESTED }, ++ [ETHTOOL_A_PREEMPT_DISABLED] = { .type = NLA_FLAG }, ++ [ETHTOOL_A_PREEMPT_SUPPORTED] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_STATUS] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_ACTIVE] = { .type = NLA_U8 }, ++ [ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE] = { .type = NLA_U32 }, ++ [ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED] = { .type = NLA_REJECT }, ++ [ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE] = { .type = NLA_U32 }, ++}; ++ ++int ethnl_set_preempt(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct nlattr *tb[ARRAY_SIZE(preempt_set_policy)]; ++ struct ethtool_fp preempt = {}; ++ struct ethnl_req_info req_info = {}; ++ struct net_device *dev; ++ bool mod = false; ++ int ret; ++ ++ ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ++ ETHTOOL_A_PREEMPT_MAX, preempt_set_policy, ++ info->extack); ++ if (ret < 0) ++ return ret; ++ ++ ret = ethnl_parse_header_dev_get(&req_info, ++ tb[ETHTOOL_A_PREEMPT_HEADER], ++ genl_info_net(info), info->extack, ++ true); ++ if (ret < 0) ++ return ret; ++ dev = req_info.dev; ++ ret = -EOPNOTSUPP; ++ if (!dev->ethtool_ops->get_preempt || ++ !dev->ethtool_ops->set_preempt) ++ goto out_dev; ++ ++ rtnl_lock(); ++ ret = ethnl_ops_begin(dev); ++ if (ret < 0) ++ goto out_rtnl; ++ ++ if (nla_get_flag(tb[ETHTOOL_A_PREEMPT_DISABLED])) { ++ preempt.disabled = 1; ++ mod = true; ++ } ++ if (tb[ETHTOOL_A_PREEMPT_ACTIVE]) { ++ ethnl_update_u8(&preempt.fp_enabled, ++ tb[ETHTOOL_A_PREEMPT_ACTIVE], &mod); ++ mod = true; ++ } ++ if (tb[ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE]) ++ ethnl_update_u32(&preempt.min_frag_size, ++ tb[ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE], &mod); ++ else ++ preempt.min_frag_size = 60; ++ if (tb[ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE]) { ++ ethnl_update_u32(&preempt.preemptible_queues_mask, ++ tb[ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE], &mod); ++ mod = true; ++ } ++ ++ ret = 0; ++ if (!mod) ++ goto out_ops; ++ ++ ret = dev->ethtool_ops->set_preempt(dev, &preempt); ++ if (ret < 0) ++ GENL_SET_ERR_MSG(info, "frame preemption settings update failed"); ++ else ++ ethtool_notify(dev, ETHTOOL_MSG_PREEMPT_NTF, NULL); ++ ++out_ops: ++ ethnl_ops_complete(dev); ++out_rtnl: ++ rtnl_unlock(); ++out_dev: ++ dev_put(dev); ++ return ret; ++} +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +index 04853c83c85c..82b46fb51530 100644 +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -1702,9 +1702,9 @@ u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offt, + bhptr = per_cpu_ptr(mib, cpu); + syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); + do { +- start = u64_stats_fetch_begin_irq(syncp); ++ start = u64_stats_fetch_begin(syncp); + v = *(((u64 *)bhptr) + offt); +- } while (u64_stats_fetch_retry_irq(syncp, start)); ++ } while (u64_stats_fetch_retry(syncp, start)); + + return v; + } +diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c +index 8370726ae7bf..487f8e98deaa 100644 +--- a/net/ipv6/seg6_local.c ++++ b/net/ipv6/seg6_local.c +@@ -1644,13 +1644,13 @@ static int put_nla_counters(struct sk_buff *skb, struct seg6_local_lwt *slwt) + + pcounters = per_cpu_ptr(slwt->pcpu_counters, i); + do { +- start = u64_stats_fetch_begin_irq(&pcounters->syncp); ++ start = u64_stats_fetch_begin(&pcounters->syncp); + + packets = u64_stats_read(&pcounters->packets); + bytes = u64_stats_read(&pcounters->bytes); + errors = u64_stats_read(&pcounters->errors); + +- } while (u64_stats_fetch_retry_irq(&pcounters->syncp, start)); ++ } while (u64_stats_fetch_retry(&pcounters->syncp, start)); + + counters.packets += packets; + counters.bytes += bytes; +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index b8c6f6a668fc..605bdb673d1e 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -2397,9 +2397,9 @@ static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats, + u64 value; + + do { +- start = u64_stats_fetch_begin_irq(&rxstats->syncp); ++ start = u64_stats_fetch_begin(&rxstats->syncp); + value = rxstats->msdu[tid]; +- } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rxstats->syncp, start)); + + return value; + } +@@ -2465,9 +2465,9 @@ static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats) + u64 value; + + do { +- start = u64_stats_fetch_begin_irq(&rxstats->syncp); ++ start = u64_stats_fetch_begin(&rxstats->syncp); + value = rxstats->bytes; +- } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); ++ } while (u64_stats_fetch_retry(&rxstats->syncp, start)); + + return value; + } +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index f1f43894efb8..dc5165d3eec4 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -1079,9 +1079,9 @@ static void mpls_get_stats(struct mpls_dev *mdev, + + p = per_cpu_ptr(mdev->stats, i); + do { +- start = u64_stats_fetch_begin_irq(&p->syncp); ++ start = u64_stats_fetch_begin(&p->syncp); + local = p->stats; +- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); ++ } while (u64_stats_fetch_retry(&p->syncp, start)); + + stats->rx_packets += local.rx_packets; + stats->rx_bytes += local.rx_bytes; +diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c +index 17a1b731a76b..2be696513629 100644 +--- a/net/netfilter/ipvs/ip_vs_ctl.c ++++ b/net/netfilter/ipvs/ip_vs_ctl.c +@@ -2299,13 +2299,13 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) + u64 conns, inpkts, outpkts, inbytes, outbytes; + + do { +- start = u64_stats_fetch_begin_irq(&u->syncp); ++ start = u64_stats_fetch_begin(&u->syncp); + conns = u64_stats_read(&u->cnt.conns); + inpkts = u64_stats_read(&u->cnt.inpkts); + outpkts = u64_stats_read(&u->cnt.outpkts); + inbytes = u64_stats_read(&u->cnt.inbytes); + outbytes = u64_stats_read(&u->cnt.outbytes); +- } while (u64_stats_fetch_retry_irq(&u->syncp, start)); ++ } while (u64_stats_fetch_retry(&u->syncp, start)); + + seq_printf(seq, "%3X %8LX %8LX %8LX %16LX %16LX\n", + i, (u64)conns, (u64)inpkts, +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 3c5cac9bd9b7..32423597bca0 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -1687,10 +1687,10 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats) + for_each_possible_cpu(cpu) { + cpu_stats = per_cpu_ptr(stats, cpu); + do { +- seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp); ++ seq = u64_stats_fetch_begin(&cpu_stats->syncp); + pkts = cpu_stats->pkts; + bytes = cpu_stats->bytes; +- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq)); ++ } while (u64_stats_fetch_retry(&cpu_stats->syncp, seq)); + total.pkts += pkts; + total.bytes += bytes; + } +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 3c7b24535409..0953f531f984 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -716,9 +716,9 @@ static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats, + percpu_stats = per_cpu_ptr(dp->stats_percpu, i); + + do { +- start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); ++ start = u64_stats_fetch_begin(&percpu_stats->syncp); + local_stats = *percpu_stats; +- } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&percpu_stats->syncp, start)); + + stats->n_hit += local_stats.n_hit; + stats->n_missed += local_stats.n_missed; +diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c +index d4a2db0b2299..0a0e4c283f02 100644 +--- a/net/openvswitch/flow_table.c ++++ b/net/openvswitch/flow_table.c +@@ -205,9 +205,9 @@ static void tbl_mask_array_reset_counters(struct mask_array *ma) + + stats = per_cpu_ptr(ma->masks_usage_stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + counter = stats->usage_cntrs[i]; +- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + ma->masks_usage_zero_cntr[i] += counter; + } +@@ -1136,10 +1136,9 @@ void ovs_flow_masks_rebalance(struct flow_table *table) + + stats = per_cpu_ptr(ma->masks_usage_stats, cpu); + do { +- start = u64_stats_fetch_begin_irq(&stats->syncp); ++ start = u64_stats_fetch_begin(&stats->syncp); + counter = stats->usage_cntrs[i]; +- } while (u64_stats_fetch_retry_irq(&stats->syncp, +- start)); ++ } while (u64_stats_fetch_retry(&stats->syncp, start)); + + masks_and_count[i].counter += counter; + } +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index 451bd8bfafd2..08daa7932d63 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -3186,9 +3186,10 @@ static int packet_release(struct socket *sock) + * Attach a packet hook. + */ + +-static int packet_do_bind(struct sock *sk, const char *name, int ifindex, ++static int packet_do_bind(struct socket *sock, const char *name, int ifindex, + __be16 proto) + { ++ struct sock *sk = sock->sk; + struct packet_sock *po = pkt_sk(sk); + struct net_device *dev = NULL; + bool unlisted = false; +@@ -3254,6 +3255,7 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex, + po->prot_hook.dev = dev; + WRITE_ONCE(po->ifindex, dev ? dev->ifindex : 0); + packet_cached_dev_assign(po, dev); ++ sock->ndev = dev; + } + dev_put(dev); + } +@@ -3298,7 +3300,8 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, + memcpy(name, uaddr->sa_data, sizeof(uaddr->sa_data)); + name[sizeof(uaddr->sa_data)] = 0; + +- return packet_do_bind(sk, name, 0, 0); ++ ++ return packet_do_bind(sock, name, 0, 0); + } + + static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +@@ -3315,7 +3318,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len + if (sll->sll_family != AF_PACKET) + return -EINVAL; + +- return packet_do_bind(sk, NULL, sll->sll_ifindex, sll->sll_protocol); ++ return packet_do_bind(sock, NULL, sll->sll_ifindex, sll->sll_protocol); + } + + static struct proto packet_proto = { +diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c +index cac870eb7897..36a6a79697e2 100644 +--- a/net/sched/sch_cbs.c ++++ b/net/sched/sch_cbs.c +@@ -379,6 +379,11 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt, + + qopt = nla_data(tb[TCA_CBS_PARMS]); + ++ if (qopt->idleslope < 0 || qopt->sendslope > 0 || qopt->hicredit < 0 || qopt->locredit > 0) { ++ NL_SET_ERR_MSG(extack, "Invalid CBS parameters"); ++ return -EINVAL; ++ } ++ + if (!qopt->offload) { + cbs_set_port_rate(dev, q); + cbs_disable_offload(dev, q); +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index b03898aba101..abfdbea767e2 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -1237,6 +1237,25 @@ static void taprio_sched_to_offload(struct net_device *dev, + offload->num_entries = i; + } + ++static void ++taprio_mqprio_qopt_reconstruct(struct net_device *dev, ++ struct tc_mqprio_qopt_offload *mqprio) ++{ ++ struct tc_mqprio_qopt *qopt = &mqprio->qopt; ++ int num_tc = netdev_get_num_tc(dev); ++ int tc, prio; ++ ++ qopt->num_tc = num_tc; ++ ++ for (prio = 0; prio <= TC_BITMASK; prio++) ++ qopt->prio_tc_map[prio] = netdev_get_prio_tc_map(dev, prio); ++ ++ for (tc = 0; tc < num_tc; tc++) { ++ qopt->count[tc] = dev->tc_to_txq[tc].count; ++ qopt->offset[tc] = dev->tc_to_txq[tc].offset; ++ } ++} ++ + static int taprio_enable_offload(struct net_device *dev, + struct taprio_sched *q, + struct sched_gate_list *sched, +@@ -1273,6 +1292,7 @@ static int taprio_enable_offload(struct net_device *dev, + return -ENOMEM; + } + offload->enable = 1; ++ taprio_mqprio_qopt_reconstruct(dev, &offload->mqprio); + taprio_sched_to_offload(dev, sched, offload); + + for (tc = 0; tc < TC_MAX_QUEUE; tc++) +diff --git a/net/socket.c b/net/socket.c +index d281a7ef4b1d..092230bb778b 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -107,6 +107,10 @@ + #include + #include + ++static int fast_raw_socket_fd = -1; ++static struct net_device *fast_raw_socket_dev; ++static struct socket *fast_raw_socket_sock = NULL; ++ + #ifdef CONFIG_NET_RX_BUSY_POLL + unsigned int sysctl_net_busy_read __read_mostly; + unsigned int sysctl_net_busy_poll __read_mostly; +@@ -664,6 +668,10 @@ static void __sock_release(struct socket *sock, struct inode *inode) + iput(SOCK_INODE(sock)); + return; + } ++ if (fast_raw_socket_sock != NULL && fast_raw_socket_sock == sock) { ++ fast_raw_socket_sock = NULL; ++ fast_raw_socket_fd = -1; ++ } + sock->file = NULL; + } + +@@ -1778,6 +1786,15 @@ int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) + &address, addrlen); + } + fput_light(sock->file, fput_needed); ++ if (fast_raw_socket_fd < 0) { ++ if (sock->type == SOCK_RAW && sock->sk->sk_family == PF_PACKET) { ++ if (sock->ndev != NULL && sock->ndev->fast_raw_device == 1) { ++ fast_raw_socket_fd = fd; ++ fast_raw_socket_dev = sock->ndev; ++ fast_raw_socket_sock = sock; ++ } ++ } ++ } + } + return err; + } +@@ -2091,6 +2108,10 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, + struct msghdr msg; + struct iovec iov; + int fput_needed; ++ if (fd == fast_raw_socket_fd) { ++ err = fast_raw_socket_dev->netdev_ops->ndo_fast_xmit(fast_raw_socket_dev, buff, len); ++ return err; ++ } + + err = import_single_range(ITER_SOURCE, buff, len, &iov, &msg.msg_iter); + if (unlikely(err)) +@@ -2111,6 +2132,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, + msg.msg_name = (struct sockaddr *)&address; + msg.msg_namelen = addr_len; + } ++ + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + msg.msg_flags = flags; +@@ -2156,6 +2178,11 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags, + struct iovec iov; + int err, err2; + int fput_needed; ++ int i; ++ if (fd == fast_raw_socket_fd) { ++ err = fast_raw_socket_dev->netdev_ops->ndo_fast_recv(fast_raw_socket_dev, ubuf, size, addr, addr_len); ++ return err; ++ } + + err = import_single_range(ITER_DEST, ubuf, size, &iov, &msg.msg_iter); + if (unlikely(err)) +diff --git a/net/tsn/genl_tsn.c b/net/tsn/genl_tsn.c +index 9adb4ec1e287..f03c35e9090d 100644 +--- a/net/tsn/genl_tsn.c ++++ b/net/tsn/genl_tsn.c +@@ -1132,12 +1132,11 @@ static int cmd_qci_sfi_get(struct genl_info *info) + return valid; + } + +- valid = tsnops->qci_sfi_counters_get(netdev, sfi_handle, +- &sficount); +- if (valid < 0) { ++ ret = tsnops->qci_sfi_counters_get(netdev, sfi_handle, &sficount); ++ if (ret < 0) { + tsn_simple_reply(info, TSN_CMD_REPLY, +- netdev->name, valid); +- return valid; ++ netdev->name, ret); ++ return ret; + } + } + +@@ -2117,6 +2116,9 @@ static int cmd_qbv_set(struct genl_info *info) + if (qbv[TSN_QBV_ATTR_CONFIGCHANGE]) + qbvconfig.config_change = 1; + ++ if (qbv[TSN_QBV_ATTR_MAXSDU]) ++ qbvconfig.maxsdu = nla_get_u32(qbv[TSN_QBV_ATTR_MAXSDU]); ++ + if (!qbv[TSN_QBV_ATTR_ADMINENTRY]) { + tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, -EINVAL); + return -1; +@@ -3414,6 +3416,7 @@ static const struct genl_ops tsnnl_ops[] = { + .cmd = TSN_CMD_PCPMAP_SET, + .doit = tsn_pcpmap_set, + .flags = GENL_ADMIN_PERM, ++ .validate = GENL_DONT_VALIDATE_STRICT, + }, + }; + +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0009-init-add-NXP-RT-support.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0009-init-add-NXP-RT-support.patch new file mode 100644 index 000000000..e72286773 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/0009-init-add-NXP-RT-support.patch @@ -0,0 +1,28 @@ +From 98287df3a9d231a31fbc8b2e15be6174d6af1673 Mon Sep 17 00:00:00 2001 +From: Mike Engel +Date: Mon, 26 Feb 2024 09:43:05 +0100 +Subject: [PATCH 09/10] init: add NXP RT support + +Signed-off-by: Mike Engel +--- + init/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/init/Kconfig b/init/Kconfig +index de255842f5d0..d45312780b3a 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1582,6 +1582,10 @@ config PRINTK + very difficult to diagnose system problems, saying N here is + strongly discouraged. + ++config HAVE_ATOMIC_CONSOLE ++ bool ++ default n ++ + config BUG + bool "BUG() support" if EXPERT + default y +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/nxp_rt_conf.cfg b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/nxp_rt_conf.cfg new file mode 100644 index 000000000..5aca538f4 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccimx93/nxp_rt_conf.cfg @@ -0,0 +1,31 @@ +.......................................................................... +. WARNING +. +. This file is a kernel configuration fragment, and not a full kernel +. configuration file. The final kernel configuration is made up of +. an assembly of processed fragments, each of which is designed to +. capture a specific part of the final configuration (e.g. platform +. configuration, feature configuration, and board specific hardware +. configuration). For more information on kernel configuration, please +. consult the product documentation. +. +.......................................................................... +CONFIG_PREEMPT_RT=y +CONFIG_EXPERT=y + +# disable SCHED_MC +# CONFIG_MCPM is not set + +# Disable CPUFREQ and CPUIDLE +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set + +# CONFIG_NUMA_BALANCING in not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_EFI_DISABLE_RUNTIME is not set +CONFIG_MEDIA_SUPPORT_FILTER=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_HID_MULTITOUCH is not set +CONFIG_FRAMEBUFFER_CONSOLE=y diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb b/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb index 794b7d441..cba404b1f 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb @@ -1,8 +1,27 @@ -# Copyright (C) 2023 Digi International +# Copyright (C) 2023-2024 Digi International require recipes-kernel/linux/linux-dey.inc SRCBRANCH = "v6.1.55/nxp/master" + +# Patch series for RT Kernel +NXP_RT_PATCHES = " \ + file://0001-arch-arm-add-NXP-RT-support.patch \ + file://0002-RT-add-RT-localversion.patch \ + file://0003-arch-arm64-add-NXP-RT-support.patch \ + file://0004-Documentation-add-NXP-RT-support.patch \ + file://0005-include-add-NXP-RT-support.patch \ + file://0006-kernel-add-NXP-RT-support.patch \ + file://0007-drivers-add-NXP-RT-support.patch \ + file://0008-net-add-RT-NXP-support.patch \ + file://0009-init-add-NXP-RT-support.patch \ + file://nxp_rt_conf.cfg \ +" + +SRC_URI:append = " \ + ${@bb.utils.contains('DISTRO_FEATURES', 'rt', '${NXP_RT_PATCHES}', '', d)} \ +" + SRCREV = "${AUTOREV}" # Blacklist btnxpuart module. It will be managed by the bluetooth-init script From 932c18622528076a2e76a7ff2729f8c4eeecbde2 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Fri, 9 Feb 2024 12:06:13 +0100 Subject: [PATCH 70/91] packagegroups: add packages related to RT This commit adds real time test tools to the system. The hwlatedetct is a program that controls the kernel hardware latency detector module. This is used to detect large system latencies independent of Linux itself. The rt-tests package is a test suite that includes the cyclictest tool to measure the difference between a thread's intended wake-up time and the time at which it actually wakes up. Signed-off-by: Mike Engel --- .../recipes-core/packagegroups/packagegroup-dey-core.bb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta-digi-dey/recipes-core/packagegroups/packagegroup-dey-core.bb b/meta-digi-dey/recipes-core/packagegroups/packagegroup-dey-core.bb index d736c7b23..b5bbd25ee 100644 --- a/meta-digi-dey/recipes-core/packagegroups/packagegroup-dey-core.bb +++ b/meta-digi-dey/recipes-core/packagegroups/packagegroup-dey-core.bb @@ -43,6 +43,7 @@ RDEPENDS:${PN} = "\ ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'firmwared', '',d)} \ ${@bb.utils.contains("MACHINE_FEATURES", "keyboard", "${VIRTUAL-RUNTIME_keymaps}", "", d)} \ ${@bb.utils.contains("MACHINE_FEATURES", "touchscreen", "${VIRTUAL-RUNTIME_touchscreen}", "",d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'rt', 'hwlatdetect', '',d)} \ init-ifupdown \ libdigiapix \ libgpiod \ @@ -54,6 +55,7 @@ RDEPENDS:${PN} = "\ os-release \ ${@bb.utils.contains('MACHINE_FEATURES', 'pci', 'pciutils', '',d)} \ recovery-utils \ + ${@bb.utils.contains('DISTRO_FEATURES', 'rt', 'rt-tests', '',d)} \ sysinfo \ ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'system-monitor', '',d)} \ usbutils \ From cc8c038401856ba16e7f246c5e505625b5636518 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Wed, 28 Feb 2024 16:10:59 +0100 Subject: [PATCH 71/91] linux-dey-5.15: add RT functionality to CCMP1 This commit adds RT functionality to CCMP1. The patches have been extracted from STM RT expansion package and includes the maineline RT patches and the STM RT driver patches and RT Kernel defconfig changes. https://onedigi.atlassian.net/browse/DEL-8880 Signed-off-by: Mike Engel --- .../recipes-kernel/linux/linux-dey.inc | 14 + .../0023-5.15-stm32mp-rt-49-r1-CLOCK.patch | 26 + .../0024-5.15-stm32mp-rt-49-r1-DMA.patch | 131 + .../0025-5.15-stm32mp-rt-49-r1-MFD.patch | 27 + .../0026-5.15-stm32mp-rt-49-r1-NET-TTY.patch | 64 + ...027-5.15-stm32mp-rt-49-r1-DEVICETREE.patch | 25 + .../0028-5.15-stm32mp-rt-49-r1-CONFIG.patch | 82 + .../linux-dey/ccmp1/patch-5.15.119-rt65.patch | 10968 ++++++++++++++++ .../recipes-kernel/linux/linux-dey_5.15.bb | 18 + 9 files changed, 11355 insertions(+) create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0023-5.15-stm32mp-rt-49-r1-CLOCK.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0024-5.15-stm32mp-rt-49-r1-DMA.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0025-5.15-stm32mp-rt-49-r1-MFD.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0026-5.15-stm32mp-rt-49-r1-NET-TTY.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0027-5.15-stm32mp-rt-49-r1-DEVICETREE.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0028-5.15-stm32mp-rt-49-r1-CONFIG.patch create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/patch-5.15.119-rt65.patch diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey.inc b/meta-digi-arm/recipes-kernel/linux/linux-dey.inc index d9c4603c1..87f6ec74c 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey.inc +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey.inc @@ -71,6 +71,20 @@ do_configure:append() { if [ -n "${@' '.join(find_cfgs(d))}" ]; then ${S}/scripts/kconfig/merge_config.sh -m -O ${B} ${B}/.config ${@" ".join(find_cfgs(d))} fi + # Apply ST-specific config fragments (ending in .config and stored in a different folder) + if [ ! -z "${KERNEL_CONFIG_FRAGMENTS}" ]; then + for f in ${KERNEL_CONFIG_FRAGMENTS} + do + # Check if the config fragment was copied into the WORKDIR from + # the OE meta data + if [ ! -e "$f" ]; then + bb_warn "Could not find kernel config fragment $f" + exit 1 + fi + done + # Now that all the fragments are located merge them. + (${S}/scripts/kconfig/merge_config.sh -m -r -O ${B} ${B}/.config ${KERNEL_CONFIG_FRAGMENTS} 1>&2 ) + fi } # Don't create custom folder for kernel artifacts diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0023-5.15-stm32mp-rt-49-r1-CLOCK.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0023-5.15-stm32mp-rt-49-r1-CLOCK.patch new file mode 100644 index 000000000..41180995b --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0023-5.15-stm32mp-rt-49-r1-CLOCK.patch @@ -0,0 +1,26 @@ +From 63e709173a20b85b473bbf4832f4e909692fd361 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Wed, 8 Feb 2023 09:54:24 +0100 +Subject: [PATCH 23/28] 5.15-stm32mp-rt-49-r1 CLOCK + +Signed-off-by: Lionel VITTE +--- + drivers/clk/stm32/clk-stm32mp13.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c +index 15ee05df8..2f7a823bf 100644 +--- a/drivers/clk/stm32/clk-stm32mp13.c ++++ b/drivers/clk/stm32/clk-stm32mp13.c +@@ -840,7 +840,7 @@ static CLK_STM32_GATE(sai1, "pclk2", 0, GATE_SAI1); + static CLK_STM32_GATE(sai2, "pclk2", 0, GATE_SAI2); + static CLK_STM32_GATE(spi1, "pclk2", 0, GATE_SPI1); + +-static CLK_STM32_GATE(syscfg, "pclk3", 0, GATE_SYSCFG); ++static CLK_STM32_GATE(syscfg, "pclk3", CLK_IS_CRITICAL, GATE_SYSCFG); + static CLK_STM32_GATE(vref, "pclk3", 0, GATE_VREF); + static CLK_STM32_GATE(dts, "pclk3", 0, GATE_DTS); + static CLK_STM32_GATE(pmbctrl, "pclk3", 0, GATE_PMBCTRL); +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0024-5.15-stm32mp-rt-49-r1-DMA.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0024-5.15-stm32mp-rt-49-r1-DMA.patch new file mode 100644 index 000000000..af368b2d0 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0024-5.15-stm32mp-rt-49-r1-DMA.patch @@ -0,0 +1,131 @@ +From 5a55de398d12848f13f7df59fb2f1853b7dd9ee8 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Wed, 8 Feb 2023 09:56:07 +0100 +Subject: [PATCH 24/28] 5.15-stm32mp-rt-49-r1 DMA + +Signed-off-by: Lionel VITTE +--- + drivers/dma/stm32-dma.c | 35 +++++++++++++++++++++++++---------- + drivers/dma/stm32-mdma.c | 4 ++++ + 2 files changed, 29 insertions(+), 10 deletions(-) + +diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c +index 7c6078c6c..128edfb4f 100644 +--- a/drivers/dma/stm32-dma.c ++++ b/drivers/dma/stm32-dma.c +@@ -238,6 +238,7 @@ struct stm32_dma_chan { + u32 residue_after_drain; + struct workqueue_struct *mdma_wq; + struct work_struct mdma_work; ++ struct completion mdma_drain_completion; + }; + + struct stm32_dma_device { +@@ -570,8 +571,9 @@ static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan) + return ndtr << width; + } + +-static int stm32_dma_mdma_drain(struct stm32_dma_chan *chan) ++static void stm32_dma_mdma_drain_worker(struct work_struct *work) + { ++ struct stm32_dma_chan *chan = container_of(work, struct stm32_dma_chan, mdma_work); + struct stm32_dma_mdma *mchan = &chan->mchan; + struct stm32_dma_sg_req *sg_req; + struct dma_device *ddev = mchan->chan->device; +@@ -583,14 +585,12 @@ static int stm32_dma_mdma_drain(struct stm32_dma_chan *chan) + int ret; + unsigned long flags; + +- flush_workqueue(chan->mdma_wq); +- + /* DMA/MDMA chain: drain remaining data in SRAM */ + + /* Get the residue on MDMA side */ + status = dmaengine_tx_status(mchan->chan, mchan->chan->cookie, &state); + if (status == DMA_COMPLETE) +- return status; ++ goto mdma_complete; + + mdma_residue = state.residue; + sg_req = &chan->desc->sg_req[chan->next_sg - 1]; +@@ -623,24 +623,25 @@ static int stm32_dma_mdma_drain(struct stm32_dma_chan *chan) + desc = ddev->device_prep_dma_memcpy(mchan->chan, dst_buf, src_buf, dma_to_write, + DMA_PREP_INTERRUPT); + if (!desc) +- return -EINVAL; ++ return; + + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret < 0) +- return ret; ++ return; + + status = dma_wait_for_async_tx(desc); + if (status != DMA_COMPLETE) { + dev_err(chan2dev(chan), "%s dma_wait_for_async_tx error\n", __func__); + dmaengine_terminate_async(mchan->chan); +- return -EBUSY; ++ return; + } + + /* We need to store residue for tx_status() */ + chan->residue_after_drain = len - (mdma_wrote + dma_to_write); + } + +- return 0; ++mdma_complete: ++ complete(&chan->mdma_drain_completion); + } + + static void stm32_dma_synchronize(struct dma_chan *c) +@@ -648,9 +649,22 @@ static void stm32_dma_synchronize(struct dma_chan *c) + struct stm32_dma_chan *chan = to_stm32_dma_chan(c); + struct stm32_dma_mdma *mchan = &chan->mchan; + +- if (chan->desc && chan->use_mdma && mchan->dir == DMA_DEV_TO_MEM) +- if (stm32_dma_mdma_drain(chan)) ++ if (chan->desc && chan->use_mdma && mchan->dir == DMA_DEV_TO_MEM) { ++ unsigned long ms = 5000 + 100; /* dma_sync_wait_timeout + extra 100ms */ ++ ++ reinit_completion(&chan->mdma_drain_completion); ++ ++ flush_workqueue(chan->mdma_wq); ++ INIT_WORK(&chan->mdma_work, stm32_dma_mdma_drain_worker); ++ ++ if (!queue_work(chan->mdma_wq, &chan->mdma_work)) ++ dev_warn(chan2dev(chan), "Work already queued\n"); ++ ++ ms = wait_for_completion_timeout(&chan->mdma_drain_completion, ++ msecs_to_jiffies(ms)); ++ if (ms == 0) + dev_err(chan2dev(chan), "%s: can't drain DMA\n", __func__); ++ } + + if (chan->use_mdma) + dmaengine_synchronize(mchan->chan); +@@ -2338,6 +2352,7 @@ static int stm32_dma_probe(struct platform_device *pdev) + dev_warn(&pdev->dev, + "can't alloc MDMA workqueue for %s\n", name); + } ++ init_completion(&chan->mdma_drain_completion); + } + } + } +diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c +index 133534663..a08c94638 100644 +--- a/drivers/dma/stm32-mdma.c ++++ b/drivers/dma/stm32-mdma.c +@@ -1270,6 +1270,10 @@ static int stm32_mdma_resume(struct dma_chan *c) + unsigned long flags; + u32 status, reg; + ++ /* Transfer can be terminated */ ++ if (!chan->desc || (stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & STM32_MDMA_CCR_EN)) ++ return -EPERM; ++ + hwdesc = chan->desc->node[chan->curr_hwdesc].hwdesc; + + spin_lock_irqsave(&chan->vchan.lock, flags); +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0025-5.15-stm32mp-rt-49-r1-MFD.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0025-5.15-stm32mp-rt-49-r1-MFD.patch new file mode 100644 index 000000000..80d4f531e --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0025-5.15-stm32mp-rt-49-r1-MFD.patch @@ -0,0 +1,27 @@ +From be5ec688053e6d136bc8ea54ed1e93d523b24580 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Wed, 8 Feb 2023 09:56:45 +0100 +Subject: [PATCH 25/28] 5.15-stm32mp-rt-49-r1 MFD + +Signed-off-by: Lionel VITTE +--- + drivers/mfd/syscon.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c +index 191fdb87c..24530dfe5 100644 +--- a/drivers/mfd/syscon.c ++++ b/drivers/mfd/syscon.c +@@ -38,6 +38,9 @@ static const struct regmap_config syscon_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, ++#ifdef CONFIG_PREEMPT_RT ++ .use_raw_spinlock = true, ++#endif + }; + + static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0026-5.15-stm32mp-rt-49-r1-NET-TTY.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0026-5.15-stm32mp-rt-49-r1-NET-TTY.patch new file mode 100644 index 000000000..4bcaaebfb --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0026-5.15-stm32mp-rt-49-r1-NET-TTY.patch @@ -0,0 +1,64 @@ +From 1f4b70cda804c4f3771902254a2614d87a1d366c Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Wed, 8 Feb 2023 09:57:06 +0100 +Subject: [PATCH 26/28] 5.15-stm32mp-rt-49-r1 NET-TTY + +Signed-off-by: Lionel VITTE +--- + drivers/tty/serial/stm32-usart.c | 32 +++++++++++--------------------- + 1 file changed, 11 insertions(+), 21 deletions(-) + +diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c +index 4d7a31664..0cd8e9672 100644 +--- a/drivers/tty/serial/stm32-usart.c ++++ b/drivers/tty/serial/stm32-usart.c +@@ -772,26 +772,16 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) + } + + if ((sr & USART_SR_RTOF) && !(stm32_port->throttled) && +- stm32_usart_rx_dma_started(stm32_port)) +- return IRQ_WAKE_THREAD; +- else +- return IRQ_HANDLED; +-} +- +-static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) +-{ +- struct uart_port *port = ptr; +- struct tty_port *tport = &port->state->port; +- unsigned int size; +- unsigned long flags; +- +- /* Receiver timeout irq for DMA RX */ +- spin_lock_irqsave(&port->lock, flags); +- size = stm32_usart_receive_chars(port, false); +- uart_unlock_and_check_sysrq_irqrestore(port, flags); +- if (size) +- tty_flip_buffer_push(tport); ++ stm32_usart_rx_dma_started(stm32_port)) { ++ unsigned long flags; + ++ spin_lock_irqsave(&port->lock, flags); ++ /* Receiver timeout irq for DMA RX */ ++ size = stm32_usart_receive_chars(port, false); ++ uart_unlock_and_check_sysrq_irqrestore(port, flags); ++ if (size) ++ tty_flip_buffer_push(tport); ++ } + return IRQ_HANDLED; + } + +@@ -980,8 +970,8 @@ static int stm32_usart_startup(struct uart_port *port) + u32 val; + int ret; + +- ret = request_threaded_irq(port->irq, stm32_usart_interrupt, +- stm32_usart_threaded_interrupt, ++ ret = request_threaded_irq(port->irq, NULL, ++ stm32_usart_interrupt, + IRQF_ONESHOT | IRQF_NO_SUSPEND, + name, port); + if (ret) +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0027-5.15-stm32mp-rt-49-r1-DEVICETREE.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0027-5.15-stm32mp-rt-49-r1-DEVICETREE.patch new file mode 100644 index 000000000..dac422be8 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0027-5.15-stm32mp-rt-49-r1-DEVICETREE.patch @@ -0,0 +1,25 @@ +From e1bd8bc5502e661be4feaadfca1889da1d48cd73 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Wed, 8 Feb 2023 09:57:43 +0100 +Subject: [PATCH 27/28] 5.15-stm32mp-rt-49-r1 DEVICETREE + +Signed-off-by: Lionel VITTE +--- + arch/arm/boot/dts/stm32mp131.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm/boot/dts/stm32mp131.dtsi b/arch/arm/boot/dts/stm32mp131.dtsi +index 8121ddc97..3fc06961a 100644 +--- a/arch/arm/boot/dts/stm32mp131.dtsi ++++ b/arch/arm/boot/dts/stm32mp131.dtsi +@@ -1241,7 +1241,6 @@ exti-interrupt-map { + syscfg: syscon@50020000 { + compatible = "st,stm32mp157-syscfg", "syscon"; + reg = <0x50020000 0x400>; +- clocks = <&rcc SYSCFG>; + }; + + lptimer2: timer@50021000 { +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0028-5.15-stm32mp-rt-49-r1-CONFIG.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0028-5.15-stm32mp-rt-49-r1-CONFIG.patch new file mode 100644 index 000000000..e697ee7e5 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/0028-5.15-stm32mp-rt-49-r1-CONFIG.patch @@ -0,0 +1,82 @@ +From 05ea3c26ccad3359d94dbe3c7ba758c2ba2f7dd9 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Wed, 8 Feb 2023 09:59:08 +0100 +Subject: [PATCH 28/28] 5.15-stm32mp-rt-49-r1 CONFIG + +Signed-off-by: Lionel VITTE +--- + .../configs/fragment-07-rt-sysvinit.config | 12 +++++++ + arch/arm/configs/fragment-07-rt.config | 32 +++++++++++++++++++ + arch/arm/configs/fragment-08-rt-mp13.config | 2 ++ + 3 files changed, 46 insertions(+) + create mode 100644 arch/arm/configs/fragment-07-rt-sysvinit.config + create mode 100644 arch/arm/configs/fragment-07-rt.config + create mode 100644 arch/arm/configs/fragment-08-rt-mp13.config + +diff --git a/arch/arm/configs/fragment-07-rt-sysvinit.config b/arch/arm/configs/fragment-07-rt-sysvinit.config +new file mode 100644 +index 000000000..49a4baf60 +--- /dev/null ++++ b/arch/arm/configs/fragment-07-rt-sysvinit.config +@@ -0,0 +1,12 @@ ++CONFIG_CGROUPS=y ++# CONFIG_CGROUP_SCHED is not set ++# CONFIG_CGROUP_PIDS is not set ++# CONFIG_CGROUP_RDMA is not set ++# CONFIG_CGROUP_FREEZER is not set ++# CONFIG_CGROUP_DEVICE is not set ++# CONFIG_CGROUP_CPUACCT is not set ++# CONFIG_CGROUP_PERF is not set ++# CONFIG_CGROUP_DEBUG is not set ++# CONFIG_CGROUP_NET_PRIO is not set ++# CONFIG_CGROUP_NET_CLASSID is not set ++ +diff --git a/arch/arm/configs/fragment-07-rt.config b/arch/arm/configs/fragment-07-rt.config +new file mode 100644 +index 000000000..98bb8735f +--- /dev/null ++++ b/arch/arm/configs/fragment-07-rt.config +@@ -0,0 +1,32 @@ ++CONFIG_PREEMPT_RT=y ++ ++# disable SCHED_MC ++# CONFIG_MCPM is not set ++ ++# Disable CPUFREQ and CPUIDLE ++# CONFIG_CPU_FREQ is not set ++# CONFIG_CPU_IDLE is not set ++ ++# Force to have HIGH_RES_TIMERS ++CONFIG_HIGH_RES_TIMERS=y ++ ++# force do not go to sleep ++# For multiple core, you should set the specific boot options ++# for isolate the core and render it tickless: "isolcpus=2,3 nohz_full=2,3" ++# Warning: to active only if SMP are present ++# CONFIG_HZ_PERIODIC=y ++ ++# to Enable ftrace, you need to enable the following configuraiton: ++# CONFIG_FTRACE=y ++# CONFIG_IRQSOFF_TRACER=y ++# CONFIG_PREEMPT_TRACER=y ++# CONFIG_SCHED_TRACER=y ++# CONFIG_FUNCTION_TRACER=y ++# By default, the ftrace for RT kernel are disabled ++# CONFIG_FTRACE is not set ++# CONFIG_IRQSOFF_TRACER is not set ++# CONFIG_PREEMPT_TRACER is not set ++# CONFIG_SCHED_TRACER is not set ++# CONFIG_FUNCTION_TRACER is not set ++ ++ +diff --git a/arch/arm/configs/fragment-08-rt-mp13.config b/arch/arm/configs/fragment-08-rt-mp13.config +new file mode 100644 +index 000000000..c70d7adc6 +--- /dev/null ++++ b/arch/arm/configs/fragment-08-rt-mp13.config +@@ -0,0 +1,2 @@ ++# Disable SMP on MP13 ++# CONFIG_SMP is not set +-- +2.34.1 + diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/patch-5.15.119-rt65.patch b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/patch-5.15.119-rt65.patch new file mode 100644 index 000000000..b2cf5ed68 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/ccmp1/patch-5.15.119-rt65.patch @@ -0,0 +1,10968 @@ +diff --git a/Documentation/admin-guide/cgroup-v1/memory.rst b/Documentation/admin-guide/cgroup-v1/memory.rst +index dd913eefbf31..33d3c988b951 100644 +--- a/Documentation/admin-guide/cgroup-v1/memory.rst ++++ b/Documentation/admin-guide/cgroup-v1/memory.rst +@@ -64,6 +64,7 @@ Brief summary of control files. + threads + cgroup.procs show list of processes + cgroup.event_control an interface for event_fd() ++ This knob is not available on CONFIG_PREEMPT_RT systems. + memory.usage_in_bytes show current usage for memory + (See 5.5 for details) + memory.memsw.usage_in_bytes show current usage for memory+Swap +@@ -75,6 +76,7 @@ Brief summary of control files. + memory.max_usage_in_bytes show max memory usage recorded + memory.memsw.max_usage_in_bytes show max memory+Swap usage recorded + memory.soft_limit_in_bytes set/show soft limit of memory usage ++ This knob is not available on CONFIG_PREEMPT_RT systems. + memory.stat show various statistics + memory.use_hierarchy set/show hierarchical account enabled + This knob is deprecated and shouldn't be +diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kcov.rst +index d2c4c27e1702..d83c9ab49427 100644 +--- a/Documentation/dev-tools/kcov.rst ++++ b/Documentation/dev-tools/kcov.rst +@@ -50,6 +50,7 @@ program using kcov: + #include + #include + #include ++ #include + + #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) + #define KCOV_ENABLE _IO('c', 100) +@@ -177,6 +178,8 @@ Comparison operands collection is similar to coverage collection: + /* Read number of comparisons collected. */ + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) { ++ uint64_t ip; ++ + type = cover[i * KCOV_WORDS_PER_CMP + 1]; + /* arg1 and arg2 - operands of the comparison. */ + arg1 = cover[i * KCOV_WORDS_PER_CMP + 2]; +@@ -251,6 +254,8 @@ selectively from different subsystems. + + .. code-block:: c + ++ /* Same includes and defines as above. */ ++ + struct kcov_remote_arg { + __u32 trace_mode; + __u32 area_size; +diff --git a/arch/alpha/include/asm/spinlock_types.h b/arch/alpha/include/asm/spinlock_types.h +index 1d5716bc060b..2526fd3be5fd 100644 +--- a/arch/alpha/include/asm/spinlock_types.h ++++ b/arch/alpha/include/asm/spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef _ALPHA_SPINLOCK_TYPES_H + #define _ALPHA_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index a8ae17f5740d..0e8631b96e0f 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -32,6 +32,7 @@ config ARM + select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7 + select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE ++ select ARCH_SUPPORTS_RT if HAVE_POSIX_CPU_TIMERS_TASK_WORK + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_USE_MEMTEST +@@ -68,7 +69,7 @@ config ARM + select HARDIRQS_SW_RESEND + select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT + select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 +- select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU ++ select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU && !PREEMPT_RT + select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU + select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL + select HAVE_ARCH_MMAP_RND_BITS if MMU +@@ -109,6 +110,7 @@ config ARM + select HAVE_PERF_EVENTS + select HAVE_PERF_REGS + select HAVE_PERF_USER_STACK_DUMP ++ select HAVE_PREEMPT_LAZY + select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE + select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RSEQ +@@ -124,6 +126,7 @@ config ARM + select OLD_SIGSUSPEND3 + select PCI_SYSCALL if PCI + select PERF_USE_VMALLOC ++ select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM + select RTC_LIB + select SYS_SUPPORTS_APM_EMULATION + select TRACE_IRQFLAGS_SUPPORT if !CPU_V7M +diff --git a/arch/arm/include/asm/spinlock_types.h b/arch/arm/include/asm/spinlock_types.h +index 5976958647fe..0c14b36ef101 100644 +--- a/arch/arm/include/asm/spinlock_types.h ++++ b/arch/arm/include/asm/spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef __ASM_SPINLOCK_TYPES_H + #define __ASM_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h +index b682189a2b5d..e5e2ceb59544 100644 +--- a/arch/arm/include/asm/thread_info.h ++++ b/arch/arm/include/asm/thread_info.h +@@ -52,6 +52,7 @@ struct cpu_context_save { + struct thread_info { + unsigned long flags; /* low level flags */ + int preempt_count; /* 0 => preemptable, <0 => bug */ ++ int preempt_lazy_count; /* 0 => preemptable, <0 => bug */ + struct task_struct *task; /* main task structure */ + __u32 cpu; /* cpu */ + __u32 cpu_domain; /* cpu domain */ +@@ -130,6 +131,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, + #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ + #define TIF_UPROBE 3 /* breakpointed or singlestepping */ + #define TIF_NOTIFY_SIGNAL 4 /* signal notifications exist */ ++#define TIF_NEED_RESCHED_LAZY 9 + + #define TIF_USING_IWMMXT 17 + #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ +@@ -149,6 +151,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, + #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) + #define _TIF_SECCOMP (1 << TIF_SECCOMP) + #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) ++#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) + #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) + + /* Checks for any syscall work in entry-common.S */ +@@ -158,7 +161,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, + /* + * Change these and you break ASM code in entry-common.S + */ +-#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ ++#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \ ++ _TIF_SIGPENDING | \ + _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ + _TIF_NOTIFY_SIGNAL) + +diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c +index a646a3f6440f..beb09d74684f 100644 +--- a/arch/arm/kernel/asm-offsets.c ++++ b/arch/arm/kernel/asm-offsets.c +@@ -43,6 +43,7 @@ int main(void) + BLANK(); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); ++ DEFINE(TI_PREEMPT_LAZY, offsetof(struct thread_info, preempt_lazy_count)); + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain)); +diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S +index 68261a83b7ad..fa7d110ce555 100644 +--- a/arch/arm/kernel/entry-armv.S ++++ b/arch/arm/kernel/entry-armv.S +@@ -206,11 +206,18 @@ __irq_svc: + + #ifdef CONFIG_PREEMPTION + ldr r8, [tsk, #TI_PREEMPT] @ get preempt count +- ldr r0, [tsk, #TI_FLAGS] @ get flags + teq r8, #0 @ if preempt count != 0 ++ bne 1f @ return from exeption ++ ldr r0, [tsk, #TI_FLAGS] @ get flags ++ tst r0, #_TIF_NEED_RESCHED @ if NEED_RESCHED is set ++ blne svc_preempt @ preempt! ++ ++ ldr r8, [tsk, #TI_PREEMPT_LAZY] @ get preempt lazy count ++ teq r8, #0 @ if preempt lazy count != 0 + movne r0, #0 @ force flags to 0 +- tst r0, #_TIF_NEED_RESCHED ++ tst r0, #_TIF_NEED_RESCHED_LAZY + blne svc_preempt ++1: + #endif + + svc_exit r5, irq = 1 @ return from exception +@@ -225,8 +232,14 @@ svc_preempt: + 1: bl preempt_schedule_irq @ irq en/disable is done inside + ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS + tst r0, #_TIF_NEED_RESCHED ++ bne 1b ++ tst r0, #_TIF_NEED_RESCHED_LAZY + reteq r8 @ go again +- b 1b ++ ldr r0, [tsk, #TI_PREEMPT_LAZY] @ get preempt lazy count ++ teq r0, #0 @ if preempt lazy count != 0 ++ beq 1b ++ ret r8 @ go again ++ + #endif + + __und_fault: +diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c +index 539897ac2828..4655f04ccdcd 100644 +--- a/arch/arm/kernel/signal.c ++++ b/arch/arm/kernel/signal.c +@@ -607,7 +607,8 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) + */ + trace_hardirqs_off(); + do { +- if (likely(thread_flags & _TIF_NEED_RESCHED)) { ++ if (likely(thread_flags & (_TIF_NEED_RESCHED | ++ _TIF_NEED_RESCHED_LAZY))) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) +diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c +index af5177801fb1..1de016008e2e 100644 +--- a/arch/arm/mm/fault.c ++++ b/arch/arm/mm/fault.c +@@ -400,6 +400,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, + if (addr < TASK_SIZE) + return do_page_fault(addr, fsr, regs); + ++ if (interrupts_enabled(regs)) ++ local_irq_enable(); ++ + if (user_mode(regs)) + goto bad_area; + +@@ -470,6 +473,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, + static int + do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + { ++ if (interrupts_enabled(regs)) ++ local_irq_enable(); ++ + do_bad_area(addr, fsr, regs); + return 0; + } +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 9d3cbe786f8d..c86b845d0d79 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -88,6 +88,7 @@ config ARM64 + select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 + select ARCH_SUPPORTS_NUMA_BALANCING ++ select ARCH_SUPPORTS_RT if HAVE_POSIX_CPU_TIMERS_TASK_WORK + select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT + select ARCH_WANT_DEFAULT_BPF_JIT + select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT +@@ -191,6 +192,7 @@ config ARM64 + select HAVE_PERF_REGS + select HAVE_PERF_USER_STACK_DUMP + select HAVE_REGS_AND_STACK_ACCESS_API ++ select HAVE_PREEMPT_LAZY + select HAVE_FUNCTION_ARG_ACCESS_API + select HAVE_FUTEX_CMPXCHG if FUTEX + select MMU_GATHER_RCU_TABLE_FREE +@@ -212,6 +214,7 @@ config ARM64 + select PCI_DOMAINS_GENERIC if PCI + select PCI_ECAM if (ACPI && PCI) + select PCI_SYSCALL if PCI ++ select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM + select POWER_RESET + select POWER_SUPPLY + select SPARSE_IRQ +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index ed57717cd004..63b39229890b 100644 +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -1001,7 +1001,7 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, + */ + static inline bool arch_faults_on_old_pte(void) + { +- WARN_ON(preemptible()); ++ WARN_ON(is_migratable()); + + return !cpu_has_hw_af(); + } +diff --git a/arch/arm64/include/asm/preempt.h b/arch/arm64/include/asm/preempt.h +index e83f0982b99c..2545c17281e1 100644 +--- a/arch/arm64/include/asm/preempt.h ++++ b/arch/arm64/include/asm/preempt.h +@@ -70,13 +70,36 @@ static inline bool __preempt_count_dec_and_test(void) + * interrupt occurring between the non-atomic READ_ONCE/WRITE_ONCE + * pair. + */ +- return !pc || !READ_ONCE(ti->preempt_count); ++ if (!pc || !READ_ONCE(ti->preempt_count)) ++ return true; ++#ifdef CONFIG_PREEMPT_LAZY ++ if ((pc & ~PREEMPT_NEED_RESCHED)) ++ return false; ++ if (current_thread_info()->preempt_lazy_count) ++ return false; ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++#else ++ return false; ++#endif + } + + static inline bool should_resched(int preempt_offset) + { ++#ifdef CONFIG_PREEMPT_LAZY ++ u64 pc = READ_ONCE(current_thread_info()->preempt_count); ++ if (pc == preempt_offset) ++ return true; ++ ++ if ((pc & ~PREEMPT_NEED_RESCHED) != preempt_offset) ++ return false; ++ ++ if (current_thread_info()->preempt_lazy_count) ++ return false; ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++#else + u64 pc = READ_ONCE(current_thread_info()->preempt_count); + return pc == preempt_offset; ++#endif + } + + #ifdef CONFIG_PREEMPTION +diff --git a/arch/arm64/include/asm/signal.h b/arch/arm64/include/asm/signal.h +index ef449f5f4ba8..5e535c3e4926 100644 +--- a/arch/arm64/include/asm/signal.h ++++ b/arch/arm64/include/asm/signal.h +@@ -22,4 +22,8 @@ static inline void __user *arch_untagged_si_addr(void __user *addr, + } + #define arch_untagged_si_addr arch_untagged_si_addr + ++#if defined(CONFIG_PREEMPT_RT) ++#define ARCH_RT_DELAYS_SIGNAL_SEND ++#endif ++ + #endif +diff --git a/arch/arm64/include/asm/spinlock_types.h b/arch/arm64/include/asm/spinlock_types.h +index 18782f0c4721..11ab1c077697 100644 +--- a/arch/arm64/include/asm/spinlock_types.h ++++ b/arch/arm64/include/asm/spinlock_types.h +@@ -5,7 +5,7 @@ + #ifndef __ASM_SPINLOCK_TYPES_H + #define __ASM_SPINLOCK_TYPES_H + +-#if !defined(__LINUX_SPINLOCK_TYPES_H) && !defined(__ASM_SPINLOCK_H) ++#if !defined(__LINUX_SPINLOCK_TYPES_RAW_H) && !defined(__ASM_SPINLOCK_H) + # error "please don't include this file directly" + #endif + +diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h +index 6623c99f0984..c55ccec33a5a 100644 +--- a/arch/arm64/include/asm/thread_info.h ++++ b/arch/arm64/include/asm/thread_info.h +@@ -26,6 +26,7 @@ struct thread_info { + #ifdef CONFIG_ARM64_SW_TTBR0_PAN + u64 ttbr0; /* saved TTBR0_EL1 */ + #endif ++ int preempt_lazy_count; /* 0 => preemptable, <0 => bug */ + union { + u64 preempt_count; /* 0 => preemptible, <0 => bug */ + struct { +@@ -67,6 +68,7 @@ int arch_dup_task_struct(struct task_struct *dst, + #define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */ + #define TIF_MTE_ASYNC_FAULT 5 /* MTE Asynchronous Tag Check Fault */ + #define TIF_NOTIFY_SIGNAL 6 /* signal notifications exist */ ++#define TIF_NEED_RESCHED_LAZY 7 + #define TIF_SYSCALL_TRACE 8 /* syscall trace active */ + #define TIF_SYSCALL_AUDIT 9 /* syscall auditing */ + #define TIF_SYSCALL_TRACEPOINT 10 /* syscall tracepoint for ftrace */ +@@ -97,8 +99,10 @@ int arch_dup_task_struct(struct task_struct *dst, + #define _TIF_SVE (1 << TIF_SVE) + #define _TIF_MTE_ASYNC_FAULT (1 << TIF_MTE_ASYNC_FAULT) + #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) ++#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) + +-#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ ++#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \ ++ _TIF_SIGPENDING | \ + _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ + _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \ + _TIF_NOTIFY_SIGNAL) +@@ -107,6 +111,8 @@ int arch_dup_task_struct(struct task_struct *dst, + _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ + _TIF_SYSCALL_EMU) + ++#define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) ++ + #ifdef CONFIG_SHADOW_CALL_STACK + #define INIT_SCS \ + .scs_base = init_shadow_call_stack, \ +diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c +index 551427ae8cc5..96a4f6c9eb78 100644 +--- a/arch/arm64/kernel/asm-offsets.c ++++ b/arch/arm64/kernel/asm-offsets.c +@@ -31,6 +31,7 @@ int main(void) + BLANK(); + DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); + DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); ++ DEFINE(TSK_TI_PREEMPT_LAZY, offsetof(struct task_struct, thread_info.preempt_lazy_count)); + #ifdef CONFIG_ARM64_SW_TTBR0_PAN + DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0)); + #endif +diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c +index 7a3fcf21b18a..5689d2b0c0b6 100644 +--- a/arch/arm64/kernel/fpsimd.c ++++ b/arch/arm64/kernel/fpsimd.c +@@ -179,10 +179,19 @@ static void __get_cpu_fpsimd_context(void) + * + * The double-underscore version must only be called if you know the task + * can't be preempted. ++ * ++ * On RT kernels local_bh_disable() is not sufficient because it only ++ * serializes soft interrupt related sections via a local lock, but stays ++ * preemptible. Disabling preemption is the right choice here as bottom ++ * half processing is always in thread context on RT kernels so it ++ * implicitly prevents bottom half processing as well. + */ + static void get_cpu_fpsimd_context(void) + { +- local_bh_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_bh_disable(); ++ else ++ preempt_disable(); + __get_cpu_fpsimd_context(); + } + +@@ -203,7 +212,10 @@ static void __put_cpu_fpsimd_context(void) + static void put_cpu_fpsimd_context(void) + { + __put_cpu_fpsimd_context(); +- local_bh_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_bh_enable(); ++ else ++ preempt_enable(); + } + + static bool have_cpu_fpsimd_context(void) +@@ -1033,6 +1045,7 @@ void fpsimd_thread_switch(struct task_struct *next) + void fpsimd_flush_thread(void) + { + int vl, supported_vl; ++ void *sve_state = NULL; + + if (!system_supports_fpsimd()) + return; +@@ -1045,7 +1058,10 @@ void fpsimd_flush_thread(void) + + if (system_supports_sve()) { + clear_thread_flag(TIF_SVE); +- sve_free(current); ++ ++ /* Defer kfree() while in atomic context */ ++ sve_state = current->thread.sve_state; ++ current->thread.sve_state = NULL; + + /* + * Reset the task vector length as required. +@@ -1079,6 +1095,7 @@ void fpsimd_flush_thread(void) + } + + put_cpu_fpsimd_context(); ++ kfree(sve_state); + } + + /* +diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c +index b3e1beccf458..03183563feb8 100644 +--- a/arch/arm64/kernel/signal.c ++++ b/arch/arm64/kernel/signal.c +@@ -922,7 +922,7 @@ static void do_signal(struct pt_regs *regs) + void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags) + { + do { +- if (thread_flags & _TIF_NEED_RESCHED) { ++ if (thread_flags & _TIF_NEED_RESCHED_MASK) { + /* Unmask Debug and SError for the next task */ + local_daif_restore(DAIF_PROCCTX_NOIRQ); + +@@ -930,6 +930,14 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags) + } else { + local_daif_restore(DAIF_PROCCTX); + ++#ifdef ARCH_RT_DELAYS_SIGNAL_SEND ++ if (unlikely(current->forced_info.si_signo)) { ++ struct task_struct *t = current; ++ force_sig_info(&t->forced_info); ++ t->forced_info.si_signo = 0; ++ } ++#endif ++ + if (thread_flags & _TIF_UPROBE) + uprobe_notify_resume(regs); + +diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c +index 3fe816c244ce..ba8c69cda361 100644 +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -828,7 +828,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) + * involves poking the GIC, which must be done in a + * non-preemptible context. + */ +- preempt_disable(); ++ migrate_disable(); + + kvm_pmu_flush_hwstate(vcpu); + +@@ -852,7 +852,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) + kvm_timer_sync_user(vcpu); + kvm_vgic_sync_hwstate(vcpu); + local_irq_enable(); +- preempt_enable(); ++ migrate_enable(); + continue; + } + +@@ -921,7 +921,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) + /* Exit types that need handling before we can be preempted */ + handle_exit_early(vcpu, ret); + +- preempt_enable(); ++ migrate_enable(); + + /* + * The ARMv8 architecture doesn't give the hypervisor +diff --git a/arch/csky/include/asm/spinlock_types.h b/arch/csky/include/asm/spinlock_types.h +index 8ff0f6ff3a00..db87a12c3827 100644 +--- a/arch/csky/include/asm/spinlock_types.h ++++ b/arch/csky/include/asm/spinlock_types.h +@@ -3,7 +3,7 @@ + #ifndef __ASM_CSKY_SPINLOCK_TYPES_H + #define __ASM_CSKY_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/hexagon/include/asm/spinlock_types.h b/arch/hexagon/include/asm/spinlock_types.h +index 19d233497ba5..d5f66495b670 100644 +--- a/arch/hexagon/include/asm/spinlock_types.h ++++ b/arch/hexagon/include/asm/spinlock_types.h +@@ -8,7 +8,7 @@ + #ifndef _ASM_SPINLOCK_TYPES_H + #define _ASM_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/ia64/include/asm/spinlock_types.h b/arch/ia64/include/asm/spinlock_types.h +index 6e345fefcdca..14b8a161c165 100644 +--- a/arch/ia64/include/asm/spinlock_types.h ++++ b/arch/ia64/include/asm/spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef _ASM_IA64_SPINLOCK_TYPES_H + #define _ASM_IA64_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig +index 27222b75d2a4..5495225807eb 100644 +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -151,6 +151,7 @@ config PPC + select ARCH_STACKWALK + select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC_BOOK3S || PPC_8xx || 40x ++ select ARCH_SUPPORTS_RT if HAVE_POSIX_CPU_TIMERS_TASK_WORK + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_CMPXCHG_LOCKREF if PPC64 + select ARCH_USE_MEMTEST +@@ -218,6 +219,7 @@ config PPC + select HAVE_HW_BREAKPOINT if PERF_EVENTS && (PPC_BOOK3S || PPC_8xx) + select HAVE_IOREMAP_PROT + select HAVE_IRQ_TIME_ACCOUNTING ++ select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE + select HAVE_KERNEL_LZO if DEFAULT_UIMAGE +@@ -234,6 +236,7 @@ config PPC + select HAVE_PERF_EVENTS_NMI if PPC64 + select HAVE_PERF_REGS + select HAVE_PERF_USER_STACK_DUMP ++ select HAVE_PREEMPT_LAZY + select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RELIABLE_STACKTRACE + select HAVE_RSEQ +diff --git a/arch/powerpc/include/asm/simple_spinlock_types.h b/arch/powerpc/include/asm/simple_spinlock_types.h +index 0f3cdd8faa95..08243338069d 100644 +--- a/arch/powerpc/include/asm/simple_spinlock_types.h ++++ b/arch/powerpc/include/asm/simple_spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef _ASM_POWERPC_SIMPLE_SPINLOCK_TYPES_H + #define _ASM_POWERPC_SIMPLE_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h +index 7ef1cd8168a0..f9e63cacd220 100644 +--- a/arch/powerpc/include/asm/smp.h ++++ b/arch/powerpc/include/asm/smp.h +@@ -62,6 +62,7 @@ struct smp_ops_t { + + extern int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us); + extern int smp_send_safe_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us); ++extern void smp_send_debugger_break_cpu(unsigned int cpu); + extern void smp_send_debugger_break(void); + extern void start_secondary_resume(void); + extern void smp_generic_give_timebase(void); +diff --git a/arch/powerpc/include/asm/spinlock_types.h b/arch/powerpc/include/asm/spinlock_types.h +index c5d742f18021..d5f8a74ed2e8 100644 +--- a/arch/powerpc/include/asm/spinlock_types.h ++++ b/arch/powerpc/include/asm/spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef _ASM_POWERPC_SPINLOCK_TYPES_H + #define _ASM_POWERPC_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/powerpc/include/asm/stackprotector.h b/arch/powerpc/include/asm/stackprotector.h +index 1c8460e23583..b1653c160bab 100644 +--- a/arch/powerpc/include/asm/stackprotector.h ++++ b/arch/powerpc/include/asm/stackprotector.h +@@ -24,7 +24,11 @@ static __always_inline void boot_init_stack_canary(void) + unsigned long canary; + + /* Try to get a semi random initial value. */ ++#ifdef CONFIG_PREEMPT_RT ++ canary = (unsigned long)&canary; ++#else + canary = get_random_canary(); ++#endif + canary ^= mftb(); + canary ^= LINUX_VERSION_CODE; + canary &= CANARY_MASK; +diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h +index 87013ac2a640..2920ed371188 100644 +--- a/arch/powerpc/include/asm/thread_info.h ++++ b/arch/powerpc/include/asm/thread_info.h +@@ -53,6 +53,8 @@ + struct thread_info { + int preempt_count; /* 0 => preemptable, + <0 => BUG */ ++ int preempt_lazy_count; /* 0 => preemptable, ++ <0 => BUG */ + unsigned long local_flags; /* private flags for thread */ + #ifdef CONFIG_LIVEPATCH + unsigned long *livepatch_sp; +@@ -99,6 +101,7 @@ void arch_setup_new_exec(void); + #define TIF_PATCH_PENDING 6 /* pending live patching update */ + #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ + #define TIF_SINGLESTEP 8 /* singlestepping active */ ++#define TIF_NEED_RESCHED_LAZY 9 /* lazy rescheduling necessary */ + #define TIF_SECCOMP 10 /* secure computing */ + #define TIF_RESTOREALL 11 /* Restore all regs (implies NOERROR) */ + #define TIF_NOERROR 12 /* Force successful syscall return */ +@@ -114,6 +117,7 @@ void arch_setup_new_exec(void); + #define TIF_POLLING_NRFLAG 19 /* true if poll_idle() is polling TIF_NEED_RESCHED */ + #define TIF_32BIT 20 /* 32 bit binary */ + ++ + /* as above, but as bit values */ + #define _TIF_SYSCALL_TRACE (1<flags); + while (unlikely(ti_flags & (_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM))) { + local_irq_enable(); +- if (ti_flags & _TIF_NEED_RESCHED) { ++ if (ti_flags & _TIF_NEED_RESCHED_MASK) { + schedule(); + } else { + /* +@@ -554,11 +554,15 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs) + /* Returning to a kernel context with local irqs enabled. */ + WARN_ON_ONCE(!(regs->msr & MSR_EE)); + again: +- if (IS_ENABLED(CONFIG_PREEMPT)) { ++ if (IS_ENABLED(CONFIG_PREEMPTION)) { + /* Return to preemptible kernel context */ + if (unlikely(current_thread_info()->flags & _TIF_NEED_RESCHED)) { + if (preempt_count() == 0) + preempt_schedule_irq(); ++ } else if (unlikely(current_thread_info()->flags & _TIF_NEED_RESCHED_LAZY)) { ++ if ((preempt_count() == 0) && ++ (current_thread_info()->preempt_lazy_count == 0)) ++ preempt_schedule_irq(); + } + } + +diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c +index c4f1d6b7d992..02e17a57da83 100644 +--- a/arch/powerpc/kernel/irq.c ++++ b/arch/powerpc/kernel/irq.c +@@ -690,6 +690,7 @@ static inline void check_stack_overflow(void) + } + } + ++#ifndef CONFIG_PREEMPT_RT + static __always_inline void call_do_softirq(const void *sp) + { + /* Temporarily switch r1 to sp, call __do_softirq() then restore r1. */ +@@ -708,6 +709,7 @@ static __always_inline void call_do_softirq(const void *sp) + "r11", "r12" + ); + } ++#endif + + static __always_inline void call_do_irq(struct pt_regs *regs, void *sp) + { +@@ -820,10 +822,12 @@ void *mcheckirq_ctx[NR_CPUS] __read_mostly; + void *softirq_ctx[NR_CPUS] __read_mostly; + void *hardirq_ctx[NR_CPUS] __read_mostly; + ++#ifndef CONFIG_PREEMPT_RT + void do_softirq_own_stack(void) + { + call_do_softirq(softirq_ctx[smp_processor_id()]); + } ++#endif + + irq_hw_number_t virq_to_hw(unsigned int virq) + { +diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c +index bdee7262c080..d57d37497862 100644 +--- a/arch/powerpc/kernel/kgdb.c ++++ b/arch/powerpc/kernel/kgdb.c +@@ -120,11 +120,19 @@ int kgdb_skipexception(int exception, struct pt_regs *regs) + + static int kgdb_debugger_ipi(struct pt_regs *regs) + { +- kgdb_nmicallback(raw_smp_processor_id(), regs); ++ int cpu = raw_smp_processor_id(); ++ ++ if (!kgdb_roundup_delay(cpu)) ++ kgdb_nmicallback(cpu, regs); + return 0; + } + + #ifdef CONFIG_SMP ++void kgdb_roundup_cpu(unsigned int cpu) ++{ ++ smp_send_debugger_break_cpu(cpu); ++} ++ + void kgdb_roundup_cpus(void) + { + smp_send_debugger_break(); +diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c +index fb95f92dcfac..308765f2e7a0 100644 +--- a/arch/powerpc/kernel/smp.c ++++ b/arch/powerpc/kernel/smp.c +@@ -590,6 +590,11 @@ static void debugger_ipi_callback(struct pt_regs *regs) + debugger_ipi(regs); + } + ++void smp_send_debugger_break_cpu(unsigned int cpu) ++{ ++ smp_send_nmi_ipi(cpu, debugger_ipi_callback, 1000000); ++} ++ + void smp_send_debugger_break(void) + { + smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, debugger_ipi_callback, 1000000); +diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c +index a08bb7cefdc5..ae34f68eedc1 100644 +--- a/arch/powerpc/kernel/traps.c ++++ b/arch/powerpc/kernel/traps.c +@@ -260,12 +260,17 @@ static char *get_mmu_str(void) + + static int __die(const char *str, struct pt_regs *regs, long err) + { ++ const char *pr = ""; ++ + printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); + ++ if (IS_ENABLED(CONFIG_PREEMPTION)) ++ pr = IS_ENABLED(CONFIG_PREEMPT_RT) ? " PREEMPT_RT" : " PREEMPT"; ++ + printk("%s PAGE_SIZE=%luK%s%s%s%s%s%s %s\n", + IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) ? "LE" : "BE", + PAGE_SIZE / 1024, get_mmu_str(), +- IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "", ++ pr, + IS_ENABLED(CONFIG_SMP) ? " SMP" : "", + IS_ENABLED(CONFIG_SMP) ? (" NR_CPUS=" __stringify(NR_CPUS)) : "", + debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "", +diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig +index ff581d70f20c..e5c84d55bdfb 100644 +--- a/arch/powerpc/kvm/Kconfig ++++ b/arch/powerpc/kvm/Kconfig +@@ -178,6 +178,7 @@ config KVM_E500MC + config KVM_MPIC + bool "KVM in-kernel MPIC emulation" + depends on KVM && E500 ++ depends on !PREEMPT_RT + select HAVE_KVM_IRQCHIP + select HAVE_KVM_IRQFD + select HAVE_KVM_IRQ_ROUTING +diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c +index ec5d84b4958c..62a80ecc6735 100644 +--- a/arch/powerpc/platforms/pseries/iommu.c ++++ b/arch/powerpc/platforms/pseries/iommu.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -200,7 +201,13 @@ static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift, + return ret; + } + +-static DEFINE_PER_CPU(__be64 *, tce_page); ++struct tce_page { ++ __be64 * page; ++ local_lock_t lock; ++}; ++static DEFINE_PER_CPU(struct tce_page, tce_page) = { ++ .lock = INIT_LOCAL_LOCK(lock), ++}; + + static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, + long npages, unsigned long uaddr, +@@ -223,9 +230,10 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, + direction, attrs); + } + +- local_irq_save(flags); /* to protect tcep and the page behind it */ ++ /* to protect tcep and the page behind it */ ++ local_lock_irqsave(&tce_page.lock, flags); + +- tcep = __this_cpu_read(tce_page); ++ tcep = __this_cpu_read(tce_page.page); + + /* This is safe to do since interrupts are off when we're called + * from iommu_alloc{,_sg}() +@@ -234,12 +242,12 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, + tcep = (__be64 *)__get_free_page(GFP_ATOMIC); + /* If allocation fails, fall back to the loop implementation */ + if (!tcep) { +- local_irq_restore(flags); ++ local_unlock_irqrestore(&tce_page.lock, flags); + return tce_build_pSeriesLP(tbl->it_index, tcenum, + tceshift, + npages, uaddr, direction, attrs); + } +- __this_cpu_write(tce_page, tcep); ++ __this_cpu_write(tce_page.page, tcep); + } + + rpn = __pa(uaddr) >> tceshift; +@@ -269,7 +277,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, + tcenum += limit; + } while (npages > 0 && !rc); + +- local_irq_restore(flags); ++ local_unlock_irqrestore(&tce_page.lock, flags); + + if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) { + ret = (int)rc; +@@ -454,16 +462,17 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, + DMA_BIDIRECTIONAL, 0); + } + +- local_irq_disable(); /* to protect tcep and the page behind it */ +- tcep = __this_cpu_read(tce_page); ++ /* to protect tcep and the page behind it */ ++ local_lock_irq(&tce_page.lock); ++ tcep = __this_cpu_read(tce_page.page); + + if (!tcep) { + tcep = (__be64 *)__get_free_page(GFP_ATOMIC); + if (!tcep) { +- local_irq_enable(); ++ local_unlock_irq(&tce_page.lock); + return -ENOMEM; + } +- __this_cpu_write(tce_page, tcep); ++ __this_cpu_write(tce_page.page, tcep); + } + + proto_tce = TCE_PCI_READ | TCE_PCI_WRITE; +@@ -506,7 +515,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, + + /* error cleanup: caller will clear whole range */ + +- local_irq_enable(); ++ local_unlock_irq(&tce_page.lock); + return rc; + } + +diff --git a/arch/riscv/include/asm/spinlock_types.h b/arch/riscv/include/asm/spinlock_types.h +index f398e7638dd6..5a35a49505da 100644 +--- a/arch/riscv/include/asm/spinlock_types.h ++++ b/arch/riscv/include/asm/spinlock_types.h +@@ -6,7 +6,7 @@ + #ifndef _ASM_RISCV_SPINLOCK_TYPES_H + #define _ASM_RISCV_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/s390/include/asm/spinlock_types.h b/arch/s390/include/asm/spinlock_types.h +index a2bbfd7df85f..b69695e39957 100644 +--- a/arch/s390/include/asm/spinlock_types.h ++++ b/arch/s390/include/asm/spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef __ASM_SPINLOCK_TYPES_H + #define __ASM_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/sh/include/asm/spinlock_types.h b/arch/sh/include/asm/spinlock_types.h +index e82369f286a2..907bda4b1619 100644 +--- a/arch/sh/include/asm/spinlock_types.h ++++ b/arch/sh/include/asm/spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef __ASM_SH_SPINLOCK_TYPES_H + #define __ASM_SH_SPINLOCK_TYPES_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c +index ef0f0827cf57..2d3eca8fee01 100644 +--- a/arch/sh/kernel/irq.c ++++ b/arch/sh/kernel/irq.c +@@ -149,6 +149,7 @@ void irq_ctx_exit(int cpu) + hardirq_ctx[cpu] = NULL; + } + ++#ifndef CONFIG_PREEMPT_RT + void do_softirq_own_stack(void) + { + struct thread_info *curctx; +@@ -176,6 +177,7 @@ void do_softirq_own_stack(void) + "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" + ); + } ++#endif + #else + static inline void handle_one_irq(unsigned int irq) + { +diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c +index c8848bb681a1..41fa1be980a3 100644 +--- a/arch/sparc/kernel/irq_64.c ++++ b/arch/sparc/kernel/irq_64.c +@@ -855,6 +855,7 @@ void __irq_entry handler_irq(int pil, struct pt_regs *regs) + set_irq_regs(old_regs); + } + ++#ifndef CONFIG_PREEMPT_RT + void do_softirq_own_stack(void) + { + void *orig_sp, *sp = softirq_stack[smp_processor_id()]; +@@ -869,6 +870,7 @@ void do_softirq_own_stack(void) + __asm__ __volatile__("mov %0, %%sp" + : : "r" (orig_sp)); + } ++#endif + + #ifdef CONFIG_HOTPLUG_CPU + void fixup_irqs(void) +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index a08ce6360382..4a4498670861 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -107,6 +107,7 @@ config X86 + select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096 + select ARCH_SUPPORTS_LTO_CLANG + select ARCH_SUPPORTS_LTO_CLANG_THIN ++ select ARCH_SUPPORTS_RT + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_MEMTEST + select ARCH_USE_QUEUED_RWLOCKS +@@ -230,6 +231,7 @@ config X86 + select HAVE_PCI + select HAVE_PERF_REGS + select HAVE_PERF_USER_STACK_DUMP ++ select HAVE_PREEMPT_LAZY + select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT + select HAVE_POSIX_CPU_TIMERS_TASK_WORK + select HAVE_REGS_AND_STACK_ACCESS_API +diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h +index e087cd7837c3..96cc92f63b06 100644 +--- a/arch/x86/include/asm/irq_stack.h ++++ b/arch/x86/include/asm/irq_stack.h +@@ -202,6 +202,7 @@ + IRQ_CONSTRAINTS, regs, vector); \ + } + ++#ifndef CONFIG_PREEMPT_RT + /* + * Macro to invoke __do_softirq on the irq stack. This is only called from + * task context when bottom halves are about to be reenabled and soft +@@ -215,6 +216,8 @@ + __this_cpu_write(hardirq_stack_inuse, false); \ + } + ++#endif ++ + #else /* CONFIG_X86_64 */ + /* System vector handlers always run on the stack they interrupted. */ + #define run_sysvec_on_irqstack_cond(func, regs) \ +diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h +index fe5efbcba824..ab8cb5fc2329 100644 +--- a/arch/x86/include/asm/preempt.h ++++ b/arch/x86/include/asm/preempt.h +@@ -90,17 +90,48 @@ static __always_inline void __preempt_count_sub(int val) + * a decrement which hits zero means we have no preempt_count and should + * reschedule. + */ +-static __always_inline bool __preempt_count_dec_and_test(void) ++static __always_inline bool ____preempt_count_dec_and_test(void) + { + return GEN_UNARY_RMWcc("decl", __preempt_count, e, __percpu_arg([var])); + } + ++static __always_inline bool __preempt_count_dec_and_test(void) ++{ ++ if (____preempt_count_dec_and_test()) ++ return true; ++#ifdef CONFIG_PREEMPT_LAZY ++ if (preempt_count()) ++ return false; ++ if (current_thread_info()->preempt_lazy_count) ++ return false; ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++#else ++ return false; ++#endif ++} ++ + /* + * Returns true when we need to resched and can (barring IRQ state). + */ + static __always_inline bool should_resched(int preempt_offset) + { ++#ifdef CONFIG_PREEMPT_LAZY ++ u32 tmp; ++ tmp = raw_cpu_read_4(__preempt_count); ++ if (tmp == preempt_offset) ++ return true; ++ ++ /* preempt count == 0 ? */ ++ tmp &= ~PREEMPT_NEED_RESCHED; ++ if (tmp != preempt_offset) ++ return false; ++ /* XXX PREEMPT_LOCK_OFFSET */ ++ if (current_thread_info()->preempt_lazy_count) ++ return false; ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++#else + return unlikely(raw_cpu_read_4(__preempt_count) == preempt_offset); ++#endif + } + + #ifdef CONFIG_PREEMPTION +diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h +index 2dfb5fea13af..fc03f4f7ed84 100644 +--- a/arch/x86/include/asm/signal.h ++++ b/arch/x86/include/asm/signal.h +@@ -28,6 +28,19 @@ typedef struct { + #define SA_IA32_ABI 0x02000000u + #define SA_X32_ABI 0x01000000u + ++/* ++ * Because some traps use the IST stack, we must keep preemption ++ * disabled while calling do_trap(), but do_trap() may call ++ * force_sig_info() which will grab the signal spin_locks for the ++ * task, which in PREEMPT_RT are mutexes. By defining ++ * ARCH_RT_DELAYS_SIGNAL_SEND the force_sig_info() will set ++ * TIF_NOTIFY_RESUME and set up the signal to be sent on exit of the ++ * trap. ++ */ ++#if defined(CONFIG_PREEMPT_RT) ++#define ARCH_RT_DELAYS_SIGNAL_SEND ++#endif ++ + #ifndef CONFIG_COMPAT + #define compat_sigset_t compat_sigset_t + typedef sigset_t compat_sigset_t; +diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h +index 24a8d6c4fb18..2fc22c27df18 100644 +--- a/arch/x86/include/asm/stackprotector.h ++++ b/arch/x86/include/asm/stackprotector.h +@@ -50,7 +50,7 @@ + */ + static __always_inline void boot_init_stack_canary(void) + { +- u64 canary; ++ u64 canary = 0; + u64 tsc; + + #ifdef CONFIG_X86_64 +@@ -61,8 +61,14 @@ static __always_inline void boot_init_stack_canary(void) + * of randomness. The TSC only matters for very early init, + * there it already has some randomness on most systems. Later + * on during the bootup the random pool has true entropy too. ++ * For preempt-rt we need to weaken the randomness a bit, as ++ * we can't call into the random generator from atomic context ++ * due to locking constraints. We just leave canary ++ * uninitialized and use the TSC based randomness on top of it. + */ ++#ifndef CONFIG_PREEMPT_RT + get_random_bytes(&canary, sizeof(canary)); ++#endif + tsc = rdtsc(); + canary += tsc + (tsc << 32UL); + canary &= CANARY_MASK; +diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h +index cf132663c219..75dc786e6365 100644 +--- a/arch/x86/include/asm/thread_info.h ++++ b/arch/x86/include/asm/thread_info.h +@@ -57,11 +57,14 @@ struct thread_info { + unsigned long flags; /* low level flags */ + unsigned long syscall_work; /* SYSCALL_WORK_ flags */ + u32 status; /* thread synchronous flags */ ++ int preempt_lazy_count; /* 0 => lazy preemptable ++ <0 => BUG */ + }; + + #define INIT_THREAD_INFO(tsk) \ + { \ + .flags = 0, \ ++ .preempt_lazy_count = 0, \ + } + + #else /* !__ASSEMBLY__ */ +@@ -90,6 +93,7 @@ struct thread_info { + #define TIF_NOTSC 16 /* TSC is not accessible in userland */ + #define TIF_NOTIFY_SIGNAL 17 /* signal notifications exist */ + #define TIF_SLD 18 /* Restore split lock detection on context switch */ ++#define TIF_NEED_RESCHED_LAZY 19 /* lazy rescheduling necessary */ + #define TIF_MEMDIE 20 /* is terminating due to OOM killer */ + #define TIF_POLLING_NRFLAG 21 /* idle is polling for TIF_NEED_RESCHED */ + #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ +@@ -114,6 +118,7 @@ struct thread_info { + #define _TIF_NOTSC (1 << TIF_NOTSC) + #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) + #define _TIF_SLD (1 << TIF_SLD) ++#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) + #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) + #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) + #define _TIF_SPEC_FORCE_UPDATE (1 << TIF_SPEC_FORCE_UPDATE) +diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c +index 044902d5a3c4..e5dd6da78713 100644 +--- a/arch/x86/kernel/irq_32.c ++++ b/arch/x86/kernel/irq_32.c +@@ -132,6 +132,7 @@ int irq_init_percpu_irqstack(unsigned int cpu) + return 0; + } + ++#ifndef CONFIG_PREEMPT_RT + void do_softirq_own_stack(void) + { + struct irq_stack *irqstk; +@@ -148,6 +149,7 @@ void do_softirq_own_stack(void) + + call_on_stack(__do_softirq, isp); + } ++#endif + + void __handle_irq(struct irq_desc *desc, struct pt_regs *regs) + { +diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c +index 3a43a2dee658..37bd37cdf2b6 100644 +--- a/arch/x86/kernel/kgdb.c ++++ b/arch/x86/kernel/kgdb.c +@@ -502,9 +502,12 @@ static int kgdb_nmi_handler(unsigned int cmd, struct pt_regs *regs) + if (atomic_read(&kgdb_active) != -1) { + /* KGDB CPU roundup */ + cpu = raw_smp_processor_id(); +- kgdb_nmicallback(cpu, regs); +- set_bit(cpu, was_in_debug_nmi); +- touch_nmi_watchdog(); ++ ++ if (!kgdb_roundup_delay(cpu)) { ++ kgdb_nmicallback(cpu, regs); ++ set_bit(cpu, was_in_debug_nmi); ++ touch_nmi_watchdog(); ++ } + + return NMI_HANDLED; + } +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 7e1e3bc74562..38639c57b462 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -8686,6 +8686,14 @@ int kvm_arch_init(void *opaque) + goto out; + } + ++#ifdef CONFIG_PREEMPT_RT ++ if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) { ++ pr_err("RT requires X86_FEATURE_CONSTANT_TSC\n"); ++ r = -EOPNOTSUPP; ++ goto out; ++ } ++#endif ++ + r = -ENOMEM; + x86_fpu_cache = kmem_cache_create("x86_fpu", sizeof(struct fpu), + __alignof__(struct fpu), SLAB_ACCOUNT, +diff --git a/arch/xtensa/include/asm/spinlock_types.h b/arch/xtensa/include/asm/spinlock_types.h +index 64c9389254f1..797aed7df3dd 100644 +--- a/arch/xtensa/include/asm/spinlock_types.h ++++ b/arch/xtensa/include/asm/spinlock_types.h +@@ -2,7 +2,7 @@ + #ifndef __ASM_SPINLOCK_TYPES_H + #define __ASM_SPINLOCK_TYPES_H + +-#if !defined(__LINUX_SPINLOCK_TYPES_H) && !defined(__ASM_SPINLOCK_H) ++#if !defined(__LINUX_SPINLOCK_TYPES_RAW_H) && !defined(__ASM_SPINLOCK_H) + # error "please don't include this file directly" + #endif + +diff --git a/block/blk-mq.c b/block/blk-mq.c +index bbbbcd2c1941..0fc928de505d 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -1567,14 +1567,14 @@ static void __blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async, + return; + + if (!async && !(hctx->flags & BLK_MQ_F_BLOCKING)) { +- int cpu = get_cpu(); ++ int cpu = get_cpu_light(); + if (cpumask_test_cpu(cpu, hctx->cpumask)) { + __blk_mq_run_hw_queue(hctx); +- put_cpu(); ++ put_cpu_light(); + return; + } + +- put_cpu(); ++ put_cpu_light(); + } + + kblockd_mod_delayed_work_on(blk_mq_hctx_next_cpu(hctx), &hctx->run_work, +diff --git a/crypto/testmgr.c b/crypto/testmgr.c +index 163a1283a866..444183fe847d 100644 +--- a/crypto/testmgr.c ++++ b/crypto/testmgr.c +@@ -1061,14 +1061,14 @@ static void generate_random_testvec_config(struct testvec_config *cfg, + + static void crypto_disable_simd_for_test(void) + { +- preempt_disable(); ++ migrate_disable(); + __this_cpu_write(crypto_simd_disabled_for_test, true); + } + + static void crypto_reenable_simd_for_test(void) + { + __this_cpu_write(crypto_simd_disabled_for_test, false); +- preempt_enable(); ++ migrate_enable(); + } + + /* +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index 6383c81ac5b3..abb695f5f5e4 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -59,6 +59,40 @@ static void zram_free_page(struct zram *zram, size_t index); + static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, + u32 index, int offset, struct bio *bio); + ++#ifdef CONFIG_PREEMPT_RT ++static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) ++{ ++ size_t index; ++ ++ for (index = 0; index < num_pages; index++) ++ spin_lock_init(&zram->table[index].lock); ++} ++ ++static int zram_slot_trylock(struct zram *zram, u32 index) ++{ ++ int ret; ++ ++ ret = spin_trylock(&zram->table[index].lock); ++ if (ret) ++ __set_bit(ZRAM_LOCK, &zram->table[index].flags); ++ return ret; ++} ++ ++static void zram_slot_lock(struct zram *zram, u32 index) ++{ ++ spin_lock(&zram->table[index].lock); ++ __set_bit(ZRAM_LOCK, &zram->table[index].flags); ++} ++ ++static void zram_slot_unlock(struct zram *zram, u32 index) ++{ ++ __clear_bit(ZRAM_LOCK, &zram->table[index].flags); ++ spin_unlock(&zram->table[index].lock); ++} ++ ++#else ++ ++static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) { } + + static int zram_slot_trylock(struct zram *zram, u32 index) + { +@@ -74,6 +108,7 @@ static void zram_slot_unlock(struct zram *zram, u32 index) + { + bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags); + } ++#endif + + static inline bool init_done(struct zram *zram) + { +@@ -1169,6 +1204,7 @@ static bool zram_meta_alloc(struct zram *zram, u64 disksize) + + if (!huge_class_size) + huge_class_size = zs_huge_class_size(zram->mem_pool); ++ zram_meta_init_table_locks(zram, num_pages); + return true; + } + +diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h +index 80c3b43b4828..d8f6d880f915 100644 +--- a/drivers/block/zram/zram_drv.h ++++ b/drivers/block/zram/zram_drv.h +@@ -63,6 +63,7 @@ struct zram_table_entry { + unsigned long element; + }; + unsigned long flags; ++ spinlock_t lock; + #ifdef CONFIG_ZRAM_MEMORY_TRACKING + ktime_t ac_time; + #endif +diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c +index dfb463ee7ca1..b19c4f745ee3 100644 +--- a/drivers/char/tpm/tpm_tis.c ++++ b/drivers/char/tpm/tpm_tis.c +@@ -50,6 +50,31 @@ static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *da + return container_of(data, struct tpm_tis_tcg_phy, priv); + } + ++#ifdef CONFIG_PREEMPT_RT ++/* ++ * Flushes previous write operations to chip so that a subsequent ++ * ioread*()s won't stall a cpu. ++ */ ++static inline void tpm_tis_flush(void __iomem *iobase) ++{ ++ ioread8(iobase + TPM_ACCESS(0)); ++} ++#else ++#define tpm_tis_flush(iobase) do { } while (0) ++#endif ++ ++static inline void tpm_tis_iowrite8(u8 b, void __iomem *iobase, u32 addr) ++{ ++ iowrite8(b, iobase + addr); ++ tpm_tis_flush(iobase); ++} ++ ++static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr) ++{ ++ iowrite32(b, iobase + addr); ++ tpm_tis_flush(iobase); ++} ++ + static int interrupts = -1; + module_param(interrupts, int, 0444); + MODULE_PARM_DESC(interrupts, "Enable interrupts"); +@@ -186,7 +211,7 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, + struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); + + while (len--) +- iowrite8(*value++, phy->iobase + addr); ++ tpm_tis_iowrite8(*value++, phy->iobase, addr); + + return 0; + } +@@ -213,7 +238,7 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value) + { + struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); + +- iowrite32(value, phy->iobase + addr); ++ tpm_tis_iowrite32(value, phy->iobase, addr); + + return 0; + } +diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c +index 332739f3eded..8589df0e8c1f 100644 +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -66,7 +66,7 @@ struct mm_struct efi_mm = { + + struct workqueue_struct *efi_rts_wq; + +-static bool disable_runtime; ++static bool disable_runtime = IS_ENABLED(CONFIG_PREEMPT_RT); + static int __init setup_noefi(char *arg) + { + disable_runtime = true; +@@ -97,6 +97,9 @@ static int __init parse_efi_cmdline(char *str) + if (parse_option_str(str, "noruntime")) + disable_runtime = true; + ++ if (parse_option_str(str, "runtime")) ++ disable_runtime = false; ++ + if (parse_option_str(str, "nosoftreserve")) + set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags); + +diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c +index 254e67141a77..7a39029b083f 100644 +--- a/drivers/gpu/drm/i915/display/intel_crtc.c ++++ b/drivers/gpu/drm/i915/display/intel_crtc.c +@@ -425,7 +425,8 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) + */ + intel_psr_wait_for_idle(new_crtc_state); + +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + + crtc->debug.min_vbl = min; + crtc->debug.max_vbl = max; +@@ -450,11 +451,13 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) + break; + } + +- local_irq_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_enable(); + + timeout = schedule_timeout(timeout); + +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + } + + finish_wait(wq, &wait); +@@ -487,7 +490,8 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) + return; + + irq_disable: +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + } + + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) +@@ -566,7 +570,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) + new_crtc_state->uapi.event = NULL; + } + +- local_irq_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_enable(); + + /* Send VRR Push to terminate Vblank */ + intel_vrr_send_push(new_crtc_state); +diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +index 209cf265bf74..6e1b9068d944 100644 +--- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c ++++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +@@ -311,10 +311,9 @@ void __intel_breadcrumbs_park(struct intel_breadcrumbs *b) + /* Kick the work once more to drain the signalers, and disarm the irq */ + irq_work_sync(&b->irq_work); + while (READ_ONCE(b->irq_armed) && !atomic_read(&b->active)) { +- local_irq_disable(); +- signal_irq_work(&b->irq_work); +- local_irq_enable(); ++ irq_work_queue(&b->irq_work); + cond_resched(); ++ irq_work_sync(&b->irq_work); + } + } + +diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h +index c41098950746..601274ba86e4 100644 +--- a/drivers/gpu/drm/i915/gt/intel_context.h ++++ b/drivers/gpu/drm/i915/gt/intel_context.h +@@ -163,7 +163,8 @@ static inline void intel_context_enter(struct intel_context *ce) + + static inline void intel_context_mark_active(struct intel_context *ce) + { +- lockdep_assert_held(&ce->timeline->mutex); ++ lockdep_assert(lockdep_is_held(&ce->timeline->mutex) || ++ test_bit(CONTEXT_IS_PARKED, &ce->flags)); + ++ce->active_count; + } + +diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h +index a63631ea0ec4..314457fb9db5 100644 +--- a/drivers/gpu/drm/i915/gt/intel_context_types.h ++++ b/drivers/gpu/drm/i915/gt/intel_context_types.h +@@ -112,6 +112,7 @@ struct intel_context { + #define CONTEXT_FORCE_SINGLE_SUBMISSION 7 + #define CONTEXT_NOPREEMPT 8 + #define CONTEXT_LRCA_DIRTY 9 ++#define CONTEXT_IS_PARKED 10 + + struct { + u64 timeout_us; +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c +index dacd62773735..73e96ca024df 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c +@@ -80,39 +80,6 @@ static int __engine_unpark(struct intel_wakeref *wf) + return 0; + } + +-#if IS_ENABLED(CONFIG_LOCKDEP) +- +-static unsigned long __timeline_mark_lock(struct intel_context *ce) +-{ +- unsigned long flags; +- +- local_irq_save(flags); +- mutex_acquire(&ce->timeline->mutex.dep_map, 2, 0, _THIS_IP_); +- +- return flags; +-} +- +-static void __timeline_mark_unlock(struct intel_context *ce, +- unsigned long flags) +-{ +- mutex_release(&ce->timeline->mutex.dep_map, _THIS_IP_); +- local_irq_restore(flags); +-} +- +-#else +- +-static unsigned long __timeline_mark_lock(struct intel_context *ce) +-{ +- return 0; +-} +- +-static void __timeline_mark_unlock(struct intel_context *ce, +- unsigned long flags) +-{ +-} +- +-#endif /* !IS_ENABLED(CONFIG_LOCKDEP) */ +- + static void duration(struct dma_fence *fence, struct dma_fence_cb *cb) + { + struct i915_request *rq = to_request(fence); +@@ -159,7 +126,6 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine) + { + struct intel_context *ce = engine->kernel_context; + struct i915_request *rq; +- unsigned long flags; + bool result = true; + + /* GPU is pointing to the void, as good as in the kernel context. */ +@@ -201,7 +167,7 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine) + * engine->wakeref.count, we may see the request completion and retire + * it causing an underflow of the engine->wakeref. + */ +- flags = __timeline_mark_lock(ce); ++ set_bit(CONTEXT_IS_PARKED, &ce->flags); + GEM_BUG_ON(atomic_read(&ce->timeline->active_count) < 0); + + rq = __i915_request_create(ce, GFP_NOWAIT); +@@ -233,7 +199,7 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine) + + result = false; + out_unlock: +- __timeline_mark_unlock(ce, flags); ++ clear_bit(CONTEXT_IS_PARKED, &ce->flags); + return result; + } + +diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +index 773ff5121833..f330457209d5 100644 +--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c ++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +@@ -1286,7 +1286,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + * and context switches) submission. + */ + +- spin_lock(&sched_engine->lock); ++ spin_lock_irq(&sched_engine->lock); + + /* + * If the queue is higher priority than the last +@@ -1386,7 +1386,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + * Even if ELSP[1] is occupied and not worthy + * of timeslices, our queue might be. + */ +- spin_unlock(&sched_engine->lock); ++ spin_unlock_irq(&sched_engine->lock); + return; + } + } +@@ -1412,7 +1412,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + + if (last && !can_merge_rq(last, rq)) { + spin_unlock(&ve->base.sched_engine->lock); +- spin_unlock(&engine->sched_engine->lock); ++ spin_unlock_irq(&engine->sched_engine->lock); + return; /* leave this for another sibling */ + } + +@@ -1574,7 +1574,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + */ + sched_engine->queue_priority_hint = queue_prio(sched_engine); + i915_sched_engine_reset_on_empty(sched_engine); +- spin_unlock(&sched_engine->lock); ++ spin_unlock_irq(&sched_engine->lock); + + /* + * We can skip poking the HW if we ended up with exactly the same set +@@ -1600,13 +1600,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine) + } + } + +-static void execlists_dequeue_irq(struct intel_engine_cs *engine) +-{ +- local_irq_disable(); /* Suspend interrupts across request submission */ +- execlists_dequeue(engine); +- local_irq_enable(); /* flush irq_work (e.g. breadcrumb enabling) */ +-} +- + static void clear_ports(struct i915_request **ports, int count) + { + memset_p((void **)ports, NULL, count); +@@ -2442,7 +2435,7 @@ static void execlists_submission_tasklet(struct tasklet_struct *t) + } + + if (!engine->execlists.pending[0]) { +- execlists_dequeue_irq(engine); ++ execlists_dequeue(engine); + start_timeslice(engine); + } + +diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c +index 9bc4f4a8e12e..547347241a47 100644 +--- a/drivers/gpu/drm/i915/i915_irq.c ++++ b/drivers/gpu/drm/i915/i915_irq.c +@@ -886,7 +886,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, + */ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + +- /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); + + /* Get optional system timestamp before query. */ + if (stime) +@@ -950,7 +951,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, + if (etime) + *etime = ktime_get(); + +- /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + +diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c +index 79da5eca60af..b9dd6100c6d1 100644 +--- a/drivers/gpu/drm/i915/i915_request.c ++++ b/drivers/gpu/drm/i915/i915_request.c +@@ -559,7 +559,6 @@ bool __i915_request_submit(struct i915_request *request) + + RQ_TRACE(request, "\n"); + +- GEM_BUG_ON(!irqs_disabled()); + lockdep_assert_held(&engine->sched_engine->lock); + + /* +@@ -668,7 +667,6 @@ void __i915_request_unsubmit(struct i915_request *request) + */ + RQ_TRACE(request, "\n"); + +- GEM_BUG_ON(!irqs_disabled()); + lockdep_assert_held(&engine->sched_engine->lock); + + /* +diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h +index 1bc1349ba3c2..a2f713b4ac2f 100644 +--- a/drivers/gpu/drm/i915/i915_request.h ++++ b/drivers/gpu/drm/i915/i915_request.h +@@ -609,7 +609,8 @@ i915_request_timeline(const struct i915_request *rq) + { + /* Valid only while the request is being constructed (or retired). */ + return rcu_dereference_protected(rq->timeline, +- lockdep_is_held(&rcu_access_pointer(rq->timeline)->mutex)); ++ lockdep_is_held(&rcu_access_pointer(rq->timeline)->mutex) || ++ test_bit(CONTEXT_IS_PARKED, &rq->context->flags)); + } + + static inline struct i915_gem_context * +diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h +index 63fec1c3c132..f345a0f12bf6 100644 +--- a/drivers/gpu/drm/i915/i915_trace.h ++++ b/drivers/gpu/drm/i915/i915_trace.h +@@ -2,6 +2,10 @@ + #if !defined(_I915_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) + #define _I915_TRACE_H_ + ++#ifdef CONFIG_PREEMPT_RT ++#define NOTRACE ++#endif ++ + #include + #include + #include +@@ -819,7 +823,7 @@ DEFINE_EVENT(i915_request, i915_request_add, + TP_ARGS(rq) + ); + +-#if defined(CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS) ++#if defined(CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS) && !defined(NOTRACE) + DEFINE_EVENT(i915_request, i915_request_guc_submit, + TP_PROTO(struct i915_request *rq), + TP_ARGS(rq) +diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h +index 5259edacde38..b36b27c09049 100644 +--- a/drivers/gpu/drm/i915/i915_utils.h ++++ b/drivers/gpu/drm/i915/i915_utils.h +@@ -343,7 +343,7 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) + #define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) + + /* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */ +-#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) ++#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT) + # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic()) + #else + # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0) +diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c +index 1cf68f85b2e1..8ccf0c928bb4 100644 +--- a/drivers/i2c/busses/i2c-cht-wc.c ++++ b/drivers/i2c/busses/i2c-cht-wc.c +@@ -99,15 +99,8 @@ static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data) + * interrupt handler as well, so running the client irq handler from + * this thread will cause things to lock up. + */ +- if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) { +- /* +- * generic_handle_irq expects local IRQs to be disabled +- * as normally it is called from interrupt context. +- */ +- local_irq_disable(); +- generic_handle_irq(adap->client_irq); +- local_irq_enable(); +- } ++ if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) ++ generic_handle_irq_safe(adap->client_irq); + + return IRQ_HANDLED; + } +diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c +index 8fb065caf30b..c232535ca8f4 100644 +--- a/drivers/i2c/i2c-core-base.c ++++ b/drivers/i2c/i2c-core-base.c +@@ -1422,7 +1422,7 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr) + if (irq <= 0) + return -ENXIO; + +- generic_handle_irq(irq); ++ generic_handle_irq_safe(irq); + + return 0; + } +diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig +index 1f1d57288085..dc6816d36d06 100644 +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -64,6 +64,7 @@ config LEDS_TRIGGER_BACKLIGHT + + config LEDS_TRIGGER_CPU + bool "LED CPU Trigger" ++ depends on !PREEMPT_RT + help + This allows LEDs to be controlled by active CPUs. This shows + the active CPUs across an array of LEDs so you can see which +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index c2a42486f985..451a22641b5a 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -2218,8 +2218,9 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) + struct raid5_percpu *percpu; + unsigned long cpu; + +- cpu = get_cpu(); ++ cpu = get_cpu_light(); + percpu = per_cpu_ptr(conf->percpu, cpu); ++ spin_lock(&percpu->lock); + if (test_bit(STRIPE_OP_BIOFILL, &ops_request)) { + ops_run_biofill(sh); + overlap_clear++; +@@ -2278,7 +2279,8 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) + if (test_and_clear_bit(R5_Overlap, &dev->flags)) + wake_up(&sh->raid_conf->wait_for_overlap); + } +- put_cpu(); ++ spin_unlock(&percpu->lock); ++ put_cpu_light(); + } + + static void free_stripe(struct kmem_cache *sc, struct stripe_head *sh) +@@ -7110,6 +7112,7 @@ static int raid456_cpu_up_prepare(unsigned int cpu, struct hlist_node *node) + __func__, cpu); + return -ENOMEM; + } ++ spin_lock_init(&per_cpu_ptr(conf->percpu, cpu)->lock); + return 0; + } + +diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h +index 5c05acf20e1f..665fe138ab4f 100644 +--- a/drivers/md/raid5.h ++++ b/drivers/md/raid5.h +@@ -635,6 +635,7 @@ struct r5conf { + int recovery_disabled; + /* per cpu variables */ + struct raid5_percpu { ++ spinlock_t lock; /* Protection for -RT */ + struct page *spare_page; /* Used when checking P/Q in raid6 */ + void *scribble; /* space for constructing buffer + * lists and performing address +diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c +index 70fa18b04ad2..b14d3f98e1eb 100644 +--- a/drivers/mfd/ezx-pcap.c ++++ b/drivers/mfd/ezx-pcap.c +@@ -193,13 +193,11 @@ static void pcap_isr_work(struct work_struct *work) + ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr); + ezx_pcap_write(pcap, PCAP_REG_ISR, isr); + +- local_irq_disable(); + service = isr & ~msr; + for (irq = pcap->irq_base; service; service >>= 1, irq++) { + if (service & 1) +- generic_handle_irq(irq); ++ generic_handle_irq_safe(irq); + } +- local_irq_enable(); + ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); + } while (gpio_get_value(pdata->gpio)); + } +diff --git a/drivers/misc/hi6421v600-irq.c b/drivers/misc/hi6421v600-irq.c +index 08535e97ff43..0585a5821d05 100644 +--- a/drivers/misc/hi6421v600-irq.c ++++ b/drivers/misc/hi6421v600-irq.c +@@ -118,8 +118,8 @@ static irqreturn_t hi6421v600_irq_handler(int irq, void *__priv) + * If both powerkey down and up IRQs are received, + * handle them at the right order + */ +- generic_handle_irq(priv->irqs[POWERKEY_DOWN]); +- generic_handle_irq(priv->irqs[POWERKEY_UP]); ++ generic_handle_irq_safe(priv->irqs[POWERKEY_DOWN]); ++ generic_handle_irq_safe(priv->irqs[POWERKEY_UP]); + pending &= ~HISI_IRQ_POWERKEY_UP_DOWN; + } + +@@ -127,7 +127,7 @@ static irqreturn_t hi6421v600_irq_handler(int irq, void *__priv) + continue; + + for_each_set_bit(offset, &pending, BITS_PER_BYTE) { +- generic_handle_irq(priv->irqs[offset + i * BITS_PER_BYTE]); ++ generic_handle_irq_safe(priv->irqs[offset + i * BITS_PER_BYTE]); + } + } + +diff --git a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c +index 2473fb5f75e5..2a5cc64227e9 100644 +--- a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c ++++ b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c +@@ -458,7 +458,7 @@ nfp_abm_qdisc_graft(struct nfp_abm_link *alink, u32 handle, u32 child_handle, + static void + nfp_abm_stats_calculate(struct nfp_alink_stats *new, + struct nfp_alink_stats *old, +- struct gnet_stats_basic_packed *bstats, ++ struct gnet_stats_basic_sync *bstats, + struct gnet_stats_queue *qstats) + { + _bstats_update(bstats, new->tx_bytes - old->tx_bytes, +diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c +index 5700c9d20a3e..be3330a1c922 100644 +--- a/drivers/net/usb/lan78xx.c ++++ b/drivers/net/usb/lan78xx.c +@@ -1367,11 +1367,8 @@ static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb) + netif_dbg(dev, link, dev->net, "PHY INTR: 0x%08x\n", intdata); + lan78xx_defer_kevent(dev, EVENT_LINK_RESET); + +- if (dev->domain_data.phyirq > 0) { +- local_irq_disable(); +- generic_handle_irq(dev->domain_data.phyirq); +- local_irq_enable(); +- } ++ if (dev->domain_data.phyirq > 0) ++ generic_handle_irq_safe(dev->domain_data.phyirq); + } else { + netdev_warn(dev->net, + "unexpected interrupt: 0x%08x\n", intdata); +diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c +index 76dbdae0e987..967431858dcd 100644 +--- a/drivers/scsi/fcoe/fcoe.c ++++ b/drivers/scsi/fcoe/fcoe.c +@@ -1450,11 +1450,11 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, + static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen) + { + struct fcoe_percpu_s *fps; +- int rc; ++ int rc, cpu = get_cpu_light(); + +- fps = &get_cpu_var(fcoe_percpu); ++ fps = &per_cpu(fcoe_percpu, cpu); + rc = fcoe_get_paged_crc_eof(skb, tlen, fps); +- put_cpu_var(fcoe_percpu); ++ put_cpu_light(); + + return rc; + } +@@ -1639,11 +1639,11 @@ static inline int fcoe_filter_frames(struct fc_lport *lport, + return 0; + } + +- stats = per_cpu_ptr(lport->stats, get_cpu()); ++ stats = per_cpu_ptr(lport->stats, get_cpu_light()); + stats->InvalidCRCCount++; + if (stats->InvalidCRCCount < 5) + printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); +- put_cpu(); ++ put_cpu_light(); + return -EINVAL; + } + +@@ -1684,7 +1684,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) + */ + hp = (struct fcoe_hdr *) skb_network_header(skb); + +- stats = per_cpu_ptr(lport->stats, get_cpu()); ++ stats = per_cpu_ptr(lport->stats, get_cpu_light()); + if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { + if (stats->ErrorFrames < 5) + printk(KERN_WARNING "fcoe: FCoE version " +@@ -1716,13 +1716,13 @@ static void fcoe_recv_frame(struct sk_buff *skb) + goto drop; + + if (!fcoe_filter_frames(lport, fp)) { +- put_cpu(); ++ put_cpu_light(); + fc_exch_recv(lport, fp); + return; + } + drop: + stats->ErrorFrames++; +- put_cpu(); ++ put_cpu_light(); + kfree_skb(skb); + } + +diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c +index 558f3f4e1859..f08feaa4f398 100644 +--- a/drivers/scsi/fcoe/fcoe_ctlr.c ++++ b/drivers/scsi/fcoe/fcoe_ctlr.c +@@ -828,7 +828,7 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) + + INIT_LIST_HEAD(&del_list); + +- stats = per_cpu_ptr(fip->lp->stats, get_cpu()); ++ stats = per_cpu_ptr(fip->lp->stats, get_cpu_light()); + + list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { + deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2; +@@ -864,7 +864,7 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) + sel_time = fcf->time; + } + } +- put_cpu(); ++ put_cpu_light(); + + list_for_each_entry_safe(fcf, next, &del_list, list) { + /* Removes fcf from current list */ +diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c +index aa223db4cf53..0ceb93800704 100644 +--- a/drivers/scsi/libfc/fc_exch.c ++++ b/drivers/scsi/libfc/fc_exch.c +@@ -825,10 +825,10 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, + } + memset(ep, 0, sizeof(*ep)); + +- cpu = get_cpu(); ++ cpu = get_cpu_light(); + pool = per_cpu_ptr(mp->pool, cpu); + spin_lock_bh(&pool->lock); +- put_cpu(); ++ put_cpu_light(); + + /* peek cache of free slot */ + if (pool->left != FC_XID_UNKNOWN) { +diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c +index 7e6347fe93f9..8a7cf1d0e968 100644 +--- a/drivers/staging/greybus/gpio.c ++++ b/drivers/staging/greybus/gpio.c +@@ -391,10 +391,7 @@ static int gb_gpio_request_handler(struct gb_operation *op) + return -EINVAL; + } + +- local_irq_disable(); +- ret = generic_handle_irq(irq); +- local_irq_enable(); +- ++ ret = generic_handle_irq_safe(irq); + if (ret) + dev_err(dev, "failed to invoke irq handler\n"); + +diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h +index bb1a98c97adf..8639210a89c7 100644 +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -156,12 +156,55 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value) + up->dl_write(up, value); + } + ++static inline void serial8250_set_IER(struct uart_8250_port *up, ++ unsigned char ier) ++{ ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ bool is_console; ++ ++ is_console = uart_console(port); ++ ++ if (is_console) ++ console_atomic_lock(flags); ++ ++ serial_out(up, UART_IER, ier); ++ ++ if (is_console) ++ console_atomic_unlock(flags); ++} ++ ++static inline unsigned char serial8250_clear_IER(struct uart_8250_port *up) ++{ ++ struct uart_port *port = &up->port; ++ unsigned int clearval = 0; ++ unsigned long flags; ++ unsigned int prior; ++ bool is_console; ++ ++ is_console = uart_console(port); ++ ++ if (up->capabilities & UART_CAP_UUE) ++ clearval = UART_IER_UUE; ++ ++ if (is_console) ++ console_atomic_lock(flags); ++ ++ prior = serial_port_in(port, UART_IER); ++ serial_port_out(port, UART_IER, clearval); ++ ++ if (is_console) ++ console_atomic_unlock(flags); ++ ++ return prior; ++} ++ + static inline bool serial8250_set_THRI(struct uart_8250_port *up) + { + if (up->ier & UART_IER_THRI) + return false; + up->ier |= UART_IER_THRI; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + return true; + } + +@@ -170,7 +213,7 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up) + if (!(up->ier & UART_IER_THRI)) + return false; + up->ier &= ~UART_IER_THRI; +- serial_out(up, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + return true; + } + +diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c +index 1890f342f090..16d5d450b32f 100644 +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -265,10 +265,8 @@ static void serial8250_backup_timeout(struct timer_list *t) + * Must disable interrupts or else we risk racing with the interrupt + * based handler. + */ +- if (up->port.irq) { +- ier = serial_in(up, UART_IER); +- serial_out(up, UART_IER, 0); +- } ++ if (up->port.irq) ++ ier = serial8250_clear_IER(up); + + iir = serial_in(up, UART_IIR); + +@@ -291,7 +289,7 @@ static void serial8250_backup_timeout(struct timer_list *t) + serial8250_tx_chars(up); + + if (up->port.irq) +- serial_out(up, UART_IER, ier); ++ serial8250_set_IER(up, ier); + + spin_unlock_irqrestore(&up->port.lock, flags); + +@@ -578,6 +576,14 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) + + #ifdef CONFIG_SERIAL_8250_CONSOLE + ++static void univ8250_console_write_atomic(struct console *co, const char *s, ++ unsigned int count) ++{ ++ struct uart_8250_port *up = &serial8250_ports[co->index]; ++ ++ serial8250_console_write_atomic(up, s, count); ++} ++ + static void univ8250_console_write(struct console *co, const char *s, + unsigned int count) + { +@@ -671,6 +677,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, + + static struct console univ8250_console = { + .name = "ttyS", ++ .write_atomic = univ8250_console_write_atomic, + .write = univ8250_console_write, + .device = uart_console_device, + .setup = univ8250_console_setup, +diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c +index 6a22f3a970f3..a6c02140eff0 100644 +--- a/drivers/tty/serial/8250/8250_fsl.c ++++ b/drivers/tty/serial/8250/8250_fsl.c +@@ -60,9 +60,18 @@ int fsl8250_handle_irq(struct uart_port *port) + + /* Stop processing interrupts on input overrun */ + if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) { ++ unsigned long flags; + unsigned long delay; ++ bool is_console; + ++ is_console = uart_console(port); ++ ++ if (is_console) ++ console_atomic_lock(flags); + up->ier = port->serial_in(port, UART_IER); ++ if (is_console) ++ console_atomic_unlock(flags); ++ + if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { + port->ops->stop_rx(port); + } else { +diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c +index 65402d05eff9..8122645ab05c 100644 +--- a/drivers/tty/serial/8250/8250_ingenic.c ++++ b/drivers/tty/serial/8250/8250_ingenic.c +@@ -146,6 +146,8 @@ OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart", + + static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) + { ++ unsigned long flags; ++ bool is_console; + int ier; + + switch (offset) { +@@ -167,7 +169,12 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) + * If we have enabled modem status IRQs we should enable + * modem mode. + */ ++ is_console = uart_console(p); ++ if (is_console) ++ console_atomic_lock(flags); + ier = p->serial_in(p, UART_IER); ++ if (is_console) ++ console_atomic_unlock(flags); + + if (ier & UART_IER_MSI) + value |= UART_MCR_MDCE | UART_MCR_FCM; +diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c +index de48a58460f4..364ee950f21a 100644 +--- a/drivers/tty/serial/8250/8250_mtk.c ++++ b/drivers/tty/serial/8250/8250_mtk.c +@@ -222,12 +222,37 @@ static void mtk8250_shutdown(struct uart_port *port) + + static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) + { +- serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask)); ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ unsigned int ier; ++ bool is_console; ++ ++ is_console = uart_console(port); ++ ++ if (is_console) ++ console_atomic_lock(flags); ++ ++ ier = serial_in(up, UART_IER); ++ serial_out(up, UART_IER, ier & (~mask)); ++ ++ if (is_console) ++ console_atomic_unlock(flags); + } + + static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask) + { +- serial_out(up, UART_IER, serial_in(up, UART_IER) | mask); ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ unsigned int ier; ++ ++ if (uart_console(port)) ++ console_atomic_lock(flags); ++ ++ ier = serial_in(up, UART_IER); ++ serial_out(up, UART_IER, ier | mask); ++ ++ if (uart_console(port)) ++ console_atomic_unlock(flags); + } + + static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index bfdd9ecc2baf..479b94b3238a 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -752,7 +752,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); + } +- serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); ++ serial8250_set_IER(p, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, efr); +@@ -1427,7 +1427,7 @@ static void serial8250_stop_rx(struct uart_port *port) + + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + up->port.read_status_mask &= ~UART_LSR_DR; +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + + serial8250_rpm_put(up); + } +@@ -1457,7 +1457,7 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p) + serial8250_clear_and_reinit_fifos(p); + + p->ier |= UART_IER_RLSI | UART_IER_RDI; +- serial_port_out(&p->port, UART_IER, p->ier); ++ serial8250_set_IER(p, p->ier); + } + } + EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); +@@ -1693,7 +1693,7 @@ static void serial8250_disable_ms(struct uart_port *port) + mctrl_gpio_disable_ms(up->gpios); + + up->ier &= ~UART_IER_MSI; +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + } + + static void serial8250_enable_ms(struct uart_port *port) +@@ -1709,7 +1709,7 @@ static void serial8250_enable_ms(struct uart_port *port) + up->ier |= UART_IER_MSI; + + serial8250_rpm_get(up); +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + serial8250_rpm_put(up); + } + +@@ -2143,14 +2143,7 @@ static void serial8250_put_poll_char(struct uart_port *port, + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get(up); +- /* +- * First save the IER then disable the interrupts +- */ +- ier = serial_port_in(port, UART_IER); +- if (up->capabilities & UART_CAP_UUE) +- serial_port_out(port, UART_IER, UART_IER_UUE); +- else +- serial_port_out(port, UART_IER, 0); ++ ier = serial8250_clear_IER(up); + + wait_for_xmitr(up, BOTH_EMPTY); + /* +@@ -2163,7 +2156,7 @@ static void serial8250_put_poll_char(struct uart_port *port, + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); +- serial_port_out(port, UART_IER, ier); ++ serial8250_set_IER(up, ier); + serial8250_rpm_put(up); + } + +@@ -2468,7 +2461,7 @@ void serial8250_do_shutdown(struct uart_port *port) + */ + spin_lock_irqsave(&port->lock, flags); + up->ier = 0; +- serial_port_out(port, UART_IER, 0); ++ serial8250_set_IER(up, 0); + spin_unlock_irqrestore(&port->lock, flags); + + synchronize_irq(port->irq); +@@ -2850,7 +2843,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + if (up->capabilities & UART_CAP_RTOIE) + up->ier |= UART_IER_RTOIE; + +- serial_port_out(port, UART_IER, up->ier); ++ serial8250_set_IER(up, up->ier); + + if (up->capabilities & UART_CAP_EFR) { + unsigned char efr = 0; +@@ -3315,7 +3308,7 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults); + + #ifdef CONFIG_SERIAL_8250_CONSOLE + +-static void serial8250_console_putchar(struct uart_port *port, int ch) ++static void serial8250_console_putchar_locked(struct uart_port *port, int ch) + { + struct uart_8250_port *up = up_to_u8250p(port); + +@@ -3323,6 +3316,18 @@ static void serial8250_console_putchar(struct uart_port *port, int ch) + serial_port_out(port, UART_TX, ch); + } + ++static void serial8250_console_putchar(struct uart_port *port, int ch) ++{ ++ struct uart_8250_port *up = up_to_u8250p(port); ++ unsigned long flags; ++ ++ wait_for_xmitr(up, UART_LSR_THRE); ++ ++ console_atomic_lock(flags); ++ serial8250_console_putchar_locked(port, ch); ++ console_atomic_unlock(flags); ++} ++ + /* + * Restore serial console when h/w power-off detected + */ +@@ -3349,6 +3354,32 @@ static void serial8250_console_restore(struct uart_8250_port *up) + serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); + } + ++void serial8250_console_write_atomic(struct uart_8250_port *up, ++ const char *s, unsigned int count) ++{ ++ struct uart_port *port = &up->port; ++ unsigned long flags; ++ unsigned int ier; ++ ++ console_atomic_lock(flags); ++ ++ touch_nmi_watchdog(); ++ ++ ier = serial8250_clear_IER(up); ++ ++ if (atomic_fetch_inc(&up->console_printing)) { ++ uart_console_write(port, "\n", 1, ++ serial8250_console_putchar_locked); ++ } ++ uart_console_write(port, s, count, serial8250_console_putchar_locked); ++ atomic_dec(&up->console_printing); ++ ++ wait_for_xmitr(up, BOTH_EMPTY); ++ serial8250_set_IER(up, ier); ++ ++ console_atomic_unlock(flags); ++} ++ + /* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... +@@ -3365,24 +3396,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int ier; +- int locked = 1; + + touch_nmi_watchdog(); + +- if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); +- else +- spin_lock_irqsave(&port->lock, flags); +- +- /* +- * First save the IER then disable the interrupts +- */ +- ier = serial_port_in(port, UART_IER); ++ spin_lock_irqsave(&port->lock, flags); + +- if (up->capabilities & UART_CAP_UUE) +- serial_port_out(port, UART_IER, UART_IER_UUE); +- else +- serial_port_out(port, UART_IER, 0); ++ ier = serial8250_clear_IER(up); + + /* check scratch reg to see if port powered off during system sleep */ + if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { +@@ -3396,7 +3415,9 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + mdelay(port->rs485.delay_rts_before_send); + } + ++ atomic_inc(&up->console_printing); + uart_console_write(port, s, count, serial8250_console_putchar); ++ atomic_dec(&up->console_printing); + + /* + * Finally, wait for transmitter to become empty +@@ -3409,8 +3430,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + if (em485->tx_stopped) + up->rs485_stop_tx(up); + } +- +- serial_port_out(port, UART_IER, ier); ++ serial8250_set_IER(up, ier); + + /* + * The receive handling will happen properly because the +@@ -3422,8 +3442,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + if (up->msr_saved_flags) + serial8250_modem_status(up); + +- if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ spin_unlock_irqrestore(&port->lock, flags); + } + + static unsigned int probe_baud(struct uart_port *port) +@@ -3443,6 +3462,7 @@ static unsigned int probe_baud(struct uart_port *port) + + int serial8250_console_setup(struct uart_port *port, char *options, bool probe) + { ++ struct uart_8250_port *up = up_to_u8250p(port); + int baud = 9600; + int bits = 8; + int parity = 'n'; +@@ -3452,6 +3472,8 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) + if (!port->iobase && !port->membase) + return -ENODEV; + ++ atomic_set(&up->console_printing, 0); ++ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else if (probe) +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index b91fe25a64a1..5986658e130b 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2340,18 +2340,24 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + { + struct uart_amba_port *uap = amba_ports[co->index]; + unsigned int old_cr = 0, new_cr; +- unsigned long flags; ++ unsigned long flags = 0; + int locked = 1; + + clk_enable(uap->clk); + +- local_irq_save(flags); ++ /* ++ * local_irq_save(flags); ++ * ++ * This local_irq_save() is nonsense. If we come in via sysrq ++ * handling then interrupts are already disabled. Aside of ++ * that the port.sysrq check is racy on SMP regardless. ++ */ + if (uap->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&uap->port.lock); ++ locked = spin_trylock_irqsave(&uap->port.lock, flags); + else +- spin_lock(&uap->port.lock); ++ spin_lock_irqsave(&uap->port.lock, flags); + + /* + * First save the CR then disable the interrupts +@@ -2377,8 +2383,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + pl011_write(old_cr, uap, REG_CR); + + if (locked) +- spin_unlock(&uap->port.lock); +- local_irq_restore(flags); ++ spin_unlock_irqrestore(&uap->port.lock, flags); + + clk_disable(uap->clk); + } +diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c +index 0862941862c8..10970632f0e4 100644 +--- a/drivers/tty/serial/omap-serial.c ++++ b/drivers/tty/serial/omap-serial.c +@@ -1255,13 +1255,10 @@ serial_omap_console_write(struct console *co, const char *s, + unsigned int ier; + int locked = 1; + +- local_irq_save(flags); +- if (up->port.sysrq) +- locked = 0; +- else if (oops_in_progress) +- locked = spin_trylock(&up->port.lock); ++ if (up->port.sysrq || oops_in_progress) ++ locked = spin_trylock_irqsave(&up->port.lock, flags); + else +- spin_lock(&up->port.lock); ++ spin_lock_irqsave(&up->port.lock, flags); + + /* + * First save the IER then disable the interrupts +@@ -1288,8 +1285,7 @@ serial_omap_console_write(struct console *co, const char *s, + check_modem_status(up); + + if (locked) +- spin_unlock(&up->port.lock); +- local_irq_restore(flags); ++ spin_unlock_irqrestore(&up->port.lock, flags); + } + + static int __init +diff --git a/drivers/virt/acrn/irqfd.c b/drivers/virt/acrn/irqfd.c +index df5184979b28..d4ad211dce7a 100644 +--- a/drivers/virt/acrn/irqfd.c ++++ b/drivers/virt/acrn/irqfd.c +@@ -17,7 +17,6 @@ + #include "acrn_drv.h" + + static LIST_HEAD(acrn_irqfd_clients); +-static DEFINE_MUTEX(acrn_irqfds_mutex); + + /** + * struct hsm_irqfd - Properties of HSM irqfd +diff --git a/fs/afs/dir_silly.c b/fs/afs/dir_silly.c +index 45cfd50a9521..502b56597f10 100644 +--- a/fs/afs/dir_silly.c ++++ b/fs/afs/dir_silly.c +@@ -239,7 +239,7 @@ int afs_silly_iput(struct dentry *dentry, struct inode *inode) + struct dentry *alias; + int ret; + +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + + _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode); + +diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c +index 1929e80c09ee..48eb8c30c6db 100644 +--- a/fs/cifs/readdir.c ++++ b/fs/cifs/readdir.c +@@ -69,7 +69,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, + struct inode *inode; + struct super_block *sb = parent->d_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + + cifs_dbg(FYI, "%s: for %s\n", __func__, name->name); + +diff --git a/fs/dcache.c b/fs/dcache.c +index cf871a81f4fd..02db80f2817f 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -2537,7 +2537,13 @@ EXPORT_SYMBOL(d_rehash); + + static inline unsigned start_dir_add(struct inode *dir) + { +- ++ /* ++ * The caller has a spinlock_t (dentry::d_lock) acquired which disables ++ * preemption on !PREEMPT_RT. On PREEMPT_RT the lock does not disable ++ * preemption and it has be done explicitly. ++ */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); + for (;;) { + unsigned n = dir->i_dir_seq; + if (!(n & 1) && cmpxchg(&dir->i_dir_seq, n, n + 1) == n) +@@ -2549,25 +2555,30 @@ static inline unsigned start_dir_add(struct inode *dir) + static inline void end_dir_add(struct inode *dir, unsigned n) + { + smp_store_release(&dir->i_dir_seq, n + 2); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); + } + + static void d_wait_lookup(struct dentry *dentry) + { +- if (d_in_lookup(dentry)) { +- DECLARE_WAITQUEUE(wait, current); +- add_wait_queue(dentry->d_wait, &wait); +- do { +- set_current_state(TASK_UNINTERRUPTIBLE); +- spin_unlock(&dentry->d_lock); +- schedule(); +- spin_lock(&dentry->d_lock); +- } while (d_in_lookup(dentry)); +- } ++ struct swait_queue __wait; ++ ++ if (!d_in_lookup(dentry)) ++ return; ++ ++ INIT_LIST_HEAD(&__wait.task_list); ++ do { ++ prepare_to_swait_exclusive(dentry->d_wait, &__wait, TASK_UNINTERRUPTIBLE); ++ spin_unlock(&dentry->d_lock); ++ schedule(); ++ spin_lock(&dentry->d_lock); ++ } while (d_in_lookup(dentry)); ++ finish_swait(dentry->d_wait, &__wait); + } + + struct dentry *d_alloc_parallel(struct dentry *parent, + const struct qstr *name, +- wait_queue_head_t *wq) ++ struct swait_queue_head *wq) + { + unsigned int hash = name->hash; + struct hlist_bl_head *b = in_lookup_hash(parent, hash); +@@ -2682,7 +2693,7 @@ void __d_lookup_done(struct dentry *dentry) + hlist_bl_lock(b); + dentry->d_flags &= ~DCACHE_PAR_LOOKUP; + __hlist_bl_del(&dentry->d_u.d_in_lookup_hash); +- wake_up_all(dentry->d_wait); ++ swake_up_all(dentry->d_wait); + dentry->d_wait = NULL; + hlist_bl_unlock(b); + INIT_HLIST_NODE(&dentry->d_u.d_alias); +diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h +index c3e4804b8fcb..9edb87e11680 100644 +--- a/fs/fscache/internal.h ++++ b/fs/fscache/internal.h +@@ -81,7 +81,6 @@ extern unsigned fscache_debug; + extern struct kobject *fscache_root; + extern struct workqueue_struct *fscache_object_wq; + extern struct workqueue_struct *fscache_op_wq; +-DECLARE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait); + + extern unsigned int fscache_hash(unsigned int salt, unsigned int *data, unsigned int n); + +diff --git a/fs/fscache/main.c b/fs/fscache/main.c +index 4207f98e405f..85f8cf3a323d 100644 +--- a/fs/fscache/main.c ++++ b/fs/fscache/main.c +@@ -41,8 +41,6 @@ struct kobject *fscache_root; + struct workqueue_struct *fscache_object_wq; + struct workqueue_struct *fscache_op_wq; + +-DEFINE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait); +- + /* these values serve as lower bounds, will be adjusted in fscache_init() */ + static unsigned fscache_object_max_active = 4; + static unsigned fscache_op_max_active = 2; +@@ -138,7 +136,6 @@ unsigned int fscache_hash(unsigned int salt, unsigned int *data, unsigned int n) + static int __init fscache_init(void) + { + unsigned int nr_cpus = num_possible_cpus(); +- unsigned int cpu; + int ret; + + fscache_object_max_active = +@@ -161,9 +158,6 @@ static int __init fscache_init(void) + if (!fscache_op_wq) + goto error_op_wq; + +- for_each_possible_cpu(cpu) +- init_waitqueue_head(&per_cpu(fscache_object_cong_wait, cpu)); +- + ret = fscache_proc_init(); + if (ret < 0) + goto error_proc; +diff --git a/fs/fscache/object.c b/fs/fscache/object.c +index 6a675652129b..7a972d144b54 100644 +--- a/fs/fscache/object.c ++++ b/fs/fscache/object.c +@@ -798,6 +798,8 @@ void fscache_object_destroy(struct fscache_object *object) + } + EXPORT_SYMBOL(fscache_object_destroy); + ++static DECLARE_WAIT_QUEUE_HEAD(fscache_object_cong_wait); ++ + /* + * enqueue an object for metadata-type processing + */ +@@ -806,16 +808,12 @@ void fscache_enqueue_object(struct fscache_object *object) + _enter("{OBJ%x}", object->debug_id); + + if (fscache_get_object(object, fscache_obj_get_queue) >= 0) { +- wait_queue_head_t *cong_wq = +- &get_cpu_var(fscache_object_cong_wait); + + if (queue_work(fscache_object_wq, &object->work)) { + if (fscache_object_congested()) +- wake_up(cong_wq); ++ wake_up(&fscache_object_cong_wait); + } else + fscache_put_object(object, fscache_obj_put_queue); +- +- put_cpu_var(fscache_object_cong_wait); + } + } + +@@ -833,16 +831,15 @@ void fscache_enqueue_object(struct fscache_object *object) + */ + bool fscache_object_sleep_till_congested(signed long *timeoutp) + { +- wait_queue_head_t *cong_wq = this_cpu_ptr(&fscache_object_cong_wait); + DEFINE_WAIT(wait); + + if (fscache_object_congested()) + return true; + +- add_wait_queue_exclusive(cong_wq, &wait); ++ add_wait_queue_exclusive(&fscache_object_cong_wait, &wait); + if (!fscache_object_congested()) + *timeoutp = schedule_timeout(*timeoutp); +- finish_wait(cong_wq, &wait); ++ finish_wait(&fscache_object_cong_wait, &wait); + + return fscache_object_congested(); + } +diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c +index d5294e663df5..ee8846818b34 100644 +--- a/fs/fuse/readdir.c ++++ b/fs/fuse/readdir.c +@@ -160,7 +160,7 @@ static int fuse_direntplus_link(struct file *file, + struct inode *dir = d_inode(parent); + struct fuse_conn *fc; + struct inode *inode; +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + + if (!o->nodeid) { + /* +diff --git a/fs/namei.c b/fs/namei.c +index 02e99606c65b..c1d11a2e7fa3 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -1635,7 +1635,7 @@ static struct dentry *__lookup_slow(const struct qstr *name, + { + struct dentry *dentry, *old; + struct inode *inode = dir->d_inode; +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + + /* Don't go there if it's already dead */ + if (unlikely(IS_DEADDIR(inode))) +@@ -3305,7 +3305,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, + struct dentry *dentry; + int error, create_error = 0; + umode_t mode = op->mode; +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + + if (unlikely(IS_DEADDIR(dir_inode))) + return ERR_PTR(-ENOENT); +diff --git a/fs/namespace.c b/fs/namespace.c +index 1a9df6afb90b..373b0e738997 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -344,8 +344,24 @@ int __mnt_want_write(struct vfsmount *m) + * incremented count after it has set MNT_WRITE_HOLD. + */ + smp_mb(); +- while (READ_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD) +- cpu_relax(); ++ might_lock(&mount_lock.lock); ++ while (READ_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD) { ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ cpu_relax(); ++ } else { ++ /* ++ * This prevents priority inversion, if the task ++ * setting MNT_WRITE_HOLD got preempted on a remote ++ * CPU, and it prevents life lock if the task setting ++ * MNT_WRITE_HOLD has a lower priority and is bound to ++ * the same CPU as the task that is spinning here. ++ */ ++ preempt_enable(); ++ lock_mount_hash(); ++ unlock_mount_hash(); ++ preempt_disable(); ++ } ++ } + /* + * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will + * be set to match its requirements. So we must not load that until +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index 32c3d0c454b1..b8ff452317e6 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -637,7 +637,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry, + unsigned long dir_verifier) + { + struct qstr filename = QSTR_INIT(entry->name, entry->len); +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + struct dentry *dentry; + struct dentry *alias; + struct inode *inode; +@@ -1873,7 +1873,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, + struct file *file, unsigned open_flags, + umode_t mode) + { +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + struct nfs_open_context *ctx; + struct dentry *res; + struct iattr attr = { .ia_valid = ATTR_OPEN }; +diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c +index d5ccf095b2a7..0944c068f5cb 100644 +--- a/fs/nfs/unlink.c ++++ b/fs/nfs/unlink.c +@@ -13,7 +13,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +@@ -184,7 +184,7 @@ nfs_async_unlink(struct dentry *dentry, const struct qstr *name) + + data->cred = get_current_cred(); + data->res.dir_attr = &data->dir_attr; +- init_waitqueue_head(&data->wq); ++ init_swait_queue_head(&data->wq); + + status = -EBUSY; + spin_lock(&dentry->d_lock); +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 300d53ee7040..6ab25d4d4037 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -96,6 +96,7 @@ + #include + #include + #include ++#include + #include + #include + #include "internal.h" +@@ -2071,7 +2072,7 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx, + + child = d_hash_and_lookup(dir, &qname); + if (!child) { +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + child = d_alloc_parallel(dir, &qname, &wq); + if (IS_ERR(child)) + goto end_instantiate; +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index 0b7a00ed6c49..a7828fce675a 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -679,7 +679,7 @@ static bool proc_sys_fill_cache(struct file *file, + + child = d_lookup(dir, &qname); + if (!child) { +- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + child = d_alloc_parallel(dir, &qname, &wq); + if (IS_ERR(child)) + return false; +diff --git a/include/asm-generic/softirq_stack.h b/include/asm-generic/softirq_stack.h +index eceeecf6a5bd..d3e2d81656e0 100644 +--- a/include/asm-generic/softirq_stack.h ++++ b/include/asm-generic/softirq_stack.h +@@ -2,7 +2,7 @@ + #ifndef __ASM_GENERIC_SOFTIRQ_STACK_H + #define __ASM_GENERIC_SOFTIRQ_STACK_H + +-#ifdef CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK ++#if defined(CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK) && !defined(CONFIG_PREEMPT_RT) + void do_softirq_own_stack(void); + #else + static inline void do_softirq_own_stack(void) +diff --git a/include/linux/console.h b/include/linux/console.h +index a97f277cfdfa..487a4266ab2c 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -16,6 +16,13 @@ + + #include + #include ++#include ++#include ++ ++struct latched_seq { ++ seqcount_latch_t latch; ++ u64 val[2]; ++}; + + struct vc_data; + struct console_font_op; +@@ -136,10 +143,12 @@ static inline int con_debug_leave(void) + #define CON_ANYTIME (16) /* Safe to call when cpu is offline */ + #define CON_BRL (32) /* Used for a braille device */ + #define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */ ++#define CON_HANDOVER (128) /* Device was previously a boot console. */ + + struct console { + char name[16]; + void (*write)(struct console *, const char *, unsigned); ++ void (*write_atomic)(struct console *co, const char *s, unsigned int count); + int (*read)(struct console *, char *, unsigned); + struct tty_driver *(*device)(struct console *, int *); + void (*unblank)(void); +@@ -149,6 +158,16 @@ struct console { + short flags; + short index; + int cflag; ++#ifdef CONFIG_PRINTK ++ char sync_buf[CONSOLE_LOG_MAX]; ++ struct latched_seq printk_seq; ++ struct latched_seq printk_sync_seq; ++#ifdef CONFIG_HAVE_NMI ++ struct latched_seq printk_sync_nmi_seq; ++#endif ++#endif /* CONFIG_PRINTK */ ++ ++ struct task_struct *thread; + uint ispeed; + uint ospeed; + void *data; +diff --git a/include/linux/dcache.h b/include/linux/dcache.h +index 9e23d33bb6f1..9f89d4887e35 100644 +--- a/include/linux/dcache.h ++++ b/include/linux/dcache.h +@@ -108,7 +108,7 @@ struct dentry { + + union { + struct list_head d_lru; /* LRU list */ +- wait_queue_head_t *d_wait; /* in-lookup ones only */ ++ struct swait_queue_head *d_wait; /* in-lookup ones only */ + }; + struct list_head d_child; /* child of parent list */ + struct list_head d_subdirs; /* our children */ +@@ -240,7 +240,7 @@ extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op + extern struct dentry * d_alloc(struct dentry *, const struct qstr *); + extern struct dentry * d_alloc_anon(struct super_block *); + extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *, +- wait_queue_head_t *); ++ struct swait_queue_head *); + extern struct dentry * d_splice_alias(struct inode *, struct dentry *); + extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *); + extern struct dentry * d_exact_alias(struct dentry *, struct inode *); +diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h +index 2e2b8d6140ed..71064a2c2caf 100644 +--- a/include/linux/entry-common.h ++++ b/include/linux/entry-common.h +@@ -57,9 +57,15 @@ + # define ARCH_EXIT_TO_USER_MODE_WORK (0) + #endif + ++#ifdef CONFIG_PREEMPT_LAZY ++# define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) ++#else ++# define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED) ++#endif ++ + #define EXIT_TO_USER_MODE_WORK \ + (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ +- _TIF_NEED_RESCHED | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ ++ _TIF_NEED_RESCHED_MASK | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ + ARCH_EXIT_TO_USER_MODE_WORK) + + /** +diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h +index ec2a47a81e42..8cd11a223260 100644 +--- a/include/linux/irq_work.h ++++ b/include/linux/irq_work.h +@@ -3,6 +3,7 @@ + #define _LINUX_IRQ_WORK_H + + #include ++#include + + /* + * An entry can be in one of four states: +@@ -16,11 +17,13 @@ + struct irq_work { + struct __call_single_node node; + void (*func)(struct irq_work *); ++ struct rcuwait irqwait; + }; + + #define __IRQ_WORK_INIT(_func, _flags) (struct irq_work){ \ + .node = { .u_flags = (_flags), }, \ + .func = (_func), \ ++ .irqwait = __RCUWAIT_INITIALIZER(irqwait), \ + } + + #define IRQ_WORK_INIT(_func) __IRQ_WORK_INIT(_func, 0) +@@ -46,6 +49,11 @@ static inline bool irq_work_is_busy(struct irq_work *work) + return atomic_read(&work->node.a_flags) & IRQ_WORK_BUSY; + } + ++static inline bool irq_work_is_hard(struct irq_work *work) ++{ ++ return atomic_read(&work->node.a_flags) & IRQ_WORK_HARD_IRQ; ++} ++ + bool irq_work_queue(struct irq_work *work); + bool irq_work_queue_on(struct irq_work *work, int cpu); + +diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h +index 59aea39785bf..d69b819b53e0 100644 +--- a/include/linux/irqdesc.h ++++ b/include/linux/irqdesc.h +@@ -160,6 +160,7 @@ static inline void generic_handle_irq_desc(struct irq_desc *desc) + + int handle_irq_desc(struct irq_desc *desc); + int generic_handle_irq(unsigned int irq); ++int generic_handle_irq_safe(unsigned int irq); + + #ifdef CONFIG_IRQ_DOMAIN + /* +diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h +index 747f40e0c326..5ec0fa71399e 100644 +--- a/include/linux/irqflags.h ++++ b/include/linux/irqflags.h +@@ -71,14 +71,6 @@ do { \ + do { \ + __this_cpu_dec(hardirq_context); \ + } while (0) +-# define lockdep_softirq_enter() \ +-do { \ +- current->softirq_context++; \ +-} while (0) +-# define lockdep_softirq_exit() \ +-do { \ +- current->softirq_context--; \ +-} while (0) + + # define lockdep_hrtimer_enter(__hrtimer) \ + ({ \ +@@ -140,6 +132,21 @@ do { \ + # define lockdep_irq_work_exit(__work) do { } while (0) + #endif + ++#if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PREEMPT_RT) ++# define lockdep_softirq_enter() \ ++do { \ ++ current->softirq_context++; \ ++} while (0) ++# define lockdep_softirq_exit() \ ++do { \ ++ current->softirq_context--; \ ++} while (0) ++ ++#else ++# define lockdep_softirq_enter() do { } while (0) ++# define lockdep_softirq_exit() do { } while (0) ++#endif ++ + #if defined(CONFIG_IRQSOFF_TRACER) || \ + defined(CONFIG_PREEMPT_TRACER) + extern void stop_critical_timings(void); +diff --git a/include/linux/kernel.h b/include/linux/kernel.h +index f56cd8879a59..49f1e924b6e6 100644 +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -111,8 +111,8 @@ static __always_inline void might_resched(void) + #endif /* CONFIG_PREEMPT_* */ + + #ifdef CONFIG_DEBUG_ATOMIC_SLEEP +-extern void ___might_sleep(const char *file, int line, int preempt_offset); +-extern void __might_sleep(const char *file, int line, int preempt_offset); ++extern void __might_resched(const char *file, int line, unsigned int offsets); ++extern void __might_sleep(const char *file, int line); + extern void __cant_sleep(const char *file, int line, int preempt_offset); + extern void __cant_migrate(const char *file, int line); + +@@ -129,7 +129,7 @@ extern void __cant_migrate(const char *file, int line); + * supposed to. + */ + # define might_sleep() \ +- do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0) ++ do { __might_sleep(__FILE__, __LINE__); might_resched(); } while (0) + /** + * cant_sleep - annotation for functions that cannot sleep + * +@@ -168,10 +168,9 @@ extern void __cant_migrate(const char *file, int line); + */ + # define non_block_end() WARN_ON(current->non_block_count-- == 0) + #else +- static inline void ___might_sleep(const char *file, int line, +- int preempt_offset) { } +- static inline void __might_sleep(const char *file, int line, +- int preempt_offset) { } ++ static inline void __might_resched(const char *file, int line, ++ unsigned int offsets) { } ++static inline void __might_sleep(const char *file, int line) { } + # define might_sleep() do { might_resched(); } while (0) + # define cant_sleep() do { } while (0) + # define cant_migrate() do { } while (0) +diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h +index 258cdde8d356..9bca0d98db5a 100644 +--- a/include/linux/kgdb.h ++++ b/include/linux/kgdb.h +@@ -212,6 +212,8 @@ extern void kgdb_call_nmi_hook(void *ignored); + */ + extern void kgdb_roundup_cpus(void); + ++extern void kgdb_roundup_cpu(unsigned int cpu); ++ + /** + * kgdb_arch_set_pc - Generic call back to the program counter + * @regs: Current &struct pt_regs. +@@ -365,5 +367,6 @@ extern void kgdb_free_init_mem(void); + #define dbg_late_init() + static inline void kgdb_panic(const char *msg) {} + static inline void kgdb_free_init_mem(void) { } ++static inline void kgdb_roundup_cpu(unsigned int cpu) {} + #endif /* ! CONFIG_KGDB */ + #endif /* _KGDB_H_ */ +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 7f8ee09c711f..e9672de22cf2 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -572,6 +573,9 @@ struct mm_struct { + bool tlb_flush_batched; + #endif + struct uprobes_state uprobes_state; ++#ifdef CONFIG_PREEMPT_RT ++ struct rcu_head delayed_drop; ++#endif + #ifdef CONFIG_HUGETLB_PAGE + atomic_long_t hugetlb_usage; + #endif +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index c0a4589ab706..0f9dadec3b46 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1941,7 +1941,6 @@ enum netdev_ml_priv_type { + * @sfp_bus: attached &struct sfp_bus structure. + * + * @qdisc_tx_busylock: lockdep class annotating Qdisc->busylock spinlock +- * @qdisc_running_key: lockdep class annotating Qdisc->running seqcount + * + * @proto_down: protocol port state information can be sent to the + * switch driver and used to set the phys state of the +@@ -2272,7 +2271,6 @@ struct net_device { + struct phy_device *phydev; + struct sfp_bus *sfp_bus; + struct lock_class_key *qdisc_tx_busylock; +- struct lock_class_key *qdisc_running_key; + bool proto_down; + unsigned wol_enabled:1; + unsigned threaded:1; +@@ -2382,13 +2380,11 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev, + #define netdev_lockdep_set_classes(dev) \ + { \ + static struct lock_class_key qdisc_tx_busylock_key; \ +- static struct lock_class_key qdisc_running_key; \ + static struct lock_class_key qdisc_xmit_lock_key; \ + static struct lock_class_key dev_addr_list_lock_key; \ + unsigned int i; \ + \ + (dev)->qdisc_tx_busylock = &qdisc_tx_busylock_key; \ +- (dev)->qdisc_running_key = &qdisc_running_key; \ + lockdep_set_class(&(dev)->addr_list_lock, \ + &dev_addr_list_lock_key); \ + for (i = 0; i < (dev)->num_tx_queues; i++) \ +diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h +index 7fcd56c6ded6..2ccb84f15aa3 100644 +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -1692,7 +1692,7 @@ struct nfs_unlinkdata { + struct nfs_removeargs args; + struct nfs_removeres res; + struct dentry *dentry; +- wait_queue_head_t wq; ++ struct swait_queue_head wq; + const struct cred *cred; + struct nfs_fattr dir_attr; + long timeout; +diff --git a/include/linux/preempt.h b/include/linux/preempt.h +index 4d244e295e85..3da73c968211 100644 +--- a/include/linux/preempt.h ++++ b/include/linux/preempt.h +@@ -122,9 +122,10 @@ + * The preempt_count offset after spin_lock() + */ + #if !defined(CONFIG_PREEMPT_RT) +-#define PREEMPT_LOCK_OFFSET PREEMPT_DISABLE_OFFSET ++#define PREEMPT_LOCK_OFFSET PREEMPT_DISABLE_OFFSET + #else +-#define PREEMPT_LOCK_OFFSET 0 ++/* Locks on RT do not disable preemption */ ++#define PREEMPT_LOCK_OFFSET 0 + #endif + + /* +@@ -174,6 +175,20 @@ extern void preempt_count_sub(int val); + #define preempt_count_inc() preempt_count_add(1) + #define preempt_count_dec() preempt_count_sub(1) + ++#ifdef CONFIG_PREEMPT_LAZY ++#define add_preempt_lazy_count(val) do { preempt_lazy_count() += (val); } while (0) ++#define sub_preempt_lazy_count(val) do { preempt_lazy_count() -= (val); } while (0) ++#define inc_preempt_lazy_count() add_preempt_lazy_count(1) ++#define dec_preempt_lazy_count() sub_preempt_lazy_count(1) ++#define preempt_lazy_count() (current_thread_info()->preempt_lazy_count) ++#else ++#define add_preempt_lazy_count(val) do { } while (0) ++#define sub_preempt_lazy_count(val) do { } while (0) ++#define inc_preempt_lazy_count() do { } while (0) ++#define dec_preempt_lazy_count() do { } while (0) ++#define preempt_lazy_count() (0) ++#endif ++ + #ifdef CONFIG_PREEMPT_COUNT + + #define preempt_disable() \ +@@ -182,13 +197,25 @@ do { \ + barrier(); \ + } while (0) + ++#define preempt_lazy_disable() \ ++do { \ ++ inc_preempt_lazy_count(); \ ++ barrier(); \ ++} while (0) ++ + #define sched_preempt_enable_no_resched() \ + do { \ + barrier(); \ + preempt_count_dec(); \ + } while (0) + +-#define preempt_enable_no_resched() sched_preempt_enable_no_resched() ++#ifndef CONFIG_PREEMPT_RT ++# define preempt_enable_no_resched() sched_preempt_enable_no_resched() ++# define preempt_check_resched_rt() barrier(); ++#else ++# define preempt_enable_no_resched() preempt_enable() ++# define preempt_check_resched_rt() preempt_check_resched() ++#endif + + #define preemptible() (preempt_count() == 0 && !irqs_disabled()) + +@@ -213,6 +240,18 @@ do { \ + __preempt_schedule(); \ + } while (0) + ++/* ++ * open code preempt_check_resched() because it is not exported to modules and ++ * used by local_unlock() or bpf_enable_instrumentation(). ++ */ ++#define preempt_lazy_enable() \ ++do { \ ++ dec_preempt_lazy_count(); \ ++ barrier(); \ ++ if (should_resched(0)) \ ++ __preempt_schedule(); \ ++} while (0) ++ + #else /* !CONFIG_PREEMPTION */ + #define preempt_enable() \ + do { \ +@@ -220,6 +259,12 @@ do { \ + preempt_count_dec(); \ + } while (0) + ++#define preempt_lazy_enable() \ ++do { \ ++ dec_preempt_lazy_count(); \ ++ barrier(); \ ++} while (0) ++ + #define preempt_enable_notrace() \ + do { \ + barrier(); \ +@@ -258,8 +303,12 @@ do { \ + #define preempt_disable_notrace() barrier() + #define preempt_enable_no_resched_notrace() barrier() + #define preempt_enable_notrace() barrier() ++#define preempt_check_resched_rt() barrier() + #define preemptible() 0 + ++#define preempt_lazy_disable() barrier() ++#define preempt_lazy_enable() barrier() ++ + #endif /* CONFIG_PREEMPT_COUNT */ + + #ifdef MODULE +@@ -278,7 +327,7 @@ do { \ + } while (0) + #define preempt_fold_need_resched() \ + do { \ +- if (tif_need_resched()) \ ++ if (tif_need_resched_now()) \ + set_preempt_need_resched(); \ + } while (0) + +@@ -394,8 +443,15 @@ extern void migrate_enable(void); + + #else + +-static inline void migrate_disable(void) { } +-static inline void migrate_enable(void) { } ++static inline void migrate_disable(void) ++{ ++ preempt_lazy_disable(); ++} ++ ++static inline void migrate_enable(void) ++{ ++ preempt_lazy_enable(); ++} + + #endif /* CONFIG_SMP */ + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 9497f6b98339..eddfc5de6ee7 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -47,6 +47,12 @@ static inline const char *printk_skip_headers(const char *buffer) + + #define CONSOLE_EXT_LOG_MAX 8192 + ++/* ++ * The maximum size of a record formatted for console printing ++ * (i.e. with the prefix prepended to every line). ++ */ ++#define CONSOLE_LOG_MAX 1024 ++ + /* printk's without a loglevel use this.. */ + #define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT + +@@ -155,6 +161,8 @@ int vprintk(const char *fmt, va_list args); + asmlinkage __printf(1, 2) __cold + int _printk(const char *fmt, ...); + ++bool pr_flush(int timeout_ms, bool reset_on_progress); ++ + /* + * Special printk facility for scheduler/timekeeping use only, _DO_NOT_USE_ ! + */ +@@ -224,6 +232,11 @@ static inline void printk_deferred_exit(void) + { + } + ++static inline bool pr_flush(int timeout_ms, bool reset_on_progress) ++{ ++ return true; ++} ++ + static inline int printk_ratelimit(void) + { + return 0; +@@ -284,17 +297,30 @@ static inline void printk_trigger_flush(void) + extern int __printk_cpu_trylock(void); + extern void __printk_wait_on_cpu_lock(void); + extern void __printk_cpu_unlock(void); ++extern bool kgdb_roundup_delay(unsigned int cpu); ++ ++#else ++ ++#define __printk_cpu_trylock() 1 ++#define __printk_wait_on_cpu_lock() ++#define __printk_cpu_unlock() ++ ++static inline bool kgdb_roundup_delay(unsigned int cpu) ++{ ++ return false; ++} ++#endif /* CONFIG_SMP */ + + /** +- * printk_cpu_lock_irqsave() - Acquire the printk cpu-reentrant spinning +- * lock and disable interrupts. ++ * raw_printk_cpu_lock_irqsave() - Acquire the printk cpu-reentrant spinning ++ * lock and disable interrupts. + * @flags: Stack-allocated storage for saving local interrupt state, +- * to be passed to printk_cpu_unlock_irqrestore(). ++ * to be passed to raw_printk_cpu_unlock_irqrestore(). + * + * If the lock is owned by another CPU, spin until it becomes available. + * Interrupts are restored while spinning. + */ +-#define printk_cpu_lock_irqsave(flags) \ ++#define raw_printk_cpu_lock_irqsave(flags) \ + for (;;) { \ + local_irq_save(flags); \ + if (__printk_cpu_trylock()) \ +@@ -304,22 +330,30 @@ extern void __printk_cpu_unlock(void); + } + + /** +- * printk_cpu_unlock_irqrestore() - Release the printk cpu-reentrant spinning +- * lock and restore interrupts. +- * @flags: Caller's saved interrupt state, from printk_cpu_lock_irqsave(). ++ * raw_printk_cpu_unlock_irqrestore() - Release the printk cpu-reentrant ++ * spinning lock and restore interrupts. ++ * @flags: Caller's saved interrupt state from raw_printk_cpu_lock_irqsave(). + */ +-#define printk_cpu_unlock_irqrestore(flags) \ ++#define raw_printk_cpu_unlock_irqrestore(flags) \ + do { \ + __printk_cpu_unlock(); \ + local_irq_restore(flags); \ +- } while (0) \ +- +-#else ++ } while (0) + +-#define printk_cpu_lock_irqsave(flags) ((void)flags) +-#define printk_cpu_unlock_irqrestore(flags) ((void)flags) ++/* ++ * Used to synchronize atomic consoles. ++ * ++ * The same as raw_printk_cpu_lock_irqsave() except that hardware interrupts ++ * are _not_ restored while spinning. ++ */ ++#define console_atomic_lock(flags) \ ++ do { \ ++ local_irq_save(flags); \ ++ while (!__printk_cpu_trylock()) \ ++ cpu_relax(); \ ++ } while (0) + +-#endif /* CONFIG_SMP */ ++#define console_atomic_unlock raw_printk_cpu_unlock_irqrestore + + extern int kptr_restrict; + +diff --git a/include/linux/ratelimit_types.h b/include/linux/ratelimit_types.h +index f0e535f199be..002266693e50 100644 +--- a/include/linux/ratelimit_types.h ++++ b/include/linux/ratelimit_types.h +@@ -4,7 +4,7 @@ + + #include + #include +-#include ++#include + + #define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) + #define DEFAULT_RATELIMIT_BURST 10 +diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h +index 13bddb841ceb..e33445348eb0 100644 +--- a/include/linux/rcupdate.h ++++ b/include/linux/rcupdate.h +@@ -94,6 +94,13 @@ void rcu_init_tasks_generic(void); + static inline void rcu_init_tasks_generic(void) { } + #endif + ++#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_TASKS_RCU_GENERIC) ++void rcu_tasks_initiate_self_tests(void); ++#else ++static inline void rcu_tasks_initiate_self_tests(void) {} ++#endif ++ ++ + #ifdef CONFIG_RCU_STALL_COMMON + void rcu_sysrq_start(void); + void rcu_sysrq_end(void); +diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h +index 9deedfeec2b1..7d049883a08a 100644 +--- a/include/linux/rtmutex.h ++++ b/include/linux/rtmutex.h +@@ -99,13 +99,22 @@ extern void __rt_mutex_init(struct rt_mutex *lock, const char *name, struct lock + + #ifdef CONFIG_DEBUG_LOCK_ALLOC + extern void rt_mutex_lock_nested(struct rt_mutex *lock, unsigned int subclass); ++extern void _rt_mutex_lock_nest_lock(struct rt_mutex *lock, struct lockdep_map *nest_lock); + #define rt_mutex_lock(lock) rt_mutex_lock_nested(lock, 0) ++#define rt_mutex_lock_nest_lock(lock, nest_lock) \ ++ do { \ ++ typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ ++ _rt_mutex_lock_nest_lock(lock, &(nest_lock)->dep_map); \ ++ } while (0) ++ + #else + extern void rt_mutex_lock(struct rt_mutex *lock); + #define rt_mutex_lock_nested(lock, subclass) rt_mutex_lock(lock) ++#define rt_mutex_lock_nest_lock(lock, nest_lock) rt_mutex_lock(lock) + #endif + + extern int rt_mutex_lock_interruptible(struct rt_mutex *lock); ++extern int rt_mutex_lock_killable(struct rt_mutex *lock); + extern int rt_mutex_trylock(struct rt_mutex *lock); + + extern void rt_mutex_unlock(struct rt_mutex *lock); +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 7c17742d359c..2cdeb099d3c9 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -118,12 +118,8 @@ struct task_group; + + #define task_is_running(task) (READ_ONCE((task)->__state) == TASK_RUNNING) + +-#define task_is_traced(task) ((READ_ONCE(task->__state) & __TASK_TRACED) != 0) +- + #define task_is_stopped(task) ((READ_ONCE(task->__state) & __TASK_STOPPED) != 0) + +-#define task_is_stopped_or_traced(task) ((READ_ONCE(task->__state) & (__TASK_STOPPED | __TASK_TRACED)) != 0) +- + /* + * Special states are those that do not use the normal wait-loop pattern. See + * the comment with set_special_state(). +@@ -1084,6 +1080,10 @@ struct task_struct { + /* Restored if set_restore_sigmask() was used: */ + sigset_t saved_sigmask; + struct sigpending pending; ++#ifdef CONFIG_PREEMPT_RT ++ /* TODO: move me into ->restart_block ? */ ++ struct kernel_siginfo forced_info; ++#endif + unsigned long sas_ss_sp; + size_t sas_ss_size; + unsigned int sas_ss_flags; +@@ -1738,6 +1738,16 @@ static __always_inline bool is_percpu_thread(void) + #endif + } + ++/* Is the current task guaranteed to stay on its current CPU? */ ++static inline bool is_migratable(void) ++{ ++#ifdef CONFIG_SMP ++ return preemptible() && !current->migration_disabled; ++#else ++ return false; ++#endif ++} ++ + /* Per-process atomic flags. */ + #define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */ + #define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */ +@@ -2013,6 +2023,118 @@ static inline int test_tsk_need_resched(struct task_struct *tsk) + return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED)); + } + ++#ifdef CONFIG_PREEMPT_LAZY ++static inline void set_tsk_need_resched_lazy(struct task_struct *tsk) ++{ ++ set_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY); ++} ++ ++static inline void clear_tsk_need_resched_lazy(struct task_struct *tsk) ++{ ++ clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY); ++} ++ ++static inline int test_tsk_need_resched_lazy(struct task_struct *tsk) ++{ ++ return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY)); ++} ++ ++static inline int need_resched_lazy(void) ++{ ++ return test_thread_flag(TIF_NEED_RESCHED_LAZY); ++} ++ ++static inline int need_resched_now(void) ++{ ++ return test_thread_flag(TIF_NEED_RESCHED); ++} ++ ++#else ++static inline void clear_tsk_need_resched_lazy(struct task_struct *tsk) { } ++static inline int need_resched_lazy(void) { return 0; } ++ ++static inline int need_resched_now(void) ++{ ++ return test_thread_flag(TIF_NEED_RESCHED); ++} ++ ++#endif ++ ++#ifdef CONFIG_PREEMPT_RT ++static inline bool task_match_saved_state(struct task_struct *p, long match_state) ++{ ++ return p->saved_state == match_state; ++} ++ ++static inline bool task_is_traced(struct task_struct *task) ++{ ++ bool traced = false; ++ ++ /* in case the task is sleeping on tasklist_lock */ ++ raw_spin_lock_irq(&task->pi_lock); ++ if (READ_ONCE(task->__state) & __TASK_TRACED) ++ traced = true; ++ else if (task->saved_state & __TASK_TRACED) ++ traced = true; ++ raw_spin_unlock_irq(&task->pi_lock); ++ return traced; ++} ++ ++static inline bool task_is_stopped_or_traced(struct task_struct *task) ++{ ++ bool traced_stopped = false; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&task->pi_lock, flags); ++ ++ if (READ_ONCE(task->__state) & (__TASK_STOPPED | __TASK_TRACED)) ++ traced_stopped = true; ++ else if (task->saved_state & (__TASK_STOPPED | __TASK_TRACED)) ++ traced_stopped = true; ++ ++ raw_spin_unlock_irqrestore(&task->pi_lock, flags); ++ return traced_stopped; ++} ++ ++#else ++ ++static inline bool task_match_saved_state(struct task_struct *p, long match_state) ++{ ++ return false; ++} ++ ++static inline bool task_is_traced(struct task_struct *task) ++{ ++ return READ_ONCE(task->__state) & __TASK_TRACED; ++} ++ ++static inline bool task_is_stopped_or_traced(struct task_struct *task) ++{ ++ return READ_ONCE(task->__state) & (__TASK_STOPPED | __TASK_TRACED); ++} ++#endif ++ ++static inline bool task_match_state_or_saved(struct task_struct *p, ++ long match_state) ++{ ++ if (READ_ONCE(p->__state) == match_state) ++ return true; ++ ++ return task_match_saved_state(p, match_state); ++} ++ ++static inline bool task_match_state_lock(struct task_struct *p, ++ long match_state) ++{ ++ bool match; ++ ++ raw_spin_lock_irq(&p->pi_lock); ++ match = task_match_state_or_saved(p, match_state); ++ raw_spin_unlock_irq(&p->pi_lock); ++ ++ return match; ++} ++ + /* + * cond_resched() and cond_resched_lock(): latency reduction via + * explicit rescheduling in places that are safe. The return +@@ -2047,7 +2169,7 @@ static inline int _cond_resched(void) { return 0; } + #endif /* !defined(CONFIG_PREEMPTION) || defined(CONFIG_PREEMPT_DYNAMIC) */ + + #define cond_resched() ({ \ +- ___might_sleep(__FILE__, __LINE__, 0); \ ++ __might_resched(__FILE__, __LINE__, 0); \ + _cond_resched(); \ + }) + +@@ -2055,19 +2177,38 @@ extern int __cond_resched_lock(spinlock_t *lock); + extern int __cond_resched_rwlock_read(rwlock_t *lock); + extern int __cond_resched_rwlock_write(rwlock_t *lock); + +-#define cond_resched_lock(lock) ({ \ +- ___might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET);\ +- __cond_resched_lock(lock); \ ++#define MIGHT_RESCHED_RCU_SHIFT 8 ++#define MIGHT_RESCHED_PREEMPT_MASK ((1U << MIGHT_RESCHED_RCU_SHIFT) - 1) ++ ++#ifndef CONFIG_PREEMPT_RT ++/* ++ * Non RT kernels have an elevated preempt count due to the held lock, ++ * but are not allowed to be inside a RCU read side critical section ++ */ ++# define PREEMPT_LOCK_RESCHED_OFFSETS PREEMPT_LOCK_OFFSET ++#else ++/* ++ * spin/rw_lock() on RT implies rcu_read_lock(). The might_sleep() check in ++ * cond_resched*lock() has to take that into account because it checks for ++ * preempt_count() and rcu_preempt_depth(). ++ */ ++# define PREEMPT_LOCK_RESCHED_OFFSETS \ ++ (PREEMPT_LOCK_OFFSET + (1U << MIGHT_RESCHED_RCU_SHIFT)) ++#endif ++ ++#define cond_resched_lock(lock) ({ \ ++ __might_resched(__FILE__, __LINE__, PREEMPT_LOCK_RESCHED_OFFSETS); \ ++ __cond_resched_lock(lock); \ + }) + +-#define cond_resched_rwlock_read(lock) ({ \ +- __might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET); \ +- __cond_resched_rwlock_read(lock); \ ++#define cond_resched_rwlock_read(lock) ({ \ ++ __might_resched(__FILE__, __LINE__, PREEMPT_LOCK_RESCHED_OFFSETS); \ ++ __cond_resched_rwlock_read(lock); \ + }) + +-#define cond_resched_rwlock_write(lock) ({ \ +- __might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET); \ +- __cond_resched_rwlock_write(lock); \ ++#define cond_resched_rwlock_write(lock) ({ \ ++ __might_resched(__FILE__, __LINE__, PREEMPT_LOCK_RESCHED_OFFSETS); \ ++ __cond_resched_rwlock_write(lock); \ + }) + + static inline void cond_resched_rcu(void) +diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h +index 95fb7aaaec8d..28e9cc60f47e 100644 +--- a/include/linux/sched/mm.h ++++ b/include/linux/sched/mm.h +@@ -49,6 +49,26 @@ static inline void mmdrop(struct mm_struct *mm) + __mmdrop(mm); + } + ++#ifdef CONFIG_PREEMPT_RT ++extern void __mmdrop_delayed(struct rcu_head *rhp); ++ ++/* ++ * Invoked from finish_task_switch(). Delegates the heavy lifting on RT ++ * kernels via RCU. ++ */ ++static inline void mmdrop_sched(struct mm_struct *mm) ++{ ++ /* Provides a full memory barrier. See mmdrop() */ ++ if (atomic_dec_and_test(&mm->mm_count)) ++ call_rcu(&mm->delayed_drop, __mmdrop_delayed); ++} ++#else ++static inline void mmdrop_sched(struct mm_struct *mm) ++{ ++ mmdrop(mm); ++} ++#endif ++ + /** + * mmget() - Pin the address space associated with a &struct mm_struct. + * @mm: The address space to pin. +diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h +index 68abc6bdd891..dfe81e08e143 100644 +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -7,6 +7,7 @@ + #ifndef _LINUX_SERIAL_8250_H + #define _LINUX_SERIAL_8250_H + ++#include + #include + #include + #include +@@ -126,6 +127,8 @@ struct uart_8250_port { + #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA + unsigned char msr_saved_flags; + ++ atomic_t console_printing; ++ + struct uart_8250_dma *dma; + const struct uart_8250_ops *ops; + +@@ -181,6 +184,8 @@ void serial8250_init_port(struct uart_8250_port *up); + void serial8250_set_defaults(struct uart_8250_port *up); + void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count); ++void serial8250_console_write_atomic(struct uart_8250_port *up, const char *s, ++ unsigned int count); + int serial8250_console_setup(struct uart_port *port, char *options, bool probe); + int serial8250_console_exit(struct uart_port *port); + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 7ed1d4472c0c..6ac2df270a97 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -301,6 +301,7 @@ struct sk_buff_head { + + __u32 qlen; + spinlock_t lock; ++ raw_spinlock_t raw_lock; + }; + + struct sk_buff; +@@ -1993,6 +1994,12 @@ static inline void skb_queue_head_init(struct sk_buff_head *list) + __skb_queue_head_init(list); + } + ++static inline void skb_queue_head_init_raw(struct sk_buff_head *list) ++{ ++ raw_spin_lock_init(&list->raw_lock); ++ __skb_queue_head_init(list); ++} ++ + static inline void skb_queue_head_init_class(struct sk_buff_head *list, + struct lock_class_key *class) + { +diff --git a/include/linux/smp.h b/include/linux/smp.h +index 510519e8a1eb..7ac9fdb5ad09 100644 +--- a/include/linux/smp.h ++++ b/include/linux/smp.h +@@ -268,6 +268,9 @@ static inline int get_boot_cpu_id(void) + #define get_cpu() ({ preempt_disable(); __smp_processor_id(); }) + #define put_cpu() preempt_enable() + ++#define get_cpu_light() ({ migrate_disable(); __smp_processor_id(); }) ++#define put_cpu_light() migrate_enable() ++ + /* + * Callback to arch code if there's nosmp or maxcpus=0 on the + * boot command line: +diff --git a/include/linux/spinlock_types_up.h b/include/linux/spinlock_types_up.h +index c09b6407ae1b..7f86a2016ac5 100644 +--- a/include/linux/spinlock_types_up.h ++++ b/include/linux/spinlock_types_up.h +@@ -1,7 +1,7 @@ + #ifndef __LINUX_SPINLOCK_TYPES_UP_H + #define __LINUX_SPINLOCK_TYPES_UP_H + +-#ifndef __LINUX_SPINLOCK_TYPES_H ++#ifndef __LINUX_SPINLOCK_TYPES_RAW_H + # error "please don't include this file directly" + #endif + +diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h +index 9a073535c0bd..0536fbba7f69 100644 +--- a/include/linux/thread_info.h ++++ b/include/linux/thread_info.h +@@ -177,7 +177,17 @@ static __always_inline unsigned long read_ti_thread_flags(struct thread_info *ti + clear_ti_thread_flag(task_thread_info(t), TIF_##fl) + #endif /* !CONFIG_GENERIC_ENTRY */ + +-#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) ++#ifdef CONFIG_PREEMPT_LAZY ++#define tif_need_resched() (test_thread_flag(TIF_NEED_RESCHED) || \ ++ test_thread_flag(TIF_NEED_RESCHED_LAZY)) ++#define tif_need_resched_now() (test_thread_flag(TIF_NEED_RESCHED)) ++#define tif_need_resched_lazy() test_thread_flag(TIF_NEED_RESCHED_LAZY) ++ ++#else ++#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) ++#define tif_need_resched_now() test_thread_flag(TIF_NEED_RESCHED) ++#define tif_need_resched_lazy() 0 ++#endif + + #ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES + static inline int arch_within_stack_frames(const void * const stack, +diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h +index ff137179e0c3..54fe3b1a638d 100644 +--- a/include/linux/trace_events.h ++++ b/include/linux/trace_events.h +@@ -69,6 +69,7 @@ struct trace_entry { + unsigned char flags; + unsigned char preempt_count; + int pid; ++ unsigned char preempt_lazy_count; + }; + + #define TRACE_EVENT_TYPE_MAX \ +@@ -158,9 +159,10 @@ static inline void tracing_generic_entry_update(struct trace_entry *entry, + unsigned int trace_ctx) + { + entry->preempt_count = trace_ctx & 0xff; ++ entry->preempt_lazy_count = (trace_ctx >> 16) & 0xff; + entry->pid = current->pid; + entry->type = type; +- entry->flags = trace_ctx >> 16; ++ entry->flags = trace_ctx >> 24; + } + + unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status); +@@ -173,6 +175,7 @@ enum trace_flag_type { + TRACE_FLAG_SOFTIRQ = 0x10, + TRACE_FLAG_PREEMPT_RESCHED = 0x20, + TRACE_FLAG_NMI = 0x40, ++ TRACE_FLAG_NEED_RESCHED_LAZY = 0x80, + }; + + #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT +diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h +index e81856c0ba13..81dc1f5e181a 100644 +--- a/include/linux/u64_stats_sync.h ++++ b/include/linux/u64_stats_sync.h +@@ -66,7 +66,7 @@ + #include + + struct u64_stats_sync { +-#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++#if BITS_PER_LONG==32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) + seqcount_t seq; + #endif + }; +@@ -83,6 +83,11 @@ static inline u64 u64_stats_read(const u64_stats_t *p) + return local64_read(&p->v); + } + ++static inline void u64_stats_set(u64_stats_t *p, u64 val) ++{ ++ local64_set(&p->v, val); ++} ++ + static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + { + local64_add(val, &p->v); +@@ -104,6 +109,11 @@ static inline u64 u64_stats_read(const u64_stats_t *p) + return p->v; + } + ++static inline void u64_stats_set(u64_stats_t *p, u64 val) ++{ ++ p->v = val; ++} ++ + static inline void u64_stats_add(u64_stats_t *p, unsigned long val) + { + p->v += val; +@@ -115,7 +125,7 @@ static inline void u64_stats_inc(u64_stats_t *p) + } + #endif + +-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) + #define u64_stats_init(syncp) seqcount_init(&(syncp)->seq) + #else + static inline void u64_stats_init(struct u64_stats_sync *syncp) +@@ -125,15 +135,19 @@ static inline void u64_stats_init(struct u64_stats_sync *syncp) + + static inline void u64_stats_update_begin(struct u64_stats_sync *syncp) + { +-#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); + write_seqcount_begin(&syncp->seq); + #endif + } + + static inline void u64_stats_update_end(struct u64_stats_sync *syncp) + { +-#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) + write_seqcount_end(&syncp->seq); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); + #endif + } + +@@ -142,8 +156,11 @@ u64_stats_update_begin_irqsave(struct u64_stats_sync *syncp) + { + unsigned long flags = 0; + +-#if BITS_PER_LONG==32 && defined(CONFIG_SMP) +- local_irq_save(flags); ++#if BITS_PER_LONG == 32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); ++ else ++ local_irq_save(flags); + write_seqcount_begin(&syncp->seq); + #endif + return flags; +@@ -153,15 +170,18 @@ static inline void + u64_stats_update_end_irqrestore(struct u64_stats_sync *syncp, + unsigned long flags) + { +-#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) + write_seqcount_end(&syncp->seq); +- local_irq_restore(flags); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); ++ else ++ local_irq_restore(flags); + #endif + } + + static inline unsigned int __u64_stats_fetch_begin(const struct u64_stats_sync *syncp) + { +-#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) + return read_seqcount_begin(&syncp->seq); + #else + return 0; +@@ -170,7 +190,7 @@ static inline unsigned int __u64_stats_fetch_begin(const struct u64_stats_sync * + + static inline unsigned int u64_stats_fetch_begin(const struct u64_stats_sync *syncp) + { +-#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (!defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_RT)) + preempt_disable(); + #endif + return __u64_stats_fetch_begin(syncp); +@@ -179,7 +199,7 @@ static inline unsigned int u64_stats_fetch_begin(const struct u64_stats_sync *sy + static inline bool __u64_stats_fetch_retry(const struct u64_stats_sync *syncp, + unsigned int start) + { +-#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)) + return read_seqcount_retry(&syncp->seq, start); + #else + return false; +@@ -189,7 +209,7 @@ static inline bool __u64_stats_fetch_retry(const struct u64_stats_sync *syncp, + static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp, + unsigned int start) + { +-#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && (!defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_RT)) + preempt_enable(); + #endif + return __u64_stats_fetch_retry(syncp, start); +@@ -203,7 +223,9 @@ static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp, + */ + static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp) + { +-#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && defined(CONFIG_PREEMPT_RT) ++ preempt_disable(); ++#elif BITS_PER_LONG == 32 && !defined(CONFIG_SMP) + local_irq_disable(); + #endif + return __u64_stats_fetch_begin(syncp); +@@ -212,7 +234,9 @@ static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync + static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp, + unsigned int start) + { +-#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) ++#if BITS_PER_LONG == 32 && defined(CONFIG_PREEMPT_RT) ++ preempt_enable(); ++#elif BITS_PER_LONG == 32 && !defined(CONFIG_SMP) + local_irq_enable(); + #endif + return __u64_stats_fetch_retry(syncp, start); +diff --git a/include/net/act_api.h b/include/net/act_api.h +index f19f7f4a463c..b5b624c7e488 100644 +--- a/include/net/act_api.h ++++ b/include/net/act_api.h +@@ -30,13 +30,13 @@ struct tc_action { + atomic_t tcfa_bindcnt; + int tcfa_action; + struct tcf_t tcfa_tm; +- struct gnet_stats_basic_packed tcfa_bstats; +- struct gnet_stats_basic_packed tcfa_bstats_hw; ++ struct gnet_stats_basic_sync tcfa_bstats; ++ struct gnet_stats_basic_sync tcfa_bstats_hw; + struct gnet_stats_queue tcfa_qstats; + struct net_rate_estimator __rcu *tcfa_rate_est; + spinlock_t tcfa_lock; +- struct gnet_stats_basic_cpu __percpu *cpu_bstats; +- struct gnet_stats_basic_cpu __percpu *cpu_bstats_hw; ++ struct gnet_stats_basic_sync __percpu *cpu_bstats; ++ struct gnet_stats_basic_sync __percpu *cpu_bstats_hw; + struct gnet_stats_queue __percpu *cpu_qstats; + struct tc_cookie __rcu *act_cookie; + struct tcf_chain __rcu *goto_chain; +@@ -206,7 +206,7 @@ static inline void tcf_action_update_bstats(struct tc_action *a, + struct sk_buff *skb) + { + if (likely(a->cpu_bstats)) { +- bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(a->cpu_bstats), skb); + return; + } + spin_lock(&a->tcfa_lock); +diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h +index 1424e02cef90..7aa2b8e1fb29 100644 +--- a/include/net/gen_stats.h ++++ b/include/net/gen_stats.h +@@ -7,14 +7,17 @@ + #include + #include + +-/* Note: this used to be in include/uapi/linux/gen_stats.h */ +-struct gnet_stats_basic_packed { +- __u64 bytes; +- __u64 packets; +-}; +- +-struct gnet_stats_basic_cpu { +- struct gnet_stats_basic_packed bstats; ++/* Throughput stats. ++ * Must be initialized beforehand with gnet_stats_basic_sync_init(). ++ * ++ * If no reads can ever occur parallel to writes (e.g. stack-allocated ++ * bstats), then the internal stat values can be written to and read ++ * from directly. Otherwise, use _bstats_set/update() for writes and ++ * gnet_stats_add_basic() for reads. ++ */ ++struct gnet_stats_basic_sync { ++ u64_stats_t bytes; ++ u64_stats_t packets; + struct u64_stats_sync syncp; + } __aligned(2 * sizeof(u64)); + +@@ -34,6 +37,7 @@ struct gnet_dump { + struct tc_stats tc_stats; + }; + ++void gnet_stats_basic_sync_init(struct gnet_stats_basic_sync *b); + int gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock, + struct gnet_dump *d, int padattr); + +@@ -42,41 +46,38 @@ int gnet_stats_start_copy_compat(struct sk_buff *skb, int type, + spinlock_t *lock, struct gnet_dump *d, + int padattr); + +-int gnet_stats_copy_basic(const seqcount_t *running, +- struct gnet_dump *d, +- struct gnet_stats_basic_cpu __percpu *cpu, +- struct gnet_stats_basic_packed *b); +-void __gnet_stats_copy_basic(const seqcount_t *running, +- struct gnet_stats_basic_packed *bstats, +- struct gnet_stats_basic_cpu __percpu *cpu, +- struct gnet_stats_basic_packed *b); +-int gnet_stats_copy_basic_hw(const seqcount_t *running, +- struct gnet_dump *d, +- struct gnet_stats_basic_cpu __percpu *cpu, +- struct gnet_stats_basic_packed *b); ++int gnet_stats_copy_basic(struct gnet_dump *d, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, bool running); ++void gnet_stats_add_basic(struct gnet_stats_basic_sync *bstats, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, bool running); ++int gnet_stats_copy_basic_hw(struct gnet_dump *d, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, bool running); + int gnet_stats_copy_rate_est(struct gnet_dump *d, + struct net_rate_estimator __rcu **ptr); + int gnet_stats_copy_queue(struct gnet_dump *d, + struct gnet_stats_queue __percpu *cpu_q, + struct gnet_stats_queue *q, __u32 qlen); +-void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats, +- const struct gnet_stats_queue __percpu *cpu_q, +- const struct gnet_stats_queue *q, __u32 qlen); ++void gnet_stats_add_queue(struct gnet_stats_queue *qstats, ++ const struct gnet_stats_queue __percpu *cpu_q, ++ const struct gnet_stats_queue *q); + int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len); + + int gnet_stats_finish_copy(struct gnet_dump *d); + +-int gen_new_estimator(struct gnet_stats_basic_packed *bstats, +- struct gnet_stats_basic_cpu __percpu *cpu_bstats, ++int gen_new_estimator(struct gnet_stats_basic_sync *bstats, ++ struct gnet_stats_basic_sync __percpu *cpu_bstats, + struct net_rate_estimator __rcu **rate_est, + spinlock_t *lock, +- seqcount_t *running, struct nlattr *opt); ++ bool running, struct nlattr *opt); + void gen_kill_estimator(struct net_rate_estimator __rcu **ptr); +-int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, +- struct gnet_stats_basic_cpu __percpu *cpu_bstats, ++int gen_replace_estimator(struct gnet_stats_basic_sync *bstats, ++ struct gnet_stats_basic_sync __percpu *cpu_bstats, + struct net_rate_estimator __rcu **ptr, + spinlock_t *lock, +- seqcount_t *running, struct nlattr *opt); ++ bool running, struct nlattr *opt); + bool gen_estimator_active(struct net_rate_estimator __rcu **ptr); + bool gen_estimator_read(struct net_rate_estimator __rcu **ptr, + struct gnet_stats_rate_est64 *sample); +diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h +index 832ab69efda5..4c3809e141f4 100644 +--- a/include/net/netfilter/xt_rateest.h ++++ b/include/net/netfilter/xt_rateest.h +@@ -6,7 +6,7 @@ + + struct xt_rateest { + /* keep lock and bstats on same cache line to speedup xt_rateest_tg() */ +- struct gnet_stats_basic_packed bstats; ++ struct gnet_stats_basic_sync bstats; + spinlock_t lock; + + +diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h +index 83a6d0792180..4a5833108083 100644 +--- a/include/net/pkt_cls.h ++++ b/include/net/pkt_cls.h +@@ -765,7 +765,7 @@ struct tc_cookie { + }; + + struct tc_qopt_offload_stats { +- struct gnet_stats_basic_packed *bstats; ++ struct gnet_stats_basic_sync *bstats; + struct gnet_stats_queue *qstats; + }; + +@@ -885,7 +885,7 @@ struct tc_gred_qopt_offload_params { + }; + + struct tc_gred_qopt_offload_stats { +- struct gnet_stats_basic_packed bstats[MAX_DPs]; ++ struct gnet_stats_basic_sync bstats[MAX_DPs]; + struct gnet_stats_queue qstats[MAX_DPs]; + struct red_stats *xstats[MAX_DPs]; + }; +diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h +index 6906da5c733e..e9fe7a613eba 100644 +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -40,6 +40,13 @@ enum qdisc_state_t { + __QDISC_STATE_DRAINING, + }; + ++enum qdisc_state2_t { ++ /* Only for !TCQ_F_NOLOCK qdisc. Never access it directly. ++ * Use qdisc_run_begin/end() or qdisc_is_running() instead. ++ */ ++ __QDISC_STATE2_RUNNING, ++}; ++ + #define QDISC_STATE_MISSED BIT(__QDISC_STATE_MISSED) + #define QDISC_STATE_DRAINING BIT(__QDISC_STATE_DRAINING) + +@@ -97,7 +104,7 @@ struct Qdisc { + struct netdev_queue *dev_queue; + + struct net_rate_estimator __rcu *rate_est; +- struct gnet_stats_basic_cpu __percpu *cpu_bstats; ++ struct gnet_stats_basic_sync __percpu *cpu_bstats; + struct gnet_stats_queue __percpu *cpu_qstats; + int pad; + refcount_t refcnt; +@@ -107,10 +114,10 @@ struct Qdisc { + */ + struct sk_buff_head gso_skb ____cacheline_aligned_in_smp; + struct qdisc_skb_head q; +- struct gnet_stats_basic_packed bstats; +- seqcount_t running; ++ struct gnet_stats_basic_sync bstats; + struct gnet_stats_queue qstats; + unsigned long state; ++ unsigned long state2; /* must be written under qdisc spinlock */ + struct Qdisc *next_sched; + struct sk_buff_head skb_bad_txq; + +@@ -143,11 +150,15 @@ static inline struct Qdisc *qdisc_refcount_inc_nz(struct Qdisc *qdisc) + return NULL; + } + ++/* For !TCQ_F_NOLOCK qdisc: callers must either call this within a qdisc ++ * root_lock section, or provide their own memory barriers -- ordering ++ * against qdisc_run_begin/end() atomic bit operations. ++ */ + static inline bool qdisc_is_running(struct Qdisc *qdisc) + { + if (qdisc->flags & TCQ_F_NOLOCK) + return spin_is_locked(&qdisc->seqlock); +- return (raw_read_seqcount(&qdisc->running) & 1) ? true : false; ++ return test_bit(__QDISC_STATE2_RUNNING, &qdisc->state2); + } + + static inline bool nolock_qdisc_is_empty(const struct Qdisc *qdisc) +@@ -167,6 +178,9 @@ static inline bool qdisc_is_empty(const struct Qdisc *qdisc) + return !READ_ONCE(qdisc->q.qlen); + } + ++/* For !TCQ_F_NOLOCK qdisc, qdisc_run_begin/end() must be invoked with ++ * the qdisc root lock acquired. ++ */ + static inline bool qdisc_run_begin(struct Qdisc *qdisc) + { + if (qdisc->flags & TCQ_F_NOLOCK) { +@@ -186,15 +200,8 @@ static inline bool qdisc_run_begin(struct Qdisc *qdisc) + * when testing it in qdisc_run_end() + */ + return spin_trylock(&qdisc->seqlock); +- } else if (qdisc_is_running(qdisc)) { +- return false; + } +- /* Variant of write_seqcount_begin() telling lockdep a trylock +- * was attempted. +- */ +- raw_write_seqcount_begin(&qdisc->running); +- seqcount_acquire(&qdisc->running.dep_map, 0, 1, _RET_IP_); +- return true; ++ return !__test_and_set_bit(__QDISC_STATE2_RUNNING, &qdisc->state2); + } + + static inline void qdisc_run_end(struct Qdisc *qdisc) +@@ -212,7 +219,7 @@ static inline void qdisc_run_end(struct Qdisc *qdisc) + &qdisc->state))) + __netif_schedule(qdisc); + } else { +- write_seqcount_end(&qdisc->running); ++ __clear_bit(__QDISC_STATE2_RUNNING, &qdisc->state2); + } + } + +@@ -576,14 +583,6 @@ static inline spinlock_t *qdisc_root_sleeping_lock(const struct Qdisc *qdisc) + return qdisc_lock(root); + } + +-static inline seqcount_t *qdisc_root_sleeping_running(const struct Qdisc *qdisc) +-{ +- struct Qdisc *root = qdisc_root_sleeping(qdisc); +- +- ASSERT_RTNL(); +- return &root->running; +-} +- + static inline struct net_device *qdisc_dev(const struct Qdisc *qdisc) + { + return qdisc->dev_queue->dev; +@@ -833,14 +832,16 @@ static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return sch->enqueue(skb, sch, to_free); + } + +-static inline void _bstats_update(struct gnet_stats_basic_packed *bstats, ++static inline void _bstats_update(struct gnet_stats_basic_sync *bstats, + __u64 bytes, __u32 packets) + { +- bstats->bytes += bytes; +- bstats->packets += packets; ++ u64_stats_update_begin(&bstats->syncp); ++ u64_stats_add(&bstats->bytes, bytes); ++ u64_stats_add(&bstats->packets, packets); ++ u64_stats_update_end(&bstats->syncp); + } + +-static inline void bstats_update(struct gnet_stats_basic_packed *bstats, ++static inline void bstats_update(struct gnet_stats_basic_sync *bstats, + const struct sk_buff *skb) + { + _bstats_update(bstats, +@@ -848,26 +849,10 @@ static inline void bstats_update(struct gnet_stats_basic_packed *bstats, + skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1); + } + +-static inline void _bstats_cpu_update(struct gnet_stats_basic_cpu *bstats, +- __u64 bytes, __u32 packets) +-{ +- u64_stats_update_begin(&bstats->syncp); +- _bstats_update(&bstats->bstats, bytes, packets); +- u64_stats_update_end(&bstats->syncp); +-} +- +-static inline void bstats_cpu_update(struct gnet_stats_basic_cpu *bstats, +- const struct sk_buff *skb) +-{ +- u64_stats_update_begin(&bstats->syncp); +- bstats_update(&bstats->bstats, skb); +- u64_stats_update_end(&bstats->syncp); +-} +- + static inline void qdisc_bstats_cpu_update(struct Qdisc *sch, + const struct sk_buff *skb) + { +- bstats_cpu_update(this_cpu_ptr(sch->cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(sch->cpu_bstats), skb); + } + + static inline void qdisc_bstats_update(struct Qdisc *sch, +@@ -956,10 +941,9 @@ static inline void qdisc_qstats_qlen_backlog(struct Qdisc *sch, __u32 *qlen, + __u32 *backlog) + { + struct gnet_stats_queue qstats = { 0 }; +- __u32 len = qdisc_qlen_sum(sch); + +- __gnet_stats_copy_queue(&qstats, sch->cpu_qstats, &sch->qstats, len); +- *qlen = qstats.qlen; ++ gnet_stats_add_queue(&qstats, sch->cpu_qstats, &sch->qstats); ++ *qlen = qstats.qlen + qdisc_qlen(sch); + *backlog = qstats.backlog; + } + +@@ -1304,7 +1288,7 @@ void psched_ppscfg_precompute(struct psched_pktrate *r, u64 pktrate64); + struct mini_Qdisc { + struct tcf_proto *filter_list; + struct tcf_block *block; +- struct gnet_stats_basic_cpu __percpu *cpu_bstats; ++ struct gnet_stats_basic_sync __percpu *cpu_bstats; + struct gnet_stats_queue __percpu *cpu_qstats; + struct rcu_head rcu; + }; +@@ -1312,7 +1296,7 @@ struct mini_Qdisc { + static inline void mini_qdisc_bstats_cpu_update(struct mini_Qdisc *miniq, + const struct sk_buff *skb) + { +- bstats_cpu_update(this_cpu_ptr(miniq->cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(miniq->cpu_bstats), skb); + } + + static inline void mini_qdisc_qstats_cpu_drop(struct mini_Qdisc *miniq) +diff --git a/init/Kconfig b/init/Kconfig +index dafc3ba6fa7a..cd852df4e7d4 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -910,7 +910,7 @@ config NUMA_BALANCING + bool "Memory placement aware NUMA scheduler" + depends on ARCH_SUPPORTS_NUMA_BALANCING + depends on !ARCH_WANT_NUMA_VARIABLE_LOCALITY +- depends on SMP && NUMA && MIGRATION ++ depends on SMP && NUMA && MIGRATION && !PREEMPT_RT + help + This option adds support for automatic NUMA aware memory/task placement. + The mechanism is quite primitive and is based on migrating memory when +@@ -1905,6 +1905,7 @@ choice + + config SLAB + bool "SLAB" ++ depends on !PREEMPT_RT + select HAVE_HARDENED_USERCOPY_ALLOCATOR + help + The regular slab allocator that is established and known to work +@@ -1925,6 +1926,7 @@ config SLUB + config SLOB + depends on EXPERT + bool "SLOB (Simple Allocator)" ++ depends on !PREEMPT_RT + help + SLOB replaces the stock allocator with a drastically simpler + allocator. SLOB is generally more space efficient but +diff --git a/init/main.c b/init/main.c +index 649d9e4201a8..ee92d608ffc4 100644 +--- a/init/main.c ++++ b/init/main.c +@@ -1606,6 +1606,7 @@ static noinline void __init kernel_init_freeable(void) + + rcu_init_tasks_generic(); + do_pre_smp_initcalls(); ++ rcu_tasks_initiate_self_tests(); + lockup_detector_init(); + + smp_init(); +diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt +index 5876e30c5740..5df0776264c2 100644 +--- a/kernel/Kconfig.preempt ++++ b/kernel/Kconfig.preempt +@@ -1,5 +1,11 @@ + # SPDX-License-Identifier: GPL-2.0-only + ++config HAVE_PREEMPT_LAZY ++ bool ++ ++config PREEMPT_LAZY ++ def_bool y if HAVE_PREEMPT_LAZY && PREEMPT_RT ++ + choice + prompt "Preemption Model" + default PREEMPT_NONE +diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c +index 1486768f2318..bb3b805436c4 100644 +--- a/kernel/cgroup/rstat.c ++++ b/kernel/cgroup/rstat.c +@@ -156,8 +156,9 @@ static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep) + raw_spinlock_t *cpu_lock = per_cpu_ptr(&cgroup_rstat_cpu_lock, + cpu); + struct cgroup *pos = NULL; ++ unsigned long flags; + +- raw_spin_lock(cpu_lock); ++ raw_spin_lock_irqsave(cpu_lock, flags); + while ((pos = cgroup_rstat_cpu_pop_updated(pos, cgrp, cpu))) { + struct cgroup_subsys_state *css; + +@@ -169,7 +170,7 @@ static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep) + css->ss->css_rstat_flush(css, cpu); + rcu_read_unlock(); + } +- raw_spin_unlock(cpu_lock); ++ raw_spin_unlock_irqrestore(cpu_lock, flags); + + /* if @may_sleep, play nice and yield if necessary */ + if (may_sleep && (need_resched() || +diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c +index 7beceb447211..28497c00e63b 100644 +--- a/kernel/debug/debug_core.c ++++ b/kernel/debug/debug_core.c +@@ -239,35 +239,42 @@ NOKPROBE_SYMBOL(kgdb_call_nmi_hook); + static DEFINE_PER_CPU(call_single_data_t, kgdb_roundup_csd) = + CSD_INIT(kgdb_call_nmi_hook, NULL); + +-void __weak kgdb_roundup_cpus(void) ++void __weak kgdb_roundup_cpu(unsigned int cpu) + { + call_single_data_t *csd; ++ int ret; ++ ++ csd = &per_cpu(kgdb_roundup_csd, cpu); ++ ++ /* ++ * If it didn't round up last time, don't try again ++ * since smp_call_function_single_async() will block. ++ * ++ * If rounding_up is false then we know that the ++ * previous call must have at least started and that ++ * means smp_call_function_single_async() won't block. ++ */ ++ if (kgdb_info[cpu].rounding_up) ++ return; ++ kgdb_info[cpu].rounding_up = true; ++ ++ ret = smp_call_function_single_async(cpu, csd); ++ if (ret) ++ kgdb_info[cpu].rounding_up = false; ++} ++NOKPROBE_SYMBOL(kgdb_roundup_cpu); ++ ++void __weak kgdb_roundup_cpus(void) ++{ + int this_cpu = raw_smp_processor_id(); + int cpu; +- int ret; + + for_each_online_cpu(cpu) { + /* No need to roundup ourselves */ + if (cpu == this_cpu) + continue; + +- csd = &per_cpu(kgdb_roundup_csd, cpu); +- +- /* +- * If it didn't round up last time, don't try again +- * since smp_call_function_single_async() will block. +- * +- * If rounding_up is false then we know that the +- * previous call must have at least started and that +- * means smp_call_function_single_async() won't block. +- */ +- if (kgdb_info[cpu].rounding_up) +- continue; +- kgdb_info[cpu].rounding_up = true; +- +- ret = smp_call_function_single_async(cpu, csd); +- if (ret) +- kgdb_info[cpu].rounding_up = false; ++ kgdb_roundup_cpu(cpu); + } + } + NOKPROBE_SYMBOL(kgdb_roundup_cpus); +diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c +index 6735ac36b718..539a2f0dc89d 100644 +--- a/kernel/debug/kdb/kdb_io.c ++++ b/kernel/debug/kdb/kdb_io.c +@@ -559,23 +559,17 @@ static void kdb_msg_write(const char *msg, int msg_len) + cp++; + } + ++ /* mirror output on atomic consoles */ + for_each_console(c) { + if (!(c->flags & CON_ENABLED)) + continue; + if (c == dbg_io_ops->cons) + continue; +- /* +- * Set oops_in_progress to encourage the console drivers to +- * disregard their internal spin locks: in the current calling +- * context the risk of deadlock is a bigger problem than risks +- * due to re-entering the console driver. We operate directly on +- * oops_in_progress rather than using bust_spinlocks() because +- * the calls bust_spinlocks() makes on exit are not appropriate +- * for this calling context. +- */ +- ++oops_in_progress; +- c->write(c, msg, msg_len); +- --oops_in_progress; ++ ++ if (!c->write_atomic) ++ continue; ++ c->write_atomic(c, msg, msg_len); ++ + touch_nmi_watchdog(); + } + } +diff --git a/kernel/entry/common.c b/kernel/entry/common.c +index e002bea6b4be..51ddfdacfc1f 100644 +--- a/kernel/entry/common.c ++++ b/kernel/entry/common.c +@@ -159,9 +159,17 @@ static unsigned long exit_to_user_mode_loop(struct pt_regs *regs, + + local_irq_enable_exit_to_user(ti_work); + +- if (ti_work & _TIF_NEED_RESCHED) ++ if (ti_work & _TIF_NEED_RESCHED_MASK) + schedule(); + ++#ifdef ARCH_RT_DELAYS_SIGNAL_SEND ++ if (unlikely(current->forced_info.si_signo)) { ++ struct task_struct *t = current; ++ force_sig_info(&t->forced_info); ++ t->forced_info.si_signo = 0; ++ } ++#endif ++ + if (ti_work & _TIF_UPROBE) + uprobe_notify_resume(regs); + +@@ -388,7 +396,7 @@ void irqentry_exit_cond_resched(void) + rcu_irq_exit_check_preempt(); + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) + WARN_ON_ONCE(!on_thread_stack()); +- if (need_resched()) ++ if (should_resched(0)) + preempt_schedule_irq(); + } + } +diff --git a/kernel/exit.c b/kernel/exit.c +index 80efdfda6662..6ff17e977392 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -64,6 +64,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -215,8 +216,14 @@ static void delayed_put_task_struct(struct rcu_head *rhp) + { + struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); + ++ kprobe_flush_task(tsk); + perf_event_delayed_put(tsk); + trace_sched_process_free(tsk); ++ ++ /* RT enabled kernels delay freeing the VMAP'ed task stack */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ put_task_stack(tsk); ++ + put_task_struct(tsk); + } + +diff --git a/kernel/fork.c b/kernel/fork.c +index 1906230a000e..47f647e6a6c3 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -289,7 +289,10 @@ static inline void free_thread_stack(struct task_struct *tsk) + return; + } + +- vfree_atomic(tsk->stack); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ vfree_atomic(tsk->stack); ++ else ++ vfree(tsk->stack); + return; + } + #endif +@@ -709,6 +712,19 @@ void __mmdrop(struct mm_struct *mm) + } + EXPORT_SYMBOL_GPL(__mmdrop); + ++#ifdef CONFIG_PREEMPT_RT ++/* ++ * RCU callback for delayed mm drop. Not strictly RCU, but call_rcu() is ++ * by far the least expensive way to do that. ++ */ ++void __mmdrop_delayed(struct rcu_head *rhp) ++{ ++ struct mm_struct *mm = container_of(rhp, struct mm_struct, delayed_drop); ++ ++ __mmdrop(mm); ++} ++#endif ++ + static void mmdrop_async_fn(struct work_struct *work) + { + struct mm_struct *mm; +diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c +index 7a45fd593245..23dc888e0885 100644 +--- a/kernel/irq/irqdesc.c ++++ b/kernel/irq/irqdesc.c +@@ -664,6 +664,29 @@ int generic_handle_irq(unsigned int irq) + } + EXPORT_SYMBOL_GPL(generic_handle_irq); + ++/** ++ * generic_handle_irq_safe - Invoke the handler for a particular irq from any ++ * context. ++ * @irq: The irq number to handle ++ * ++ * Returns: 0 on success, a negative value on error. ++ * ++ * This function can be called from any context (IRQ or process context). It ++ * will report an error if not invoked from IRQ context and the irq has been ++ * marked to enforce IRQ-context only. ++ */ ++int generic_handle_irq_safe(unsigned int irq) ++{ ++ unsigned long flags; ++ int ret; ++ ++ local_irq_save(flags); ++ ret = handle_irq_desc(irq_to_desc(irq)); ++ local_irq_restore(flags); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(generic_handle_irq_safe); ++ + #ifdef CONFIG_IRQ_DOMAIN + /** + * generic_handle_domain_irq - Invoke the handler for a HW irq belonging +diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c +index 9862372e0f01..78d90ac0528c 100644 +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -1301,6 +1301,8 @@ static int irq_thread(void *data) + + irq_thread_set_ready(desc, action); + ++ sched_set_fifo(current); ++ + if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD, + &action->thread_flags)) + handler_fn = irq_forced_thread_fn; +@@ -1466,8 +1468,6 @@ setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary) + if (IS_ERR(t)) + return PTR_ERR(t); + +- sched_set_fifo(t); +- + /* + * We keep the reference to the task struct even if + * the thread dies to avoid that the interrupt code +@@ -2861,7 +2861,7 @@ EXPORT_SYMBOL_GPL(irq_get_irqchip_state); + * This call sets the internal irqchip state of an interrupt, + * depending on the value of @which. + * +- * This function should be called with preemption disabled if the ++ * This function should be called with migration disabled if the + * interrupt controller has per-cpu registers. + */ + int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, +diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c +index c481d8458325..02b2daf07441 100644 +--- a/kernel/irq/spurious.c ++++ b/kernel/irq/spurious.c +@@ -447,6 +447,10 @@ MODULE_PARM_DESC(noirqdebug, "Disable irq lockup detection when true"); + + static int __init irqfixup_setup(char *str) + { ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ pr_warn("irqfixup boot option not supported with PREEMPT_RT\n"); ++ return 1; ++ } + irqfixup = 1; + printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n"); + printk(KERN_WARNING "This may impact system performance.\n"); +@@ -459,6 +463,10 @@ module_param(irqfixup, int, 0644); + + static int __init irqpoll_setup(char *str) + { ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ pr_warn("irqpoll boot option not supported with PREEMPT_RT\n"); ++ return 1; ++ } + irqfixup = 2; + printk(KERN_WARNING "Misrouted IRQ fixup and polling support " + "enabled\n"); +diff --git a/kernel/irq_work.c b/kernel/irq_work.c +index db8c248ebc8c..f7df715ec28e 100644 +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c +@@ -18,11 +18,36 @@ + #include + #include + #include ++#include + #include + #include + + static DEFINE_PER_CPU(struct llist_head, raised_list); + static DEFINE_PER_CPU(struct llist_head, lazy_list); ++static DEFINE_PER_CPU(struct task_struct *, irq_workd); ++ ++static void wake_irq_workd(void) ++{ ++ struct task_struct *tsk = __this_cpu_read(irq_workd); ++ ++ if (!llist_empty(this_cpu_ptr(&lazy_list)) && tsk) ++ wake_up_process(tsk); ++} ++ ++#ifdef CONFIG_SMP ++static void irq_work_wake(struct irq_work *entry) ++{ ++ wake_irq_workd(); ++} ++ ++static DEFINE_PER_CPU(struct irq_work, irq_work_wakeup) = ++ IRQ_WORK_INIT_HARD(irq_work_wake); ++#endif ++ ++static int irq_workd_should_run(unsigned int cpu) ++{ ++ return !llist_empty(this_cpu_ptr(&lazy_list)); ++} + + /* + * Claim the entry so that no one else will poke at it. +@@ -52,15 +77,29 @@ void __weak arch_irq_work_raise(void) + /* Enqueue on current CPU, work must already be claimed and preempt disabled */ + static void __irq_work_queue_local(struct irq_work *work) + { ++ struct llist_head *list; ++ bool rt_lazy_work = false; ++ bool lazy_work = false; ++ int work_flags; ++ ++ work_flags = atomic_read(&work->node.a_flags); ++ if (work_flags & IRQ_WORK_LAZY) ++ lazy_work = true; ++ else if (IS_ENABLED(CONFIG_PREEMPT_RT) && ++ !(work_flags & IRQ_WORK_HARD_IRQ)) ++ rt_lazy_work = true; ++ ++ if (lazy_work || rt_lazy_work) ++ list = this_cpu_ptr(&lazy_list); ++ else ++ list = this_cpu_ptr(&raised_list); ++ ++ if (!llist_add(&work->node.llist, list)) ++ return; ++ + /* If the work is "lazy", handle it from next tick if any */ +- if (atomic_read(&work->node.a_flags) & IRQ_WORK_LAZY) { +- if (llist_add(&work->node.llist, this_cpu_ptr(&lazy_list)) && +- tick_nohz_tick_stopped()) +- arch_irq_work_raise(); +- } else { +- if (llist_add(&work->node.llist, this_cpu_ptr(&raised_list))) +- arch_irq_work_raise(); +- } ++ if (!lazy_work || tick_nohz_tick_stopped()) ++ arch_irq_work_raise(); + } + + /* Enqueue the irq work @work on the current CPU */ +@@ -104,17 +143,34 @@ bool irq_work_queue_on(struct irq_work *work, int cpu) + if (cpu != smp_processor_id()) { + /* Arch remote IPI send/receive backend aren't NMI safe */ + WARN_ON_ONCE(in_nmi()); ++ ++ /* ++ * On PREEMPT_RT the items which are not marked as ++ * IRQ_WORK_HARD_IRQ are added to the lazy list and a HARD work ++ * item is used on the remote CPU to wake the thread. ++ */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT) && ++ !(atomic_read(&work->node.a_flags) & IRQ_WORK_HARD_IRQ)) { ++ ++ if (!llist_add(&work->node.llist, &per_cpu(lazy_list, cpu))) ++ goto out; ++ ++ work = &per_cpu(irq_work_wakeup, cpu); ++ if (!irq_work_claim(work)) ++ goto out; ++ } ++ + __smp_call_single_queue(cpu, &work->node.llist); + } else { + __irq_work_queue_local(work); + } ++out: + preempt_enable(); + + return true; + #endif /* CONFIG_SMP */ + } + +- + bool irq_work_needs_cpu(void) + { + struct llist_head *raised, *lazy; +@@ -160,6 +216,10 @@ void irq_work_single(void *arg) + * else claimed it meanwhile. + */ + (void)atomic_cmpxchg(&work->node.a_flags, flags, flags & ~IRQ_WORK_BUSY); ++ ++ if ((IS_ENABLED(CONFIG_PREEMPT_RT) && !irq_work_is_hard(work)) || ++ !arch_irq_work_has_interrupt()) ++ rcuwait_wake_up(&work->irqwait); + } + + static void irq_work_run_list(struct llist_head *list) +@@ -167,7 +227,12 @@ static void irq_work_run_list(struct llist_head *list) + struct irq_work *work, *tmp; + struct llist_node *llnode; + +- BUG_ON(!irqs_disabled()); ++ /* ++ * On PREEMPT_RT IRQ-work which is not marked as HARD will be processed ++ * in a per-CPU thread in preemptible context. Only the items which are ++ * marked as IRQ_WORK_HARD_IRQ will be processed in hardirq context. ++ */ ++ BUG_ON(!irqs_disabled() && !IS_ENABLED(CONFIG_PREEMPT_RT)); + + if (llist_empty(list)) + return; +@@ -184,7 +249,10 @@ static void irq_work_run_list(struct llist_head *list) + void irq_work_run(void) + { + irq_work_run_list(this_cpu_ptr(&raised_list)); +- irq_work_run_list(this_cpu_ptr(&lazy_list)); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ irq_work_run_list(this_cpu_ptr(&lazy_list)); ++ else ++ wake_irq_workd(); + } + EXPORT_SYMBOL_GPL(irq_work_run); + +@@ -194,7 +262,11 @@ void irq_work_tick(void) + + if (!llist_empty(raised) && !arch_irq_work_has_interrupt()) + irq_work_run_list(raised); +- irq_work_run_list(this_cpu_ptr(&lazy_list)); ++ ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ irq_work_run_list(this_cpu_ptr(&lazy_list)); ++ else ++ wake_irq_workd(); + } + + /* +@@ -204,8 +276,42 @@ void irq_work_tick(void) + void irq_work_sync(struct irq_work *work) + { + lockdep_assert_irqs_enabled(); ++ might_sleep(); ++ ++ if ((IS_ENABLED(CONFIG_PREEMPT_RT) && !irq_work_is_hard(work)) || ++ !arch_irq_work_has_interrupt()) { ++ rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work), ++ TASK_UNINTERRUPTIBLE); ++ return; ++ } + + while (irq_work_is_busy(work)) + cpu_relax(); + } + EXPORT_SYMBOL_GPL(irq_work_sync); ++ ++static void run_irq_workd(unsigned int cpu) ++{ ++ irq_work_run_list(this_cpu_ptr(&lazy_list)); ++} ++ ++static void irq_workd_setup(unsigned int cpu) ++{ ++ sched_set_fifo_low(current); ++} ++ ++static struct smp_hotplug_thread irqwork_threads = { ++ .store = &irq_workd, ++ .setup = irq_workd_setup, ++ .thread_should_run = irq_workd_should_run, ++ .thread_fn = run_irq_workd, ++ .thread_comm = "irq_work/%u", ++}; ++ ++static __init int irq_work_init_threads(void) ++{ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ BUG_ON(smpboot_register_percpu_thread(&irqwork_threads)); ++ return 0; ++} ++early_initcall(irq_work_init_threads); +diff --git a/kernel/kcov.c b/kernel/kcov.c +index 80bfe71bbe13..36ca640c4f8e 100644 +--- a/kernel/kcov.c ++++ b/kernel/kcov.c +@@ -88,6 +88,7 @@ static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas); + + struct kcov_percpu_data { + void *irq_area; ++ local_lock_t lock; + + unsigned int saved_mode; + unsigned int saved_size; +@@ -96,7 +97,9 @@ struct kcov_percpu_data { + int saved_sequence; + }; + +-static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data); ++static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data) = { ++ .lock = INIT_LOCAL_LOCK(lock), ++}; + + /* Must be called with kcov_remote_lock locked. */ + static struct kcov_remote *kcov_remote_find(u64 handle) +@@ -824,7 +827,7 @@ void kcov_remote_start(u64 handle) + if (!in_task() && !in_serving_softirq()) + return; + +- local_irq_save(flags); ++ local_lock_irqsave(&kcov_percpu_data.lock, flags); + + /* + * Check that kcov_remote_start() is not called twice in background +@@ -832,7 +835,7 @@ void kcov_remote_start(u64 handle) + */ + mode = READ_ONCE(t->kcov_mode); + if (WARN_ON(in_task() && kcov_mode_enabled(mode))) { +- local_irq_restore(flags); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + return; + } + /* +@@ -841,14 +844,15 @@ void kcov_remote_start(u64 handle) + * happened while collecting coverage from a background thread. + */ + if (WARN_ON(in_serving_softirq() && t->kcov_softirq)) { +- local_irq_restore(flags); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + return; + } + + spin_lock(&kcov_remote_lock); + remote = kcov_remote_find(handle); + if (!remote) { +- spin_unlock_irqrestore(&kcov_remote_lock, flags); ++ spin_unlock(&kcov_remote_lock); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + return; + } + kcov_debug("handle = %llx, context: %s\n", handle, +@@ -869,19 +873,19 @@ void kcov_remote_start(u64 handle) + size = CONFIG_KCOV_IRQ_AREA_SIZE; + area = this_cpu_ptr(&kcov_percpu_data)->irq_area; + } +- spin_unlock_irqrestore(&kcov_remote_lock, flags); ++ spin_unlock(&kcov_remote_lock); + + /* Can only happen when in_task(). */ + if (!area) { ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + area = vmalloc(size * sizeof(unsigned long)); + if (!area) { + kcov_put(kcov); + return; + } ++ local_lock_irqsave(&kcov_percpu_data.lock, flags); + } + +- local_irq_save(flags); +- + /* Reset coverage size. */ + *(u64 *)area = 0; + +@@ -891,7 +895,7 @@ void kcov_remote_start(u64 handle) + } + kcov_start(t, kcov, size, area, mode, sequence); + +- local_irq_restore(flags); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + + } + EXPORT_SYMBOL(kcov_remote_start); +@@ -965,12 +969,12 @@ void kcov_remote_stop(void) + if (!in_task() && !in_serving_softirq()) + return; + +- local_irq_save(flags); ++ local_lock_irqsave(&kcov_percpu_data.lock, flags); + + mode = READ_ONCE(t->kcov_mode); + barrier(); + if (!kcov_mode_enabled(mode)) { +- local_irq_restore(flags); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + return; + } + /* +@@ -978,12 +982,12 @@ void kcov_remote_stop(void) + * actually found the remote handle and started collecting coverage. + */ + if (in_serving_softirq() && !t->kcov_softirq) { +- local_irq_restore(flags); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + return; + } + /* Make sure that kcov_softirq is only set when in softirq. */ + if (WARN_ON(!in_serving_softirq() && t->kcov_softirq)) { +- local_irq_restore(flags); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + return; + } + +@@ -1013,7 +1017,7 @@ void kcov_remote_stop(void) + spin_unlock(&kcov_remote_lock); + } + +- local_irq_restore(flags); ++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags); + + /* Get in kcov_remote_start(). */ + kcov_put(kcov); +@@ -1034,8 +1038,8 @@ static int __init kcov_init(void) + int cpu; + + for_each_possible_cpu(cpu) { +- void *area = vmalloc(CONFIG_KCOV_IRQ_AREA_SIZE * +- sizeof(unsigned long)); ++ void *area = vmalloc_node(CONFIG_KCOV_IRQ_AREA_SIZE * ++ sizeof(unsigned long), cpu_to_node(cpu)); + if (!area) + return -ENOMEM; + per_cpu_ptr(&kcov_percpu_data, cpu)->irq_area = area; +diff --git a/kernel/kprobes.c b/kernel/kprobes.c +index 7e9fa1b7ff67..d83e818ffbdb 100644 +--- a/kernel/kprobes.c ++++ b/kernel/kprobes.c +@@ -1248,10 +1248,10 @@ void kprobe_busy_end(void) + } + + /* +- * This function is called from finish_task_switch when task tk becomes dead, +- * so that we can recycle any function-return probe instances associated +- * with this task. These left over instances represent probed functions +- * that have been called but will never return. ++ * This function is called from delayed_put_task_struct() when a task is ++ * dead and cleaned up to recycle any function-return probe instances ++ * associated with this task. These left over instances represent probed ++ * functions that have been called but will never return. + */ + void kprobe_flush_task(struct task_struct *tk) + { +diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c +index e20c19e3ba49..777168d58f02 100644 +--- a/kernel/ksysfs.c ++++ b/kernel/ksysfs.c +@@ -143,6 +143,15 @@ KERNEL_ATTR_RO(vmcoreinfo); + + #endif /* CONFIG_CRASH_CORE */ + ++#if defined(CONFIG_PREEMPT_RT) ++static ssize_t realtime_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%d\n", 1); ++} ++KERNEL_ATTR_RO(realtime); ++#endif ++ + /* whether file capabilities are enabled */ + static ssize_t fscaps_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +@@ -233,6 +242,9 @@ static struct attribute * kernel_attrs[] = { + #ifndef CONFIG_TINY_RCU + &rcu_expedited_attr.attr, + &rcu_normal_attr.attr, ++#endif ++#ifdef CONFIG_PREEMPT_RT ++ &realtime_attr.attr, + #endif + NULL + }; +diff --git a/kernel/kthread.c b/kernel/kthread.c +index e319a1b62586..c3870b2a150d 100644 +--- a/kernel/kthread.c ++++ b/kernel/kthread.c +@@ -270,6 +270,7 @@ EXPORT_SYMBOL_GPL(kthread_parkme); + + static int kthread(void *_create) + { ++ static const struct sched_param param = { .sched_priority = 0 }; + /* Copy data: it's on kthread's stack */ + struct kthread_create_info *create = _create; + int (*threadfn)(void *data) = create->threadfn; +@@ -300,6 +301,13 @@ static int kthread(void *_create) + init_completion(&self->parked); + current->vfork_done = &self->exited; + ++ /* ++ * The new thread inherited kthreadd's priority and CPU mask. Reset ++ * back to default in case they have been changed. ++ */ ++ sched_setscheduler_nocheck(current, SCHED_NORMAL, ¶m); ++ set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_FLAG_KTHREAD)); ++ + /* OK, tell user we're spawned, wait for stop or wakeup */ + __set_current_state(TASK_UNINTERRUPTIBLE); + create->result = current; +@@ -397,7 +405,6 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data), + } + task = create->result; + if (!IS_ERR(task)) { +- static const struct sched_param param = { .sched_priority = 0 }; + char name[TASK_COMM_LEN]; + + /* +@@ -406,13 +413,6 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data), + */ + vsnprintf(name, sizeof(name), namefmt, args); + set_task_comm(task, name); +- /* +- * root may have changed our (kthreadd's) priority or CPU mask. +- * The kernel thread should not inherit these properties. +- */ +- sched_setscheduler_nocheck(task, SCHED_NORMAL, ¶m); +- set_cpus_allowed_ptr(task, +- housekeeping_cpumask(HK_FLAG_KTHREAD)); + } + kfree(create); + return task; +diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index e6a282bc1665..ce3c8a4a5506 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -5470,6 +5470,7 @@ static noinstr void check_flags(unsigned long flags) + } + } + ++#ifndef CONFIG_PREEMPT_RT + /* + * We dont accurately track softirq state in e.g. + * hardirq contexts (such as on 4KSTACKS), so only +@@ -5484,6 +5485,7 @@ static noinstr void check_flags(unsigned long flags) + DEBUG_LOCKS_WARN_ON(!current->softirqs_enabled); + } + } ++#endif + + if (!debug_locks) + print_irqtrace_events(current); +diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c +index b7fa3ee3aa1d..108b963a783b 100644 +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -1135,8 +1135,26 @@ static int __sched task_blocks_on_rt_mutex(struct rt_mutex_base *lock, + * which is wrong, as the other waiter is not in a deadlock + * situation. + */ +- if (owner == task) ++ if (owner == task) { ++#if defined(DEBUG_WW_MUTEXES) && defined(CONFIG_DEBUG_LOCKING_API_SELFTESTS) ++ /* ++ * The lockdep selftest for ww-mutex assumes in a few cases ++ * the ww_ctx->contending_lock assignment via ++ * __ww_mutex_check_kill() which does not happen if the rtmutex ++ * detects the deadlock early. ++ */ ++ if (build_ww_mutex() && ww_ctx) { ++ struct rt_mutex *rtm; ++ ++ /* Check whether the waiter should backout immediately */ ++ rtm = container_of(lock, struct rt_mutex, rtmutex); ++ ++ __ww_mutex_add_waiter(waiter, rtm, ww_ctx); ++ __ww_mutex_check_kill(rtm, waiter, ww_ctx); ++ } ++#endif + return -EDEADLK; ++ } + + raw_spin_lock(&task->pi_lock); + waiter->task = task; +diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c +index a461be2f873d..cb9fdff76a8a 100644 +--- a/kernel/locking/rtmutex_api.c ++++ b/kernel/locking/rtmutex_api.c +@@ -21,12 +21,13 @@ int max_lock_depth = 1024; + */ + static __always_inline int __rt_mutex_lock_common(struct rt_mutex *lock, + unsigned int state, ++ struct lockdep_map *nest_lock, + unsigned int subclass) + { + int ret; + + might_sleep(); +- mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); ++ mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, _RET_IP_); + ret = __rt_mutex_lock(&lock->rtmutex, state); + if (ret) + mutex_release(&lock->dep_map, _RET_IP_); +@@ -48,10 +49,16 @@ EXPORT_SYMBOL(rt_mutex_base_init); + */ + void __sched rt_mutex_lock_nested(struct rt_mutex *lock, unsigned int subclass) + { +- __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass); ++ __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, NULL, subclass); + } + EXPORT_SYMBOL_GPL(rt_mutex_lock_nested); + ++void __sched _rt_mutex_lock_nest_lock(struct rt_mutex *lock, struct lockdep_map *nest_lock) ++{ ++ __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, nest_lock, 0); ++} ++EXPORT_SYMBOL_GPL(_rt_mutex_lock_nest_lock); ++ + #else /* !CONFIG_DEBUG_LOCK_ALLOC */ + + /** +@@ -61,7 +68,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock_nested); + */ + void __sched rt_mutex_lock(struct rt_mutex *lock) + { +- __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0); ++ __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, NULL, 0); + } + EXPORT_SYMBOL_GPL(rt_mutex_lock); + #endif +@@ -77,10 +84,25 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock); + */ + int __sched rt_mutex_lock_interruptible(struct rt_mutex *lock) + { +- return __rt_mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0); ++ return __rt_mutex_lock_common(lock, TASK_INTERRUPTIBLE, NULL, 0); + } + EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible); + ++/** ++ * rt_mutex_lock_killable - lock a rt_mutex killable ++ * ++ * @lock: the rt_mutex to be locked ++ * ++ * Returns: ++ * 0 on success ++ * -EINTR when interrupted by a signal ++ */ ++int __sched rt_mutex_lock_killable(struct rt_mutex *lock) ++{ ++ return __rt_mutex_lock_common(lock, TASK_KILLABLE, NULL, 0); ++} ++EXPORT_SYMBOL_GPL(rt_mutex_lock_killable); ++ + /** + * rt_mutex_trylock - try to lock a rt_mutex + * +diff --git a/kernel/locking/spinlock_rt.c b/kernel/locking/spinlock_rt.c +index d2912e44d61f..9e396a09fe0f 100644 +--- a/kernel/locking/spinlock_rt.c ++++ b/kernel/locking/spinlock_rt.c +@@ -24,6 +24,17 @@ + #define RT_MUTEX_BUILD_SPINLOCKS + #include "rtmutex.c" + ++/* ++ * __might_resched() skips the state check as rtlocks are state ++ * preserving. Take RCU nesting into account as spin/read/write_lock() can ++ * legitimately nest into an RCU read side critical section. ++ */ ++#define RTLOCK_RESCHED_OFFSETS \ ++ (rcu_preempt_depth() << MIGHT_RESCHED_RCU_SHIFT) ++ ++#define rtlock_might_resched() \ ++ __might_resched(__FILE__, __LINE__, RTLOCK_RESCHED_OFFSETS) ++ + static __always_inline void rtlock_lock(struct rt_mutex_base *rtm) + { + if (unlikely(!rt_mutex_cmpxchg_acquire(rtm, NULL, current))) +@@ -32,7 +43,7 @@ static __always_inline void rtlock_lock(struct rt_mutex_base *rtm) + + static __always_inline void __rt_spin_lock(spinlock_t *lock) + { +- ___might_sleep(__FILE__, __LINE__, 0); ++ rtlock_might_resched(); + rtlock_lock(&lock->lock); + rcu_read_lock(); + migrate_disable(); +@@ -210,7 +221,7 @@ EXPORT_SYMBOL(rt_write_trylock); + + void __sched rt_read_lock(rwlock_t *rwlock) + { +- ___might_sleep(__FILE__, __LINE__, 0); ++ rtlock_might_resched(); + rwlock_acquire_read(&rwlock->dep_map, 0, 0, _RET_IP_); + rwbase_read_lock(&rwlock->rwbase, TASK_RTLOCK_WAIT); + rcu_read_lock(); +@@ -220,7 +231,7 @@ EXPORT_SYMBOL(rt_read_lock); + + void __sched rt_write_lock(rwlock_t *rwlock) + { +- ___might_sleep(__FILE__, __LINE__, 0); ++ rtlock_might_resched(); + rwlock_acquire(&rwlock->dep_map, 0, 0, _RET_IP_); + rwbase_write_lock(&rwlock->rwbase, TASK_RTLOCK_WAIT); + rcu_read_lock(); +@@ -246,12 +257,6 @@ void __sched rt_write_unlock(rwlock_t *rwlock) + } + EXPORT_SYMBOL(rt_write_unlock); + +-int __sched rt_rwlock_is_contended(rwlock_t *rwlock) +-{ +- return rw_base_is_contended(&rwlock->rwbase); +-} +-EXPORT_SYMBOL(rt_rwlock_is_contended); +- + #ifdef CONFIG_DEBUG_LOCK_ALLOC + void __rt_rwlock_init(rwlock_t *rwlock, const char *name, + struct lock_class_key *key) +diff --git a/kernel/panic.c b/kernel/panic.c +index 47933d4c769b..ea5269f486cc 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -245,12 +245,27 @@ void check_panic_on_warn(const char *origin) + void panic(const char *fmt, ...) + { + static char buf[1024]; ++ va_list args2; + va_list args; + long i, i_next = 0, len; + int state = 0; + int old_cpu, this_cpu; + bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; + ++ console_verbose(); ++ pr_emerg("Kernel panic - not syncing:\n"); ++ va_start(args2, fmt); ++ va_copy(args, args2); ++ vprintk(fmt, args2); ++ va_end(args2); ++#ifdef CONFIG_DEBUG_BUGVERBOSE ++ /* ++ * Avoid nested stack-dumping if a panic occurs during oops processing ++ */ ++ if (!test_taint(TAINT_DIE) && oops_in_progress <= 1) ++ dump_stack(); ++#endif ++ pr_flush(1000, true); + if (panic_on_warn) { + /* + * This thread may hit another WARN() in the panic path. +@@ -291,24 +306,13 @@ void panic(const char *fmt, ...) + if (old_cpu != PANIC_CPU_INVALID && old_cpu != this_cpu) + panic_smp_self_stop(); + +- console_verbose(); + bust_spinlocks(1); +- va_start(args, fmt); + len = vscnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (len && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + +- pr_emerg("Kernel panic - not syncing: %s\n", buf); +-#ifdef CONFIG_DEBUG_BUGVERBOSE +- /* +- * Avoid nested stack-dumping if a panic occurs during oops processing +- */ +- if (!test_taint(TAINT_DIE) && oops_in_progress <= 1) +- dump_stack(); +-#endif +- + /* + * If kgdb is enabled, give it a chance to run before we stop all + * the other CPUs or else we won't be able to debug processes left +@@ -617,9 +621,11 @@ static u64 oops_id; + + static int init_oops_id(void) + { ++#ifndef CONFIG_PREEMPT_RT + if (!oops_id) + get_random_bytes(&oops_id, sizeof(oops_id)); + else ++#endif + oops_id++; + + return 0; +@@ -630,6 +636,7 @@ static void print_oops_end_marker(void) + { + init_oops_id(); + pr_warn("---[ end trace %016llx ]---\n", (unsigned long long)oops_id); ++ pr_flush(1000, true); + } + + /* +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 8d856b7c2e5a..7f27cfee283e 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -44,6 +44,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -268,11 +271,6 @@ static void __up_console_sem(unsigned long ip) + */ + static int console_locked, console_suspended; + +-/* +- * If exclusive_console is non-NULL then only this console is to be printed to. +- */ +-static struct console *exclusive_console; +- + /* + * Array of consoles built from command line options (console=) + */ +@@ -352,10 +350,13 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; + * non-prinatable characters are escaped in the "\xff" notation. + */ + ++#ifdef CONFIG_PRINTK + /* syslog_lock protects syslog_* variables and write access to clear_seq. */ + static DEFINE_MUTEX(syslog_lock); + +-#ifdef CONFIG_PRINTK ++/* Set to enable sync mode. Once set, it is never cleared. */ ++static bool sync_mode; ++ + DECLARE_WAIT_QUEUE_HEAD(log_wait); + /* All 3 protected by @syslog_lock. */ + /* the next printk record to read by syslog(READ) or /proc/kmsg */ +@@ -363,17 +364,6 @@ static u64 syslog_seq; + static size_t syslog_partial; + static bool syslog_time; + +-/* All 3 protected by @console_sem. */ +-/* the next printk record to write to the console */ +-static u64 console_seq; +-static u64 exclusive_console_stop_seq; +-static unsigned long console_dropped; +- +-struct latched_seq { +- seqcount_latch_t latch; +- u64 val[2]; +-}; +- + /* + * The next printk record to read after the last 'clear' command. There are + * two copies (updated with seqcount_latch) so that reads can locklessly +@@ -391,9 +381,6 @@ static struct latched_seq clear_seq = { + #define PREFIX_MAX 32 + #endif + +-/* the maximum size of a formatted record (i.e. with prefix added per line) */ +-#define CONSOLE_LOG_MAX 1024 +- + /* the maximum size allowed to be reserved for a record */ + #define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX) + +@@ -437,7 +424,7 @@ bool printk_percpu_data_ready(void) + return __printk_percpu_data_ready; + } + +-/* Must be called under syslog_lock. */ ++/* Must be called under associated write-protection lock. */ + static void latched_seq_write(struct latched_seq *ls, u64 val) + { + raw_write_seqcount_latch(&ls->latch); +@@ -1771,188 +1758,152 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) + return do_syslog(type, buf, len, SYSLOG_FROM_READER); + } + +-/* +- * Special console_lock variants that help to reduce the risk of soft-lockups. +- * They allow to pass console_lock to another printk() call using a busy wait. +- */ ++int printk_delay_msec __read_mostly; + +-#ifdef CONFIG_LOCKDEP +-static struct lockdep_map console_owner_dep_map = { +- .name = "console_owner" +-}; +-#endif ++static inline void printk_delay(int level) ++{ ++ boot_delay_msec(level); + +-static DEFINE_RAW_SPINLOCK(console_owner_lock); +-static struct task_struct *console_owner; +-static bool console_waiter; ++ if (unlikely(printk_delay_msec)) { ++ int m = printk_delay_msec; + +-/** +- * console_lock_spinning_enable - mark beginning of code where another +- * thread might safely busy wait +- * +- * This basically converts console_lock into a spinlock. This marks +- * the section where the console_lock owner can not sleep, because +- * there may be a waiter spinning (like a spinlock). Also it must be +- * ready to hand over the lock at the end of the section. +- */ +-static void console_lock_spinning_enable(void) ++ while (m--) { ++ mdelay(1); ++ touch_nmi_watchdog(); ++ } ++ } ++} ++ ++static bool kernel_sync_mode(void) + { +- raw_spin_lock(&console_owner_lock); +- console_owner = current; +- raw_spin_unlock(&console_owner_lock); ++ return (oops_in_progress || sync_mode); ++} + +- /* The waiter may spin on us after setting console_owner */ +- spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_); ++static bool console_may_sync(struct console *con) ++{ ++ if (!(con->flags & CON_ENABLED)) ++ return false; ++ if (con->write_atomic && kernel_sync_mode()) ++ return true; ++ if (con->write_atomic && (con->flags & CON_HANDOVER) && !con->thread) ++ return true; ++ if (con->write && (con->flags & CON_BOOT) && !con->thread) ++ return true; ++ return false; + } + +-/** +- * console_lock_spinning_disable_and_check - mark end of code where another +- * thread was able to busy wait and check if there is a waiter +- * +- * This is called at the end of the section where spinning is allowed. +- * It has two functions. First, it is a signal that it is no longer +- * safe to start busy waiting for the lock. Second, it checks if +- * there is a busy waiter and passes the lock rights to her. +- * +- * Important: Callers lose the lock if there was a busy waiter. +- * They must not touch items synchronized by console_lock +- * in this case. +- * +- * Return: 1 if the lock rights were passed, 0 otherwise. +- */ +-static int console_lock_spinning_disable_and_check(void) ++static bool call_sync_console_driver(struct console *con, const char *text, size_t text_len) + { +- int waiter; ++ if (!(con->flags & CON_ENABLED)) ++ return false; + +- raw_spin_lock(&console_owner_lock); +- waiter = READ_ONCE(console_waiter); +- console_owner = NULL; +- raw_spin_unlock(&console_owner_lock); ++ if (con->write_atomic && kernel_sync_mode()) { ++ con->write_atomic(con, text, text_len); ++ return true; ++ } + +- if (!waiter) { +- spin_release(&console_owner_dep_map, _THIS_IP_); +- return 0; ++ if (con->write_atomic && (con->flags & CON_HANDOVER) && !con->thread) { ++ if (console_trylock()) { ++ con->write_atomic(con, text, text_len); ++ console_unlock(); ++ return true; ++ } ++ ++ } else if (con->write && (con->flags & CON_BOOT) && !con->thread) { ++ if (console_trylock()) { ++ con->write(con, text, text_len); ++ console_unlock(); ++ return true; ++ } + } + +- /* The waiter is now free to continue */ +- WRITE_ONCE(console_waiter, false); ++ return false; ++} + +- spin_release(&console_owner_dep_map, _THIS_IP_); ++static bool have_atomic_console(void) ++{ ++ struct console *con; + +- /* +- * Hand off console_lock to waiter. The waiter will perform +- * the up(). After this, the waiter is the console_lock owner. +- */ +- mutex_release(&console_lock_dep_map, _THIS_IP_); +- return 1; ++ for_each_console(con) { ++ if (!(con->flags & CON_ENABLED)) ++ continue; ++ if (con->write_atomic) ++ return true; ++ } ++ return false; + } + +-/** +- * console_trylock_spinning - try to get console_lock by busy waiting +- * +- * This allows to busy wait for the console_lock when the current +- * owner is running in specially marked sections. It means that +- * the current owner is running and cannot reschedule until it +- * is ready to lose the lock. +- * +- * Return: 1 if we got the lock, 0 othrewise +- */ +-static int console_trylock_spinning(void) ++static bool print_sync(struct console *con, u64 *seq) + { +- struct task_struct *owner = NULL; +- bool waiter; +- bool spin = false; +- unsigned long flags; ++ struct printk_info info; ++ struct printk_record r; ++ size_t text_len; + +- if (console_trylock()) +- return 1; ++ prb_rec_init_rd(&r, &info, &con->sync_buf[0], sizeof(con->sync_buf)); + +- printk_safe_enter_irqsave(flags); ++ if (!prb_read_valid(prb, *seq, &r)) ++ return false; + +- raw_spin_lock(&console_owner_lock); +- owner = READ_ONCE(console_owner); +- waiter = READ_ONCE(console_waiter); +- if (!waiter && owner && owner != current) { +- WRITE_ONCE(console_waiter, true); +- spin = true; +- } +- raw_spin_unlock(&console_owner_lock); ++ text_len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time); + +- /* +- * If there is an active printk() writing to the +- * consoles, instead of having it write our data too, +- * see if we can offload that load from the active +- * printer, and do some printing ourselves. +- * Go into a spin only if there isn't already a waiter +- * spinning, and there is an active printer, and +- * that active printer isn't us (recursive printk?). +- */ +- if (!spin) { +- printk_safe_exit_irqrestore(flags); +- return 0; +- } ++ if (!call_sync_console_driver(con, &con->sync_buf[0], text_len)) ++ return false; + +- /* We spin waiting for the owner to release us */ +- spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_); +- /* Owner will clear console_waiter on hand off */ +- while (READ_ONCE(console_waiter)) +- cpu_relax(); +- spin_release(&console_owner_dep_map, _THIS_IP_); ++ *seq = r.info->seq; + +- printk_safe_exit_irqrestore(flags); +- /* +- * The owner passed the console lock to us. +- * Since we did not spin on console lock, annotate +- * this as a trylock. Otherwise lockdep will +- * complain. +- */ +- mutex_acquire(&console_lock_dep_map, 0, 1, _THIS_IP_); ++ touch_softlockup_watchdog_sync(); ++ clocksource_touch_watchdog(); ++ rcu_cpu_stall_reset(); ++ touch_nmi_watchdog(); + +- return 1; ++ if (text_len) ++ printk_delay(r.info->level); ++ ++ return true; + } + +-/* +- * Call the console drivers, asking them to write out +- * log_buf[start] to log_buf[end - 1]. +- * The console_lock must be held. +- */ +-static void call_console_drivers(const char *ext_text, size_t ext_len, +- const char *text, size_t len) ++static u64 read_console_seq(struct console *con) + { +- static char dropped_text[64]; +- size_t dropped_len = 0; +- struct console *con; ++ u64 seq2; ++ u64 seq; + +- trace_console_rcuidle(text, len); ++ seq = latched_seq_read_nolock(&con->printk_seq); ++ seq2 = latched_seq_read_nolock(&con->printk_sync_seq); ++ if (seq2 > seq) ++ seq = seq2; ++#ifdef CONFIG_HAVE_NMI ++ seq2 = latched_seq_read_nolock(&con->printk_sync_nmi_seq); ++ if (seq2 > seq) ++ seq = seq2; ++#endif ++ return seq; ++} + +- if (!console_drivers) +- return; ++static void print_sync_until(struct console *con, u64 seq, bool is_locked) ++{ ++ u64 printk_seq; + +- if (console_dropped) { +- dropped_len = snprintf(dropped_text, sizeof(dropped_text), +- "** %lu printk messages dropped **\n", +- console_dropped); +- console_dropped = 0; +- } ++ while (!__printk_cpu_trylock()) ++ cpu_relax(); + +- for_each_console(con) { +- if (exclusive_console && con != exclusive_console) +- continue; +- if (!(con->flags & CON_ENABLED)) +- continue; +- if (!con->write) +- continue; +- if (!cpu_online(smp_processor_id()) && +- !(con->flags & CON_ANYTIME)) +- continue; +- if (con->flags & CON_EXTENDED) +- con->write(con, ext_text, ext_len); +- else { +- if (dropped_len) +- con->write(con, dropped_text, dropped_len); +- con->write(con, text, len); +- } ++ for (;;) { ++ printk_seq = read_console_seq(con); ++ if (printk_seq >= seq) ++ break; ++ if (!print_sync(con, &printk_seq)) ++ break; ++ ++ if (is_locked) ++ latched_seq_write(&con->printk_seq, printk_seq + 1); ++#ifdef CONFIG_PRINTK_NMI ++ else if (in_nmi()) ++ latched_seq_write(&con->printk_sync_nmi_seq, printk_seq + 1); ++#endif ++ else ++ latched_seq_write(&con->printk_sync_seq, printk_seq + 1); + } ++ ++ __printk_cpu_unlock(); + } + + /* +@@ -2025,20 +1976,6 @@ static u8 *__printk_recursion_counter(void) + local_irq_restore(flags); \ + } while (0) + +-int printk_delay_msec __read_mostly; +- +-static inline void printk_delay(void) +-{ +- if (unlikely(printk_delay_msec)) { +- int m = printk_delay_msec; +- +- while (m--) { +- mdelay(1); +- touch_nmi_watchdog(); +- } +- } +-} +- + static inline u32 printk_caller_id(void) + { + return in_task() ? task_pid_nr(current) : +@@ -2126,6 +2063,7 @@ int vprintk_store(int facility, int level, + const u32 caller_id = printk_caller_id(); + struct prb_reserved_entry e; + enum printk_info_flags flags = 0; ++ bool final_commit = false; + struct printk_record r; + unsigned long irqflags; + u16 trunc_msg_len = 0; +@@ -2136,6 +2074,7 @@ int vprintk_store(int facility, int level, + u16 text_len; + int ret = 0; + u64 ts_nsec; ++ u64 seq; + + /* + * Since the duration of printk() can vary depending on the message +@@ -2174,6 +2113,7 @@ int vprintk_store(int facility, int level, + if (flags & LOG_CONT) { + prb_rec_init_wr(&r, reserve_size); + if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) { ++ seq = r.info->seq; + text_len = printk_sprint(&r.text_buf[r.info->text_len], reserve_size, + facility, &flags, fmt, args); + r.info->text_len += text_len; +@@ -2181,6 +2121,7 @@ int vprintk_store(int facility, int level, + if (flags & LOG_NEWLINE) { + r.info->flags |= LOG_NEWLINE; + prb_final_commit(&e); ++ final_commit = true; + } else { + prb_commit(&e); + } +@@ -2204,6 +2145,7 @@ int vprintk_store(int facility, int level, + if (!prb_reserve(&e, prb, &r)) + goto out; + } ++ seq = r.info->seq; + + /* fill message */ + text_len = printk_sprint(&r.text_buf[0], reserve_size, facility, &flags, fmt, args); +@@ -2219,13 +2161,25 @@ int vprintk_store(int facility, int level, + memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info)); + + /* A message without a trailing newline can be continued. */ +- if (!(flags & LOG_NEWLINE)) ++ if (!(flags & LOG_NEWLINE)) { + prb_commit(&e); +- else ++ } else { + prb_final_commit(&e); ++ final_commit = true; ++ } + + ret = text_len + trunc_msg_len; + out: ++ /* only the kernel may perform synchronous printing */ ++ if (facility == 0 && final_commit) { ++ struct console *con; ++ ++ for_each_console(con) { ++ if (console_may_sync(con)) ++ print_sync_until(con, seq + 1, false); ++ } ++ } ++ + printk_exit_irqrestore(recursion_ptr, irqflags); + return ret; + } +@@ -2235,40 +2189,16 @@ asmlinkage int vprintk_emit(int facility, int level, + const char *fmt, va_list args) + { + int printed_len; +- bool in_sched = false; + + /* Suppress unimportant messages after panic happens */ + if (unlikely(suppress_printk)) + return 0; + +- if (level == LOGLEVEL_SCHED) { ++ if (level == LOGLEVEL_SCHED) + level = LOGLEVEL_DEFAULT; +- in_sched = true; +- } +- +- boot_delay_msec(level); +- printk_delay(); + + printed_len = vprintk_store(facility, level, dev_info, fmt, args); + +- /* If called from the scheduler, we can not call up(). */ +- if (!in_sched) { +- /* +- * Disable preemption to avoid being preempted while holding +- * console_sem which would prevent anyone from printing to +- * console +- */ +- preempt_disable(); +- /* +- * Try to acquire and then immediately release the console +- * semaphore. The release will print out buffers and wake up +- * /dev/kmsg and syslog() users. +- */ +- if (console_trylock_spinning()) +- console_unlock(); +- preempt_enable(); +- } +- + wake_up_klogd(); + return printed_len; + } +@@ -2293,37 +2223,162 @@ asmlinkage __visible int _printk(const char *fmt, ...) + } + EXPORT_SYMBOL(_printk); + +-#else /* CONFIG_PRINTK */ ++static int printk_kthread_func(void *data) ++{ ++ struct console *con = data; ++ unsigned long dropped = 0; ++ char *dropped_text = NULL; ++ struct printk_info info; ++ struct printk_record r; ++ char *ext_text = NULL; ++ size_t dropped_len; ++ int ret = -ENOMEM; ++ char *text = NULL; ++ char *write_text; ++ size_t len; ++ int error; ++ u64 seq; ++ ++ if (con->flags & CON_EXTENDED) { ++ ext_text = kmalloc(CONSOLE_EXT_LOG_MAX, GFP_KERNEL); ++ if (!ext_text) ++ goto out; ++ } ++ text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); ++ dropped_text = kmalloc(64, GFP_KERNEL); ++ if (!text || !dropped_text) ++ goto out; ++ if (con->flags & CON_EXTENDED) ++ write_text = ext_text; ++ else ++ write_text = text; ++ ++ seq = read_console_seq(con); + +-#define CONSOLE_LOG_MAX 0 +-#define printk_time false ++ prb_rec_init_rd(&r, &info, text, LOG_LINE_MAX + PREFIX_MAX); + +-#define prb_read_valid(rb, seq, r) false +-#define prb_first_valid_seq(rb) 0 ++ for (;;) { ++ error = wait_event_interruptible(log_wait, ++ prb_read_valid(prb, seq, &r) || kthread_should_stop()); + +-static u64 syslog_seq; +-static u64 console_seq; +-static u64 exclusive_console_stop_seq; +-static unsigned long console_dropped; ++ if (kthread_should_stop()) ++ break; ++ ++ if (error) ++ continue; ++ ++ if (seq != r.info->seq) { ++ dropped += r.info->seq - seq; ++ seq = r.info->seq; ++ } ++ ++ seq++; ++ ++ if (!(con->flags & CON_ENABLED)) ++ continue; ++ ++ if (suppress_message_printing(r.info->level)) ++ continue; ++ ++ if (con->flags & CON_EXTENDED) { ++ len = info_print_ext_header(ext_text, ++ CONSOLE_EXT_LOG_MAX, ++ r.info); ++ len += msg_print_ext_body(ext_text + len, ++ CONSOLE_EXT_LOG_MAX - len, ++ &r.text_buf[0], r.info->text_len, ++ &r.info->dev_info); ++ } else { ++ len = record_print_text(&r, ++ console_msg_format & MSG_FORMAT_SYSLOG, ++ printk_time); ++ } ++ ++ console_lock(); ++ ++ /* ++ * Even though the printk kthread is always preemptible, it is ++ * still not allowed to call cond_resched() from within ++ * console drivers. The task may become non-preemptible in the ++ * console driver call chain. For example, vt_console_print() ++ * takes a spinlock and then can call into fbcon_redraw(), ++ * which can conditionally invoke cond_resched(). ++ */ ++ console_may_schedule = 0; ++ ++ if (kernel_sync_mode() && con->write_atomic) { ++ console_unlock(); ++ break; ++ } ++ ++ if (!(con->flags & CON_EXTENDED) && dropped) { ++ dropped_len = snprintf(dropped_text, 64, ++ "** %lu printk messages dropped **\n", ++ dropped); ++ dropped = 0; ++ ++ con->write(con, dropped_text, dropped_len); ++ printk_delay(r.info->level); ++ } ++ ++ con->write(con, write_text, len); ++ if (len) ++ printk_delay(r.info->level); + +-static size_t record_print_text(const struct printk_record *r, +- bool syslog, bool time) ++ latched_seq_write(&con->printk_seq, seq); ++ ++ console_unlock(); ++ } ++ ret = 0; ++out: ++ kfree(dropped_text); ++ kfree(text); ++ kfree(ext_text); ++ pr_info("%sconsole [%s%d]: printing thread stopped\n", ++ (con->flags & CON_BOOT) ? "boot" : "", ++ con->name, con->index); ++ return ret; ++} ++ ++/* Must be called within console_lock(). */ ++static void start_printk_kthread(struct console *con) + { +- return 0; ++ con->thread = kthread_run(printk_kthread_func, con, ++ "pr/%s%d", con->name, con->index); ++ if (IS_ERR(con->thread)) { ++ pr_err("%sconsole [%s%d]: unable to start printing thread\n", ++ (con->flags & CON_BOOT) ? "boot" : "", ++ con->name, con->index); ++ return; ++ } ++ pr_info("%sconsole [%s%d]: printing thread started\n", ++ (con->flags & CON_BOOT) ? "boot" : "", ++ con->name, con->index); + } +-static ssize_t info_print_ext_header(char *buf, size_t size, +- struct printk_info *info) ++ ++/* protected by console_lock */ ++static bool kthreads_started; ++ ++/* Must be called within console_lock(). */ ++static void console_try_thread(struct console *con) + { +- return 0; ++ if (kthreads_started) { ++ start_printk_kthread(con); ++ return; ++ } ++ ++ /* ++ * The printing threads have not been started yet. If this console ++ * can print synchronously, print all unprinted messages. ++ */ ++ if (console_may_sync(con)) { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ print_sync_until(con, prb_next_seq(prb), true); ++ local_irq_restore(flags); ++ } + } +-static ssize_t msg_print_ext_body(char *buf, size_t size, +- char *text, size_t text_len, +- struct dev_printk_info *dev_info) { return 0; } +-static void console_lock_spinning_enable(void) { } +-static int console_lock_spinning_disable_and_check(void) { return 0; } +-static void call_console_drivers(const char *ext_text, size_t ext_len, +- const char *text, size_t len) {} +-static bool suppress_message_printing(int level) { return false; } + + #endif /* CONFIG_PRINTK */ + +@@ -2580,34 +2635,6 @@ int is_console_locked(void) + } + EXPORT_SYMBOL(is_console_locked); + +-/* +- * Check if we have any console that is capable of printing while cpu is +- * booting or shutting down. Requires console_sem. +- */ +-static int have_callable_console(void) +-{ +- struct console *con; +- +- for_each_console(con) +- if ((con->flags & CON_ENABLED) && +- (con->flags & CON_ANYTIME)) +- return 1; +- +- return 0; +-} +- +-/* +- * Can we actually use the console at this time on this cpu? +- * +- * Console drivers may assume that per-cpu resources have been allocated. So +- * unless they're explicitly marked as being able to cope (CON_ANYTIME) don't +- * call them until this CPU is officially up. +- */ +-static inline int can_use_console(void) +-{ +- return cpu_online(raw_smp_processor_id()) || have_callable_console(); +-} +- + /** + * console_unlock - unlock the console system + * +@@ -2624,140 +2651,13 @@ static inline int can_use_console(void) + */ + void console_unlock(void) + { +- static char ext_text[CONSOLE_EXT_LOG_MAX]; +- static char text[CONSOLE_LOG_MAX]; +- unsigned long flags; +- bool do_cond_resched, retry; +- struct printk_info info; +- struct printk_record r; +- u64 __maybe_unused next_seq; +- + if (console_suspended) { + up_console_sem(); + return; + } + +- prb_rec_init_rd(&r, &info, text, sizeof(text)); +- +- /* +- * Console drivers are called with interrupts disabled, so +- * @console_may_schedule should be cleared before; however, we may +- * end up dumping a lot of lines, for example, if called from +- * console registration path, and should invoke cond_resched() +- * between lines if allowable. Not doing so can cause a very long +- * scheduling stall on a slow console leading to RCU stall and +- * softlockup warnings which exacerbate the issue with more +- * messages practically incapacitating the system. +- * +- * console_trylock() is not able to detect the preemptive +- * context reliably. Therefore the value must be stored before +- * and cleared after the "again" goto label. +- */ +- do_cond_resched = console_may_schedule; +-again: +- console_may_schedule = 0; +- +- /* +- * We released the console_sem lock, so we need to recheck if +- * cpu is online and (if not) is there at least one CON_ANYTIME +- * console. +- */ +- if (!can_use_console()) { +- console_locked = 0; +- up_console_sem(); +- return; +- } +- +- for (;;) { +- size_t ext_len = 0; +- int handover; +- size_t len; +- +-skip: +- if (!prb_read_valid(prb, console_seq, &r)) +- break; +- +- if (console_seq != r.info->seq) { +- console_dropped += r.info->seq - console_seq; +- console_seq = r.info->seq; +- } +- +- if (suppress_message_printing(r.info->level)) { +- /* +- * Skip record we have buffered and already printed +- * directly to the console when we received it, and +- * record that has level above the console loglevel. +- */ +- console_seq++; +- goto skip; +- } +- +- /* Output to all consoles once old messages replayed. */ +- if (unlikely(exclusive_console && +- console_seq >= exclusive_console_stop_seq)) { +- exclusive_console = NULL; +- } +- +- /* +- * Handle extended console text first because later +- * record_print_text() will modify the record buffer in-place. +- */ +- if (nr_ext_console_drivers) { +- ext_len = info_print_ext_header(ext_text, +- sizeof(ext_text), +- r.info); +- ext_len += msg_print_ext_body(ext_text + ext_len, +- sizeof(ext_text) - ext_len, +- &r.text_buf[0], +- r.info->text_len, +- &r.info->dev_info); +- } +- len = record_print_text(&r, +- console_msg_format & MSG_FORMAT_SYSLOG, +- printk_time); +- console_seq++; +- +- /* +- * While actively printing out messages, if another printk() +- * were to occur on another CPU, it may wait for this one to +- * finish. This task can not be preempted if there is a +- * waiter waiting to take over. +- * +- * Interrupts are disabled because the hand over to a waiter +- * must not be interrupted until the hand over is completed +- * (@console_waiter is cleared). +- */ +- printk_safe_enter_irqsave(flags); +- console_lock_spinning_enable(); +- +- stop_critical_timings(); /* don't trace print latency */ +- call_console_drivers(ext_text, ext_len, text, len); +- start_critical_timings(); +- +- handover = console_lock_spinning_disable_and_check(); +- printk_safe_exit_irqrestore(flags); +- if (handover) +- return; +- +- if (do_cond_resched) +- cond_resched(); +- } +- +- /* Get consistent value of the next-to-be-used sequence number. */ +- next_seq = console_seq; +- + console_locked = 0; + up_console_sem(); +- +- /* +- * Someone could have filled up the buffer again, so re-check if there's +- * something to flush. In case we cannot trylock the console_sem again, +- * there's a new owner and the console_unlock() from them will do the +- * flush, no worries. +- */ +- retry = prb_read_valid(prb, next_seq, NULL); +- if (retry && console_trylock()) +- goto again; + } + EXPORT_SYMBOL(console_unlock); + +@@ -2807,18 +2707,20 @@ void console_unblank(void) + */ + void console_flush_on_panic(enum con_flush_mode mode) + { +- /* +- * If someone else is holding the console lock, trylock will fail +- * and may_schedule may be set. Ignore and proceed to unlock so +- * that messages are flushed out. As this can be called from any +- * context and we don't want to get preempted while flushing, +- * ensure may_schedule is cleared. +- */ +- console_trylock(); +- console_may_schedule = 0; ++ if (!console_trylock()) ++ return; ++ ++#ifdef CONFIG_PRINTK ++ if (mode == CONSOLE_REPLAY_ALL) { ++ struct console *c; ++ u64 seq; ++ ++ seq = prb_first_valid_seq(prb); ++ for_each_console(c) ++ latched_seq_write(&c->printk_seq, seq); ++ } ++#endif + +- if (mode == CONSOLE_REPLAY_ALL) +- console_seq = prb_first_valid_seq(prb); + console_unlock(); + } + +@@ -2954,6 +2856,7 @@ static int try_enable_new_console(struct console *newcon, bool user_specified) + void register_console(struct console *newcon) + { + struct console *bcon = NULL; ++ u64 __maybe_unused seq = 0; + int err; + + for_each_console(bcon) { +@@ -2976,6 +2879,8 @@ void register_console(struct console *newcon) + } + } + ++ newcon->thread = NULL; ++ + if (console_drivers && console_drivers->flags & CON_BOOT) + bcon = console_drivers; + +@@ -3017,8 +2922,10 @@ void register_console(struct console *newcon) + * the real console are the same physical device, it's annoying to + * see the beginning boot messages twice + */ +- if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) ++ if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { + newcon->flags &= ~CON_PRINTBUFFER; ++ newcon->flags |= CON_HANDOVER; ++ } + + /* + * Put this console in the list - keep the +@@ -3040,27 +2947,21 @@ void register_console(struct console *newcon) + if (newcon->flags & CON_EXTENDED) + nr_ext_console_drivers++; + +- if (newcon->flags & CON_PRINTBUFFER) { +- /* +- * console_unlock(); will print out the buffered messages +- * for us. +- * +- * We're about to replay the log buffer. Only do this to the +- * just-registered console to avoid excessive message spam to +- * the already-registered consoles. +- * +- * Set exclusive_console with disabled interrupts to reduce +- * race window with eventual console_flush_on_panic() that +- * ignores console_lock. +- */ +- exclusive_console = newcon; +- exclusive_console_stop_seq = console_seq; ++#ifdef CONFIG_PRINTK ++ if (!(newcon->flags & CON_PRINTBUFFER)) ++ seq = prb_next_seq(prb); + +- /* Get a consistent copy of @syslog_seq. */ +- mutex_lock(&syslog_lock); +- console_seq = syslog_seq; +- mutex_unlock(&syslog_lock); +- } ++ seqcount_latch_init(&newcon->printk_seq.latch); ++ latched_seq_write(&newcon->printk_seq, seq); ++ seqcount_latch_init(&newcon->printk_sync_seq.latch); ++ latched_seq_write(&newcon->printk_sync_seq, seq); ++#ifdef CONFIG_HAVE_NMI ++ seqcount_latch_init(&newcon->printk_sync_nmi_seq.latch); ++ latched_seq_write(&newcon->printk_sync_nmi_seq, seq); ++#endif ++ ++ console_try_thread(newcon); ++#endif /* CONFIG_PRINTK */ + console_unlock(); + console_sysfs_notify(); + +@@ -3134,6 +3035,9 @@ int unregister_console(struct console *console) + console_unlock(); + console_sysfs_notify(); + ++ if (console->thread && !IS_ERR(console->thread)) ++ kthread_stop(console->thread); ++ + if (console->exit) + res = console->exit(console); + +@@ -3216,6 +3120,15 @@ static int __init printk_late_init(void) + unregister_console(con); + } + } ++ ++#ifdef CONFIG_PRINTK ++ console_lock(); ++ for_each_console(con) ++ start_printk_kthread(con); ++ kthreads_started = true; ++ console_unlock(); ++#endif ++ + ret = cpuhp_setup_state_nocalls(CPUHP_PRINTK_DEAD, "printk:dead", NULL, + console_cpu_notify); + WARN_ON(ret < 0); +@@ -3239,14 +3152,8 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work) + { + int pending = this_cpu_xchg(printk_pending, 0); + +- if (pending & PRINTK_PENDING_OUTPUT) { +- /* If trylock fails, someone else is doing the printing */ +- if (console_trylock()) +- console_unlock(); +- } +- + if (pending & PRINTK_PENDING_WAKEUP) +- wake_up_interruptible(&log_wait); ++ wake_up_interruptible_all(&log_wait); + } + + static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = +@@ -3293,7 +3200,7 @@ void defer_console_output(void) + + void printk_trigger_flush(void) + { +- defer_console_output(); ++ wake_up_klogd(); + } + + int vprintk_deferred(const char *fmt, va_list args) +@@ -3444,6 +3351,24 @@ void kmsg_dump(enum kmsg_dump_reason reason) + { + struct kmsg_dumper *dumper; + ++ if (!oops_in_progress) { ++ /* ++ * If atomic consoles are available, activate kernel sync mode ++ * to make sure any final messages are visible. The trailing ++ * printk message is important to flush any pending messages. ++ */ ++ if (have_atomic_console()) { ++ sync_mode = true; ++ pr_info("enabled sync mode\n"); ++ } ++ ++ /* ++ * Give the printing threads time to flush, allowing up to ++ * 1s of no printing forward progress before giving up. ++ */ ++ pr_flush(1000, true); ++ } ++ + rcu_read_lock(); + list_for_each_entry_rcu(dumper, &dump_list, list) { + enum kmsg_dump_reason max_reason = dumper->max_reason; +@@ -3626,6 +3551,7 @@ EXPORT_SYMBOL_GPL(kmsg_dump_rewind); + #ifdef CONFIG_SMP + static atomic_t printk_cpulock_owner = ATOMIC_INIT(-1); + static atomic_t printk_cpulock_nested = ATOMIC_INIT(0); ++static unsigned int kgdb_cpu = -1; + + /** + * __printk_wait_on_cpu_lock() - Busy wait until the printk cpu-reentrant +@@ -3705,6 +3631,9 @@ EXPORT_SYMBOL(__printk_cpu_trylock); + */ + void __printk_cpu_unlock(void) + { ++ bool trigger_kgdb = false; ++ unsigned int cpu; ++ + if (atomic_read(&printk_cpulock_nested)) { + atomic_dec(&printk_cpulock_nested); + return; +@@ -3715,6 +3644,12 @@ void __printk_cpu_unlock(void) + * LMM(__printk_cpu_unlock:A) + */ + ++ cpu = smp_processor_id(); ++ if (kgdb_cpu == cpu) { ++ trigger_kgdb = true; ++ kgdb_cpu = -1; ++ } ++ + /* + * Guarantee loads and stores from this CPU when it was the + * lock owner are visible to the next lock owner. This pairs +@@ -3735,6 +3670,98 @@ void __printk_cpu_unlock(void) + */ + atomic_set_release(&printk_cpulock_owner, + -1); /* LMM(__printk_cpu_unlock:B) */ ++ ++ if (trigger_kgdb) { ++ pr_warn("re-triggering kgdb roundup for CPU#%d\n", cpu); ++ kgdb_roundup_cpu(cpu); ++ } + } + EXPORT_SYMBOL(__printk_cpu_unlock); ++ ++bool kgdb_roundup_delay(unsigned int cpu) ++{ ++ if (cpu != atomic_read(&printk_cpulock_owner)) ++ return false; ++ ++ kgdb_cpu = cpu; ++ return true; ++} ++EXPORT_SYMBOL(kgdb_roundup_delay); + #endif /* CONFIG_SMP */ ++ ++#ifdef CONFIG_PRINTK ++static void pr_msleep(bool may_sleep, int ms) ++{ ++ if (may_sleep) { ++ msleep(ms); ++ } else { ++ while (ms--) ++ udelay(1000); ++ } ++} ++ ++/** ++ * pr_flush() - Wait for printing threads to catch up. ++ * ++ * @timeout_ms: The maximum time (in ms) to wait. ++ * @reset_on_progress: Reset the timeout if forward progress is seen. ++ * ++ * A value of 0 for @timeout_ms means no waiting will occur. A value of -1 ++ * represents infinite waiting. ++ * ++ * If @reset_on_progress is true, the timeout will be reset whenever any ++ * printer has been seen to make some forward progress. ++ * ++ * Context: Any context. ++ * Return: true if all enabled printers are caught up. ++ */ ++bool pr_flush(int timeout_ms, bool reset_on_progress) ++{ ++ int remaining = timeout_ms; ++ struct console *con; ++ u64 last_diff = 0; ++ bool may_sleep; ++ u64 printk_seq; ++ u64 diff; ++ u64 seq; ++ ++ may_sleep = (preemptible() && ++ !in_softirq() && ++ system_state >= SYSTEM_RUNNING); ++ ++ seq = prb_next_seq(prb); ++ ++ for (;;) { ++ diff = 0; ++ ++ for_each_console(con) { ++ if (!(con->flags & CON_ENABLED)) ++ continue; ++ printk_seq = read_console_seq(con); ++ if (printk_seq < seq) ++ diff += seq - printk_seq; ++ } ++ ++ if (diff != last_diff && reset_on_progress) ++ remaining = timeout_ms; ++ ++ if (diff == 0 || remaining == 0) ++ break; ++ ++ if (remaining < 0) { ++ pr_msleep(may_sleep, 100); ++ } else if (remaining < 100) { ++ pr_msleep(may_sleep, remaining); ++ remaining = 0; ++ } else { ++ pr_msleep(may_sleep, 100); ++ remaining -= 100; ++ } ++ ++ last_diff = diff; ++ } ++ ++ return (diff == 0); ++} ++EXPORT_SYMBOL(pr_flush); ++#endif /* CONFIG_PRINTK */ +diff --git a/kernel/ptrace.c b/kernel/ptrace.c +index 0cf547531ddf..0df2de214daa 100644 +--- a/kernel/ptrace.c ++++ b/kernel/ptrace.c +@@ -197,7 +197,18 @@ static bool ptrace_freeze_traced(struct task_struct *task) + spin_lock_irq(&task->sighand->siglock); + if (task_is_traced(task) && !looks_like_a_spurious_pid(task) && + !__fatal_signal_pending(task)) { ++#ifdef CONFIG_PREEMPT_RT ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&task->pi_lock, flags); ++ if (READ_ONCE(task->__state) & __TASK_TRACED) ++ WRITE_ONCE(task->__state, __TASK_TRACED); ++ else ++ task->saved_state = __TASK_TRACED; ++ raw_spin_unlock_irqrestore(&task->pi_lock, flags); ++#else + WRITE_ONCE(task->__state, __TASK_TRACED); ++#endif + ret = true; + } + spin_unlock_irq(&task->sighand->siglock); +@@ -207,7 +218,11 @@ static bool ptrace_freeze_traced(struct task_struct *task) + + static void ptrace_unfreeze_traced(struct task_struct *task) + { +- if (READ_ONCE(task->__state) != __TASK_TRACED) ++ unsigned long flags; ++ bool frozen = true; ++ ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT) && ++ READ_ONCE(task->__state) != __TASK_TRACED) + return; + + WARN_ON(!task->ptrace || task->parent != current); +@@ -217,12 +232,21 @@ static void ptrace_unfreeze_traced(struct task_struct *task) + * Recheck state under the lock to close this race. + */ + spin_lock_irq(&task->sighand->siglock); +- if (READ_ONCE(task->__state) == __TASK_TRACED) { +- if (__fatal_signal_pending(task)) +- wake_up_state(task, __TASK_TRACED); +- else +- WRITE_ONCE(task->__state, TASK_TRACED); +- } ++ raw_spin_lock_irqsave(&task->pi_lock, flags); ++ if (READ_ONCE(task->__state) == __TASK_TRACED) ++ WRITE_ONCE(task->__state, TASK_TRACED); ++ ++#ifdef CONFIG_PREEMPT_RT ++ else if (task->saved_state == __TASK_TRACED) ++ task->saved_state = TASK_TRACED; ++#endif ++ else ++ frozen = false; ++ raw_spin_unlock_irqrestore(&task->pi_lock, flags); ++ ++ if (frozen && __fatal_signal_pending(task)) ++ wake_up_state(task, __TASK_TRACED); ++ + spin_unlock_irq(&task->sighand->siglock); + } + +diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h +index 94b8ee84bc78..509ea934305c 100644 +--- a/kernel/rcu/tasks.h ++++ b/kernel/rcu/tasks.h +@@ -1362,7 +1362,7 @@ static void test_rcu_tasks_callback(struct rcu_head *rhp) + rttd->notrun = true; + } + +-static void rcu_tasks_initiate_self_tests(void) ++void rcu_tasks_initiate_self_tests(void) + { + pr_info("Running RCU-tasks wait API self tests\n"); + #ifdef CONFIG_TASKS_RCU +@@ -1399,9 +1399,7 @@ static int rcu_tasks_verify_self_tests(void) + return ret; + } + late_initcall(rcu_tasks_verify_self_tests); +-#else /* #ifdef CONFIG_PROVE_RCU */ +-static void rcu_tasks_initiate_self_tests(void) { } +-#endif /* #else #ifdef CONFIG_PROVE_RCU */ ++#endif /* #ifdef CONFIG_PROVE_RCU */ + + void __init rcu_init_tasks_generic(void) + { +@@ -1416,9 +1414,6 @@ void __init rcu_init_tasks_generic(void) + #ifdef CONFIG_TASKS_TRACE_RCU + rcu_spawn_tasks_trace_kthread(); + #endif +- +- // Run the self-tests. +- rcu_tasks_initiate_self_tests(); + } + + #else /* #ifdef CONFIG_TASKS_RCU_GENERIC */ +diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c +index df016f6d0662..8ea272f7eb18 100644 +--- a/kernel/rcu/tree.c ++++ b/kernel/rcu/tree.c +@@ -2280,13 +2280,13 @@ rcu_report_qs_rdp(struct rcu_data *rdp) + { + unsigned long flags; + unsigned long mask; +- bool needwake = false; +- const bool offloaded = rcu_rdp_is_offloaded(rdp); ++ bool offloaded, needwake = false; + struct rcu_node *rnp; + + WARN_ON_ONCE(rdp->cpu != smp_processor_id()); + rnp = rdp->mynode; + raw_spin_lock_irqsave_rcu_node(rnp, flags); ++ offloaded = rcu_rdp_is_offloaded(rdp); + if (rdp->cpu_no_qs.b.norm || rdp->gp_seq != rnp->gp_seq || + rdp->gpwrap) { + +@@ -2448,7 +2448,7 @@ static void rcu_do_batch(struct rcu_data *rdp) + int div; + bool __maybe_unused empty; + unsigned long flags; +- const bool offloaded = rcu_rdp_is_offloaded(rdp); ++ bool offloaded; + struct rcu_head *rhp; + struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl); + long bl, count = 0; +@@ -2474,6 +2474,7 @@ static void rcu_do_batch(struct rcu_data *rdp) + rcu_nocb_lock(rdp); + WARN_ON_ONCE(cpu_is_offline(smp_processor_id())); + pending = rcu_segcblist_n_cbs(&rdp->cblist); ++ offloaded = rcu_rdp_is_offloaded(rdp); + div = READ_ONCE(rcu_divisor); + div = div < 0 ? 7 : div > sizeof(long) * 8 - 2 ? sizeof(long) * 8 - 2 : div; + bl = max(rdp->blimit, pending >> div); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index d34a56f16d13..cd0983900823 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -75,7 +75,11 @@ __read_mostly int sysctl_resched_latency_warn_once = 1; + * Number of tasks to iterate in a single balance run. + * Limited because this is done with IRQs disabled. + */ ++#ifdef CONFIG_PREEMPT_RT ++const_debug unsigned int sysctl_sched_nr_migrate = 8; ++#else + const_debug unsigned int sysctl_sched_nr_migrate = 32; ++#endif + + /* + * period over which we measure -rt task CPU usage in us. +@@ -983,6 +987,46 @@ void resched_curr(struct rq *rq) + trace_sched_wake_idle_without_ipi(cpu); + } + ++#ifdef CONFIG_PREEMPT_LAZY ++ ++static int tsk_is_polling(struct task_struct *p) ++{ ++#ifdef TIF_POLLING_NRFLAG ++ return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); ++#else ++ return 0; ++#endif ++} ++ ++void resched_curr_lazy(struct rq *rq) ++{ ++ struct task_struct *curr = rq->curr; ++ int cpu; ++ ++ if (!sched_feat(PREEMPT_LAZY)) { ++ resched_curr(rq); ++ return; ++ } ++ ++ if (test_tsk_need_resched(curr)) ++ return; ++ ++ if (test_tsk_need_resched_lazy(curr)) ++ return; ++ ++ set_tsk_need_resched_lazy(curr); ++ ++ cpu = cpu_of(rq); ++ if (cpu == smp_processor_id()) ++ return; ++ ++ /* NEED_RESCHED_LAZY must be visible before we test polling */ ++ smp_mb(); ++ if (!tsk_is_polling(curr)) ++ smp_send_reschedule(cpu); ++} ++#endif ++ + void resched_cpu(int cpu) + { + struct rq *rq = cpu_rq(cpu); +@@ -2141,6 +2185,7 @@ void migrate_disable(void) + preempt_disable(); + this_rq()->nr_pinned++; + p->migration_disabled = 1; ++ preempt_lazy_disable(); + preempt_enable(); + } + EXPORT_SYMBOL_GPL(migrate_disable); +@@ -2152,6 +2197,8 @@ void migrate_enable(void) + if (p->migration_disabled > 1) { + p->migration_disabled--; + return; ++ } else if (WARN_ON_ONCE(p->migration_disabled == 0)) { ++ return; + } + + /* +@@ -2169,6 +2216,7 @@ void migrate_enable(void) + barrier(); + p->migration_disabled = 0; + this_rq()->nr_pinned--; ++ preempt_lazy_enable(); + preempt_enable(); + } + EXPORT_SYMBOL_GPL(migrate_enable); +@@ -3235,7 +3283,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state + * is actually now running somewhere else! + */ + while (task_running(rq, p)) { +- if (match_state && unlikely(READ_ONCE(p->__state) != match_state)) ++ if (match_state && !task_match_state_lock(p, match_state)) + return 0; + cpu_relax(); + } +@@ -3250,7 +3298,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state + running = task_running(rq, p); + queued = task_on_rq_queued(p); + ncsw = 0; +- if (!match_state || READ_ONCE(p->__state) == match_state) ++ if (!match_state || task_match_state_or_saved(p, match_state)) + ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ + task_rq_unlock(rq, p, &rf); + +@@ -3284,7 +3332,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state + ktime_t to = NSEC_PER_SEC / HZ; + + set_current_state(TASK_UNINTERRUPTIBLE); +- schedule_hrtimeout(&to, HRTIMER_MODE_REL); ++ schedule_hrtimeout(&to, HRTIMER_MODE_REL_HARD); + continue; + } + +@@ -4427,6 +4475,9 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) + p->on_cpu = 0; + #endif + init_task_preempt_count(p); ++#ifdef CONFIG_HAVE_PREEMPT_LAZY ++ task_thread_info(p)->preempt_lazy_count = 0; ++#endif + #ifdef CONFIG_SMP + plist_node_init(&p->pushable_tasks, MAX_PRIO); + RB_CLEAR_NODE(&p->pushable_dl_tasks); +@@ -4922,20 +4973,18 @@ static struct rq *finish_task_switch(struct task_struct *prev) + */ + if (mm) { + membarrier_mm_sync_core_before_usermode(mm); +- mmdrop(mm); ++ mmdrop_sched(mm); + } + if (unlikely(prev_state == TASK_DEAD)) { + if (prev->sched_class->task_dead) + prev->sched_class->task_dead(prev); + + /* +- * Remove function-return probe instances associated with this +- * task and put them back on the free list. ++ * Release VMAP'ed task stack immediate for reuse. On RT ++ * enabled kernels this is delayed for latency reasons. + */ +- kprobe_flush_task(prev); +- +- /* Task is done with its stack. */ +- put_task_stack(prev); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ put_task_stack(prev); + + put_task_struct_rcu_user(prev); + } +@@ -6335,6 +6384,7 @@ static void __sched notrace __schedule(unsigned int sched_mode) + + next = pick_next_task(rq, prev, &rf); + clear_tsk_need_resched(prev); ++ clear_tsk_need_resched_lazy(prev); + clear_preempt_need_resched(); + #ifdef CONFIG_SCHED_DEBUG + rq->last_seen_need_resched_ns = 0; +@@ -6556,6 +6606,30 @@ static void __sched notrace preempt_schedule_common(void) + } while (need_resched()); + } + ++#ifdef CONFIG_PREEMPT_LAZY ++/* ++ * If TIF_NEED_RESCHED is then we allow to be scheduled away since this is ++ * set by a RT task. Oterwise we try to avoid beeing scheduled out as long as ++ * preempt_lazy_count counter >0. ++ */ ++static __always_inline int preemptible_lazy(void) ++{ ++ if (test_thread_flag(TIF_NEED_RESCHED)) ++ return 1; ++ if (current_thread_info()->preempt_lazy_count) ++ return 0; ++ return 1; ++} ++ ++#else ++ ++static inline int preemptible_lazy(void) ++{ ++ return 1; ++} ++ ++#endif ++ + #ifdef CONFIG_PREEMPTION + /* + * This is the entry point to schedule() from in-kernel preemption +@@ -6569,7 +6643,8 @@ asmlinkage __visible void __sched notrace preempt_schedule(void) + */ + if (likely(!preemptible())) + return; +- ++ if (!preemptible_lazy()) ++ return; + preempt_schedule_common(); + } + NOKPROBE_SYMBOL(preempt_schedule); +@@ -6602,6 +6677,9 @@ asmlinkage __visible void __sched notrace preempt_schedule_notrace(void) + if (likely(!preemptible())) + return; + ++ if (!preemptible_lazy()) ++ return; ++ + do { + /* + * Because the function tracer can trace preempt_count_sub() +@@ -8754,7 +8832,9 @@ void __init init_idle(struct task_struct *idle, int cpu) + + /* Set the preempt count _outside_ the spinlocks! */ + init_idle_preempt_count(idle, cpu); +- ++#ifdef CONFIG_HAVE_PREEMPT_LAZY ++ task_thread_info(idle)->preempt_lazy_count = 0; ++#endif + /* + * The idle tasks have their own, simple scheduling class: + */ +@@ -9555,14 +9635,8 @@ void __init sched_init(void) + } + + #ifdef CONFIG_DEBUG_ATOMIC_SLEEP +-static inline int preempt_count_equals(int preempt_offset) +-{ +- int nested = preempt_count() + rcu_preempt_depth(); +- +- return (nested == preempt_offset); +-} + +-void __might_sleep(const char *file, int line, int preempt_offset) ++void __might_sleep(const char *file, int line) + { + unsigned int state = get_current_state(); + /* +@@ -9576,11 +9650,32 @@ void __might_sleep(const char *file, int line, int preempt_offset) + (void *)current->task_state_change, + (void *)current->task_state_change); + +- ___might_sleep(file, line, preempt_offset); ++ __might_resched(file, line, 0); + } + EXPORT_SYMBOL(__might_sleep); + +-void ___might_sleep(const char *file, int line, int preempt_offset) ++static void print_preempt_disable_ip(int preempt_offset, unsigned long ip) ++{ ++ if (!IS_ENABLED(CONFIG_DEBUG_PREEMPT)) ++ return; ++ ++ if (preempt_count() == preempt_offset) ++ return; ++ ++ pr_err("Preemption disabled at:"); ++ print_ip_sym(KERN_ERR, ip); ++} ++ ++static inline bool resched_offsets_ok(unsigned int offsets) ++{ ++ unsigned int nested = preempt_count(); ++ ++ nested += rcu_preempt_depth() << MIGHT_RESCHED_RCU_SHIFT; ++ ++ return nested == offsets; ++} ++ ++void __might_resched(const char *file, int line, unsigned int offsets) + { + /* Ratelimiting timestamp: */ + static unsigned long prev_jiffy; +@@ -9590,7 +9685,7 @@ void ___might_sleep(const char *file, int line, int preempt_offset) + /* WARN_ON_ONCE() by default, no rate limit required: */ + rcu_sleep_check(); + +- if ((preempt_count_equals(preempt_offset) && !irqs_disabled() && ++ if ((resched_offsets_ok(offsets) && !irqs_disabled() && + !is_idle_task(current) && !current->non_block_count) || + system_state == SYSTEM_BOOTING || system_state > SYSTEM_RUNNING || + oops_in_progress) +@@ -9603,29 +9698,33 @@ void ___might_sleep(const char *file, int line, int preempt_offset) + /* Save this before calling printk(), since that will clobber it: */ + preempt_disable_ip = get_preempt_disable_ip(current); + +- printk(KERN_ERR +- "BUG: sleeping function called from invalid context at %s:%d\n", +- file, line); +- printk(KERN_ERR +- "in_atomic(): %d, irqs_disabled(): %d, non_block: %d, pid: %d, name: %s\n", +- in_atomic(), irqs_disabled(), current->non_block_count, +- current->pid, current->comm); ++ pr_err("BUG: sleeping function called from invalid context at %s:%d\n", ++ file, line); ++ pr_err("in_atomic(): %d, irqs_disabled(): %d, non_block: %d, pid: %d, name: %s\n", ++ in_atomic(), irqs_disabled(), current->non_block_count, ++ current->pid, current->comm); ++ pr_err("preempt_count: %x, expected: %x\n", preempt_count(), ++ offsets & MIGHT_RESCHED_PREEMPT_MASK); ++ ++ if (IS_ENABLED(CONFIG_PREEMPT_RCU)) { ++ pr_err("RCU nest depth: %d, expected: %u\n", ++ rcu_preempt_depth(), offsets >> MIGHT_RESCHED_RCU_SHIFT); ++ } + + if (task_stack_end_corrupted(current)) +- printk(KERN_EMERG "Thread overran stack, or stack corrupted\n"); ++ pr_emerg("Thread overran stack, or stack corrupted\n"); + + debug_show_held_locks(current); + if (irqs_disabled()) + print_irqtrace_events(current); +- if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) +- && !preempt_count_equals(preempt_offset)) { +- pr_err("Preemption disabled at:"); +- print_ip_sym(KERN_ERR, preempt_disable_ip); +- } ++ ++ print_preempt_disable_ip(offsets & MIGHT_RESCHED_PREEMPT_MASK, ++ preempt_disable_ip); ++ + dump_stack(); + add_taint(TAINT_WARN, LOCKDEP_STILL_OK); + } +-EXPORT_SYMBOL(___might_sleep); ++EXPORT_SYMBOL(__might_resched); + + void __cant_sleep(const char *file, int line, int preempt_offset) + { +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 646a6ae4b250..c02ecc105f0c 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -4651,7 +4651,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) + ideal_runtime = sched_slice(cfs_rq, curr); + delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; + if (delta_exec > ideal_runtime) { +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + /* + * The current task ran long enough, ensure it doesn't get + * re-elected due to buddy favours. +@@ -4675,7 +4675,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) + return; + + if (delta > ideal_runtime) +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + } + + static void +@@ -4821,7 +4821,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) + * validating it and just reschedule. + */ + if (queued) { +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + return; + } + /* +@@ -4961,7 +4961,7 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) + * hierarchy can be throttled + */ + if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr)) +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + } + + static __always_inline +@@ -5724,7 +5724,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p) + + if (delta < 0) { + if (task_current(rq, p)) +- resched_curr(rq); ++ resched_curr_lazy(rq); + return; + } + hrtick_start(rq, delta); +@@ -7449,7 +7449,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ + return; + + preempt: +- resched_curr(rq); ++ resched_curr_lazy(rq); + /* + * Only set the backward buddy when the current task is still + * on the rq. This can happen when a wakeup gets interleaved +@@ -11508,7 +11508,7 @@ static void task_fork_fair(struct task_struct *p) + * 'current' within the tree based on its new key value. + */ + swap(curr->vruntime, se->vruntime); +- resched_curr(rq); ++ resched_curr_lazy(rq); + } + + se->vruntime -= cfs_rq->min_vruntime; +@@ -11535,7 +11535,7 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) + */ + if (task_current(rq, p)) { + if (p->prio > oldprio) +- resched_curr(rq); ++ resched_curr_lazy(rq); + } else + check_preempt_curr(rq, p, 0); + } +diff --git a/kernel/sched/features.h b/kernel/sched/features.h +index c4947c1b5edb..e13090e33f3c 100644 +--- a/kernel/sched/features.h ++++ b/kernel/sched/features.h +@@ -46,11 +46,19 @@ SCHED_FEAT(DOUBLE_TICK, false) + */ + SCHED_FEAT(NONTASK_CAPACITY, true) + ++#ifdef CONFIG_PREEMPT_RT ++SCHED_FEAT(TTWU_QUEUE, false) ++# ifdef CONFIG_PREEMPT_LAZY ++SCHED_FEAT(PREEMPT_LAZY, true) ++# endif ++#else ++ + /* + * Queue remote wakeups on the target CPU and process them + * using the scheduler IPI. Reduces rq->lock contention/bounces. + */ + SCHED_FEAT(TTWU_QUEUE, true) ++#endif + + /* + * When doing wakeups, attempt to limit superfluous scans of the LLC domain. +diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h +index 6312f1904825..36483b794a00 100644 +--- a/kernel/sched/sched.h ++++ b/kernel/sched/sched.h +@@ -2327,6 +2327,15 @@ extern void reweight_task(struct task_struct *p, int prio); + extern void resched_curr(struct rq *rq); + extern void resched_cpu(int cpu); + ++#ifdef CONFIG_PREEMPT_LAZY ++extern void resched_curr_lazy(struct rq *rq); ++#else ++static inline void resched_curr_lazy(struct rq *rq) ++{ ++ resched_curr(rq); ++} ++#endif ++ + extern struct rt_bandwidth def_rt_bandwidth; + extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime); + +diff --git a/kernel/sched/swait.c b/kernel/sched/swait.c +index e1c655f928c7..f230b1ac7f91 100644 +--- a/kernel/sched/swait.c ++++ b/kernel/sched/swait.c +@@ -64,6 +64,7 @@ void swake_up_all(struct swait_queue_head *q) + struct swait_queue *curr; + LIST_HEAD(tmp); + ++ WARN_ON(irqs_disabled()); + raw_spin_lock_irq(&q->lock); + list_splice_init(&q->task_list, &tmp); + while (!list_empty(&tmp)) { +diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c +index 4e8698e62f07..3d0157bd4e14 100644 +--- a/kernel/sched/topology.c ++++ b/kernel/sched/topology.c +@@ -526,7 +526,7 @@ static int init_rootdomain(struct root_domain *rd) + #ifdef HAVE_RT_PUSH_IPI + rd->rto_cpu = -1; + raw_spin_lock_init(&rd->rto_lock); +- init_irq_work(&rd->rto_push_work, rto_push_irq_work_func); ++ rd->rto_push_work = IRQ_WORK_INIT_HARD(rto_push_irq_work_func); + #endif + + rd->visit_gen = 0; +diff --git a/kernel/signal.c b/kernel/signal.c +index c7dbb19219b9..0bbd89fbf240 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -1324,6 +1324,34 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, + struct k_sigaction *action; + int sig = info->si_signo; + ++ /* ++ * On some archs, PREEMPT_RT has to delay sending a signal from a trap ++ * since it can not enable preemption, and the signal code's spin_locks ++ * turn into mutexes. Instead, it must set TIF_NOTIFY_RESUME which will ++ * send the signal on exit of the trap. ++ */ ++#ifdef ARCH_RT_DELAYS_SIGNAL_SEND ++ if (in_atomic()) { ++ struct task_struct *t = current; ++ ++ if (WARN_ON_ONCE(t->forced_info.si_signo)) ++ return 0; ++ ++ if (is_si_special(info)) { ++ WARN_ON_ONCE(info != SEND_SIG_PRIV); ++ t->forced_info.si_signo = info->si_signo; ++ t->forced_info.si_errno = 0; ++ t->forced_info.si_code = SI_KERNEL; ++ t->forced_info.si_pid = 0; ++ t->forced_info.si_uid = 0; ++ } else { ++ t->forced_info = *info; ++ } ++ ++ set_tsk_thread_flag(t, TIF_NOTIFY_RESUME); ++ return 0; ++ } ++#endif + spin_lock_irqsave(&t->sighand->siglock, flags); + action = &t->sighand->action[sig-1]; + ignored = action->sa.sa_handler == SIG_IGN; +@@ -2308,16 +2336,8 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t + if (gstop_done && ptrace_reparented(current)) + do_notify_parent_cldstop(current, false, why); + +- /* +- * Don't want to allow preemption here, because +- * sys_ptrace() needs this task to be inactive. +- * +- * XXX: implement read_unlock_no_resched(). +- */ +- preempt_disable(); + read_unlock(&tasklist_lock); + cgroup_enter_frozen(); +- preempt_enable_no_resched(); + freezable_schedule(); + cgroup_leave_frozen(true); + } else { +diff --git a/kernel/smp.c b/kernel/smp.c +index 82825345432c..9d3c8c56d904 100644 +--- a/kernel/smp.c ++++ b/kernel/smp.c +@@ -690,10 +690,20 @@ void flush_smp_call_function_from_idle(void) + + cfd_seq_store(this_cpu_ptr(&cfd_seq_local)->idle, CFD_SEQ_NOCPU, + smp_processor_id(), CFD_SEQ_IDLE); ++ + local_irq_save(flags); + flush_smp_call_function_queue(true); +- if (local_softirq_pending()) +- do_softirq(); ++ ++ if (local_softirq_pending()) { ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ do_softirq(); ++ } else { ++ struct task_struct *ksoftirqd = this_cpu_ksoftirqd(); ++ ++ if (ksoftirqd && !task_is_running(ksoftirqd)) ++ wake_up_process(ksoftirqd); ++ } ++ } + + local_irq_restore(flags); + } +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 0202f23ae960..7fc118c87b9d 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -2646,7 +2646,13 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status) + trace_flags |= TRACE_FLAG_NEED_RESCHED; + if (test_preempt_need_resched()) + trace_flags |= TRACE_FLAG_PREEMPT_RESCHED; +- return (trace_flags << 16) | (min_t(unsigned int, pc & 0xff, 0xf)) | ++#ifdef CONFIG_PREEMPT_LAZY ++ if (need_resched_lazy()) ++ trace_flags |= TRACE_FLAG_NEED_RESCHED_LAZY; ++#endif ++ ++ return (trace_flags << 24) | (min_t(unsigned int, pc & 0xff, 0xf)) | ++ (preempt_lazy_count() & 0xff) << 16 | + (min_t(unsigned int, migration_disable_value(), 0xf)) << 4; + } + +@@ -4227,15 +4233,17 @@ unsigned long trace_total_entries(struct trace_array *tr) + + static void print_lat_help_header(struct seq_file *m) + { +- seq_puts(m, "# _------=> CPU# \n" +- "# / _-----=> irqs-off \n" +- "# | / _----=> need-resched \n" +- "# || / _---=> hardirq/softirq \n" +- "# ||| / _--=> preempt-depth \n" +- "# |||| / _-=> migrate-disable \n" +- "# ||||| / delay \n" +- "# cmd pid |||||| time | caller \n" +- "# \\ / |||||| \\ | / \n"); ++ seq_puts(m, "# _--------=> CPU# \n" ++ "# / _-------=> irqs-off \n" ++ "# | / _------=> need-resched \n" ++ "# || / _-----=> need-resched-lazy\n" ++ "# ||| / _----=> hardirq/softirq \n" ++ "# |||| / _---=> preempt-depth \n" ++ "# ||||| / _--=> preempt-lazy-depth\n" ++ "# |||||| / _-=> migrate-disable \n" ++ "# ||||||| / delay \n" ++ "# cmd pid |||||||| time | caller \n" ++ "# \\ / |||||||| \\ | / \n"); + } + + static void print_event_info(struct array_buffer *buf, struct seq_file *m) +@@ -4269,14 +4277,16 @@ static void print_func_help_header_irq(struct array_buffer *buf, struct seq_file + + print_event_info(buf, m); + +- seq_printf(m, "# %.*s _-----=> irqs-off\n", prec, space); +- seq_printf(m, "# %.*s / _----=> need-resched\n", prec, space); +- seq_printf(m, "# %.*s| / _---=> hardirq/softirq\n", prec, space); +- seq_printf(m, "# %.*s|| / _--=> preempt-depth\n", prec, space); +- seq_printf(m, "# %.*s||| / _-=> migrate-disable\n", prec, space); +- seq_printf(m, "# %.*s|||| / delay\n", prec, space); +- seq_printf(m, "# TASK-PID %.*s CPU# ||||| TIMESTAMP FUNCTION\n", prec, " TGID "); +- seq_printf(m, "# | | %.*s | ||||| | |\n", prec, " | "); ++ seq_printf(m, "# %.*s _-------=> irqs-off\n", prec, space); ++ seq_printf(m, "# %.*s / _------=> need-resched\n", prec, space); ++ seq_printf(m, "# %.*s| / _-----=> need-resched-lazy\n", prec, space); ++ seq_printf(m, "# %.*s|| / _----=> hardirq/softirq\n", prec, space); ++ seq_printf(m, "# %.*s||| / _---=> preempt-depth\n", prec, space); ++ seq_printf(m, "# %.*s|||| / _--=> preempt-lazy-depth\n", prec, space); ++ seq_printf(m, "# %.*s||||| / _-=> migrate-disable\n", prec, space); ++ seq_printf(m, "# %.*s|||||| / delay\n", prec, space); ++ seq_printf(m, "# TASK-PID %.*s CPU# ||||||| TIMESTAMP FUNCTION\n", prec, " TGID "); ++ seq_printf(m, "# | | %.*s | ||||||| | |\n", prec, " | "); + } + + void +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 160298d285c0..9ec3c6c38cc3 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -193,6 +193,7 @@ static int trace_define_common_fields(void) + /* Holds both preempt_count and migrate_disable */ + __common_field(unsigned char, preempt_count); + __common_field(int, pid); ++ __common_field(unsigned char, preempt_lazy_count); + + return ret; + } +diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c +index 6b4d3f3abdae..460bc8245e4a 100644 +--- a/kernel/trace/trace_output.c ++++ b/kernel/trace/trace_output.c +@@ -451,6 +451,7 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) + { + char hardsoft_irq; + char need_resched; ++ char need_resched_lazy; + char irqs_off; + int hardirq; + int softirq; +@@ -481,6 +482,9 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) + break; + } + ++ need_resched_lazy = ++ (entry->flags & TRACE_FLAG_NEED_RESCHED_LAZY) ? 'L' : '.'; ++ + hardsoft_irq = + (nmi && hardirq) ? 'Z' : + nmi ? 'z' : +@@ -489,14 +493,20 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) + softirq ? 's' : + '.' ; + +- trace_seq_printf(s, "%c%c%c", +- irqs_off, need_resched, hardsoft_irq); ++ trace_seq_printf(s, "%c%c%c%c", ++ irqs_off, need_resched, need_resched_lazy, ++ hardsoft_irq); + + if (entry->preempt_count & 0xf) + trace_seq_printf(s, "%x", entry->preempt_count & 0xf); + else + trace_seq_putc(s, '.'); + ++ if (entry->preempt_lazy_count) ++ trace_seq_printf(s, "%x", entry->preempt_lazy_count); ++ else ++ trace_seq_putc(s, '.'); ++ + if (entry->preempt_count & 0xf0) + trace_seq_printf(s, "%x", entry->preempt_count >> 4); + else +diff --git a/lib/bug.c b/lib/bug.c +index 45a0584f6541..03a87df69ed2 100644 +--- a/lib/bug.c ++++ b/lib/bug.c +@@ -206,6 +206,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) + else + pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n", + (void *)bugaddr); ++ pr_flush(1000, true); + + return BUG_TRAP_TYPE_BUG; + } +diff --git a/lib/dump_stack.c b/lib/dump_stack.c +index 6b7f1bf6715d..6e8ae42c7e27 100644 +--- a/lib/dump_stack.c ++++ b/lib/dump_stack.c +@@ -102,9 +102,9 @@ asmlinkage __visible void dump_stack_lvl(const char *log_lvl) + * Permit this cpu to perform nested stack dumps while serialising + * against other CPUs + */ +- printk_cpu_lock_irqsave(flags); ++ raw_printk_cpu_lock_irqsave(flags); + __dump_stack(log_lvl); +- printk_cpu_unlock_irqrestore(flags); ++ raw_printk_cpu_unlock_irqrestore(flags); + } + EXPORT_SYMBOL(dump_stack_lvl); + +diff --git a/lib/irq_poll.c b/lib/irq_poll.c +index 2f17b488d58e..2b9f797642f6 100644 +--- a/lib/irq_poll.c ++++ b/lib/irq_poll.c +@@ -191,11 +191,13 @@ static int irq_poll_cpu_dead(unsigned int cpu) + * If a CPU goes away, splice its entries to the current CPU + * and trigger a run of the softirq + */ ++ local_bh_disable(); + local_irq_disable(); + list_splice_init(&per_cpu(blk_cpu_iopoll, cpu), + this_cpu_ptr(&blk_cpu_iopoll)); + __raise_softirq_irqoff(IRQ_POLL_SOFTIRQ); + local_irq_enable(); ++ local_bh_enable(); + + return 0; + } +diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c +index 161108e5d2fe..1266ea3726d7 100644 +--- a/lib/locking-selftest.c ++++ b/lib/locking-selftest.c +@@ -26,6 +26,12 @@ + #include + #include + ++#ifdef CONFIG_PREEMPT_RT ++# define NON_RT(...) ++#else ++# define NON_RT(...) __VA_ARGS__ ++#endif ++ + /* + * Change this to 1 if you want to see the failure printouts: + */ +@@ -139,7 +145,7 @@ static DEFINE_RT_MUTEX(rtmutex_Z2); + + #endif + +-static local_lock_t local_A = INIT_LOCAL_LOCK(local_A); ++static DEFINE_PER_CPU(local_lock_t, local_A); + + /* + * non-inlined runtime initializers, to let separate locks share +@@ -712,12 +718,18 @@ GENERATE_TESTCASE(ABCDBCDA_rtmutex); + + #undef E + ++#ifdef CONFIG_PREEMPT_RT ++# define RT_PREPARE_DBL_UNLOCK() { migrate_disable(); rcu_read_lock(); } ++#else ++# define RT_PREPARE_DBL_UNLOCK() ++#endif + /* + * Double unlock: + */ + #define E() \ + \ + LOCK(A); \ ++ RT_PREPARE_DBL_UNLOCK(); \ + UNLOCK(A); \ + UNLOCK(A); /* fail */ + +@@ -802,6 +814,7 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_rlock) + #include "locking-selftest-wlock-hardirq.h" + GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-spin-softirq.h" + GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_spin) + +@@ -810,10 +823,12 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_rlock) + + #include "locking-selftest-wlock-softirq.h" + GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_wlock) ++#endif + + #undef E1 + #undef E2 + ++#ifndef CONFIG_PREEMPT_RT + /* + * Enabling hardirqs with a softirq-safe lock held: + */ +@@ -846,6 +861,8 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2A_rlock) + #undef E1 + #undef E2 + ++#endif ++ + /* + * Enabling irqs with an irq-safe lock held: + */ +@@ -875,6 +892,7 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_hard_rlock) + #include "locking-selftest-wlock-hardirq.h" + GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-spin-softirq.h" + GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_spin) + +@@ -883,6 +901,7 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_rlock) + + #include "locking-selftest-wlock-softirq.h" + GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_wlock) ++#endif + + #undef E1 + #undef E2 +@@ -921,6 +940,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_hard_rlock) + #include "locking-selftest-wlock-hardirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-spin-softirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_spin) + +@@ -929,6 +949,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_rlock) + + #include "locking-selftest-wlock-softirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_wlock) ++#endif + + #undef E1 + #undef E2 +@@ -969,6 +990,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_hard_rlock) + #include "locking-selftest-wlock-hardirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-spin-softirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_spin) + +@@ -977,6 +999,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_rlock) + + #include "locking-selftest-wlock-softirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_wlock) ++#endif + + #undef E1 + #undef E2 +@@ -1031,6 +1054,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_hard_rlock) + #include "locking-selftest-wlock-hardirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-spin-softirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_spin) + +@@ -1039,6 +1063,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_rlock) + + #include "locking-selftest-wlock-softirq.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_wlock) ++#endif + + #undef E1 + #undef E2 +@@ -1206,12 +1231,14 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_rlock) + #include "locking-selftest-wlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-softirq.h" + #include "locking-selftest-rlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_rlock) + + #include "locking-selftest-wlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_wlock) ++#endif + + #undef E1 + #undef E2 +@@ -1252,12 +1279,14 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_rlock) + #include "locking-selftest-wlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-softirq.h" + #include "locking-selftest-rlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_rlock) + + #include "locking-selftest-wlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_wlock) ++#endif + + #undef E1 + #undef E2 +@@ -1306,12 +1335,14 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_rlock) + #include "locking-selftest-wlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_wlock) + ++#ifndef CONFIG_PREEMPT_RT + #include "locking-selftest-softirq.h" + #include "locking-selftest-rlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_rlock) + + #include "locking-selftest-wlock.h" + GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_wlock) ++#endif + + #ifdef CONFIG_DEBUG_LOCK_ALLOC + # define I_SPINLOCK(x) lockdep_reset_lock(&lock_##x.dep_map) +@@ -1320,7 +1351,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_wlock) + # define I_MUTEX(x) lockdep_reset_lock(&mutex_##x.dep_map) + # define I_RWSEM(x) lockdep_reset_lock(&rwsem_##x.dep_map) + # define I_WW(x) lockdep_reset_lock(&x.dep_map) +-# define I_LOCAL_LOCK(x) lockdep_reset_lock(&local_##x.dep_map) ++# define I_LOCAL_LOCK(x) lockdep_reset_lock(this_cpu_ptr(&local_##x.dep_map)) + #ifdef CONFIG_RT_MUTEXES + # define I_RTMUTEX(x) lockdep_reset_lock(&rtmutex_##x.dep_map) + #endif +@@ -1380,7 +1411,7 @@ static void reset_locks(void) + init_shared_classes(); + raw_spin_lock_init(&raw_lock_A); + raw_spin_lock_init(&raw_lock_B); +- local_lock_init(&local_A); ++ local_lock_init(this_cpu_ptr(&local_A)); + + ww_mutex_init(&o, &ww_lockdep); ww_mutex_init(&o2, &ww_lockdep); ww_mutex_init(&o3, &ww_lockdep); + memset(&t, 0, sizeof(t)); memset(&t2, 0, sizeof(t2)); +@@ -1398,7 +1429,13 @@ static int unexpected_testcase_failures; + + static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask) + { +- unsigned long saved_preempt_count = preempt_count(); ++ int saved_preempt_count = preempt_count(); ++#ifdef CONFIG_PREEMPT_RT ++#ifdef CONFIG_SMP ++ int saved_mgd_count = current->migration_disabled; ++#endif ++ int saved_rcu_count = current->rcu_read_lock_nesting; ++#endif + + WARN_ON(irqs_disabled()); + +@@ -1432,6 +1469,18 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask) + * count, so restore it: + */ + preempt_count_set(saved_preempt_count); ++ ++#ifdef CONFIG_PREEMPT_RT ++#ifdef CONFIG_SMP ++ while (current->migration_disabled > saved_mgd_count) ++ migrate_enable(); ++#endif ++ ++ while (current->rcu_read_lock_nesting > saved_rcu_count) ++ rcu_read_unlock(); ++ WARN_ON_ONCE(current->rcu_read_lock_nesting < saved_rcu_count); ++#endif ++ + #ifdef CONFIG_TRACE_IRQFLAGS + if (softirq_count()) + current->softirqs_enabled = 0; +@@ -1499,7 +1548,7 @@ static inline void print_testname(const char *testname) + + #define DO_TESTCASE_2x2RW(desc, name, nr) \ + DO_TESTCASE_2RW("hard-"desc, name##_hard, nr) \ +- DO_TESTCASE_2RW("soft-"desc, name##_soft, nr) \ ++ NON_RT(DO_TESTCASE_2RW("soft-"desc, name##_soft, nr)) \ + + #define DO_TESTCASE_6x2x2RW(desc, name) \ + DO_TESTCASE_2x2RW(desc, name, 123); \ +@@ -1547,19 +1596,19 @@ static inline void print_testname(const char *testname) + + #define DO_TESTCASE_2I(desc, name, nr) \ + DO_TESTCASE_1("hard-"desc, name##_hard, nr); \ +- DO_TESTCASE_1("soft-"desc, name##_soft, nr); ++ NON_RT(DO_TESTCASE_1("soft-"desc, name##_soft, nr)); + + #define DO_TESTCASE_2IB(desc, name, nr) \ + DO_TESTCASE_1B("hard-"desc, name##_hard, nr); \ +- DO_TESTCASE_1B("soft-"desc, name##_soft, nr); ++ NON_RT(DO_TESTCASE_1B("soft-"desc, name##_soft, nr)); + + #define DO_TESTCASE_6I(desc, name, nr) \ + DO_TESTCASE_3("hard-"desc, name##_hard, nr); \ +- DO_TESTCASE_3("soft-"desc, name##_soft, nr); ++ NON_RT(DO_TESTCASE_3("soft-"desc, name##_soft, nr)); + + #define DO_TESTCASE_6IRW(desc, name, nr) \ + DO_TESTCASE_3RW("hard-"desc, name##_hard, nr); \ +- DO_TESTCASE_3RW("soft-"desc, name##_soft, nr); ++ NON_RT(DO_TESTCASE_3RW("soft-"desc, name##_soft, nr)); + + #define DO_TESTCASE_2x3(desc, name) \ + DO_TESTCASE_3(desc, name, 12); \ +@@ -1651,6 +1700,20 @@ static void ww_test_fail_acquire(void) + #endif + } + ++#ifdef CONFIG_PREEMPT_RT ++#define ww_mutex_base_lock(b) rt_mutex_lock(b) ++#define ww_mutex_base_lock_nest_lock(b, b2) rt_mutex_lock_nest_lock(b, b2) ++#define ww_mutex_base_lock_interruptible(b) rt_mutex_lock_interruptible(b) ++#define ww_mutex_base_lock_killable(b) rt_mutex_lock_killable(b) ++#define ww_mutex_base_unlock(b) rt_mutex_unlock(b) ++#else ++#define ww_mutex_base_lock(b) mutex_lock(b) ++#define ww_mutex_base_lock_nest_lock(b, b2) mutex_lock_nest_lock(b, b2) ++#define ww_mutex_base_lock_interruptible(b) mutex_lock_interruptible(b) ++#define ww_mutex_base_lock_killable(b) mutex_lock_killable(b) ++#define ww_mutex_base_unlock(b) mutex_unlock(b) ++#endif ++ + static void ww_test_normal(void) + { + int ret; +@@ -1665,50 +1728,50 @@ static void ww_test_normal(void) + + /* mutex_lock (and indirectly, mutex_lock_nested) */ + o.ctx = (void *)~0UL; +- mutex_lock(&o.base); +- mutex_unlock(&o.base); ++ ww_mutex_base_lock(&o.base); ++ ww_mutex_base_unlock(&o.base); + WARN_ON(o.ctx != (void *)~0UL); + + /* mutex_lock_interruptible (and *_nested) */ + o.ctx = (void *)~0UL; +- ret = mutex_lock_interruptible(&o.base); ++ ret = ww_mutex_base_lock_interruptible(&o.base); + if (!ret) +- mutex_unlock(&o.base); ++ ww_mutex_base_unlock(&o.base); + else + WARN_ON(1); + WARN_ON(o.ctx != (void *)~0UL); + + /* mutex_lock_killable (and *_nested) */ + o.ctx = (void *)~0UL; +- ret = mutex_lock_killable(&o.base); ++ ret = ww_mutex_base_lock_killable(&o.base); + if (!ret) +- mutex_unlock(&o.base); ++ ww_mutex_base_unlock(&o.base); + else + WARN_ON(1); + WARN_ON(o.ctx != (void *)~0UL); + + /* trylock, succeeding */ + o.ctx = (void *)~0UL; +- ret = mutex_trylock(&o.base); ++ ret = ww_mutex_base_trylock(&o.base); + WARN_ON(!ret); + if (ret) +- mutex_unlock(&o.base); ++ ww_mutex_base_unlock(&o.base); + else + WARN_ON(1); + WARN_ON(o.ctx != (void *)~0UL); + + /* trylock, failing */ + o.ctx = (void *)~0UL; +- mutex_lock(&o.base); +- ret = mutex_trylock(&o.base); ++ ww_mutex_base_lock(&o.base); ++ ret = ww_mutex_base_trylock(&o.base); + WARN_ON(ret); +- mutex_unlock(&o.base); ++ ww_mutex_base_unlock(&o.base); + WARN_ON(o.ctx != (void *)~0UL); + + /* nest_lock */ + o.ctx = (void *)~0UL; +- mutex_lock_nest_lock(&o.base, &t); +- mutex_unlock(&o.base); ++ ww_mutex_base_lock_nest_lock(&o.base, &t); ++ ww_mutex_base_unlock(&o.base); + WARN_ON(o.ctx != (void *)~0UL); + } + +@@ -1721,7 +1784,7 @@ static void ww_test_two_contexts(void) + static void ww_test_diff_class(void) + { + WWAI(&t); +-#ifdef CONFIG_DEBUG_MUTEXES ++#ifdef DEBUG_WW_MUTEXES + t.ww_class = NULL; + #endif + WWL(&o, &t); +@@ -1785,7 +1848,7 @@ static void ww_test_edeadlk_normal(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + o2.ctx = &t2; + mutex_release(&o2.base.dep_map, _THIS_IP_); + +@@ -1801,7 +1864,7 @@ static void ww_test_edeadlk_normal(void) + + o2.ctx = NULL; + mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); +- mutex_unlock(&o2.base); ++ ww_mutex_base_unlock(&o2.base); + WWU(&o); + + WWL(&o2, &t); +@@ -1811,7 +1874,7 @@ static void ww_test_edeadlk_normal_slow(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +@@ -1827,7 +1890,7 @@ static void ww_test_edeadlk_normal_slow(void) + + o2.ctx = NULL; + mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); +- mutex_unlock(&o2.base); ++ ww_mutex_base_unlock(&o2.base); + WWU(&o); + + ww_mutex_lock_slow(&o2, &t); +@@ -1837,7 +1900,7 @@ static void ww_test_edeadlk_no_unlock(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + o2.ctx = &t2; + mutex_release(&o2.base.dep_map, _THIS_IP_); + +@@ -1853,7 +1916,7 @@ static void ww_test_edeadlk_no_unlock(void) + + o2.ctx = NULL; + mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); +- mutex_unlock(&o2.base); ++ ww_mutex_base_unlock(&o2.base); + + WWL(&o2, &t); + } +@@ -1862,7 +1925,7 @@ static void ww_test_edeadlk_no_unlock_slow(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +@@ -1878,7 +1941,7 @@ static void ww_test_edeadlk_no_unlock_slow(void) + + o2.ctx = NULL; + mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); +- mutex_unlock(&o2.base); ++ ww_mutex_base_unlock(&o2.base); + + ww_mutex_lock_slow(&o2, &t); + } +@@ -1887,7 +1950,7 @@ static void ww_test_edeadlk_acquire_more(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +@@ -1908,7 +1971,7 @@ static void ww_test_edeadlk_acquire_more_slow(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +@@ -1929,11 +1992,11 @@ static void ww_test_edeadlk_acquire_more_edeadlk(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +- mutex_lock(&o3.base); ++ ww_mutex_base_lock(&o3.base); + mutex_release(&o3.base.dep_map, _THIS_IP_); + o3.ctx = &t2; + +@@ -1955,11 +2018,11 @@ static void ww_test_edeadlk_acquire_more_edeadlk_slow(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +- mutex_lock(&o3.base); ++ ww_mutex_base_lock(&o3.base); + mutex_release(&o3.base.dep_map, _THIS_IP_); + o3.ctx = &t2; + +@@ -1980,7 +2043,7 @@ static void ww_test_edeadlk_acquire_wrong(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +@@ -2005,7 +2068,7 @@ static void ww_test_edeadlk_acquire_wrong_slow(void) + { + int ret; + +- mutex_lock(&o2.base); ++ ww_mutex_base_lock(&o2.base); + mutex_release(&o2.base.dep_map, _THIS_IP_); + o2.ctx = &t2; + +@@ -2646,8 +2709,8 @@ static void wait_context_tests(void) + + static void local_lock_2(void) + { +- local_lock_acquire(&local_A); /* IRQ-ON */ +- local_lock_release(&local_A); ++ local_lock(&local_A); /* IRQ-ON */ ++ local_unlock(&local_A); + + HARDIRQ_ENTER(); + spin_lock(&lock_A); /* IN-IRQ */ +@@ -2656,18 +2719,18 @@ static void local_lock_2(void) + + HARDIRQ_DISABLE(); + spin_lock(&lock_A); +- local_lock_acquire(&local_A); /* IN-IRQ <-> IRQ-ON cycle, false */ +- local_lock_release(&local_A); ++ local_lock(&local_A); /* IN-IRQ <-> IRQ-ON cycle, false */ ++ local_unlock(&local_A); + spin_unlock(&lock_A); + HARDIRQ_ENABLE(); + } + + static void local_lock_3A(void) + { +- local_lock_acquire(&local_A); /* IRQ-ON */ ++ local_lock(&local_A); /* IRQ-ON */ + spin_lock(&lock_B); /* IRQ-ON */ + spin_unlock(&lock_B); +- local_lock_release(&local_A); ++ local_unlock(&local_A); + + HARDIRQ_ENTER(); + spin_lock(&lock_A); /* IN-IRQ */ +@@ -2676,18 +2739,18 @@ static void local_lock_3A(void) + + HARDIRQ_DISABLE(); + spin_lock(&lock_A); +- local_lock_acquire(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ +- local_lock_release(&local_A); ++ local_lock(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ ++ local_unlock(&local_A); + spin_unlock(&lock_A); + HARDIRQ_ENABLE(); + } + + static void local_lock_3B(void) + { +- local_lock_acquire(&local_A); /* IRQ-ON */ ++ local_lock(&local_A); /* IRQ-ON */ + spin_lock(&lock_B); /* IRQ-ON */ + spin_unlock(&lock_B); +- local_lock_release(&local_A); ++ local_unlock(&local_A); + + HARDIRQ_ENTER(); + spin_lock(&lock_A); /* IN-IRQ */ +@@ -2696,8 +2759,8 @@ static void local_lock_3B(void) + + HARDIRQ_DISABLE(); + spin_lock(&lock_A); +- local_lock_acquire(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ +- local_lock_release(&local_A); ++ local_lock(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ ++ local_unlock(&local_A); + spin_unlock(&lock_A); + HARDIRQ_ENABLE(); + +@@ -2812,7 +2875,7 @@ void locking_selftest(void) + printk("------------------------\n"); + printk("| Locking API testsuite:\n"); + printk("----------------------------------------------------------------------------\n"); +- printk(" | spin |wlock |rlock |mutex | wsem | rsem |\n"); ++ printk(" | spin |wlock |rlock |mutex | wsem | rsem |rtmutex\n"); + printk(" --------------------------------------------------------------------------\n"); + + init_shared_classes(); +@@ -2885,12 +2948,11 @@ void locking_selftest(void) + DO_TESTCASE_6x1RR("rlock W1R2/R2R3/W3W1", W1R2_R2R3_W3W1); + + printk(" --------------------------------------------------------------------------\n"); +- + /* + * irq-context testcases: + */ + DO_TESTCASE_2x6("irqs-on + irq-safe-A", irqsafe1); +- DO_TESTCASE_2x3("sirq-safe-A => hirqs-on", irqsafe2A); ++ NON_RT(DO_TESTCASE_2x3("sirq-safe-A => hirqs-on", irqsafe2A)); + DO_TESTCASE_2x6("safe-A + irqs-on", irqsafe2B); + DO_TESTCASE_6x6("safe-A + unsafe-B #1", irqsafe3); + DO_TESTCASE_6x6("safe-A + unsafe-B #2", irqsafe4); +diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c +index 199ab201d501..06410209197a 100644 +--- a/lib/nmi_backtrace.c ++++ b/lib/nmi_backtrace.c +@@ -99,7 +99,7 @@ bool nmi_cpu_backtrace(struct pt_regs *regs) + * Allow nested NMI backtraces while serializing + * against other CPUs. + */ +- printk_cpu_lock_irqsave(flags); ++ raw_printk_cpu_lock_irqsave(flags); + if (!READ_ONCE(backtrace_idle) && regs && cpu_in_idle(instruction_pointer(regs))) { + pr_warn("NMI backtrace for cpu %d skipped: idling at %pS\n", + cpu, (void *)instruction_pointer(regs)); +@@ -110,7 +110,7 @@ bool nmi_cpu_backtrace(struct pt_regs *regs) + else + dump_stack(); + } +- printk_cpu_unlock_irqrestore(flags); ++ raw_printk_cpu_unlock_irqrestore(flags); + cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); + return true; + } +diff --git a/lib/scatterlist.c b/lib/scatterlist.c +index abb3432ed744..d5e82e4a57ad 100644 +--- a/lib/scatterlist.c ++++ b/lib/scatterlist.c +@@ -828,8 +828,7 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter) + * stops @miter. + * + * Context: +- * Don't care if @miter is stopped, or not proceeded yet. +- * Otherwise, preemption disabled if the SG_MITER_ATOMIC is set. ++ * Don't care. + * + * Returns: + * true if @miter contains the valid mapping. false if end of sg +@@ -865,8 +864,7 @@ EXPORT_SYMBOL(sg_miter_skip); + * @miter->addr and @miter->length point to the current mapping. + * + * Context: +- * Preemption disabled if SG_MITER_ATOMIC. Preemption must stay disabled +- * till @miter is stopped. May sleep if !SG_MITER_ATOMIC. ++ * May sleep if !SG_MITER_ATOMIC. + * + * Returns: + * true if @miter contains the next mapping. false if end of sg +@@ -906,8 +904,7 @@ EXPORT_SYMBOL(sg_miter_next); + * need to be released during iteration. + * + * Context: +- * Preemption disabled if the SG_MITER_ATOMIC is set. Don't care +- * otherwise. ++ * Don't care otherwise. + */ + void sg_miter_stop(struct sg_mapping_iter *miter) + { +@@ -922,7 +919,7 @@ void sg_miter_stop(struct sg_mapping_iter *miter) + flush_dcache_page(miter->page); + + if (miter->__flags & SG_MITER_ATOMIC) { +- WARN_ON_ONCE(preemptible()); ++ WARN_ON_ONCE(!pagefault_disabled()); + kunmap_atomic(miter->addr); + } else + kunmap(miter->page); +diff --git a/localversion-rt b/localversion-rt +new file mode 100644 +index 000000000000..e2eb19782d4c +--- /dev/null ++++ b/localversion-rt +@@ -0,0 +1 @@ ++-rt65 +diff --git a/mm/Kconfig b/mm/Kconfig +index c048dea7e342..88778414465b 100644 +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -371,7 +371,7 @@ config NOMMU_INITIAL_TRIM_EXCESS + + config TRANSPARENT_HUGEPAGE + bool "Transparent Hugepage Support" +- depends on HAVE_ARCH_TRANSPARENT_HUGEPAGE ++ depends on HAVE_ARCH_TRANSPARENT_HUGEPAGE && !PREEMPT_RT + select COMPACTION + select XARRAY_MULTI + help +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index b68b2fe639fd..71b7b7371595 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -654,6 +654,35 @@ static u64 flush_next_time; + + #define FLUSH_TIME (2UL*HZ) + ++/* ++ * Accessors to ensure that preemption is disabled on PREEMPT_RT because it can ++ * not rely on this as part of an acquired spinlock_t lock. These functions are ++ * never used in hardirq context on PREEMPT_RT and therefore disabling preemtion ++ * is sufficient. ++ */ ++static void memcg_stats_lock(void) ++{ ++#ifdef CONFIG_PREEMPT_RT ++ preempt_disable(); ++#else ++ VM_BUG_ON(!irqs_disabled()); ++#endif ++} ++ ++static void __memcg_stats_lock(void) ++{ ++#ifdef CONFIG_PREEMPT_RT ++ preempt_disable(); ++#endif ++} ++ ++static void memcg_stats_unlock(void) ++{ ++#ifdef CONFIG_PREEMPT_RT ++ preempt_enable(); ++#endif ++} ++ + static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val) + { + unsigned int x; +@@ -737,6 +766,27 @@ void __mod_memcg_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx, + pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec); + memcg = pn->memcg; + ++ /* ++ * The caller from rmap relay on disabled preemption becase they never ++ * update their counter from in-interrupt context. For these two ++ * counters we check that the update is never performed from an ++ * interrupt context while other caller need to have disabled interrupt. ++ */ ++ __memcg_stats_lock(); ++ if (IS_ENABLED(CONFIG_DEBUG_VM) && !IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ switch (idx) { ++ case NR_ANON_MAPPED: ++ case NR_FILE_MAPPED: ++ case NR_ANON_THPS: ++ case NR_SHMEM_PMDMAPPED: ++ case NR_FILE_PMDMAPPED: ++ WARN_ON_ONCE(!in_task()); ++ break; ++ default: ++ WARN_ON_ONCE(!irqs_disabled()); ++ } ++ } ++ + /* Update memcg */ + __this_cpu_add(memcg->vmstats_percpu->state[idx], val); + +@@ -744,6 +794,7 @@ void __mod_memcg_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx, + __this_cpu_add(pn->lruvec_stats_percpu->state[idx], val); + + memcg_rstat_updated(memcg, val); ++ memcg_stats_unlock(); + } + + /** +@@ -844,8 +895,10 @@ void __count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx, + if (mem_cgroup_disabled()) + return; + ++ memcg_stats_lock(); + __this_cpu_add(memcg->vmstats_percpu->events[idx], count); + memcg_rstat_updated(memcg, count); ++ memcg_stats_unlock(); + } + + static unsigned long memcg_events(struct mem_cgroup *memcg, int event) +@@ -909,6 +962,9 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg, + */ + static void memcg_check_events(struct mem_cgroup *memcg, struct page *page) + { ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ return; ++ + /* threshold event is triggered in finer grain than soft limit */ + if (unlikely(mem_cgroup_event_ratelimit(memcg, + MEM_CGROUP_TARGET_THRESH))) { +@@ -2102,39 +2158,37 @@ void unlock_page_memcg(struct page *page) + } + EXPORT_SYMBOL(unlock_page_memcg); + +-struct obj_stock { ++struct memcg_stock_pcp { ++ local_lock_t stock_lock; ++ struct mem_cgroup *cached; /* this never be root cgroup */ ++ unsigned int nr_pages; ++ + #ifdef CONFIG_MEMCG_KMEM + struct obj_cgroup *cached_objcg; + struct pglist_data *cached_pgdat; + unsigned int nr_bytes; + int nr_slab_reclaimable_b; + int nr_slab_unreclaimable_b; +-#else +- int dummy[0]; + #endif +-}; +- +-struct memcg_stock_pcp { +- struct mem_cgroup *cached; /* this never be root cgroup */ +- unsigned int nr_pages; +- struct obj_stock task_obj; +- struct obj_stock irq_obj; + + struct work_struct work; + unsigned long flags; + #define FLUSHING_CACHED_CHARGE 0 + }; +-static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock); ++static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock) = { ++ .stock_lock = INIT_LOCAL_LOCK(stock_lock), ++}; + static DEFINE_MUTEX(percpu_charge_mutex); + + #ifdef CONFIG_MEMCG_KMEM +-static void drain_obj_stock(struct obj_stock *stock); ++static struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock); + static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, + struct mem_cgroup *root_memcg); + + #else +-static inline void drain_obj_stock(struct obj_stock *stock) ++static inline struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock) + { ++ return NULL; + } + static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, + struct mem_cgroup *root_memcg) +@@ -2144,41 +2198,6 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, + #endif + + /* +- * Most kmem_cache_alloc() calls are from user context. The irq disable/enable +- * sequence used in this case to access content from object stock is slow. +- * To optimize for user context access, there are now two object stocks for +- * task context and interrupt context access respectively. +- * +- * The task context object stock can be accessed by disabling preemption only +- * which is cheap in non-preempt kernel. The interrupt context object stock +- * can only be accessed after disabling interrupt. User context code can +- * access interrupt object stock, but not vice versa. +- */ +-static inline struct obj_stock *get_obj_stock(unsigned long *pflags) +-{ +- struct memcg_stock_pcp *stock; +- +- if (likely(in_task())) { +- *pflags = 0UL; +- preempt_disable(); +- stock = this_cpu_ptr(&memcg_stock); +- return &stock->task_obj; +- } +- +- local_irq_save(*pflags); +- stock = this_cpu_ptr(&memcg_stock); +- return &stock->irq_obj; +-} +- +-static inline void put_obj_stock(unsigned long flags) +-{ +- if (likely(in_task())) +- preempt_enable(); +- else +- local_irq_restore(flags); +-} +- +-/** + * consume_stock: Try to consume stocked charge on this cpu. + * @memcg: memcg to consume from. + * @nr_pages: how many pages to charge. +@@ -2198,7 +2217,7 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) + if (nr_pages > MEMCG_CHARGE_BATCH) + return ret; + +- local_irq_save(flags); ++ local_lock_irqsave(&memcg_stock.stock_lock, flags); + + stock = this_cpu_ptr(&memcg_stock); + if (memcg == stock->cached && stock->nr_pages >= nr_pages) { +@@ -2206,7 +2225,7 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) + ret = true; + } + +- local_irq_restore(flags); ++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags); + + return ret; + } +@@ -2235,6 +2254,7 @@ static void drain_stock(struct memcg_stock_pcp *stock) + static void drain_local_stock(struct work_struct *dummy) + { + struct memcg_stock_pcp *stock; ++ struct obj_cgroup *old = NULL; + unsigned long flags; + + /* +@@ -2242,28 +2262,25 @@ static void drain_local_stock(struct work_struct *dummy) + * drain_stock races is that we always operate on local CPU stock + * here with IRQ disabled + */ +- local_irq_save(flags); ++ local_lock_irqsave(&memcg_stock.stock_lock, flags); + + stock = this_cpu_ptr(&memcg_stock); +- drain_obj_stock(&stock->irq_obj); +- if (in_task()) +- drain_obj_stock(&stock->task_obj); ++ old = drain_obj_stock(stock); + drain_stock(stock); + clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags); + +- local_irq_restore(flags); ++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags); ++ if (old) ++ obj_cgroup_put(old); + } + + /* + * Cache charges(val) to local per_cpu area. + * This will be consumed by consume_stock() function, later. + */ +-static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) ++static void __refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) + { + struct memcg_stock_pcp *stock; +- unsigned long flags; +- +- local_irq_save(flags); + + stock = this_cpu_ptr(&memcg_stock); + if (stock->cached != memcg) { /* reset if necessary */ +@@ -2275,8 +2292,15 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) + + if (stock->nr_pages > MEMCG_CHARGE_BATCH) + drain_stock(stock); ++} + +- local_irq_restore(flags); ++static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) ++{ ++ unsigned long flags; ++ ++ local_lock_irqsave(&memcg_stock.stock_lock, flags); ++ __refill_stock(memcg, nr_pages); ++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags); + } + + /* +@@ -2296,7 +2320,8 @@ static void drain_all_stock(struct mem_cgroup *root_memcg) + * as well as workers from this path always operate on the local + * per-cpu data. CPU up doesn't touch memcg_stock at all. + */ +- curcpu = get_cpu(); ++ migrate_disable(); ++ curcpu = smp_processor_id(); + for_each_online_cpu(cpu) { + struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu); + struct mem_cgroup *memcg; +@@ -2319,7 +2344,7 @@ static void drain_all_stock(struct mem_cgroup *root_memcg) + schedule_work_on(cpu, &stock->work); + } + } +- put_cpu(); ++ migrate_enable(); + mutex_unlock(&percpu_charge_mutex); + } + +@@ -3084,17 +3109,21 @@ void __memcg_kmem_uncharge_page(struct page *page, int order) + void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat, + enum node_stat_item idx, int nr) + { ++ struct memcg_stock_pcp *stock; ++ struct obj_cgroup *old = NULL; + unsigned long flags; +- struct obj_stock *stock = get_obj_stock(&flags); + int *bytes; + ++ local_lock_irqsave(&memcg_stock.stock_lock, flags); ++ stock = this_cpu_ptr(&memcg_stock); ++ + /* + * Save vmstat data in stock and skip vmstat array update unless + * accumulating over a page of vmstat data or when pgdat or idx + * changes. + */ + if (stock->cached_objcg != objcg) { +- drain_obj_stock(stock); ++ old = drain_obj_stock(stock); + obj_cgroup_get(objcg); + stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes) + ? atomic_xchg(&objcg->nr_charged_bytes, 0) : 0; +@@ -3138,38 +3167,53 @@ void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat, + if (nr) + mod_objcg_mlstate(objcg, pgdat, idx, nr); + +- put_obj_stock(flags); ++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags); ++ if (old) ++ obj_cgroup_put(old); + } + + static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes) + { ++ struct memcg_stock_pcp *stock; + unsigned long flags; +- struct obj_stock *stock = get_obj_stock(&flags); + bool ret = false; + ++ local_lock_irqsave(&memcg_stock.stock_lock, flags); ++ ++ stock = this_cpu_ptr(&memcg_stock); + if (objcg == stock->cached_objcg && stock->nr_bytes >= nr_bytes) { + stock->nr_bytes -= nr_bytes; + ret = true; + } + +- put_obj_stock(flags); ++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags); + + return ret; + } + +-static void drain_obj_stock(struct obj_stock *stock) ++static struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock) + { + struct obj_cgroup *old = stock->cached_objcg; + + if (!old) +- return; ++ return NULL; + + if (stock->nr_bytes) { + unsigned int nr_pages = stock->nr_bytes >> PAGE_SHIFT; + unsigned int nr_bytes = stock->nr_bytes & (PAGE_SIZE - 1); + +- if (nr_pages) +- obj_cgroup_uncharge_pages(old, nr_pages); ++ if (nr_pages) { ++ struct mem_cgroup *memcg; ++ ++ memcg = get_mem_cgroup_from_objcg(old); ++ ++ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) ++ page_counter_uncharge(&memcg->kmem, nr_pages); ++ ++ __refill_stock(memcg, nr_pages); ++ ++ css_put(&memcg->css); ++ } + + /* + * The leftover is flushed to the centralized per-memcg value. +@@ -3204,8 +3248,12 @@ static void drain_obj_stock(struct obj_stock *stock) + stock->cached_pgdat = NULL; + } + +- obj_cgroup_put(old); + stock->cached_objcg = NULL; ++ /* ++ * The `old' objects needs to be released by the caller via ++ * obj_cgroup_put() outside of memcg_stock_pcp::stock_lock. ++ */ ++ return old; + } + + static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, +@@ -3213,13 +3261,8 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, + { + struct mem_cgroup *memcg; + +- if (in_task() && stock->task_obj.cached_objcg) { +- memcg = obj_cgroup_memcg(stock->task_obj.cached_objcg); +- if (memcg && mem_cgroup_is_descendant(memcg, root_memcg)) +- return true; +- } +- if (stock->irq_obj.cached_objcg) { +- memcg = obj_cgroup_memcg(stock->irq_obj.cached_objcg); ++ if (stock->cached_objcg) { ++ memcg = obj_cgroup_memcg(stock->cached_objcg); + if (memcg && mem_cgroup_is_descendant(memcg, root_memcg)) + return true; + } +@@ -3230,12 +3273,16 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, + static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes, + bool allow_uncharge) + { ++ struct memcg_stock_pcp *stock; ++ struct obj_cgroup *old = NULL; + unsigned long flags; +- struct obj_stock *stock = get_obj_stock(&flags); + unsigned int nr_pages = 0; + ++ local_lock_irqsave(&memcg_stock.stock_lock, flags); ++ ++ stock = this_cpu_ptr(&memcg_stock); + if (stock->cached_objcg != objcg) { /* reset if necessary */ +- drain_obj_stock(stock); ++ old = drain_obj_stock(stock); + obj_cgroup_get(objcg); + stock->cached_objcg = objcg; + stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes) +@@ -3249,7 +3296,9 @@ static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes, + stock->nr_bytes &= (PAGE_SIZE - 1); + } + +- put_obj_stock(flags); ++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags); ++ if (old) ++ obj_cgroup_put(old); + + if (nr_pages) + obj_cgroup_uncharge_pages(objcg, nr_pages); +@@ -3816,8 +3865,12 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of, + } + break; + case RES_SOFT_LIMIT: +- memcg->soft_limit = nr_pages; +- ret = 0; ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ ret = -EOPNOTSUPP; ++ } else { ++ memcg->soft_limit = nr_pages; ++ ret = 0; ++ } + break; + } + return ret ?: nbytes; +@@ -4798,6 +4851,9 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of, + char *endp; + int ret; + ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ return -EOPNOTSUPP; ++ + buf = strstrip(buf); + + efd = simple_strtoul(buf, &endp, 10); +@@ -6889,7 +6945,6 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug) + unsigned long nr_pages; + struct mem_cgroup *memcg; + struct obj_cgroup *objcg; +- bool use_objcg = PageMemcgKmem(page); + + VM_BUG_ON_PAGE(PageLRU(page), page); + +@@ -6898,7 +6953,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug) + * page memcg or objcg at this point, we have fully + * exclusive access to the page. + */ +- if (use_objcg) { ++ if (PageMemcgKmem(page)) { + objcg = __page_objcg(page); + /* + * This get matches the put at the end of the function and +@@ -6926,7 +6981,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug) + + nr_pages = compound_nr(page); + +- if (use_objcg) { ++ if (PageMemcgKmem(page)) { + ug->nr_memory += nr_pages; + ug->nr_kmem += nr_pages; + +@@ -7256,8 +7311,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) + * important here to have the interrupts disabled because it is the + * only synchronisation we have for updating the per-CPU variables. + */ +- VM_BUG_ON(!irqs_disabled()); ++ memcg_stats_lock(); + mem_cgroup_charge_statistics(memcg, page, -nr_entries); ++ memcg_stats_unlock(); + memcg_check_events(memcg, page); + + css_put(&memcg->css); +diff --git a/mm/memory.c b/mm/memory.c +index 8d71a82462dd..e2a9f89bbcf2 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -5305,7 +5305,7 @@ void __might_fault(const char *file, int line) + return; + if (pagefault_disabled()) + return; +- __might_sleep(file, line, 0); ++ __might_sleep(file, line); + #if defined(CONFIG_DEBUG_ATOMIC_SLEEP) + if (current->mm) + might_lock_read(¤t->mm->mmap_lock); +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index f320ee2bd34a..33355028122a 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -3149,9 +3149,9 @@ static void drain_local_pages_wq(struct work_struct *work) + * cpu which is alright but we also have to make sure to not move to + * a different one. + */ +- preempt_disable(); ++ migrate_disable(); + drain_local_pages(drain->zone); +- preempt_enable(); ++ migrate_enable(); + } + + /* +diff --git a/mm/vmalloc.c b/mm/vmalloc.c +index 3e482209a1c4..1a59b7b4ff67 100644 +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -1918,11 +1918,12 @@ static void *new_vmap_block(unsigned int order, gfp_t gfp_mask) + return ERR_PTR(err); + } + +- vbq = &get_cpu_var(vmap_block_queue); ++ get_cpu_light(); ++ vbq = this_cpu_ptr(&vmap_block_queue); + spin_lock(&vbq->lock); + list_add_tail_rcu(&vb->free_list, &vbq->free); + spin_unlock(&vbq->lock); +- put_cpu_var(vmap_block_queue); ++ put_cpu_light(); + + return vaddr; + } +@@ -2001,7 +2002,8 @@ static void *vb_alloc(unsigned long size, gfp_t gfp_mask) + order = get_order(size); + + rcu_read_lock(); +- vbq = &get_cpu_var(vmap_block_queue); ++ get_cpu_light(); ++ vbq = this_cpu_ptr(&vmap_block_queue); + list_for_each_entry_rcu(vb, &vbq->free, free_list) { + unsigned long pages_off; + +@@ -2024,7 +2026,7 @@ static void *vb_alloc(unsigned long size, gfp_t gfp_mask) + break; + } + +- put_cpu_var(vmap_block_queue); ++ put_cpu_light(); + rcu_read_unlock(); + + /* Allocate new block if nothing was found */ +diff --git a/mm/workingset.c b/mm/workingset.c +index 880d882f3325..2a9ed5aeb6fa 100644 +--- a/mm/workingset.c ++++ b/mm/workingset.c +@@ -433,6 +433,8 @@ static struct list_lru shadow_nodes; + + void workingset_update_node(struct xa_node *node) + { ++ struct address_space *mapping; ++ + /* + * Track non-empty nodes that contain only shadow entries; + * unlink those that contain pages or are being freed. +@@ -441,7 +443,8 @@ void workingset_update_node(struct xa_node *node) + * already where they should be. The list_empty() test is safe + * as node->private_list is protected by the i_pages lock. + */ +- VM_WARN_ON_ONCE(!irqs_disabled()); /* For __inc_lruvec_page_state */ ++ mapping = container_of(node->array, struct address_space, i_pages); ++ lockdep_assert_held(&mapping->i_pages.xa_lock); + + if (node->count && node->count == node->nr_values) { + if (list_empty(&node->private_list)) { +diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c +index 439deb8decbc..a66431853394 100644 +--- a/mm/zsmalloc.c ++++ b/mm/zsmalloc.c +@@ -57,6 +57,7 @@ + #include + #include + #include ++#include + + #define ZSPAGE_MAGIC 0x58 + +@@ -77,6 +78,20 @@ + + #define ZS_HANDLE_SIZE (sizeof(unsigned long)) + ++#ifdef CONFIG_PREEMPT_RT ++ ++struct zsmalloc_handle { ++ unsigned long addr; ++ spinlock_t lock; ++}; ++ ++#define ZS_HANDLE_ALLOC_SIZE (sizeof(struct zsmalloc_handle)) ++ ++#else ++ ++#define ZS_HANDLE_ALLOC_SIZE (sizeof(unsigned long)) ++#endif ++ + /* + * Object location (, ) is encoded as + * a single (unsigned long) handle value. +@@ -293,6 +308,7 @@ struct zspage { + }; + + struct mapping_area { ++ local_lock_t lock; + char *vm_buf; /* copy buffer for objects that span pages */ + char *vm_addr; /* address of kmap_atomic()'ed pages */ + enum zs_mapmode vm_mm; /* mapping mode */ +@@ -322,7 +338,7 @@ static void SetZsPageMovable(struct zs_pool *pool, struct zspage *zspage) {} + + static int create_cache(struct zs_pool *pool) + { +- pool->handle_cachep = kmem_cache_create("zs_handle", ZS_HANDLE_SIZE, ++ pool->handle_cachep = kmem_cache_create("zs_handle", ZS_HANDLE_ALLOC_SIZE, + 0, 0, NULL); + if (!pool->handle_cachep) + return 1; +@@ -346,10 +362,27 @@ static void destroy_cache(struct zs_pool *pool) + + static unsigned long cache_alloc_handle(struct zs_pool *pool, gfp_t gfp) + { +- return (unsigned long)kmem_cache_alloc(pool->handle_cachep, +- gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); ++ void *p; ++ ++ p = kmem_cache_alloc(pool->handle_cachep, ++ gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); ++#ifdef CONFIG_PREEMPT_RT ++ if (p) { ++ struct zsmalloc_handle *zh = p; ++ ++ spin_lock_init(&zh->lock); ++ } ++#endif ++ return (unsigned long)p; + } + ++#ifdef CONFIG_PREEMPT_RT ++static struct zsmalloc_handle *zs_get_pure_handle(unsigned long handle) ++{ ++ return (void *)(handle & ~((1 << OBJ_TAG_BITS) - 1)); ++} ++#endif ++ + static void cache_free_handle(struct zs_pool *pool, unsigned long handle) + { + kmem_cache_free(pool->handle_cachep, (void *)handle); +@@ -368,12 +401,18 @@ static void cache_free_zspage(struct zs_pool *pool, struct zspage *zspage) + + static void record_obj(unsigned long handle, unsigned long obj) + { ++#ifdef CONFIG_PREEMPT_RT ++ struct zsmalloc_handle *zh = zs_get_pure_handle(handle); ++ ++ WRITE_ONCE(zh->addr, obj); ++#else + /* + * lsb of @obj represents handle lock while other bits + * represent object value the handle is pointing so + * updating shouldn't do store tearing. + */ + WRITE_ONCE(*(unsigned long *)handle, obj); ++#endif + } + + /* zpool driver */ +@@ -455,7 +494,9 @@ MODULE_ALIAS("zpool-zsmalloc"); + #endif /* CONFIG_ZPOOL */ + + /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */ +-static DEFINE_PER_CPU(struct mapping_area, zs_map_area); ++static DEFINE_PER_CPU(struct mapping_area, zs_map_area) = { ++ .lock = INIT_LOCAL_LOCK(lock), ++}; + + static bool is_zspage_isolated(struct zspage *zspage) + { +@@ -862,7 +903,13 @@ static unsigned long location_to_obj(struct page *page, unsigned int obj_idx) + + static unsigned long handle_to_obj(unsigned long handle) + { ++#ifdef CONFIG_PREEMPT_RT ++ struct zsmalloc_handle *zh = zs_get_pure_handle(handle); ++ ++ return zh->addr; ++#else + return *(unsigned long *)handle; ++#endif + } + + static unsigned long obj_to_head(struct page *page, void *obj) +@@ -876,22 +923,46 @@ static unsigned long obj_to_head(struct page *page, void *obj) + + static inline int testpin_tag(unsigned long handle) + { ++#ifdef CONFIG_PREEMPT_RT ++ struct zsmalloc_handle *zh = zs_get_pure_handle(handle); ++ ++ return spin_is_locked(&zh->lock); ++#else + return bit_spin_is_locked(HANDLE_PIN_BIT, (unsigned long *)handle); ++#endif + } + + static inline int trypin_tag(unsigned long handle) + { ++#ifdef CONFIG_PREEMPT_RT ++ struct zsmalloc_handle *zh = zs_get_pure_handle(handle); ++ ++ return spin_trylock(&zh->lock); ++#else + return bit_spin_trylock(HANDLE_PIN_BIT, (unsigned long *)handle); ++#endif + } + + static void pin_tag(unsigned long handle) __acquires(bitlock) + { ++#ifdef CONFIG_PREEMPT_RT ++ struct zsmalloc_handle *zh = zs_get_pure_handle(handle); ++ ++ return spin_lock(&zh->lock); ++#else + bit_spin_lock(HANDLE_PIN_BIT, (unsigned long *)handle); ++#endif + } + + static void unpin_tag(unsigned long handle) __releases(bitlock) + { ++#ifdef CONFIG_PREEMPT_RT ++ struct zsmalloc_handle *zh = zs_get_pure_handle(handle); ++ ++ return spin_unlock(&zh->lock); ++#else + bit_spin_unlock(HANDLE_PIN_BIT, (unsigned long *)handle); ++#endif + } + + static void reset_page(struct page *page) +@@ -1274,7 +1345,8 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle, + class = pool->size_class[class_idx]; + off = (class->size * obj_idx) & ~PAGE_MASK; + +- area = &get_cpu_var(zs_map_area); ++ local_lock(&zs_map_area.lock); ++ area = this_cpu_ptr(&zs_map_area); + area->vm_mm = mm; + if (off + class->size <= PAGE_SIZE) { + /* this object is contained entirely within a page */ +@@ -1328,7 +1400,7 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle) + + __zs_unmap_object(area, pages, off, class->size); + } +- put_cpu_var(zs_map_area); ++ local_unlock(&zs_map_area.lock); + + migrate_read_unlock(zspage); + unpin_tag(handle); +diff --git a/net/Kconfig b/net/Kconfig +index 76a3385943e5..bd7386eede23 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -292,7 +292,7 @@ config CGROUP_NET_CLASSID + + config NET_RX_BUSY_POLL + bool +- default y ++ default y if !PREEMPT_RT + + config BQL + bool +diff --git a/net/core/dev.c b/net/core/dev.c +index 4d698ccf4172..4bed27338ed9 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -225,14 +225,14 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) + static inline void rps_lock(struct softnet_data *sd) + { + #ifdef CONFIG_RPS +- spin_lock(&sd->input_pkt_queue.lock); ++ raw_spin_lock(&sd->input_pkt_queue.raw_lock); + #endif + } + + static inline void rps_unlock(struct softnet_data *sd) + { + #ifdef CONFIG_RPS +- spin_unlock(&sd->input_pkt_queue.lock); ++ raw_spin_unlock(&sd->input_pkt_queue.raw_lock); + #endif + } + +@@ -3046,6 +3046,7 @@ static void __netif_reschedule(struct Qdisc *q) + sd->output_queue_tailp = &q->next_sched; + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_restore(flags); ++ preempt_check_resched_rt(); + } + + void __netif_schedule(struct Qdisc *q) +@@ -3108,6 +3109,7 @@ void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason) + __this_cpu_write(softnet_data.completion_queue, skb); + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_restore(flags); ++ preempt_check_resched_rt(); + } + EXPORT_SYMBOL(__dev_kfree_skb_irq); + +@@ -3841,7 +3843,11 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, + * This permits qdisc->running owner to get the lock more + * often and dequeue packets faster. + */ ++#ifdef CONFIG_PREEMPT_RT ++ contended = true; ++#else + contended = qdisc_is_running(q); ++#endif + if (unlikely(contended)) + spin_lock(&q->busylock); + +@@ -4669,6 +4675,7 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu, + rps_unlock(sd); + + local_irq_restore(flags); ++ preempt_check_resched_rt(); + + atomic_long_inc(&skb->dev->rx_dropped); + kfree_skb(skb); +@@ -4909,7 +4916,7 @@ static int netif_rx_internal(struct sk_buff *skb) + struct rps_dev_flow voidflow, *rflow = &voidflow; + int cpu; + +- preempt_disable(); ++ migrate_disable(); + rcu_read_lock(); + + cpu = get_rps_cpu(skb->dev, skb, &rflow); +@@ -4919,14 +4926,14 @@ static int netif_rx_internal(struct sk_buff *skb) + ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); + + rcu_read_unlock(); +- preempt_enable(); ++ migrate_enable(); + } else + #endif + { + unsigned int qtail; + +- ret = enqueue_to_backlog(skb, get_cpu(), &qtail); +- put_cpu(); ++ ret = enqueue_to_backlog(skb, get_cpu_light(), &qtail); ++ put_cpu_light(); + } + return ret; + } +@@ -4965,11 +4972,9 @@ int netif_rx_ni(struct sk_buff *skb) + + trace_netif_rx_ni_entry(skb); + +- preempt_disable(); ++ local_bh_disable(); + err = netif_rx_internal(skb); +- if (local_softirq_pending()) +- do_softirq(); +- preempt_enable(); ++ local_bh_enable(); + trace_netif_rx_ni_exit(err); + + return err; +@@ -6413,12 +6418,14 @@ static void net_rps_action_and_irq_enable(struct softnet_data *sd) + sd->rps_ipi_list = NULL; + + local_irq_enable(); ++ preempt_check_resched_rt(); + + /* Send pending IPI's to kick RPS processing on remote cpus. */ + net_rps_send_ipi(remsd); + } else + #endif + local_irq_enable(); ++ preempt_check_resched_rt(); + } + + static bool sd_has_rps_ipi_waiting(struct softnet_data *sd) +@@ -6496,6 +6503,7 @@ void __napi_schedule(struct napi_struct *n) + local_irq_save(flags); + ____napi_schedule(this_cpu_ptr(&softnet_data), n); + local_irq_restore(flags); ++ preempt_check_resched_rt(); + } + EXPORT_SYMBOL(__napi_schedule); + +@@ -11316,6 +11324,7 @@ static int dev_cpu_dead(unsigned int oldcpu) + + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_enable(); ++ preempt_check_resched_rt(); + + #ifdef CONFIG_RPS + remsd = oldsd->rps_ipi_list; +@@ -11329,7 +11338,7 @@ static int dev_cpu_dead(unsigned int oldcpu) + netif_rx_ni(skb); + input_queue_head_incr(oldsd); + } +- while ((skb = skb_dequeue(&oldsd->input_pkt_queue))) { ++ while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) { + netif_rx_ni(skb); + input_queue_head_incr(oldsd); + } +@@ -11644,7 +11653,7 @@ static int __init net_dev_init(void) + + INIT_WORK(flush, flush_backlog); + +- skb_queue_head_init(&sd->input_pkt_queue); ++ skb_queue_head_init_raw(&sd->input_pkt_queue); + skb_queue_head_init(&sd->process_queue); + #ifdef CONFIG_XFRM_OFFLOAD + skb_queue_head_init(&sd->xfrm_backlog); +diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c +index 8e582e29a41e..4fcbdd71c59f 100644 +--- a/net/core/gen_estimator.c ++++ b/net/core/gen_estimator.c +@@ -40,10 +40,10 @@ + */ + + struct net_rate_estimator { +- struct gnet_stats_basic_packed *bstats; ++ struct gnet_stats_basic_sync *bstats; + spinlock_t *stats_lock; +- seqcount_t *running; +- struct gnet_stats_basic_cpu __percpu *cpu_bstats; ++ bool running; ++ struct gnet_stats_basic_sync __percpu *cpu_bstats; + u8 ewma_log; + u8 intvl_log; /* period : (250ms << intvl_log) */ + +@@ -60,13 +60,13 @@ struct net_rate_estimator { + }; + + static void est_fetch_counters(struct net_rate_estimator *e, +- struct gnet_stats_basic_packed *b) ++ struct gnet_stats_basic_sync *b) + { +- memset(b, 0, sizeof(*b)); ++ gnet_stats_basic_sync_init(b); + if (e->stats_lock) + spin_lock(e->stats_lock); + +- __gnet_stats_copy_basic(e->running, b, e->cpu_bstats, e->bstats); ++ gnet_stats_add_basic(b, e->cpu_bstats, e->bstats, e->running); + + if (e->stats_lock) + spin_unlock(e->stats_lock); +@@ -76,14 +76,18 @@ static void est_fetch_counters(struct net_rate_estimator *e, + static void est_timer(struct timer_list *t) + { + struct net_rate_estimator *est = from_timer(est, t, timer); +- struct gnet_stats_basic_packed b; ++ struct gnet_stats_basic_sync b; ++ u64 b_bytes, b_packets; + u64 rate, brate; + + est_fetch_counters(est, &b); +- brate = (b.bytes - est->last_bytes) << (10 - est->intvl_log); ++ b_bytes = u64_stats_read(&b.bytes); ++ b_packets = u64_stats_read(&b.packets); ++ ++ brate = (b_bytes - est->last_bytes) << (10 - est->intvl_log); + brate = (brate >> est->ewma_log) - (est->avbps >> est->ewma_log); + +- rate = (b.packets - est->last_packets) << (10 - est->intvl_log); ++ rate = (b_packets - est->last_packets) << (10 - est->intvl_log); + rate = (rate >> est->ewma_log) - (est->avpps >> est->ewma_log); + + write_seqcount_begin(&est->seq); +@@ -91,8 +95,8 @@ static void est_timer(struct timer_list *t) + est->avpps += rate; + write_seqcount_end(&est->seq); + +- est->last_bytes = b.bytes; +- est->last_packets = b.packets; ++ est->last_bytes = b_bytes; ++ est->last_packets = b_packets; + + est->next_jiffies += ((HZ/4) << est->intvl_log); + +@@ -109,7 +113,9 @@ static void est_timer(struct timer_list *t) + * @cpu_bstats: bstats per cpu + * @rate_est: rate estimator statistics + * @lock: lock for statistics and control path +- * @running: qdisc running seqcount ++ * @running: true if @bstats represents a running qdisc, thus @bstats' ++ * internal values might change during basic reads. Only used ++ * if @bstats_cpu is NULL + * @opt: rate estimator configuration TLV + * + * Creates a new rate estimator with &bstats as source and &rate_est +@@ -121,16 +127,16 @@ static void est_timer(struct timer_list *t) + * Returns 0 on success or a negative error code. + * + */ +-int gen_new_estimator(struct gnet_stats_basic_packed *bstats, +- struct gnet_stats_basic_cpu __percpu *cpu_bstats, ++int gen_new_estimator(struct gnet_stats_basic_sync *bstats, ++ struct gnet_stats_basic_sync __percpu *cpu_bstats, + struct net_rate_estimator __rcu **rate_est, + spinlock_t *lock, +- seqcount_t *running, ++ bool running, + struct nlattr *opt) + { + struct gnet_estimator *parm = nla_data(opt); + struct net_rate_estimator *old, *est; +- struct gnet_stats_basic_packed b; ++ struct gnet_stats_basic_sync b; + int intvl_log; + + if (nla_len(opt) < sizeof(*parm)) +@@ -164,8 +170,8 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, + est_fetch_counters(est, &b); + if (lock) + local_bh_enable(); +- est->last_bytes = b.bytes; +- est->last_packets = b.packets; ++ est->last_bytes = u64_stats_read(&b.bytes); ++ est->last_packets = u64_stats_read(&b.packets); + + if (lock) + spin_lock_bh(lock); +@@ -214,7 +220,9 @@ EXPORT_SYMBOL(gen_kill_estimator); + * @cpu_bstats: bstats per cpu + * @rate_est: rate estimator statistics + * @lock: lock for statistics and control path +- * @running: qdisc running seqcount (might be NULL) ++ * @running: true if @bstats represents a running qdisc, thus @bstats' ++ * internal values might change during basic reads. Only used ++ * if @cpu_bstats is NULL + * @opt: rate estimator configuration TLV + * + * Replaces the configuration of a rate estimator by calling +@@ -222,11 +230,11 @@ EXPORT_SYMBOL(gen_kill_estimator); + * + * Returns 0 on success or a negative error code. + */ +-int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, +- struct gnet_stats_basic_cpu __percpu *cpu_bstats, ++int gen_replace_estimator(struct gnet_stats_basic_sync *bstats, ++ struct gnet_stats_basic_sync __percpu *cpu_bstats, + struct net_rate_estimator __rcu **rate_est, + spinlock_t *lock, +- seqcount_t *running, struct nlattr *opt) ++ bool running, struct nlattr *opt) + { + return gen_new_estimator(bstats, cpu_bstats, rate_est, + lock, running, opt); +diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c +index e491b083b348..a10335b4ba2d 100644 +--- a/net/core/gen_stats.c ++++ b/net/core/gen_stats.c +@@ -18,7 +18,7 @@ + #include + #include + #include +- ++#include + + static inline int + gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size, int padattr) +@@ -114,63 +114,112 @@ gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock, + } + EXPORT_SYMBOL(gnet_stats_start_copy); + +-static void +-__gnet_stats_copy_basic_cpu(struct gnet_stats_basic_packed *bstats, +- struct gnet_stats_basic_cpu __percpu *cpu) ++/* Must not be inlined, due to u64_stats seqcount_t lockdep key */ ++void gnet_stats_basic_sync_init(struct gnet_stats_basic_sync *b) + { ++ u64_stats_set(&b->bytes, 0); ++ u64_stats_set(&b->packets, 0); ++ u64_stats_init(&b->syncp); ++} ++EXPORT_SYMBOL(gnet_stats_basic_sync_init); ++ ++static void gnet_stats_add_basic_cpu(struct gnet_stats_basic_sync *bstats, ++ struct gnet_stats_basic_sync __percpu *cpu) ++{ ++ u64 t_bytes = 0, t_packets = 0; + int i; + + for_each_possible_cpu(i) { +- struct gnet_stats_basic_cpu *bcpu = per_cpu_ptr(cpu, i); ++ struct gnet_stats_basic_sync *bcpu = per_cpu_ptr(cpu, i); + unsigned int start; + u64 bytes, packets; + + do { + start = u64_stats_fetch_begin_irq(&bcpu->syncp); +- bytes = bcpu->bstats.bytes; +- packets = bcpu->bstats.packets; ++ bytes = u64_stats_read(&bcpu->bytes); ++ packets = u64_stats_read(&bcpu->packets); + } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); + +- bstats->bytes += bytes; +- bstats->packets += packets; ++ t_bytes += bytes; ++ t_packets += packets; ++ } ++ _bstats_update(bstats, t_bytes, t_packets); ++} ++ ++void gnet_stats_add_basic(struct gnet_stats_basic_sync *bstats, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, bool running) ++{ ++ unsigned int start; ++ u64 bytes = 0; ++ u64 packets = 0; ++ ++ WARN_ON_ONCE((cpu || running) && in_hardirq()); ++ ++ if (cpu) { ++ gnet_stats_add_basic_cpu(bstats, cpu); ++ return; + } ++ do { ++ if (running) ++ start = u64_stats_fetch_begin_irq(&b->syncp); ++ bytes = u64_stats_read(&b->bytes); ++ packets = u64_stats_read(&b->packets); ++ } while (running && u64_stats_fetch_retry_irq(&b->syncp, start)); ++ ++ _bstats_update(bstats, bytes, packets); + } ++EXPORT_SYMBOL(gnet_stats_add_basic); + +-void +-__gnet_stats_copy_basic(const seqcount_t *running, +- struct gnet_stats_basic_packed *bstats, +- struct gnet_stats_basic_cpu __percpu *cpu, +- struct gnet_stats_basic_packed *b) ++static void gnet_stats_read_basic(u64 *ret_bytes, u64 *ret_packets, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, bool running) + { +- unsigned int seq; ++ unsigned int start; + + if (cpu) { +- __gnet_stats_copy_basic_cpu(bstats, cpu); ++ u64 t_bytes = 0, t_packets = 0; ++ int i; ++ ++ for_each_possible_cpu(i) { ++ struct gnet_stats_basic_sync *bcpu = per_cpu_ptr(cpu, i); ++ unsigned int start; ++ u64 bytes, packets; ++ ++ do { ++ start = u64_stats_fetch_begin_irq(&bcpu->syncp); ++ bytes = u64_stats_read(&bcpu->bytes); ++ packets = u64_stats_read(&bcpu->packets); ++ } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); ++ ++ t_bytes += bytes; ++ t_packets += packets; ++ } ++ *ret_bytes = t_bytes; ++ *ret_packets = t_packets; + return; + } + do { + if (running) +- seq = read_seqcount_begin(running); +- bstats->bytes = b->bytes; +- bstats->packets = b->packets; +- } while (running && read_seqcount_retry(running, seq)); ++ start = u64_stats_fetch_begin_irq(&b->syncp); ++ *ret_bytes = u64_stats_read(&b->bytes); ++ *ret_packets = u64_stats_read(&b->packets); ++ } while (running && u64_stats_fetch_retry_irq(&b->syncp, start)); + } +-EXPORT_SYMBOL(__gnet_stats_copy_basic); + + static int +-___gnet_stats_copy_basic(const seqcount_t *running, +- struct gnet_dump *d, +- struct gnet_stats_basic_cpu __percpu *cpu, +- struct gnet_stats_basic_packed *b, +- int type) ++___gnet_stats_copy_basic(struct gnet_dump *d, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, ++ int type, bool running) + { +- struct gnet_stats_basic_packed bstats = {0}; ++ u64 bstats_bytes, bstats_packets; + +- __gnet_stats_copy_basic(running, &bstats, cpu, b); ++ gnet_stats_read_basic(&bstats_bytes, &bstats_packets, cpu, b, running); + + if (d->compat_tc_stats && type == TCA_STATS_BASIC) { +- d->tc_stats.bytes = bstats.bytes; +- d->tc_stats.packets = bstats.packets; ++ d->tc_stats.bytes = bstats_bytes; ++ d->tc_stats.packets = bstats_packets; + } + + if (d->tail) { +@@ -178,24 +227,28 @@ ___gnet_stats_copy_basic(const seqcount_t *running, + int res; + + memset(&sb, 0, sizeof(sb)); +- sb.bytes = bstats.bytes; +- sb.packets = bstats.packets; ++ sb.bytes = bstats_bytes; ++ sb.packets = bstats_packets; + res = gnet_stats_copy(d, type, &sb, sizeof(sb), TCA_STATS_PAD); +- if (res < 0 || sb.packets == bstats.packets) ++ if (res < 0 || sb.packets == bstats_packets) + return res; + /* emit 64bit stats only if needed */ +- return gnet_stats_copy(d, TCA_STATS_PKT64, &bstats.packets, +- sizeof(bstats.packets), TCA_STATS_PAD); ++ return gnet_stats_copy(d, TCA_STATS_PKT64, &bstats_packets, ++ sizeof(bstats_packets), TCA_STATS_PAD); + } + return 0; + } + + /** + * gnet_stats_copy_basic - copy basic statistics into statistic TLV +- * @running: seqcount_t pointer + * @d: dumping handle + * @cpu: copy statistic per cpu + * @b: basic statistics ++ * @running: true if @b represents a running qdisc, thus @b's ++ * internal values might change during basic reads. ++ * Only used if @cpu is NULL ++ * ++ * Context: task; must not be run from IRQ or BH contexts + * + * Appends the basic statistics to the top level TLV created by + * gnet_stats_start_copy(). +@@ -204,22 +257,25 @@ ___gnet_stats_copy_basic(const seqcount_t *running, + * if the room in the socket buffer was not sufficient. + */ + int +-gnet_stats_copy_basic(const seqcount_t *running, +- struct gnet_dump *d, +- struct gnet_stats_basic_cpu __percpu *cpu, +- struct gnet_stats_basic_packed *b) ++gnet_stats_copy_basic(struct gnet_dump *d, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, ++ bool running) + { +- return ___gnet_stats_copy_basic(running, d, cpu, b, +- TCA_STATS_BASIC); ++ return ___gnet_stats_copy_basic(d, cpu, b, TCA_STATS_BASIC, running); + } + EXPORT_SYMBOL(gnet_stats_copy_basic); + + /** + * gnet_stats_copy_basic_hw - copy basic hw statistics into statistic TLV +- * @running: seqcount_t pointer + * @d: dumping handle + * @cpu: copy statistic per cpu + * @b: basic statistics ++ * @running: true if @b represents a running qdisc, thus @b's ++ * internal values might change during basic reads. ++ * Only used if @cpu is NULL ++ * ++ * Context: task; must not be run from IRQ or BH contexts + * + * Appends the basic statistics to the top level TLV created by + * gnet_stats_start_copy(). +@@ -228,13 +284,12 @@ EXPORT_SYMBOL(gnet_stats_copy_basic); + * if the room in the socket buffer was not sufficient. + */ + int +-gnet_stats_copy_basic_hw(const seqcount_t *running, +- struct gnet_dump *d, +- struct gnet_stats_basic_cpu __percpu *cpu, +- struct gnet_stats_basic_packed *b) ++gnet_stats_copy_basic_hw(struct gnet_dump *d, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, ++ bool running) + { +- return ___gnet_stats_copy_basic(running, d, cpu, b, +- TCA_STATS_BASIC_HW); ++ return ___gnet_stats_copy_basic(d, cpu, b, TCA_STATS_BASIC_HW, running); + } + EXPORT_SYMBOL(gnet_stats_copy_basic_hw); + +@@ -282,16 +337,15 @@ gnet_stats_copy_rate_est(struct gnet_dump *d, + } + EXPORT_SYMBOL(gnet_stats_copy_rate_est); + +-static void +-__gnet_stats_copy_queue_cpu(struct gnet_stats_queue *qstats, +- const struct gnet_stats_queue __percpu *q) ++static void gnet_stats_add_queue_cpu(struct gnet_stats_queue *qstats, ++ const struct gnet_stats_queue __percpu *q) + { + int i; + + for_each_possible_cpu(i) { + const struct gnet_stats_queue *qcpu = per_cpu_ptr(q, i); + +- qstats->qlen = 0; ++ qstats->qlen += qcpu->backlog; + qstats->backlog += qcpu->backlog; + qstats->drops += qcpu->drops; + qstats->requeues += qcpu->requeues; +@@ -299,24 +353,21 @@ __gnet_stats_copy_queue_cpu(struct gnet_stats_queue *qstats, + } + } + +-void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats, +- const struct gnet_stats_queue __percpu *cpu, +- const struct gnet_stats_queue *q, +- __u32 qlen) ++void gnet_stats_add_queue(struct gnet_stats_queue *qstats, ++ const struct gnet_stats_queue __percpu *cpu, ++ const struct gnet_stats_queue *q) + { + if (cpu) { +- __gnet_stats_copy_queue_cpu(qstats, cpu); ++ gnet_stats_add_queue_cpu(qstats, cpu); + } else { +- qstats->qlen = q->qlen; +- qstats->backlog = q->backlog; +- qstats->drops = q->drops; +- qstats->requeues = q->requeues; +- qstats->overlimits = q->overlimits; ++ qstats->qlen += q->qlen; ++ qstats->backlog += q->backlog; ++ qstats->drops += q->drops; ++ qstats->requeues += q->requeues; ++ qstats->overlimits += q->overlimits; + } +- +- qstats->qlen = qlen; + } +-EXPORT_SYMBOL(__gnet_stats_copy_queue); ++EXPORT_SYMBOL(gnet_stats_add_queue); + + /** + * gnet_stats_copy_queue - copy queue statistics into statistics TLV +@@ -339,7 +390,8 @@ gnet_stats_copy_queue(struct gnet_dump *d, + { + struct gnet_stats_queue qstats = {0}; + +- __gnet_stats_copy_queue(&qstats, cpu_q, q, qlen); ++ gnet_stats_add_queue(&qstats, cpu_q, q); ++ qstats.qlen = qlen; + + if (d->compat_tc_stats) { + d->tc_stats.drops = qstats.drops; +diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c +index 0d5c422f8745..8aec1b529364 100644 +--- a/net/netfilter/xt_RATEEST.c ++++ b/net/netfilter/xt_RATEEST.c +@@ -94,11 +94,11 @@ static unsigned int + xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par) + { + const struct xt_rateest_target_info *info = par->targinfo; +- struct gnet_stats_basic_packed *stats = &info->est->bstats; ++ struct gnet_stats_basic_sync *stats = &info->est->bstats; + + spin_lock_bh(&info->est->lock); +- stats->bytes += skb->len; +- stats->packets++; ++ u64_stats_add(&stats->bytes, skb->len); ++ u64_stats_inc(&stats->packets); + spin_unlock_bh(&info->est->lock); + + return XT_CONTINUE; +@@ -143,6 +143,7 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) + if (!est) + goto err1; + ++ gnet_stats_basic_sync_init(&est->bstats); + strlcpy(est->name, info->name, sizeof(est->name)); + spin_lock_init(&est->lock); + est->refcnt = 1; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index d775676956bf..94c05713ecf8 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -486,16 +486,18 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, + atomic_set(&p->tcfa_bindcnt, 1); + + if (cpustats) { +- p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); ++ p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_sync); + if (!p->cpu_bstats) + goto err1; +- p->cpu_bstats_hw = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); ++ p->cpu_bstats_hw = netdev_alloc_pcpu_stats(struct gnet_stats_basic_sync); + if (!p->cpu_bstats_hw) + goto err2; + p->cpu_qstats = alloc_percpu(struct gnet_stats_queue); + if (!p->cpu_qstats) + goto err3; + } ++ gnet_stats_basic_sync_init(&p->tcfa_bstats); ++ gnet_stats_basic_sync_init(&p->tcfa_bstats_hw); + spin_lock_init(&p->tcfa_lock); + p->tcfa_index = index; + p->tcfa_tm.install = jiffies; +@@ -505,7 +507,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, + if (est) { + err = gen_new_estimator(&p->tcfa_bstats, p->cpu_bstats, + &p->tcfa_rate_est, +- &p->tcfa_lock, NULL, est); ++ &p->tcfa_lock, false, est); + if (err) + goto err4; + } +@@ -1141,13 +1143,13 @@ void tcf_action_update_stats(struct tc_action *a, u64 bytes, u64 packets, + u64 drops, bool hw) + { + if (a->cpu_bstats) { +- _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets); ++ _bstats_update(this_cpu_ptr(a->cpu_bstats), bytes, packets); + + this_cpu_ptr(a->cpu_qstats)->drops += drops; + + if (hw) +- _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats_hw), +- bytes, packets); ++ _bstats_update(this_cpu_ptr(a->cpu_bstats_hw), ++ bytes, packets); + return; + } + +@@ -1186,9 +1188,10 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p, + if (err < 0) + goto errout; + +- if (gnet_stats_copy_basic(NULL, &d, p->cpu_bstats, &p->tcfa_bstats) < 0 || +- gnet_stats_copy_basic_hw(NULL, &d, p->cpu_bstats_hw, +- &p->tcfa_bstats_hw) < 0 || ++ if (gnet_stats_copy_basic(&d, p->cpu_bstats, ++ &p->tcfa_bstats, false) < 0 || ++ gnet_stats_copy_basic_hw(&d, p->cpu_bstats_hw, ++ &p->tcfa_bstats_hw, false) < 0 || + gnet_stats_copy_rate_est(&d, &p->tcfa_rate_est) < 0 || + gnet_stats_copy_queue(&d, p->cpu_qstats, + &p->tcfa_qstats, +diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c +index 2a05bad56ef3..a77d8908e737 100644 +--- a/net/sched/act_bpf.c ++++ b/net/sched/act_bpf.c +@@ -41,7 +41,7 @@ static int tcf_bpf_act(struct sk_buff *skb, const struct tc_action *act, + int action, filter_res; + + tcf_lastuse_update(&prog->tcf_tm); +- bstats_cpu_update(this_cpu_ptr(prog->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(prog->common.cpu_bstats), skb); + + filter = rcu_dereference(prog->filter); + if (at_ingress) { +diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c +index ec987ec75807..41ba55e60b1b 100644 +--- a/net/sched/act_ife.c ++++ b/net/sched/act_ife.c +@@ -718,7 +718,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a, + u8 *tlv_data; + u16 metalen; + +- bstats_cpu_update(this_cpu_ptr(ife->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb); + tcf_lastuse_update(&ife->tcf_tm); + + if (skb_at_tc_ingress(skb)) +@@ -806,7 +806,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, + exceed_mtu = true; + } + +- bstats_cpu_update(this_cpu_ptr(ife->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb); + tcf_lastuse_update(&ife->tcf_tm); + + if (!metalen) { /* no metadata to send */ +diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c +index d010c5b8e83b..d39b74331c26 100644 +--- a/net/sched/act_mpls.c ++++ b/net/sched/act_mpls.c +@@ -59,7 +59,7 @@ static int tcf_mpls_act(struct sk_buff *skb, const struct tc_action *a, + int ret, mac_len; + + tcf_lastuse_update(&m->tcf_tm); +- bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(m->common.cpu_bstats), skb); + + /* Ensure 'data' points at mac_header prior calling mpls manipulating + * functions. +diff --git a/net/sched/act_police.c b/net/sched/act_police.c +index db1d021c16be..d4ac56e4579c 100644 +--- a/net/sched/act_police.c ++++ b/net/sched/act_police.c +@@ -125,7 +125,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, + police->common.cpu_bstats, + &police->tcf_rate_est, + &police->tcf_lock, +- NULL, est); ++ false, est); + if (err) + goto failure; + } else if (tb[TCA_POLICE_AVRATE] && +@@ -262,7 +262,7 @@ static int tcf_police_act(struct sk_buff *skb, const struct tc_action *a, + int ret; + + tcf_lastuse_update(&police->tcf_tm); +- bstats_cpu_update(this_cpu_ptr(police->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(police->common.cpu_bstats), skb); + + ret = READ_ONCE(police->tcf_action); + p = rcu_dereference_bh(police->params); +diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c +index ca67d9644917..ef35df94182f 100644 +--- a/net/sched/act_sample.c ++++ b/net/sched/act_sample.c +@@ -170,7 +170,7 @@ static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a, + int retval; + + tcf_lastuse_update(&s->tcf_tm); +- bstats_cpu_update(this_cpu_ptr(s->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(s->common.cpu_bstats), skb); + retval = READ_ONCE(s->tcf_action); + + psample_group = rcu_dereference_bh(s->psample_group); +diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c +index 788527154025..8c1d60bde93e 100644 +--- a/net/sched/act_simple.c ++++ b/net/sched/act_simple.c +@@ -36,7 +36,8 @@ static int tcf_simp_act(struct sk_buff *skb, const struct tc_action *a, + * then it would look like "hello_3" (without quotes) + */ + pr_info("simple: %s_%llu\n", +- (char *)d->tcfd_defdata, d->tcf_bstats.packets); ++ (char *)d->tcfd_defdata, ++ u64_stats_read(&d->tcf_bstats.packets)); + spin_unlock(&d->tcf_lock); + return d->tcf_action; + } +diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c +index 6088ceaf582e..f6df717b9f17 100644 +--- a/net/sched/act_skbedit.c ++++ b/net/sched/act_skbedit.c +@@ -31,7 +31,7 @@ static int tcf_skbedit_act(struct sk_buff *skb, const struct tc_action *a, + int action; + + tcf_lastuse_update(&d->tcf_tm); +- bstats_cpu_update(this_cpu_ptr(d->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(d->common.cpu_bstats), skb); + + params = rcu_dereference_bh(d->params); + action = READ_ONCE(d->tcf_action); +diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c +index ee9cc0abf9e1..2083612d8780 100644 +--- a/net/sched/act_skbmod.c ++++ b/net/sched/act_skbmod.c +@@ -31,7 +31,7 @@ static int tcf_skbmod_act(struct sk_buff *skb, const struct tc_action *a, + u64 flags; + + tcf_lastuse_update(&d->tcf_tm); +- bstats_cpu_update(this_cpu_ptr(d->common.cpu_bstats), skb); ++ bstats_update(this_cpu_ptr(d->common.cpu_bstats), skb); + + action = READ_ONCE(d->tcf_action); + if (unlikely(action == TC_ACT_SHOT)) +diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c +index 328db5e1b0ea..c910046bbe4f 100644 +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -884,7 +884,7 @@ static void qdisc_offload_graft_root(struct net_device *dev, + static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, + u32 portid, u32 seq, u16 flags, int event) + { +- struct gnet_stats_basic_cpu __percpu *cpu_bstats = NULL; ++ struct gnet_stats_basic_sync __percpu *cpu_bstats = NULL; + struct gnet_stats_queue __percpu *cpu_qstats = NULL; + struct tcmsg *tcm; + struct nlmsghdr *nlh; +@@ -942,8 +942,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, + cpu_qstats = q->cpu_qstats; + } + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(q), +- &d, cpu_bstats, &q->bstats) < 0 || ++ if (gnet_stats_copy_basic(&d, cpu_bstats, &q->bstats, true) < 0 || + gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 || + gnet_stats_copy_queue(&d, cpu_qstats, &q->qstats, qlen) < 0) + goto nla_put_failure; +@@ -1275,26 +1274,17 @@ static struct Qdisc *qdisc_create(struct net_device *dev, + rcu_assign_pointer(sch->stab, stab); + } + if (tca[TCA_RATE]) { +- seqcount_t *running; +- + err = -EOPNOTSUPP; + if (sch->flags & TCQ_F_MQROOT) { + NL_SET_ERR_MSG(extack, "Cannot attach rate estimator to a multi-queue root qdisc"); + goto err_out4; + } + +- if (sch->parent != TC_H_ROOT && +- !(sch->flags & TCQ_F_INGRESS) && +- (!p || !(p->flags & TCQ_F_MQROOT))) +- running = qdisc_root_sleeping_running(sch); +- else +- running = &sch->running; +- + err = gen_new_estimator(&sch->bstats, + sch->cpu_bstats, + &sch->rate_est, + NULL, +- running, ++ true, + tca[TCA_RATE]); + if (err) { + NL_SET_ERR_MSG(extack, "Failed to generate new estimator"); +@@ -1370,7 +1360,7 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca, + sch->cpu_bstats, + &sch->rate_est, + NULL, +- qdisc_root_sleeping_running(sch), ++ true, + tca[TCA_RATE]); + } + out: +diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c +index 33737169cc2d..28e1897e0da7 100644 +--- a/net/sched/sch_atm.c ++++ b/net/sched/sch_atm.c +@@ -52,7 +52,7 @@ struct atm_flow_data { + struct atm_qdisc_data *parent; /* parent qdisc */ + struct socket *sock; /* for closing */ + int ref; /* reference count */ +- struct gnet_stats_basic_packed bstats; ++ struct gnet_stats_basic_sync bstats; + struct gnet_stats_queue qstats; + struct list_head list; + struct atm_flow_data *excess; /* flow for excess traffic; +@@ -551,6 +551,7 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt, + pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); + INIT_LIST_HEAD(&p->flows); + INIT_LIST_HEAD(&p->link.list); ++ gnet_stats_basic_sync_init(&p->link.bstats); + list_add(&p->link.list, &p->flows); + p->link.q = qdisc_create_dflt(sch->dev_queue, + &pfifo_qdisc_ops, sch->handle, extack); +@@ -654,8 +655,7 @@ atm_tc_dump_class_stats(struct Qdisc *sch, unsigned long arg, + { + struct atm_flow_data *flow = (struct atm_flow_data *)arg; + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, NULL, &flow->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &flow->bstats, true) < 0 || + gnet_stats_copy_queue(d, NULL, &flow->qstats, flow->q->q.qlen) < 0) + return -1; + +diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c +index 46b3dd71777d..c3a74a2266b0 100644 +--- a/net/sched/sch_cbq.c ++++ b/net/sched/sch_cbq.c +@@ -116,7 +116,7 @@ struct cbq_class { + long avgidle; + long deficit; /* Saved deficit for WRR */ + psched_time_t penalized; +- struct gnet_stats_basic_packed bstats; ++ struct gnet_stats_basic_sync bstats; + struct gnet_stats_queue qstats; + struct net_rate_estimator __rcu *rate_est; + struct tc_cbq_xstats xstats; +@@ -565,8 +565,7 @@ cbq_update(struct cbq_sched_data *q) + long avgidle = cl->avgidle; + long idle; + +- cl->bstats.packets++; +- cl->bstats.bytes += len; ++ _bstats_update(&cl->bstats, len, 1); + + /* + * (now - last) is total time between packet right edges. +@@ -1383,8 +1382,7 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg, + if (cl->undertime != PSCHED_PASTPERFECT) + cl->xstats.undertime = cl->undertime - q->now; + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, NULL, &cl->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &cl->bstats, true) < 0 || + gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || + gnet_stats_copy_queue(d, NULL, &cl->qstats, qlen) < 0) + return -1; +@@ -1518,7 +1516,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t + err = gen_replace_estimator(&cl->bstats, NULL, + &cl->rate_est, + NULL, +- qdisc_root_sleeping_running(sch), ++ true, + tca[TCA_RATE]); + if (err) { + NL_SET_ERR_MSG(extack, "Failed to replace specified rate estimator"); +@@ -1610,6 +1608,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t + if (cl == NULL) + goto failure; + ++ gnet_stats_basic_sync_init(&cl->bstats); + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); + if (err) { + kfree(cl); +@@ -1618,9 +1617,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t + + if (tca[TCA_RATE]) { + err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est, +- NULL, +- qdisc_root_sleeping_running(sch), +- tca[TCA_RATE]); ++ NULL, true, tca[TCA_RATE]); + if (err) { + NL_SET_ERR_MSG(extack, "Couldn't create new estimator"); + tcf_block_put(cl->block); +diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c +index 80a88e208d2b..4e5b1cf11b85 100644 +--- a/net/sched/sch_drr.c ++++ b/net/sched/sch_drr.c +@@ -19,7 +19,7 @@ struct drr_class { + struct Qdisc_class_common common; + unsigned int filter_cnt; + +- struct gnet_stats_basic_packed bstats; ++ struct gnet_stats_basic_sync bstats; + struct gnet_stats_queue qstats; + struct net_rate_estimator __rcu *rate_est; + struct list_head alist; +@@ -85,8 +85,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, NULL, + &cl->rate_est, +- NULL, +- qdisc_root_sleeping_running(sch), ++ NULL, true, + tca[TCA_RATE]); + if (err) { + NL_SET_ERR_MSG(extack, "Failed to replace estimator"); +@@ -106,6 +105,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (cl == NULL) + return -ENOBUFS; + ++ gnet_stats_basic_sync_init(&cl->bstats); + cl->common.classid = classid; + cl->quantum = quantum; + cl->qdisc = qdisc_create_dflt(sch->dev_queue, +@@ -118,9 +118,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, NULL, &cl->rate_est, +- NULL, +- qdisc_root_sleeping_running(sch), +- tca[TCA_RATE]); ++ NULL, true, tca[TCA_RATE]); + if (err) { + NL_SET_ERR_MSG(extack, "Failed to replace estimator"); + qdisc_put(cl->qdisc); +@@ -267,8 +265,7 @@ static int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg, + if (qlen) + xstats.deficit = cl->deficit; + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, NULL, &cl->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &cl->bstats, true) < 0 || + gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || + gnet_stats_copy_queue(d, cl_q->cpu_qstats, &cl_q->qstats, qlen) < 0) + return -1; +diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c +index 175e07b3d25c..8de4365886e8 100644 +--- a/net/sched/sch_ets.c ++++ b/net/sched/sch_ets.c +@@ -41,7 +41,7 @@ struct ets_class { + struct Qdisc *qdisc; + u32 quantum; + u32 deficit; +- struct gnet_stats_basic_packed bstats; ++ struct gnet_stats_basic_sync bstats; + struct gnet_stats_queue qstats; + }; + +@@ -325,8 +325,7 @@ static int ets_class_dump_stats(struct Qdisc *sch, unsigned long arg, + struct ets_class *cl = ets_class_from_arg(sch, arg); + struct Qdisc *cl_q = cl->qdisc; + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, NULL, &cl_q->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &cl_q->bstats, true) < 0 || + qdisc_qstats_copy(d, cl_q) < 0) + return -1; + +@@ -661,7 +660,6 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, + + q->nbands = nbands; + for (i = nstrict; i < q->nstrict; i++) { +- INIT_LIST_HEAD(&q->classes[i].alist); + if (q->classes[i].qdisc->q.qlen) { + list_add_tail(&q->classes[i].alist, &q->active); + q->classes[i].deficit = quanta[i]; +@@ -689,7 +687,11 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, + ets_offload_change(sch); + for (i = q->nbands; i < oldbands; i++) { + qdisc_put(q->classes[i].qdisc); +- memset(&q->classes[i], 0, sizeof(q->classes[i])); ++ q->classes[i].qdisc = NULL; ++ q->classes[i].quantum = 0; ++ q->classes[i].deficit = 0; ++ gnet_stats_basic_sync_init(&q->classes[i].bstats); ++ memset(&q->classes[i].qstats, 0, sizeof(q->classes[i].qstats)); + } + return 0; + } +@@ -698,7 +700,7 @@ static int ets_qdisc_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) + { + struct ets_sched *q = qdisc_priv(sch); +- int err; ++ int err, i; + + if (!opt) + return -EINVAL; +@@ -708,6 +710,9 @@ static int ets_qdisc_init(struct Qdisc *sch, struct nlattr *opt, + return err; + + INIT_LIST_HEAD(&q->active); ++ for (i = 0; i < TCQ_ETS_MAX_BANDS; i++) ++ INIT_LIST_HEAD(&q->classes[i].alist); ++ + return ets_qdisc_change(sch, opt, extack); + } + +diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c +index 02299785209c..b979ae2f551c 100644 +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -304,8 +304,8 @@ static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, + + /* + * Transmit possibly several skbs, and handle the return status as +- * required. Owning running seqcount bit guarantees that +- * only one CPU can execute this function. ++ * required. Owning qdisc running bit guarantees that only one CPU ++ * can execute this function. + * + * Returns to the caller: + * false - hardware queue frozen backoff +@@ -606,7 +606,6 @@ struct Qdisc noop_qdisc = { + .ops = &noop_qdisc_ops, + .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), + .dev_queue = &noop_netdev_queue, +- .running = SEQCNT_ZERO(noop_qdisc.running), + .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock), + .gso_skb = { + .next = (struct sk_buff *)&noop_qdisc.gso_skb, +@@ -867,7 +866,6 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = { + EXPORT_SYMBOL(pfifo_fast_ops); + + static struct lock_class_key qdisc_tx_busylock; +-static struct lock_class_key qdisc_running_key; + + struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + const struct Qdisc_ops *ops, +@@ -892,11 +890,12 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + __skb_queue_head_init(&sch->gso_skb); + __skb_queue_head_init(&sch->skb_bad_txq); + qdisc_skb_head_init(&sch->q); ++ gnet_stats_basic_sync_init(&sch->bstats); + spin_lock_init(&sch->q.lock); + + if (ops->static_flags & TCQ_F_CPUSTATS) { + sch->cpu_bstats = +- netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); ++ netdev_alloc_pcpu_stats(struct gnet_stats_basic_sync); + if (!sch->cpu_bstats) + goto errout1; + +@@ -916,10 +915,6 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + lockdep_set_class(&sch->seqlock, + dev->qdisc_tx_busylock ?: &qdisc_tx_busylock); + +- seqcount_init(&sch->running); +- lockdep_set_class(&sch->running, +- dev->qdisc_running_key ?: &qdisc_running_key); +- + sch->ops = ops; + sch->flags = ops->static_flags; + sch->enqueue = ops->enqueue; +diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c +index 621dc6afde8f..1073c76d05c4 100644 +--- a/net/sched/sch_gred.c ++++ b/net/sched/sch_gred.c +@@ -56,6 +56,7 @@ struct gred_sched { + u32 DPs; + u32 def; + struct red_vars wred_set; ++ struct tc_gred_qopt_offload *opt; + }; + + static inline int gred_wred_mode(struct gred_sched *table) +@@ -311,48 +312,50 @@ static void gred_offload(struct Qdisc *sch, enum tc_gred_command command) + { + struct gred_sched *table = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); +- struct tc_gred_qopt_offload opt = { +- .command = command, +- .handle = sch->handle, +- .parent = sch->parent, +- }; ++ struct tc_gred_qopt_offload *opt = table->opt; + + if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc) + return; + ++ memset(opt, 0, sizeof(*opt)); ++ opt->command = command; ++ opt->handle = sch->handle; ++ opt->parent = sch->parent; ++ + if (command == TC_GRED_REPLACE) { + unsigned int i; + +- opt.set.grio_on = gred_rio_mode(table); +- opt.set.wred_on = gred_wred_mode(table); +- opt.set.dp_cnt = table->DPs; +- opt.set.dp_def = table->def; ++ opt->set.grio_on = gred_rio_mode(table); ++ opt->set.wred_on = gred_wred_mode(table); ++ opt->set.dp_cnt = table->DPs; ++ opt->set.dp_def = table->def; + + for (i = 0; i < table->DPs; i++) { + struct gred_sched_data *q = table->tab[i]; + + if (!q) + continue; +- opt.set.tab[i].present = true; +- opt.set.tab[i].limit = q->limit; +- opt.set.tab[i].prio = q->prio; +- opt.set.tab[i].min = q->parms.qth_min >> q->parms.Wlog; +- opt.set.tab[i].max = q->parms.qth_max >> q->parms.Wlog; +- opt.set.tab[i].is_ecn = gred_use_ecn(q); +- opt.set.tab[i].is_harddrop = gred_use_harddrop(q); +- opt.set.tab[i].probability = q->parms.max_P; +- opt.set.tab[i].backlog = &q->backlog; ++ opt->set.tab[i].present = true; ++ opt->set.tab[i].limit = q->limit; ++ opt->set.tab[i].prio = q->prio; ++ opt->set.tab[i].min = q->parms.qth_min >> q->parms.Wlog; ++ opt->set.tab[i].max = q->parms.qth_max >> q->parms.Wlog; ++ opt->set.tab[i].is_ecn = gred_use_ecn(q); ++ opt->set.tab[i].is_harddrop = gred_use_harddrop(q); ++ opt->set.tab[i].probability = q->parms.max_P; ++ opt->set.tab[i].backlog = &q->backlog; + } +- opt.set.qstats = &sch->qstats; ++ opt->set.qstats = &sch->qstats; + } + +- dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_GRED, &opt); ++ dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_GRED, opt); + } + + static int gred_offload_dump_stats(struct Qdisc *sch) + { + struct gred_sched *table = qdisc_priv(sch); + struct tc_gred_qopt_offload *hw_stats; ++ u64 bytes = 0, packets = 0; + unsigned int i; + int ret; + +@@ -364,9 +367,11 @@ static int gred_offload_dump_stats(struct Qdisc *sch) + hw_stats->handle = sch->handle; + hw_stats->parent = sch->parent; + +- for (i = 0; i < MAX_DPs; i++) ++ for (i = 0; i < MAX_DPs; i++) { ++ gnet_stats_basic_sync_init(&hw_stats->stats.bstats[i]); + if (table->tab[i]) + hw_stats->stats.xstats[i] = &table->tab[i]->stats; ++ } + + ret = qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_GRED, hw_stats); + /* Even if driver returns failure adjust the stats - in case offload +@@ -375,19 +380,19 @@ static int gred_offload_dump_stats(struct Qdisc *sch) + for (i = 0; i < MAX_DPs; i++) { + if (!table->tab[i]) + continue; +- table->tab[i]->packetsin += hw_stats->stats.bstats[i].packets; +- table->tab[i]->bytesin += hw_stats->stats.bstats[i].bytes; ++ table->tab[i]->packetsin += u64_stats_read(&hw_stats->stats.bstats[i].packets); ++ table->tab[i]->bytesin += u64_stats_read(&hw_stats->stats.bstats[i].bytes); + table->tab[i]->backlog += hw_stats->stats.qstats[i].backlog; + +- _bstats_update(&sch->bstats, +- hw_stats->stats.bstats[i].bytes, +- hw_stats->stats.bstats[i].packets); ++ bytes += u64_stats_read(&hw_stats->stats.bstats[i].bytes); ++ packets += u64_stats_read(&hw_stats->stats.bstats[i].packets); + sch->qstats.qlen += hw_stats->stats.qstats[i].qlen; + sch->qstats.backlog += hw_stats->stats.qstats[i].backlog; + sch->qstats.drops += hw_stats->stats.qstats[i].drops; + sch->qstats.requeues += hw_stats->stats.qstats[i].requeues; + sch->qstats.overlimits += hw_stats->stats.qstats[i].overlimits; + } ++ _bstats_update(&sch->bstats, bytes, packets); + + kfree(hw_stats); + return ret; +@@ -728,6 +733,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt, + static int gred_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) + { ++ struct gred_sched *table = qdisc_priv(sch); + struct nlattr *tb[TCA_GRED_MAX + 1]; + int err; + +@@ -751,6 +757,12 @@ static int gred_init(struct Qdisc *sch, struct nlattr *opt, + sch->limit = qdisc_dev(sch)->tx_queue_len + * psched_mtu(qdisc_dev(sch)); + ++ if (qdisc_dev(sch)->netdev_ops->ndo_setup_tc) { ++ table->opt = kzalloc(sizeof(*table->opt), GFP_KERNEL); ++ if (!table->opt) ++ return -ENOMEM; ++ } ++ + return gred_change_table_def(sch, tb[TCA_GRED_DPS], extack); + } + +@@ -907,6 +919,7 @@ static void gred_destroy(struct Qdisc *sch) + gred_destroy_vq(table->tab[i]); + } + gred_offload(sch, TC_GRED_DESTROY); ++ kfree(table->opt); + } + + static struct Qdisc_ops gred_qdisc_ops __read_mostly = { +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index c802a027b4f3..03efc40e42fc 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -111,7 +111,7 @@ enum hfsc_class_flags { + struct hfsc_class { + struct Qdisc_class_common cl_common; + +- struct gnet_stats_basic_packed bstats; ++ struct gnet_stats_basic_sync bstats; + struct gnet_stats_queue qstats; + struct net_rate_estimator __rcu *rate_est; + struct tcf_proto __rcu *filter_list; /* filter list */ +@@ -965,7 +965,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + err = gen_replace_estimator(&cl->bstats, NULL, + &cl->rate_est, + NULL, +- qdisc_root_sleeping_running(sch), ++ true, + tca[TCA_RATE]); + if (err) + return err; +@@ -1033,9 +1033,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + + if (tca[TCA_RATE]) { + err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est, +- NULL, +- qdisc_root_sleeping_running(sch), +- tca[TCA_RATE]); ++ NULL, true, tca[TCA_RATE]); + if (err) { + tcf_block_put(cl->block); + kfree(cl); +@@ -1328,7 +1326,7 @@ hfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg, + xstats.work = cl->cl_total; + xstats.rtwork = cl->cl_cumul; + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d, NULL, &cl->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &cl->bstats, true) < 0 || + gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || + gnet_stats_copy_queue(d, NULL, &cl->qstats, qlen) < 0) + return -1; +@@ -1406,6 +1404,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt, + if (err) + return err; + ++ gnet_stats_basic_sync_init(&q->root.bstats); + q->root.cl_common.classid = sch->handle; + q->root.sched = q; + q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, +diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c +index 8ce999e4ca32..a90e4fffdfd9 100644 +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -113,8 +113,8 @@ struct htb_class { + /* + * Written often fields + */ +- struct gnet_stats_basic_packed bstats; +- struct gnet_stats_basic_packed bstats_bias; ++ struct gnet_stats_basic_sync bstats; ++ struct gnet_stats_basic_sync bstats_bias; + struct tc_htb_xstats xstats; /* our special stats */ + + /* token bucket parameters */ +@@ -1309,10 +1309,11 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, + static void htb_offload_aggregate_stats(struct htb_sched *q, + struct htb_class *cl) + { ++ u64 bytes = 0, packets = 0; + struct htb_class *c; + unsigned int i; + +- memset(&cl->bstats, 0, sizeof(cl->bstats)); ++ gnet_stats_basic_sync_init(&cl->bstats); + + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(c, &q->clhash.hash[i], common.hnode) { +@@ -1324,14 +1325,15 @@ static void htb_offload_aggregate_stats(struct htb_sched *q, + if (p != cl) + continue; + +- cl->bstats.bytes += c->bstats_bias.bytes; +- cl->bstats.packets += c->bstats_bias.packets; ++ bytes += u64_stats_read(&c->bstats_bias.bytes); ++ packets += u64_stats_read(&c->bstats_bias.packets); + if (c->level == 0) { +- cl->bstats.bytes += c->leaf.q->bstats.bytes; +- cl->bstats.packets += c->leaf.q->bstats.packets; ++ bytes += u64_stats_read(&c->leaf.q->bstats.bytes); ++ packets += u64_stats_read(&c->leaf.q->bstats.packets); + } + } + } ++ _bstats_update(&cl->bstats, bytes, packets); + } + + static int +@@ -1358,16 +1360,16 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d) + if (cl->leaf.q) + cl->bstats = cl->leaf.q->bstats; + else +- memset(&cl->bstats, 0, sizeof(cl->bstats)); +- cl->bstats.bytes += cl->bstats_bias.bytes; +- cl->bstats.packets += cl->bstats_bias.packets; ++ gnet_stats_basic_sync_init(&cl->bstats); ++ _bstats_update(&cl->bstats, ++ u64_stats_read(&cl->bstats_bias.bytes), ++ u64_stats_read(&cl->bstats_bias.packets)); + } else { + htb_offload_aggregate_stats(q, cl); + } + } + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, NULL, &cl->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &cl->bstats, true) < 0 || + gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || + gnet_stats_copy_queue(d, NULL, &qs, qlen) < 0) + return -1; +@@ -1582,8 +1584,9 @@ static int htb_destroy_class_offload(struct Qdisc *sch, struct htb_class *cl, + } + + if (cl->parent) { +- cl->parent->bstats_bias.bytes += q->bstats.bytes; +- cl->parent->bstats_bias.packets += q->bstats.packets; ++ _bstats_update(&cl->parent->bstats_bias, ++ u64_stats_read(&q->bstats.bytes), ++ u64_stats_read(&q->bstats.packets)); + } + + offload_opt = (struct tc_htb_qopt_offload) { +@@ -1875,6 +1878,9 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, + if (!cl) + goto failure; + ++ gnet_stats_basic_sync_init(&cl->bstats); ++ gnet_stats_basic_sync_init(&cl->bstats_bias); ++ + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); + if (err) { + kfree(cl); +@@ -1884,7 +1890,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, + err = gen_new_estimator(&cl->bstats, NULL, + &cl->rate_est, + NULL, +- qdisc_root_sleeping_running(sch), ++ true, + tca[TCA_RATE] ? : &est.nla); + if (err) + goto err_block_put; +@@ -1948,8 +1954,9 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, + htb_graft_helper(dev_queue, old_q); + goto err_kill_estimator; + } +- parent->bstats_bias.bytes += old_q->bstats.bytes; +- parent->bstats_bias.packets += old_q->bstats.packets; ++ _bstats_update(&parent->bstats_bias, ++ u64_stats_read(&old_q->bstats.bytes), ++ u64_stats_read(&old_q->bstats.packets)); + qdisc_put(old_q); + } + new_q = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops, +@@ -2009,7 +2016,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, + err = gen_replace_estimator(&cl->bstats, NULL, + &cl->rate_est, + NULL, +- qdisc_root_sleeping_running(sch), ++ true, + tca[TCA_RATE]); + if (err) + return err; +diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c +index db18d8a860f9..24c5d97d88dd 100644 +--- a/net/sched/sch_mq.c ++++ b/net/sched/sch_mq.c +@@ -153,10 +153,9 @@ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb) + struct net_device *dev = qdisc_dev(sch); + struct Qdisc *qdisc; + unsigned int ntx; +- __u32 qlen = 0; + + sch->q.qlen = 0; +- memset(&sch->bstats, 0, sizeof(sch->bstats)); ++ gnet_stats_basic_sync_init(&sch->bstats); + memset(&sch->qstats, 0, sizeof(sch->qstats)); + + /* MQ supports lockless qdiscs. However, statistics accounting needs +@@ -168,25 +167,11 @@ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb) + qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping; + spin_lock_bh(qdisc_lock(qdisc)); + +- if (qdisc_is_percpu_stats(qdisc)) { +- qlen = qdisc_qlen_sum(qdisc); +- __gnet_stats_copy_basic(NULL, &sch->bstats, +- qdisc->cpu_bstats, +- &qdisc->bstats); +- __gnet_stats_copy_queue(&sch->qstats, +- qdisc->cpu_qstats, +- &qdisc->qstats, qlen); +- sch->q.qlen += qlen; +- } else { +- sch->q.qlen += qdisc->q.qlen; +- sch->bstats.bytes += qdisc->bstats.bytes; +- sch->bstats.packets += qdisc->bstats.packets; +- sch->qstats.qlen += qdisc->qstats.qlen; +- sch->qstats.backlog += qdisc->qstats.backlog; +- sch->qstats.drops += qdisc->qstats.drops; +- sch->qstats.requeues += qdisc->qstats.requeues; +- sch->qstats.overlimits += qdisc->qstats.overlimits; +- } ++ gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats, ++ &qdisc->bstats, false); ++ gnet_stats_add_queue(&sch->qstats, qdisc->cpu_qstats, ++ &qdisc->qstats); ++ sch->q.qlen += qdisc_qlen(qdisc); + + spin_unlock_bh(qdisc_lock(qdisc)); + } +@@ -269,8 +254,7 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct netdev_queue *dev_queue = mq_queue_get(sch, cl); + + sch = dev_queue->qdisc_sleeping; +- if (gnet_stats_copy_basic(&sch->running, d, sch->cpu_bstats, +- &sch->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, sch->cpu_bstats, &sch->bstats, true) < 0 || + qdisc_qstats_copy(d, sch) < 0) + return -1; + return 0; +diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c +index 50e15add6068..42d4101e4f3d 100644 +--- a/net/sched/sch_mqprio.c ++++ b/net/sched/sch_mqprio.c +@@ -412,7 +412,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb) + unsigned int ntx, tc; + + sch->q.qlen = 0; +- memset(&sch->bstats, 0, sizeof(sch->bstats)); ++ gnet_stats_basic_sync_init(&sch->bstats); + memset(&sch->qstats, 0, sizeof(sch->qstats)); + + /* MQ supports lockless qdiscs. However, statistics accounting needs +@@ -424,25 +424,11 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb) + qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping; + spin_lock_bh(qdisc_lock(qdisc)); + +- if (qdisc_is_percpu_stats(qdisc)) { +- __u32 qlen = qdisc_qlen_sum(qdisc); +- +- __gnet_stats_copy_basic(NULL, &sch->bstats, +- qdisc->cpu_bstats, +- &qdisc->bstats); +- __gnet_stats_copy_queue(&sch->qstats, +- qdisc->cpu_qstats, +- &qdisc->qstats, qlen); +- sch->q.qlen += qlen; +- } else { +- sch->q.qlen += qdisc->q.qlen; +- sch->bstats.bytes += qdisc->bstats.bytes; +- sch->bstats.packets += qdisc->bstats.packets; +- sch->qstats.backlog += qdisc->qstats.backlog; +- sch->qstats.drops += qdisc->qstats.drops; +- sch->qstats.requeues += qdisc->qstats.requeues; +- sch->qstats.overlimits += qdisc->qstats.overlimits; +- } ++ gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats, ++ &qdisc->bstats, false); ++ gnet_stats_add_queue(&sch->qstats, qdisc->cpu_qstats, ++ &qdisc->qstats); ++ sch->q.qlen += qdisc_qlen(qdisc); + + spin_unlock_bh(qdisc_lock(qdisc)); + } +@@ -534,12 +520,13 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, + { + if (cl >= TC_H_MIN_PRIORITY) { + int i; +- __u32 qlen = 0; ++ __u32 qlen; + struct gnet_stats_queue qstats = {0}; +- struct gnet_stats_basic_packed bstats = {0}; ++ struct gnet_stats_basic_sync bstats; + struct net_device *dev = qdisc_dev(sch); + struct netdev_tc_txq tc = dev->tc_to_txq[cl & TC_BITMASK]; + ++ gnet_stats_basic_sync_init(&bstats); + /* Drop lock here it will be reclaimed before touching + * statistics this is required because the d->lock we + * hold here is the look on dev_queue->qdisc_sleeping +@@ -554,40 +541,28 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, + + spin_lock_bh(qdisc_lock(qdisc)); + +- if (qdisc_is_percpu_stats(qdisc)) { +- qlen = qdisc_qlen_sum(qdisc); +- +- __gnet_stats_copy_basic(NULL, &bstats, +- qdisc->cpu_bstats, +- &qdisc->bstats); +- __gnet_stats_copy_queue(&qstats, +- qdisc->cpu_qstats, +- &qdisc->qstats, +- qlen); +- } else { +- qlen += qdisc->q.qlen; +- bstats.bytes += qdisc->bstats.bytes; +- bstats.packets += qdisc->bstats.packets; +- qstats.backlog += qdisc->qstats.backlog; +- qstats.drops += qdisc->qstats.drops; +- qstats.requeues += qdisc->qstats.requeues; +- qstats.overlimits += qdisc->qstats.overlimits; +- } ++ gnet_stats_add_basic(&bstats, qdisc->cpu_bstats, ++ &qdisc->bstats, false); ++ gnet_stats_add_queue(&qstats, qdisc->cpu_qstats, ++ &qdisc->qstats); ++ sch->q.qlen += qdisc_qlen(qdisc); ++ + spin_unlock_bh(qdisc_lock(qdisc)); + } ++ qlen = qdisc_qlen(sch) + qstats.qlen; + + /* Reclaim root sleeping lock before completing stats */ + if (d->lock) + spin_lock_bh(d->lock); +- if (gnet_stats_copy_basic(NULL, d, NULL, &bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &bstats, false) < 0 || + gnet_stats_copy_queue(d, NULL, &qstats, qlen) < 0) + return -1; + } else { + struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl); + + sch = dev_queue->qdisc_sleeping; +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d, +- sch->cpu_bstats, &sch->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, sch->cpu_bstats, ++ &sch->bstats, true) < 0 || + qdisc_qstats_copy(d, sch) < 0) + return -1; + } +diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c +index 8b99f07aa3a7..f28050c7f12d 100644 +--- a/net/sched/sch_multiq.c ++++ b/net/sched/sch_multiq.c +@@ -337,8 +337,7 @@ static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct Qdisc *cl_q; + + cl_q = q->queues[cl - 1]; +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, cl_q->cpu_bstats, &cl_q->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, cl_q->cpu_bstats, &cl_q->bstats, true) < 0 || + qdisc_qstats_copy(d, cl_q) < 0) + return -1; + +diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c +index 2e0b1e7f5466..c03a11dd990f 100644 +--- a/net/sched/sch_prio.c ++++ b/net/sched/sch_prio.c +@@ -359,8 +359,8 @@ static int prio_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct Qdisc *cl_q; + + cl_q = q->queues[cl - 1]; +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, cl_q->cpu_bstats, &cl_q->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, cl_q->cpu_bstats, ++ &cl_q->bstats, true) < 0 || + qdisc_qstats_copy(d, cl_q) < 0) + return -1; + +diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c +index 4c51aeb78f14..e591c3547b12 100644 +--- a/net/sched/sch_qfq.c ++++ b/net/sched/sch_qfq.c +@@ -131,7 +131,7 @@ struct qfq_class { + + unsigned int filter_cnt; + +- struct gnet_stats_basic_packed bstats; ++ struct gnet_stats_basic_sync bstats; + struct gnet_stats_queue qstats; + struct net_rate_estimator __rcu *rate_est; + struct Qdisc *qdisc; +@@ -452,7 +452,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + err = gen_replace_estimator(&cl->bstats, NULL, + &cl->rate_est, + NULL, +- qdisc_root_sleeping_running(sch), ++ true, + tca[TCA_RATE]); + if (err) + return err; +@@ -466,6 +466,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (cl == NULL) + return -ENOBUFS; + ++ gnet_stats_basic_sync_init(&cl->bstats); + cl->common.classid = classid; + cl->deficit = lmax; + +@@ -478,7 +479,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + err = gen_new_estimator(&cl->bstats, NULL, + &cl->rate_est, + NULL, +- qdisc_root_sleeping_running(sch), ++ true, + tca[TCA_RATE]); + if (err) + goto destroy_class; +@@ -640,8 +641,7 @@ static int qfq_dump_class_stats(struct Qdisc *sch, unsigned long arg, + xstats.weight = cl->agg->class_weight; + xstats.lmax = cl->agg->lmax; + +- if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), +- d, NULL, &cl->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &cl->bstats, true) < 0 || + gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || + qdisc_qstats_copy(d, cl->qdisc) < 0) + return -1; +@@ -1235,8 +1235,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- cl->bstats.bytes += len; +- cl->bstats.packets += gso_segs; ++ _bstats_update(&cl->bstats, len, gso_segs); + sch->qstats.backlog += len; + ++sch->q.qlen; + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index e203deacc953..30497d446af5 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -1987,7 +1987,7 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); + + sch = dev_queue->qdisc_sleeping; +- if (gnet_stats_copy_basic(&sch->running, d, NULL, &sch->bstats) < 0 || ++ if (gnet_stats_copy_basic(d, NULL, &sch->bstats, true) < 0 || + qdisc_qstats_copy(d, sch) < 0) + return -1; + return 0; +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index 5ff8f902f14d..2ea5c3f18fd4 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -441,7 +441,7 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt) + if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) + return; + +- cpu = get_cpu(); ++ cpu = get_cpu_light(); + pool = svc_pool_for_cpu(xprt->xpt_server, cpu); + + atomic_long_inc(&pool->sp_stats.packets); +@@ -465,7 +465,7 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt) + rqstp = NULL; + out_unlock: + rcu_read_unlock(); +- put_cpu(); ++ put_cpu_light(); + trace_svc_xprt_do_enqueue(xprt, rqstp); + } + EXPORT_SYMBOL_GPL(svc_xprt_do_enqueue); +diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c +index 5a90aa527877..642d0748c169 100644 +--- a/samples/kfifo/bytestream-example.c ++++ b/samples/kfifo/bytestream-example.c +@@ -22,10 +22,10 @@ + #define PROC_FIFO "bytestream-fifo" + + /* lock for procfs read access */ +-static DEFINE_MUTEX(read_lock); ++static DEFINE_MUTEX(read_access); + + /* lock for procfs write access */ +-static DEFINE_MUTEX(write_lock); ++static DEFINE_MUTEX(write_access); + + /* + * define DYNAMIC in this example for a dynamically allocated fifo. +@@ -116,12 +116,12 @@ static ssize_t fifo_write(struct file *file, const char __user *buf, + int ret; + unsigned int copied; + +- if (mutex_lock_interruptible(&write_lock)) ++ if (mutex_lock_interruptible(&write_access)) + return -ERESTARTSYS; + + ret = kfifo_from_user(&test, buf, count, &copied); + +- mutex_unlock(&write_lock); ++ mutex_unlock(&write_access); + if (ret) + return ret; + +@@ -134,12 +134,12 @@ static ssize_t fifo_read(struct file *file, char __user *buf, + int ret; + unsigned int copied; + +- if (mutex_lock_interruptible(&read_lock)) ++ if (mutex_lock_interruptible(&read_access)) + return -ERESTARTSYS; + + ret = kfifo_to_user(&test, buf, count, &copied); + +- mutex_unlock(&read_lock); ++ mutex_unlock(&read_access); + if (ret) + return ret; + +diff --git a/samples/kfifo/inttype-example.c b/samples/kfifo/inttype-example.c +index e5403d8c971a..c61482ba94f4 100644 +--- a/samples/kfifo/inttype-example.c ++++ b/samples/kfifo/inttype-example.c +@@ -22,10 +22,10 @@ + #define PROC_FIFO "int-fifo" + + /* lock for procfs read access */ +-static DEFINE_MUTEX(read_lock); ++static DEFINE_MUTEX(read_access); + + /* lock for procfs write access */ +-static DEFINE_MUTEX(write_lock); ++static DEFINE_MUTEX(write_access); + + /* + * define DYNAMIC in this example for a dynamically allocated fifo. +@@ -109,12 +109,12 @@ static ssize_t fifo_write(struct file *file, const char __user *buf, + int ret; + unsigned int copied; + +- if (mutex_lock_interruptible(&write_lock)) ++ if (mutex_lock_interruptible(&write_access)) + return -ERESTARTSYS; + + ret = kfifo_from_user(&test, buf, count, &copied); + +- mutex_unlock(&write_lock); ++ mutex_unlock(&write_access); + if (ret) + return ret; + +@@ -127,12 +127,12 @@ static ssize_t fifo_read(struct file *file, char __user *buf, + int ret; + unsigned int copied; + +- if (mutex_lock_interruptible(&read_lock)) ++ if (mutex_lock_interruptible(&read_access)) + return -ERESTARTSYS; + + ret = kfifo_to_user(&test, buf, count, &copied); + +- mutex_unlock(&read_lock); ++ mutex_unlock(&read_access); + if (ret) + return ret; + +diff --git a/samples/kfifo/record-example.c b/samples/kfifo/record-example.c +index f64f3d62d6c2..e4087b2d3fc4 100644 +--- a/samples/kfifo/record-example.c ++++ b/samples/kfifo/record-example.c +@@ -22,10 +22,10 @@ + #define PROC_FIFO "record-fifo" + + /* lock for procfs read access */ +-static DEFINE_MUTEX(read_lock); ++static DEFINE_MUTEX(read_access); + + /* lock for procfs write access */ +-static DEFINE_MUTEX(write_lock); ++static DEFINE_MUTEX(write_access); + + /* + * define DYNAMIC in this example for a dynamically allocated fifo. +@@ -123,12 +123,12 @@ static ssize_t fifo_write(struct file *file, const char __user *buf, + int ret; + unsigned int copied; + +- if (mutex_lock_interruptible(&write_lock)) ++ if (mutex_lock_interruptible(&write_access)) + return -ERESTARTSYS; + + ret = kfifo_from_user(&test, buf, count, &copied); + +- mutex_unlock(&write_lock); ++ mutex_unlock(&write_access); + if (ret) + return ret; + +@@ -141,12 +141,12 @@ static ssize_t fifo_read(struct file *file, char __user *buf, + int ret; + unsigned int copied; + +- if (mutex_lock_interruptible(&read_lock)) ++ if (mutex_lock_interruptible(&read_access)) + return -ERESTARTSYS; + + ret = kfifo_to_user(&test, buf, count, &copied); + +- mutex_unlock(&read_lock); ++ mutex_unlock(&read_access); + if (ret) + return ret; + +diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c +index 3f3f56f6be4d..5dbcdc5b22b5 100644 +--- a/security/smack/smack_lsm.c ++++ b/security/smack/smack_lsm.c +@@ -51,8 +51,10 @@ + #define SMK_RECEIVING 1 + #define SMK_SENDING 2 + ++#ifdef SMACK_IPV6_PORT_LABELING + static DEFINE_MUTEX(smack_ipv6_lock); + static LIST_HEAD(smk_ipv6_port_list); ++#endif + struct kmem_cache *smack_rule_cache; + int smack_enabled __initdata; + +@@ -2603,7 +2605,6 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) + mutex_unlock(&smack_ipv6_lock); + return; + } +-#endif + + /** + * smk_ipv6_port_check - check Smack port access +@@ -2666,6 +2667,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, + + return smk_ipv6_check(skp, object, address, act); + } ++#endif + + /** + * smack_inode_setsecurity - set smack xattrs +@@ -2852,8 +2854,9 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, + rc = smk_ipv6_check(ssp->smk_out, rsp, sip, + SMK_CONNECTING); + } +- if (__is_defined(SMACK_IPV6_PORT_LABELING)) +- rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING); ++#ifdef SMACK_IPV6_PORT_LABELING ++ rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING); ++#endif + + return rc; + } +diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c +index e95c7c018e7d..4f2c2379531b 100644 +--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c ++++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c +@@ -288,7 +288,6 @@ const struct snd_soc_dai_ops mtk_afe_fe_ops = { + }; + EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); + +-static DEFINE_MUTEX(irqs_lock); + int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) + { + int i; diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb index cc65d7536..21efc5450 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey_5.15.bb @@ -7,6 +7,24 @@ SRCBRANCH:stm32mpcommon = "v5.15.118/stm/master" SRCREV = "${AUTOREV}" SRCREV:stm32mpcommon = "${AUTOREV}" +STM_RT_PATCHES = " \ + file://patch-5.15.119-rt65.patch \ + file://0023-5.15-stm32mp-rt-49-r1-CLOCK.patch \ + file://0024-5.15-stm32mp-rt-49-r1-DMA.patch \ + file://0025-5.15-stm32mp-rt-49-r1-MFD.patch \ + file://0026-5.15-stm32mp-rt-49-r1-NET-TTY.patch \ + file://0027-5.15-stm32mp-rt-49-r1-DEVICETREE.patch \ + file://0028-5.15-stm32mp-rt-49-r1-CONFIG.patch \ +" + +SRC_URI:append:stm32mpcommon = " \ + ${@bb.utils.contains('DISTRO_FEATURES', 'rt', '${STM_RT_PATCHES}', '', d)} \ +" + +KERNEL_CONFIG_FRAGMENTS:append:stm32mpcommon = " ${@bb.utils.contains('DISTRO_FEATURES', 'rt', '${S}/arch/arm/configs/fragment-07-rt.config', '', d)}" +KERNEL_CONFIG_FRAGMENTS:append:stm32mpcommon = " ${@bb.utils.contains('DISTRO_FEATURES', 'rt', '${S}/arch/arm/configs/fragment-07-rt-sysvinit.config', '', d)}" +KERNEL_CONFIG_FRAGMENTS:append:ccmp13 = " ${@bb.utils.contains('DISTRO_FEATURES', 'rt', '${S}/arch/arm/configs/fragment-08-rt-mp13.config', '', d)}" + do_assemble_fitimage:append:ccmp1() { # # Step 9: Add public keys to the different U-Boot dtb files From 59025531c5493211063d51ba655c5945f87a89e8 Mon Sep 17 00:00:00 2001 From: Gonzalo Ruiz Date: Mon, 29 Apr 2024 16:08:29 +0200 Subject: [PATCH 72/91] ccmp15: add DT overlay for configuring a MIPI display https://onedigi.atlassian.net/browse/DEL-8999 Signed-off-by: Gonzalo Ruiz --- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index ce7cb5ec3..ebeb091e9 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -38,6 +38,7 @@ STM32MP_KERNEL_DEVICETREE:ccmp15-dvk += " \ ccmp157-dvk.dtb \ _ov_board_can1_ccmp15-dvk.dtbo \ _ov_board_can2_ccmp15-dvk.dtbo \ + _ov_board_dlc0200ccp04df-mipi-dsi_ccmp15-dvk.dtbo \ _ov_board_eth0-10-100_ccmp15-dvk.dtbo \ _ov_board_fusion10-lvds_ccmp15-dvk.dtbo \ _ov_board_fusion7-parallel_ccmp15-dvk.dtbo \ From a288a03ef59b1af6bac6e68bc0398120ad8c3144 Mon Sep 17 00:00:00 2001 From: Gonzalo Ruiz Date: Thu, 2 May 2024 11:44:44 +0200 Subject: [PATCH 73/91] firmware_qualcomm: ccimx8m: update US Board Data File calibration Update BDF file used on CC8MN and CC8MM with a new calibration (GOLDEN3) to obtain a flatter frequency response and a better EVM performance. Reference calibration file is obtained from 'qca6574au-le-2-2-2_qca_oem' repo at tag 'r00005.1' under path 'wlanfw/cnss_proc/wlan/fw/target/sdio_dst/qc6174/bdwlan30.bin' (MD5SUM: 8a40d95698825e1718bee640b1f7982a). Target output powers tables and CTL tables remain intact. Changes required to pass the EN 300 328 V2.2.2 blocking test also remain intact. New BDF file: - bdwlan30_US.bin (86180198440e6ab53734aabf0112c6ba) https://onedigi.atlassian.net/browse/DEL-9001 Signed-off-by: Gonzalo Ruiz --- .../firmware-qualcomm/ccimx8m/bdwlan30_US.bin | Bin 8124 -> 8124 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/firmware-qualcomm/firmware-qualcomm/ccimx8m/bdwlan30_US.bin b/meta-digi-arm/recipes-bsp/firmware-qualcomm/firmware-qualcomm/ccimx8m/bdwlan30_US.bin index caf52219d498105f0d61ebc2091f1ee335d331b7..5aaaf7eea34ebcd42a52f6397e7bc9abd70fbe89 100644 GIT binary patch delta 2577 zcmZuyTUQfT6sE0KmlrB3ltBhMdJ4wNQ9v%4Dlm$eqXdu$1 zHss#77k|k9G@1(a8MRA`xhFFt(GGLp>gqFIwDdgtd^8yf8#PN$v)@|7p%aE8f#uu_ zD;bTNc=1s-Yh4eu8I=-vmixuBqW$Kf#mCu4)=0=OR0%xEJ)fD1n&y6pkU*6L9^1L) znPjxvtX=vZv_?Yhg^-mQE7}Xdlk9h3(waAUn)`Vs6^)n&Ai@LI+?R5{f%|}Y7)&?- zhT)s6WLKaN)9~E6NXrMFXIIQo3rej09|W2bHUa>6X{~Af2qvtz&#Z^0$b5Y*p8N4m zD%xe%{QA!a@7WPFh==tFGEL{$J^s*n>i(qa=p;U;N5~)@W)pnc$+-8_AvA`WK1;r$ z57;7Kc3!xDs4b`+hjf#~Xq+W@%DL@+sZOA2oYC)*hxB{4!e2Unx__xn=mhT6d&mI2 z!ftTOnQ<4?F_gl$^}9B?Pam;o{AcHP_mz4KeTF;qF49jgvFm)&`NFl;E9eHc^jpNH zU$ck&iL>m!Q0q|;pVZHh2pwcYe8TzM&8QJ{5fAC(qL8on1831)QtMC)HgrNvdXZh@ zV-9m?)e!2zQ9Vu)G|AH3UU0r~xq1{e<90m+#2AYMF$Kgn)QNla0dkd&GK;63yY7A9 zwE)i(Eby998+4(UMCnyF%9Bpoy$i-cVH_65<6t}|Vr4QhkxUByYp{`yPeCPpl(Jz_ z$-H_1)ni>hNzT#;8{|XIg!_fsC|cM}F3`)+!YSvLdq+j+5I&|KCmr-W>*tr95qCphJC$7!(PK2!l?FD-h>RVZ z1e0PPIaarO4KYW9=fHi(!Zd_L zfeHn_3Ry@h*sWD*Y9d7FhFd&L@P$IJl%NPKlB9R235dd8R znYbk)Dq~6G0+?uuU;8Y$hqb**dCW5U0jO3=@+OuM(=@FLr22&WehJLQCyl7BeXFE*rG(wJxNSRxI7PJgvlPQB6-UkGJ=6^fo(EkEH z>L&CN{#dUj`{_~E!rL9W zcPBxwSm@Q#Bdi(pLZJ64e0Gg`Ym}U(-Ry$+?ko`84uVx6SRlSFNS$H#<{Ga?@Y;kR zLI?ft*fXY&FPA9xesmPK=mrTBie>b!J~#^*2LSKGj1>JiaHz=yCTdk z@@vkR%hU~mr@qBIj2dyP-buRY0K39(I8*M7--New_BWh(9FGg*5>$q(^jdO+HnVmfa(dTzGC}XyO~ctPMx_|8 e5$H9t>0orY1C05jv~&`2#j1d z#Qp6pOZl*0{4wWg*Qq*xfXB1;?zw2HGLQ4E^{ww)tGm~J)A6Qb z_nT1ezrXL!zh`gf^FJ;u3=UXydo%xHVKUKeo!HrVrFLz<%>S@3H`s60ZEvmpGcz7- zHv<~j$Zs#qBnGWho9k<9nTcqJS*?L@^7&Pnh+24aV{JV%88uC$fv@r}Rs-g8PF81x4`v9 zeq9^+`G0@?i`_?t>2)^Ar^URq)fdj1`wB7AMK7~B9~I+rO3gaU?o%YlIGtv5d__Ey z&()Umqx%bLC7m?NES?l8nN~B-BliiqL#F8*Tj5W|*K$*BJ3qU>p=Q!fFR}rCRosxD zsf@GWK1LH{iq5hnn?Dg>$#wP0`N{niHInnRn_c08*d0dRj+iJ>r=q{uFcZ@u9p1WHpOj@bQIJd+#c}v}Oq`Qc^NH2}E zQGQ!Y$ysGDIZxeh&{@(#J6RM0lQIQ?GZ5&x<1EIniCgk6xLX8wXMwQOCoIQ>eKEZ} z<`=o=7xDh{3YY&|LUrUEJu#QS!3zT4cDTTErlAzXng0f+-oWmFb`^fb5d5&RJVF|!qbk2SE8nt_Y} z4&)wM1Ca)!0&C#04ZsLKhL1wVfY}hPF!tz-We*v~K^*jv#_*9M@+h5wlu9G`cotGT zAgEK83S0<)e&G7pfcx#~wL$MS9Kto}88aR}X9NRqD*%A%(j3JIFH&V~ zGl^?(2#^>cfk0gWN#6$m;i_~NfF=N#29}{)30#e3L7*D)tDn+9EWeyCFD>sB@0C`4yH38xCN?z`@mK3e$2Pn0u~F^ms9tkzn~XtXz%f24dBLAw&CgWz2ofCVepnc?T z^e7AQQ{t>_Rhc5IITfSu5`pTn?(FlXC9@ z-$9@6q^OrIz!wF+6Qqtdu(m|uevUa4?ljs3B*)}_#upCnp&VBbGXz`lxuI75uOgq>mn-7SDys7Ru zS$Dw?^txI!=XKS4g3B+Qelg$ez6srrA*u<1@2bz2ap%$dFr_MX9HtbO5oJ2P5a$Uz z&$@Y^FVLQFrr~+?2z8)0P90bz94raU6$E;OI<6?Nyd(6pTpnlnc$_H+Eb?W*@E*G~ z_i~_qzdwZ*4oLy;x7WflVR`IY;KjEb=L&H}f%;sY^Pm3Wvb*muv0`WJvXdC9hvft_ zf#p;jiFW*FEz|@951VrO)x4SytEwm*|5(nfn&zrVL9{iS1rlS4GX zPVm#BQJz=bPM@17Y)`%IQYsDG^AS2sDrpTn$?HXn>{L-_5aK9lq8Gr3ceZZ8+45R_ okW^6EM!?r3+f)zmjiCl|*!vFX^S=Ye)qQ8yU3&fb5%$6V0k{{ER{#J2 From 720c5f7218efe8a9310bd6c6e1340beda109befa Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Tue, 28 May 2024 17:57:01 +0200 Subject: [PATCH 74/91] libubootenv: rework patchset with Digi-specific functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move Digi code out of the upstream files to minimize conflicts in version migrations. * Remove all the TEE client copied code and use the libteeclient library. * Some fixes in the Optee-based environment encryption * Some simplifications in CAAM-based environment encryption. https://onedigi.atlassian.net/browse/DUB-1079 Signed-off-by: Javier Viguera --- ...U-Boot-environment-access-functions.patch} | 4 +- ...port-to-set-dynamic-location-of-env.patch} | 24 +- ...-for-environment-encryption-by-CAAM.patch} | 440 +-- ...t-for-environment-encryption-using-O.patch | 259 ++ ...d-HWID-from-nvmem-device-if-not-avai.patch | 105 - ...t-for-environment-encryption-for-CCM.patch | 2802 ----------------- .../libubootenv/libubootenv_%.bbappend | 15 +- 7 files changed, 543 insertions(+), 3106 deletions(-) rename meta-digi-arm/recipes-bsp/libubootenv/libubootenv/{0002-Implement-U-Boot-environment-access-functions.patch => 0001-Implement-U-Boot-environment-access-functions.patch} (97%) rename meta-digi-arm/recipes-bsp/libubootenv/libubootenv/{0003-tools-env-add-support-to-set-dynamic-location-of-env.patch => 0002-tools-env-add-support-to-set-dynamic-location-of-env.patch} (88%) rename meta-digi-arm/recipes-bsp/libubootenv/libubootenv/{0001-Implement-support-for-environment-encryption-by-CAAM.patch => 0003-Implement-support-for-environment-encryption-by-CAAM.patch} (76%) create mode 100644 meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-Implement-support-for-environment-encryption-using-O.patch delete mode 100644 meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch delete mode 100644 meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-U-Boot-environment-access-functions.patch similarity index 97% rename from meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch rename to meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-U-Boot-environment-access-functions.patch index d585a18ad..93730a30b 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-U-Boot-environment-access-functions.patch @@ -52,10 +52,10 @@ index 3ed3244..e83b3a5 100644 } #endif diff --git a/src/uboot_env.c b/src/uboot_env.c -index 750b736..b7ad4c4 100644 +index ae85c7e..358dfbb 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -2234,3 +2234,99 @@ void libuboot_exit(struct uboot_ctx *ctx) +@@ -2103,3 +2103,99 @@ void libuboot_exit(struct uboot_ctx *ctx) free(ctx); } diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-tools-env-add-support-to-set-dynamic-location-of-env.patch similarity index 88% rename from meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch rename to meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-tools-env-add-support-to-set-dynamic-location-of-env.patch index 5bf01172a..a91e17420 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-tools-env-add-support-to-set-dynamic-location-of-env.patch @@ -27,10 +27,10 @@ Signed-off-by: Gabriel Valcazar 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/uboot_env.c b/src/uboot_env.c -index b7ad4c4..924a6cf 100644 +index 358dfbb..c1f334e 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -591,6 +591,73 @@ static int check_env_device(struct uboot_flash_env *dev) +@@ -581,6 +581,73 @@ static int check_env_device(struct uboot_flash_env *dev) return 0; } @@ -104,7 +104,7 @@ index b7ad4c4..924a6cf 100644 static bool check_compatible_devices(struct uboot_ctx *ctx) { if (!ctx->redundant) -@@ -602,6 +669,12 @@ static bool check_compatible_devices(struct uboot_ctx *ctx) +@@ -592,6 +659,12 @@ static bool check_compatible_devices(struct uboot_ctx *ctx) return false; if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize) return false; @@ -117,7 +117,7 @@ index b7ad4c4..924a6cf 100644 return true; } -@@ -648,7 +721,7 @@ static int fileread(struct uboot_flash_env *dev, void *data) +@@ -638,7 +711,7 @@ static int fileread(struct uboot_flash_env *dev, void *data) return ret; } @@ -126,7 +126,7 @@ index b7ad4c4..924a6cf 100644 { size_t count; size_t blocksize; -@@ -667,6 +740,17 @@ static int mtdread(struct uboot_flash_env *dev, void *data) +@@ -657,6 +730,17 @@ static int mtdread(struct uboot_flash_env *dev, void *data) ret = read(dev->fd, data, dev->envsize); break; case MTD_NANDFLASH: @@ -144,7 +144,7 @@ index b7ad4c4..924a6cf 100644 if (dev->offset) if (lseek(dev->fd, dev->offset, SEEK_SET) < 0) { ret = -EIO; -@@ -742,7 +826,7 @@ static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data) +@@ -732,7 +816,7 @@ static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data) ret = fileread(dev, data); break; case DEVICE_MTD: @@ -154,13 +154,13 @@ index b7ad4c4..924a6cf 100644 case DEVICE_UBI: ret = ubiread(dev, data); diff --git a/src/uboot_private.h b/src/uboot_private.h -index ee2d305..84bd1bc 100644 +index 40e5446..c8fecc4 100644 --- a/src/uboot_private.h +++ b/src/uboot_private.h -@@ -116,10 +116,14 @@ struct uboot_ctx { +@@ -114,10 +114,14 @@ LIST_HEAD(vars, var_entry); + struct uboot_ctx { + /** true if the environment is redundant */ bool redundant; - /** true if the environment is encrypted */ - bool encrypted; + /** true if the environment is dynamic */ + bool dynamic_env; /** set to valid after a successful load */ @@ -169,6 +169,6 @@ index ee2d305..84bd1bc 100644 size_t size; + /** top limit of the dynamic environment */ + loff_t top_limit; - /** usable environment size */ - unsigned int usable_size; /** devices where environment is stored */ + struct uboot_flash_env envdevs[2]; + /** Set which device contains the current(last valid) environment */ diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-Implement-support-for-environment-encryption-by-CAAM.patch similarity index 76% rename from meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch rename to meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-Implement-support-for-environment-encryption-by-CAAM.patch index d08d3f4e4..0bc88feb2 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-Implement-support-for-environment-encryption-by-CAAM.patch @@ -15,26 +15,63 @@ Signed-off-by: Diaz de Grenu, Jose Signed-off-by: Gonzalo Ruiz Signed-off-by: Hector Palacios Signed-off-by: Gabriel Valcazar + + # This is the commit message #2: + +fall back to read HWID from nvmem device if not available on DT + +Old U-Boot versions don't populate the HWID on the device tree. This may +be used as a key modifier for TrustFence encryption and, if not available +on the DT, newer firmware may be unable to unencrypt the U-Boot +environment. + +This patch implements a fall-back function to query the HWID directly from +the nvmem device node if it cannot locate it at the DT. +This is only implemented for ccimx6 family, which may be in the case of +having an old U-Boot. + +https://onedigi.atlassian.net/browse/DEL-8444 + +Signed-off-by: Hector Palacios + + # This is the commit message #3: + +ubootenv: generalize env encryption code + +Generalize the code to make room for Optee-based encryption. +* Move the code to the crypt.c/h files to minimize changes on the upstream + uboot_env.c file. +* Rename env_caam_get_keymod to env_get_keymod as this function is not + CAAM-specific. +* Create a public env_crypt function that will select the proper (CAAM, + Optee) implementation. + +Signed-off-by: Javier Viguera --- - src/CMakeLists.txt | 2 + - src/caam_keyblob.h | 42 +++++++ - src/md5.c | 275 ++++++++++++++++++++++++++++++++++++++++++++ - src/md5.h | 24 ++++ - src/uboot_env.c | 131 +++++++++++++++++++++ - src/uboot_private.h | 4 + - 6 files changed, 478 insertions(+) + src/CMakeLists.txt | 4 + + src/caam_keyblob.h | 42 +++++++ + src/crypt.c | 179 +++++++++++++++++++++++++++++ + src/crypt.h | 10 ++ + src/md5.c | 275 +++++++++++++++++++++++++++++++++++++++++++++ + src/md5.h | 24 ++++ + src/uboot_env.c | 18 +++ + 7 files changed, 552 insertions(+) create mode 100644 src/caam_keyblob.h + create mode 100644 src/crypt.c + create mode 100644 src/crypt.h create mode 100644 src/md5.c create mode 100644 src/md5.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index ababe0f..fb1efa2 100644 +index ababe0f..638f1c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt -@@ -4,6 +4,8 @@ +@@ -4,6 +4,10 @@ cmake_minimum_required (VERSION 2.6) # Sources and private headers SET(libubootenv_SOURCES ++ crypt.c ++ crypt.h + md5.c + md5.h uboot_env.c @@ -88,6 +125,207 @@ index 0000000..e313e87 +#endif + +#endif /* CAAM_KEYBLOB_H */ +diff --git a/src/crypt.c b/src/crypt.c +new file mode 100644 +index 0000000..213cffd +--- /dev/null ++++ b/src/crypt.c +@@ -0,0 +1,179 @@ ++/* ++ * Copyright 2024 Digi International Inc ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "caam_keyblob.h" ++#include "md5.h" ++ ++/* ++ * The BLOB includes a random AES-256 key (32 bytes) and a ++ * Message Authentication Code (MAC) (16 bytes) ++ */ ++#define BLOB_OVERHEAD 48 ++#define CAAM_KEY_DEV "/dev/caam_kb" ++#define MAX_HWID_WORDS 4 ++ ++/* Function that checks if machine is compatible (on the DT) */ ++static bool machine_is_compatible(char *machine) ++{ ++ int fd, nchars, len = 0; ++ int ret = false; ++ char str[256]; ++ char *p = str; ++ ++ fd = open("/proc/device-tree/compatible", O_RDONLY); ++ if (fd < 0) ++ return false; ++ ++ nchars = read(fd, str, 255); ++ while (len < nchars) { ++ if (!strcmp(p, machine)) { ++ ret = true; ++ break; ++ } ++ len += strlen(p) + 1; ++ p += strlen(p) + 1; ++ } ++ close(fd); ++ ++ return ret; ++} ++ ++static int env_get_keymod(unsigned char output[16]) ++{ ++ int i; ++ int len; ++ int fd; ++ uint32_t ocotp_hwid[MAX_HWID_WORDS]; ++ char dt_prop[32]; ++ char buf[sizeof(uint32_t)]; ++ ++ for (i = 0; i < MAX_HWID_WORDS; i++) { ++ sprintf(dt_prop, "/proc/device-tree/digi,hwid_%d", i); ++ if (access(dt_prop, F_OK) != -1) { ++ fd = open(dt_prop, O_RDONLY); ++ if (fd < 0) ++ return fd; ++ len = read(fd, buf, sizeof(uint32_t)); ++ if (len < 0) { ++ close(fd); ++ return -1; ++ } ++ ocotp_hwid[i] = ntohl(*(uint32_t *) buf); ++ close(fd); ++ } else if (machine_is_compatible("digi,ccimx6ul") || ++ machine_is_compatible("digi,ccimx6")) { ++ /* ++ * If HWID not available on the DT (old U-Boot version), ++ * fall back to read it directly from the nvmem device. ++ */ ++ int hwid_offset = 136; /* (Bank * 8 + Word) * 4 */ ++ ++ /* HWID for CC6 family only has two words */ ++ if (i == 2) ++ break; ++ ++ fd = open("/sys/bus/nvmem/devices/imx-ocotp0/nvmem", ++ O_RDONLY); ++ if (fd < 0) ++ return fd; ++ len = lseek(fd, hwid_offset + i * 4, SEEK_SET); ++ ++ len = read(fd, buf, sizeof(unsigned int)); ++ if (len < 0) { ++ close(fd); ++ return -1; ++ } ++ ocotp_hwid[i] = *(unsigned int *)buf; ++ close(fd); ++ } else { ++ break; ++ } ++ } ++ ++ /* Calculate md5sum on the raw HWID array */ ++ md5((unsigned char *)(&ocotp_hwid), sizeof(uint32_t) * i, output); ++ ++ return 0; ++} ++ ++static int env_caam_crypt(char *data, unsigned int size, const int enc) ++{ ++ struct caam_kb_data enc_data; ++ int fd; ++ int ret = 0; ++ const int len = size; ++ int ioctl_mode; ++ char *buffer; ++ unsigned char key_modifier[16]; ++ ++ ret = env_get_keymod(key_modifier); ++ if (ret) ++ return ret; ++ ++ enc_data.keymod = (char *)key_modifier; ++ enc_data.keymod_len = sizeof(key_modifier); ++ ++ enc_data.keyblob_len = len; ++ enc_data.rawkey_len = len - BLOB_OVERHEAD; ++ ++ buffer = malloc(len); ++ if (!buffer) { ++ printf("Could not allocate memory\n"); ++ return -1; ++ } ++ ++ if (enc) { ++ enc_data.rawkey = data; ++ ioctl_mode = CAAM_KB_ENCRYPT; ++ enc_data.keyblob = buffer; ++ } else { ++ enc_data.keyblob = data; ++ ioctl_mode = CAAM_KB_DECRYPT; ++ enc_data.rawkey = buffer; ++ } ++ ++ if ((fd = open(CAAM_KEY_DEV, O_RDWR)) < 0) { ++ ret = fd; ++ goto free; ++ } ++ ++ ret = ioctl(fd, ioctl_mode, &enc_data); ++ if (ret) { ++ printf("CAAM_KEY_DEV ioctl failed: %d\n", ret); ++ goto out; ++ } ++ ++ memcpy(data, buffer, enc ? len : len - BLOB_OVERHEAD); ++ ++out: ++ close(fd); ++free: ++ free(buffer); ++ ++ return ret; ++} ++ ++int env_crypt(char *data, unsigned int size, const int enc) ++{ ++ return env_caam_crypt(data, size, enc); ++} ++ ++int is_env_encrypted(void) ++{ ++ const char *dt_prop = "/proc/device-tree/digi,uboot-env,encrypted"; ++ ++ return access(dt_prop, F_OK) != -1; ++} +diff --git a/src/crypt.h b/src/crypt.h +new file mode 100644 +index 0000000..8d85c7f +--- /dev/null ++++ b/src/crypt.h +@@ -0,0 +1,10 @@ ++/* ++ * Copyright 2024 Digi International Inc ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#pragma once ++ ++int env_crypt(char *data, unsigned int size, const int enc); ++int is_env_encrypted(void); diff --git a/src/md5.c b/src/md5.c new file mode 100644 index 0000000..47ae8bf @@ -400,146 +638,26 @@ index 0000000..02a9a9d + +#endif /* _MD5_H */ diff --git a/src/uboot_env.c b/src/uboot_env.c -index ae85c7e..750b736 100644 +index c1f334e..30ef835 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c -@@ -34,11 +34,21 @@ - #include - #include - #include -+#include +@@ -37,6 +37,7 @@ #include #include -+#include "caam_keyblob.h" -+#include "md5.h" ++#include "crypt.h" #include "uboot_private.h" -+/* -+ * The BLOB includes a random AES-256 key (32 bytes) and a -+ * Message Authentication Code (MAC) (16 bytes) -+ */ -+#define BLOB_OVERHEAD 48 -+#define CAAM_KEY_DEV "/dev/caam_kb" -+ #define UBI_MAX_VOLUME 128 - - #define DEVICE_MTD_NAME "/dev/mtd" -@@ -1028,6 +1038,105 @@ const struct uboot_version_info *libuboot_version_info(void) - return &libinfo; - } - -+static int is_env_encrypted(void) -+{ -+ const char *dt_prop = "/proc/device-tree/digi,uboot-env,encrypted"; -+ -+ return access(dt_prop, F_OK) != -1; -+} -+ -+#define MAX_HWID_WORDS 4 -+static int env_caam_get_keymod(unsigned char output[16]) -+{ -+ int i; -+ int len; -+ int fd; -+ uint32_t ocotp_hwid[MAX_HWID_WORDS]; -+ char dt_prop[32]; -+ -+ for (i = 0; i < MAX_HWID_WORDS; i++) { -+ sprintf(dt_prop, "/proc/device-tree/digi,hwid_%d", i); -+ if (access(dt_prop, F_OK) != -1) { -+ char buf[sizeof(uint32_t)]; -+ -+ fd = open(dt_prop, O_RDONLY); -+ if (fd < 0) -+ return fd; -+ len = read(fd, buf, sizeof(uint32_t)); -+ if (len < 0) { -+ close(fd); -+ return -1; -+ } -+ ocotp_hwid[i] = ntohl(*(uint32_t *)buf); -+ close(fd); -+ } else { -+ break; -+ } -+ } -+ -+ /* Calculate md5sum on the raw HWID array */ -+ md5((unsigned char *)(&ocotp_hwid), sizeof(uint32_t) * i, output); -+ -+ return 0; -+} -+ -+static int env_caam_crypt(char *data, unsigned int size, const int enc) -+{ -+ struct caam_kb_data enc_data; -+ int fd; -+ int ret = 0; -+ const int len = size; -+ int ioctl_mode; -+ char *buffer; -+ unsigned char key_modifier[16]; -+ -+ ret = env_caam_get_keymod(key_modifier); -+ if (ret) -+ return ret; -+ -+ enc_data.keymod = (char *)key_modifier; -+ enc_data.keymod_len = sizeof(key_modifier); -+ -+ enc_data.keyblob_len = len; -+ enc_data.rawkey_len = len - BLOB_OVERHEAD; -+ -+ buffer = malloc(len); -+ if (!buffer) { -+ printf("Could not allocate memory\n"); -+ return -1; -+ } -+ -+ if (enc) { -+ enc_data.rawkey = data; -+ ioctl_mode = CAAM_KB_ENCRYPT; -+ enc_data.keyblob = buffer; -+ } else { -+ enc_data.keyblob = data; -+ ioctl_mode = CAAM_KB_DECRYPT; -+ enc_data.rawkey = buffer; -+ } -+ -+ if ((fd = open(CAAM_KEY_DEV, O_RDWR)) < 0) { -+ ret = fd; -+ goto free; -+ } -+ -+ ret = ioctl(fd, ioctl_mode, &enc_data); -+ if (ret) { -+ printf("CAAM_KEY_DEV ioctl failed: %d\n", ret); -+ goto out; -+ } -+ -+ memcpy(data, buffer, enc ? len : len - BLOB_OVERHEAD); -+ -+out: -+ close(fd); -+free: -+ free(buffer); -+ -+ return ret; -+} -+ - int libuboot_env_store(struct uboot_ctx *ctx) - { - struct var_entry *entry; -@@ -1103,6 +1212,15 @@ int libuboot_env_store(struct uboot_ctx *ctx) +@@ -1187,6 +1188,15 @@ int libuboot_env_store(struct uboot_ctx *ctx) ((struct uboot_env_redund *)image)->flags = flags; } -+ if (ctx->encrypted) { -+ ret = env_caam_crypt(data, ctx->usable_size, 1); ++ if (is_env_encrypted()) { ++ size_t usable_envsize = ctx->size - offsetdata; ++ ret = env_crypt(data, usable_envsize, 1); + if (ret) { -+ fprintf(stderr, -+ "Error: can't encrypt env for flash\n"); ++ fprintf(stderr, "Error: can't encrypt env for flash\n"); + return ret; + } + } @@ -547,56 +665,18 @@ index ae85c7e..750b736 100644 *(uint32_t *)image = crc32(0, (uint8_t *)data, ctx->size - offsetdata); copy = ctx->redundant ? (ctx->current ? 0 : 1) : 0; -@@ -1167,6 +1285,13 @@ static int libuboot_load(struct uboot_ctx *ctx) +@@ -1251,6 +1261,14 @@ static int libuboot_load(struct uboot_ctx *ctx) } crc = *(uint32_t *)(buf[i] + offsetcrc); dev->crc = crc32(0, (uint8_t *)data, usable_envsize); -+ if (ctx->encrypted) { -+ ret = env_caam_crypt((char *)data, ctx->usable_size, 0); ++ if (is_env_encrypted()) { ++ ret = env_crypt(data, usable_envsize, 0); + if (ret) { -+ fprintf(stderr, "Error: can't decrypt environment\n"); ++ fprintf(stderr, ++ "Error: can't decrypt environment\n"); + return ret; + } + } crcenv[i] = dev->crc == crc; if (ctx->redundant) dev->flags = *(uint8_t *)(buf[i] + offsetflags); -@@ -1773,6 +1898,11 @@ int libuboot_read_config_ext(struct uboot_ctx **ctxlist, const char *config) - break; - } - } -+ -+ ctx->usable_size = ctx->size - sizeof(uint32_t); -+ if (ctx->redundant) -+ ctx->usable_size -= sizeof(char); -+ - if (ndev == 0) - retval = -EINVAL; - -@@ -2042,6 +2172,7 @@ int libuboot_initialize(struct uboot_ctx **out, - return -ENOMEM; - - ctx->valid = false; -+ ctx->encrypted = is_env_encrypted(); - ret = libuboot_configure(ctx, envdevs); - - if (ret < 0) { -diff --git a/src/uboot_private.h b/src/uboot_private.h -index 40e5446..ee2d305 100644 ---- a/src/uboot_private.h -+++ b/src/uboot_private.h -@@ -114,10 +114,14 @@ LIST_HEAD(vars, var_entry); - struct uboot_ctx { - /** true if the environment is redundant */ - bool redundant; -+ /** true if the environment is encrypted */ -+ bool encrypted; - /** set to valid after a successful load */ - bool valid; - /** size of the environment */ - size_t size; -+ /** usable environment size */ -+ unsigned int usable_size; - /** devices where environment is stored */ - struct uboot_flash_env envdevs[2]; - /** Set which device contains the current(last valid) environment */ diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-Implement-support-for-environment-encryption-using-O.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-Implement-support-for-environment-encryption-using-O.patch new file mode 100644 index 000000000..848c927a2 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-Implement-support-for-environment-encryption-using-O.patch @@ -0,0 +1,259 @@ +From: Mike Engel +Date: Fri, 26 May 2023 11:21:43 +0200 +Subject: [PATCH] Implement support for environment encryption using Optee + +Co-authored-by: Javier Viguera +Signed-off-by: Mike Engel +Signed-off-by: Javier Viguera +--- + src/CMakeLists.txt | 3 + + src/crypt.c | 10 ++- + src/crypt_optee.c | 172 +++++++++++++++++++++++++++++++++++++++++++++ + src/crypt_optee.h | 10 +++ + 4 files changed, 194 insertions(+), 1 deletion(-) + create mode 100644 src/crypt_optee.c + create mode 100644 src/crypt_optee.h + +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index 638f1c1..f218b35 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -6,6 +6,8 @@ cmake_minimum_required (VERSION 2.6) + SET(libubootenv_SOURCES + crypt.c + crypt.h ++ crypt_optee.c ++ crypt_optee.h + md5.c + md5.h + uboot_env.c +@@ -26,6 +28,7 @@ ADD_LIBRARY(ubootenv_static STATIC ${libubootenv_SOURCES} ${include_HEADERS}) + SET_TARGET_PROPERTIES(ubootenv_static PROPERTIES OUTPUT_NAME ubootenv) + add_executable(fw_printenv fw_printenv.c) + target_link_libraries(ubootenv z yaml) ++target_link_libraries(ubootenv teec) + target_link_libraries(fw_printenv ubootenv) + add_custom_target(fw_setenv ALL ${CMAKE_COMMAND} -E create_symlink fw_printenv fw_setenv) + +diff --git a/src/crypt.c b/src/crypt.c +index 213cffd..e3f9a5d 100644 +--- a/src/crypt.c ++++ b/src/crypt.c +@@ -15,6 +15,7 @@ + #include + + #include "caam_keyblob.h" ++#include "crypt_optee.h" + #include "md5.h" + + /* +@@ -168,7 +169,14 @@ free: + + int env_crypt(char *data, unsigned int size, const int enc) + { +- return env_caam_crypt(data, size, enc); ++ if (is_env_optee_encrypted()) { ++ unsigned char key_modifier[16]; ++ if (env_get_keymod(key_modifier)) ++ return -1; ++ return env_optee_crypt((char *)key_modifier, data, size, enc); ++ } else { ++ return env_caam_crypt(data, size, enc); ++ } + } + + int is_env_encrypted(void) +diff --git a/src/crypt_optee.c b/src/crypt_optee.c +new file mode 100644 +index 0000000..fc74141 +--- /dev/null ++++ b/src/crypt_optee.c +@@ -0,0 +1,172 @@ ++/* ++ * Copyright 2024 Digi International Inc ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define AES_BLOCK_LENGTH 16 ++ ++/* From TA's public header (aes_ta.h) */ ++#define TA_AES_UUID \ ++ { 0xc2fad363, 0x5d9f, 0x4fc4, \ ++ { 0xa4, 0x17, 0x55, 0x58, 0x41, 0xe0, 0x57, 0x45 } } ++#define TA_AES_ALGO_ECB 0 ++#define TA_AES_ALGO_CBC 1 ++#define TA_AES_ALGO_CTR 2 ++#define TA_AES_SIZE_128BIT (128 / 8) ++#define TA_AES_SIZE_256BIT (256 / 8) ++#define TA_AES_MODE_DECODE 0 ++#define TA_AES_MODE_ENCODE 1 ++#define TA_AES_CMD_PREPARE 0 ++#define TA_AES_CMD_SET_KEY 1 ++#define TA_AES_CMD_SET_IV 2 ++#define TA_AES_CMD_CIPHER 3 ++ ++struct tee_ctx { ++ TEEC_Context ctx; ++ TEEC_Session sess; ++}; ++ ++static void prepare_tee_session(struct tee_ctx *ctx) ++{ ++ TEEC_Result ret; ++ uint32_t origin; ++ TEEC_UUID uuid = TA_AES_UUID; ++ ++ ret = TEEC_InitializeContext(NULL, &ctx->ctx); ++ if (ret != TEEC_SUCCESS) ++ printf("TEEC_InitializeContext failed with code 0x%x", ret); ++ ++ /* Open a session with the TA */ ++ ret = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid, ++ TEEC_LOGIN_PUBLIC, NULL, NULL, &origin); ++ if (ret != TEEC_SUCCESS) ++ printf("TEEC_Opensession failed with code 0x%x origin 0x%x", ++ ret, origin); ++ ++} ++ ++static void terminate_tee_session(struct tee_ctx *ctx) ++{ ++ TEEC_CloseSession(&ctx->sess); ++ TEEC_FinalizeContext(&ctx->ctx); ++} ++ ++static void prepare_aes(struct tee_ctx *ctx, int encode) ++{ ++ TEEC_Operation op; ++ uint32_t origin; ++ TEEC_Result res; ++ ++ memset(&op, 0, sizeof(op)); ++ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, ++ TEEC_VALUE_INPUT, ++ TEEC_VALUE_INPUT, TEEC_NONE); ++ ++ op.params[0].value.a = TA_AES_ALGO_CTR; ++ op.params[1].value.a = TA_AES_SIZE_256BIT; ++ op.params[2].value.a = encode ? TA_AES_MODE_ENCODE : TA_AES_MODE_DECODE; ++ ++ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_PREPARE, &op, &origin); ++ if (res != TEEC_SUCCESS) ++ printf("TEEC_InvokeCommand(PREPARE) failed 0x%x origin 0x%x", ++ res, origin); ++} ++ ++static void set_key(struct tee_ctx *ctx, size_t key_sz) ++{ ++ TEEC_Operation op; ++ uint32_t origin; ++ TEEC_Result res; ++ ++ memset(&op, 0, sizeof(op)); ++ ++ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, ++ TEEC_NONE, TEEC_NONE, TEEC_NONE); ++ ++ op.params[0].value.a = key_sz; ++ ++ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_KEY, &op, &origin); ++ if (res != TEEC_SUCCESS) ++ printf("TEEC_InvokeCommand(SET_KEY) failed 0x%x origin 0x%x", ++ res, origin); ++} ++ ++static void set_iv(struct tee_ctx *ctx, char *iv, size_t iv_sz) ++{ ++ TEEC_Operation op; ++ uint32_t origin; ++ TEEC_Result res; ++ ++ memset(&op, 0, sizeof(op)); ++ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, ++ TEEC_NONE, TEEC_NONE, TEEC_NONE); ++ op.params[0].tmpref.buffer = iv; ++ op.params[0].tmpref.size = iv_sz; ++ ++ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_IV, &op, &origin); ++ if (res != TEEC_SUCCESS) ++ printf("TEEC_InvokeCommand(SET_IV) failed 0x%x origin 0x%x", ++ res, origin); ++} ++ ++static void cipher_buffer(struct tee_ctx *ctx, char *in, char *out, size_t sz) ++{ ++ TEEC_Operation op; ++ uint32_t origin; ++ TEEC_Result res; ++ ++ memset(&op, 0, sizeof(op)); ++ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, ++ TEEC_MEMREF_TEMP_OUTPUT, ++ TEEC_NONE, TEEC_NONE); ++ op.params[0].tmpref.buffer = in; ++ op.params[0].tmpref.size = sz; ++ op.params[1].tmpref.buffer = out; ++ op.params[1].tmpref.size = sz; ++ ++ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_CIPHER, &op, &origin); ++ if (res != TEEC_SUCCESS) ++ printf("TEEC_InvokeCommand(CIPHER) failed 0x%x origin 0x%x", ++ res, origin); ++} ++ ++int env_optee_crypt(char *keymod, char *data, unsigned int size, const int enc) ++{ ++ struct tee_ctx tee; ++ char *cryptdata; ++ int ret = 0; ++ ++ prepare_tee_session(&tee); ++ prepare_aes(&tee, enc); ++ set_key(&tee, TA_AES_SIZE_256BIT); ++ set_iv(&tee, keymod, AES_BLOCK_LENGTH); ++ cryptdata = calloc(1, size); ++ if (cryptdata) { ++ cipher_buffer(&tee, data, cryptdata, size); ++ memcpy(data, cryptdata, size); ++ free(cryptdata); ++ } else { ++ printf("%s: can't allocate memory\n", __func__); ++ ret = -ENOMEM; ++ } ++ terminate_tee_session(&tee); ++ ++ return ret; ++} ++ ++int is_env_optee_encrypted(void) ++{ ++ const char *dt_prop = ++ "/proc/device-tree/digi,uboot-env,encrypted-optee"; ++ ++ return access(dt_prop, F_OK) != -1; ++} +diff --git a/src/crypt_optee.h b/src/crypt_optee.h +new file mode 100644 +index 0000000..e0c77a7 +--- /dev/null ++++ b/src/crypt_optee.h +@@ -0,0 +1,10 @@ ++/* ++ * Copyright 2024 Digi International Inc ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#pragma once ++ ++int env_optee_crypt(char *keymod, char *data, unsigned int size, const int enc); ++int is_env_optee_encrypted(void); diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch deleted file mode 100644 index 0f369f5b7..000000000 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch +++ /dev/null @@ -1,105 +0,0 @@ -From: Hector Palacios -Date: Mon, 3 Apr 2023 18:21:07 +0200 -Subject: [PATCH] fall back to read HWID from nvmem device if not available on - DT - -Old U-Boot versions don't populate the HWID on the device tree. This may -be used as a key modifier for TrustFence encryption and, if not available -on the DT, newer firmware may be unable to unencrypt the U-Boot -environment. - -This patch implements a fall-back function to query the HWID directly from -the nvmem device node if it cannot locate it at the DT. -This is only implemented for ccimx6 family, which may be in the case of -having an old U-Boot. - -Signed-off-by: Hector Palacios - -https://onedigi.atlassian.net/browse/DEL-8444 ---- - src/uboot_env.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 52 insertions(+), 2 deletions(-) - -diff --git a/src/uboot_env.c b/src/uboot_env.c -index 924a6cf..d507cac 100644 ---- a/src/uboot_env.c -+++ b/src/uboot_env.c -@@ -1129,6 +1129,32 @@ static int is_env_encrypted(void) - return access(dt_prop, F_OK) != -1; - } - -+/* Function that checks if machine is compatible (on the DT) */ -+static bool machine_is_compatible(char *machine) -+{ -+ int fd, nchars, len = 0; -+ int ret = false; -+ char str[256]; -+ char *p = str; -+ -+ fd = open("/proc/device-tree/compatible", O_RDONLY); -+ if (fd < 0) -+ return false; -+ -+ nchars = read(fd, str, 255); -+ while (len < nchars) { -+ if (!strcmp(p, machine)) { -+ ret = true; -+ break; -+ } -+ len += strlen(p) + 1; -+ p += strlen(p) + 1; -+ } -+ -+ close(fd); -+ return ret; -+} -+ - #define MAX_HWID_WORDS 4 - static int env_caam_get_keymod(unsigned char output[16]) - { -@@ -1137,12 +1163,11 @@ static int env_caam_get_keymod(unsigned char output[16]) - int fd; - uint32_t ocotp_hwid[MAX_HWID_WORDS]; - char dt_prop[32]; -+ char buf[sizeof(uint32_t)]; - - for (i = 0; i < MAX_HWID_WORDS; i++) { - sprintf(dt_prop, "/proc/device-tree/digi,hwid_%d", i); - if (access(dt_prop, F_OK) != -1) { -- char buf[sizeof(uint32_t)]; -- - fd = open(dt_prop, O_RDONLY); - if (fd < 0) - return fd; -@@ -1153,6 +1178,31 @@ static int env_caam_get_keymod(unsigned char output[16]) - } - ocotp_hwid[i] = ntohl(*(uint32_t *)buf); - close(fd); -+ } else if (machine_is_compatible("digi,ccimx6ul") || -+ machine_is_compatible("digi,ccimx6")) { -+ /* -+ * If HWID not available on the DT (old U-Boot version), -+ * fall back to read it directly from the nvmem device. -+ */ -+ int hwid_offset = 136; /* (Bank * 8 + Word) * 4 */ -+ -+ /* HWID for CC6 family only has two words */ -+ if (i == 2) -+ break; -+ -+ fd = open("/sys/bus/nvmem/devices/imx-ocotp0/nvmem", -+ O_RDONLY); -+ if (fd < 0) -+ return fd; -+ len = lseek(fd, hwid_offset + i * 4, SEEK_SET); -+ -+ len = read(fd, buf, sizeof(unsigned int)); -+ if (len < 0) { -+ close(fd); -+ return -1; -+ } -+ ocotp_hwid[i] = *(unsigned int *)buf; -+ close(fd); - } else { - break; - } diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch deleted file mode 100644 index 83c262155..000000000 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0005-Implement-support-for-environment-encryption-for-CCM.patch +++ /dev/null @@ -1,2802 +0,0 @@ -From: Mike Engel -Date: Fri, 26 May 2023 11:21:43 +0200 -Subject: [PATCH] Implement support for environment encryption for CCMP1 - -This commit implements environment encryption/decryption of the -u-boot environment in Linux using cryp controller on the CCMP1 -platform. - -Signed-off-by: Mike Engel ---- - src/CMakeLists.txt | 4 + - src/ta_ccmp1_aes.h | 84 +++ - src/tee.h | 417 ++++++++++++++ - src/tee_bench.h | 77 +++ - src/tee_client_api.c | 958 ++++++++++++++++++++++++++++++++ - src/tee_client_api.h | 555 ++++++++++++++++++ - src/tee_client_api_extensions.h | 57 ++ - src/teec_benchmark.h | 37 ++ - src/teec_trace.c | 141 +++++ - src/teec_trace.h | 148 +++++ - src/uboot_env.c | 180 +++++- - 11 files changed, 2654 insertions(+), 4 deletions(-) - create mode 100644 src/ta_ccmp1_aes.h - create mode 100644 src/tee.h - create mode 100644 src/tee_bench.h - create mode 100644 src/tee_client_api.c - create mode 100644 src/tee_client_api.h - create mode 100644 src/tee_client_api_extensions.h - create mode 100644 src/teec_benchmark.h - create mode 100644 src/teec_trace.c - create mode 100644 src/teec_trace.h - -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index fb1efa2..04353e9 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -4,6 +4,10 @@ - cmake_minimum_required (VERSION 2.6) - # Sources and private headers - SET(libubootenv_SOURCES -+ teec_trace.c -+ teec_trace.h -+ tee_client_api.c -+ tee_client_api.h - md5.c - md5.h - uboot_env.c -diff --git a/src/ta_ccmp1_aes.h b/src/ta_ccmp1_aes.h -new file mode 100644 -index 0000000..ceab07d ---- /dev/null -+++ b/src/ta_ccmp1_aes.h -@@ -0,0 +1,84 @@ -+/* -+ * Copyright 2023 Digi International Inc -+ * -+ * SPDX-License-Identifier: GPL-2.0+ -+ */ -+ -+#ifndef __TA_CCMP1_AES_H__ -+#define __TA_CCMP1_AES_H__ -+ -+/* -+ * AES is a stream cipher which works a block at a time, with each block -+ * in this case being AES_BLOCK_LENGTH bytes. -+ */ -+ -+enum { -+ AES_STATECOLS = 4, /* columns in the state & expanded key */ -+ AES128_KEYCOLS = 4, /* columns in a key for aes128 */ -+ AES192_KEYCOLS = 6, /* columns in a key for aes128 */ -+ AES256_KEYCOLS = 8, /* columns in a key for aes128 */ -+ AES128_ROUNDS = 10, /* rounds in encryption for aes128 */ -+ AES192_ROUNDS = 12, /* rounds in encryption for aes192 */ -+ AES256_ROUNDS = 14, /* rounds in encryption for aes256 */ -+ AES128_KEY_LENGTH = 128 / 8, -+ AES192_KEY_LENGTH = 192 / 8, -+ AES256_KEY_LENGTH = 256 / 8, -+ AES128_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES128_ROUNDS + 1), -+ AES192_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES192_ROUNDS + 1), -+ AES256_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES256_ROUNDS + 1), -+ AES_BLOCK_LENGTH = 128 / 8, -+}; -+ -+struct aes_ctx { -+ TEEC_Context ctx; -+ TEEC_Session sess; -+}; -+ -+/* The function IDs implemented in the associated TA */ -+ -+/* -+ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering -+ * param[0] (value) Algorithmus -+ * param[1] (value) Key size -+ * param[2] (value) encryption mode (encrypt/decrypt) -+ * param[3] unused -+ */ -+#define TA_AES_CMD_PREPARE 0 -+ -+/* -+ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering -+ * param[0] (memref) key data, size shall equal key length -+ * param[1] unused -+ * param[2] unused -+ * param[3] unused -+ */ -+#define TA_AES_CMD_SET_KEY 1 -+ -+/* -+ * TA_AES_CMD_SET_IV - reset IV -+ * param[0] (memref) initial vector, size shall equal block length -+ * param[1] unused -+ * param[2] unused -+ * param[3] unused -+ */ -+#define TA_AES_CMD_SET_IV 2 -+ -+/* -+ * TA_AES_CMD_CIPHER - Cipher input buffer into output buffer -+ * param[0] (memref) input buffer -+ * param[1] (memref) output buffer (shall be bigger than input buffer) -+ * param[2] unused -+ * param[3] unused -+ */ -+#define TA_AES_CMD_CIPHER 3 -+ -+#define TA_AES_MODE_ENCODE 1 -+#define TA_AES_MODE_DECODE 0 -+ -+#define TA_AES_ALGO_CTR 2 -+ -+/* UUID of the TA */ -+#define TA_STM32MP_CRYP_UUID { 0xc2fad363, 0x5d9f, 0x4fc4, \ -+ { 0xa4, 0x17, 0x55, 0x58, 0x41, 0xe0, 0x57, 0x45 } } -+ -+#endif /* __TA_CCMP1_AES_H__ */ -\ No newline at end of file -diff --git a/src/tee.h b/src/tee.h -new file mode 100644 -index 0000000..f883ebc ---- /dev/null -+++ b/src/tee.h -@@ -0,0 +1,417 @@ -+/* -+ * Copyright (c) 2015-2016, Linaro Limited -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef __TEE_H -+#define __TEE_H -+ -+#include -+#include -+ -+/* -+ * This file describes the API provided by a TEE driver to user space. -+ * -+ * Each TEE driver defines a TEE specific protocol which is used for the -+ * data passed back and forth using TEE_IOC_CMD. -+ */ -+ -+/* Helpers to make the ioctl defines */ -+#define TEE_IOC_MAGIC 0xa4 -+#define TEE_IOC_BASE 0 -+ -+/* Flags relating to shared memory */ -+#define TEE_IOCTL_SHM_MAPPED 0x1 /* memory mapped in normal world */ -+#define TEE_IOCTL_SHM_DMA_BUF 0x2 /* dma-buf handle on shared memory */ -+ -+#define TEE_MAX_ARG_SIZE 1024 -+ -+#define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */ -+#define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */ -+#define TEE_GEN_CAP_REG_MEM (1 << 2)/* Supports registering shared memory */ -+#define TEE_GEN_CAP_MEMREF_NULL (1 << 3) /* Support NULL MemRef */ -+ -+#define TEE_MEMREF_NULL ((__u64)-1) /* NULL MemRef Buffer */ -+ -+/* -+ * TEE Implementation ID -+ */ -+#define TEE_IMPL_ID_OPTEE 1 -+#define TEE_IMPL_ID_AMDTEE 2 -+ -+/* -+ * OP-TEE specific capabilities -+ */ -+#define TEE_OPTEE_CAP_TZ (1 << 0) -+ -+/** -+ * struct tee_ioctl_version_data - TEE version -+ * @impl_id: [out] TEE implementation id -+ * @impl_caps: [out] Implementation specific capabilities -+ * @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above -+ * -+ * Identifies the TEE implementation, @impl_id is one of TEE_IMPL_ID_* above. -+ * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_* -+ * is valid when @impl_id == TEE_IMPL_ID_OPTEE. -+ */ -+struct tee_ioctl_version_data { -+ __u32 impl_id; -+ __u32 impl_caps; -+ __u32 gen_caps; -+}; -+ -+/** -+ * TEE_IOC_VERSION - query version of TEE -+ * -+ * Takes a tee_ioctl_version_data struct and returns with the TEE version -+ * data filled in. -+ */ -+#define TEE_IOC_VERSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 0, \ -+ struct tee_ioctl_version_data) -+ -+/** -+ * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument -+ * @size: [in/out] Size of shared memory to allocate -+ * @flags: [in/out] Flags to/from allocation. -+ * @id: [out] Identifier of the shared memory -+ * -+ * The flags field should currently be zero as input. Updated by the call -+ * with actual flags as defined by TEE_IOCTL_SHM_* above. -+ * This structure is used as argument for TEE_IOC_SHM_ALLOC below. -+ */ -+struct tee_ioctl_shm_alloc_data { -+ __u64 size; -+ __u32 flags; -+ __s32 id; -+}; -+ -+/** -+ * TEE_IOC_SHM_ALLOC - allocate shared memory -+ * -+ * Allocates shared memory between the user space process and secure OS. -+ * -+ * Returns a file descriptor on success or < 0 on failure -+ * -+ * The returned file descriptor is used to map the shared memory into user -+ * space. The shared memory is freed when the descriptor is closed and the -+ * memory is unmapped. -+ */ -+#define TEE_IOC_SHM_ALLOC _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 1, \ -+ struct tee_ioctl_shm_alloc_data) -+ -+/** -+ * struct tee_ioctl_shm_register_fd_data - Shared memory registering argument -+ * @fd: [in] file descriptor identifying the shared memory -+ * @size: [out] Size of shared memory to allocate -+ * @flags: [in] Flags to/from allocation. -+ * @id: [out] Identifier of the shared memory -+ * -+ * The flags field should currently be zero as input. Updated by the call -+ * with actual flags as defined by TEE_IOCTL_SHM_* above. -+ * This structure is used as argument for TEE_IOC_SHM_ALLOC below. -+ */ -+struct tee_ioctl_shm_register_fd_data { -+ __s64 fd; -+ __u64 size; -+ __u32 flags; -+ __s32 id; -+} __aligned(8); -+ -+/* -+ * Attributes for struct tee_ioctl_param, selects field in the union -+ */ -+#define TEE_IOCTL_PARAM_ATTR_TYPE_NONE 0 /* parameter not used */ -+ -+/* -+ * These defines value parameters (struct tee_ioctl_param_value) -+ */ -+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT 1 -+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT 2 -+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT 3 /* input and output */ -+ -+/* -+ * These defines shared memory reference parameters (struct -+ * tee_ioctl_param_memref) -+ */ -+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT 5 -+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6 -+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */ -+ -+/* -+ * Mask for the type part of the attribute, leaves room for more types -+ */ -+#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff -+ -+/* Meta parameter carrying extra information about the message. */ -+#define TEE_IOCTL_PARAM_ATTR_META 0x100 -+ -+/* Mask of all known attr bits */ -+#define TEE_IOCTL_PARAM_ATTR_MASK \ -+ (TEE_IOCTL_PARAM_ATTR_TYPE_MASK | TEE_IOCTL_PARAM_ATTR_META) -+ -+/* -+ * Matches TEEC_LOGIN_* in GP TEE Client API -+ * Are only defined for GP compliant TEEs -+ */ -+#define TEE_IOCTL_LOGIN_PUBLIC 0 -+#define TEE_IOCTL_LOGIN_USER 1 -+#define TEE_IOCTL_LOGIN_GROUP 2 -+#define TEE_IOCTL_LOGIN_APPLICATION 4 -+#define TEE_IOCTL_LOGIN_USER_APPLICATION 5 -+#define TEE_IOCTL_LOGIN_GROUP_APPLICATION 6 -+ -+/** -+ * struct tee_ioctl_param - parameter -+ * @attr: attributes -+ * @a: if a memref, offset into the shared memory object, else a value parameter -+ * @b: if a memref, size of the buffer, else a value parameter -+ * @c: if a memref, shared memory identifier, else a value parameter -+ * -+ * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in -+ * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and -+ * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE -+ * indicates that none of the members are used. -+ * -+ * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an -+ * identifier representing the shared memory object. A memref can reference -+ * a part of a shared memory by specifying an offset (@a) and size (@b) of -+ * the object. To supply the entire shared memory object set the offset -+ * (@a) to 0 and size (@b) to the previously returned size of the object. -+ */ -+struct tee_ioctl_param { -+ __u64 attr; -+ __u64 a; -+ __u64 b; -+ __u64 c; -+}; -+ -+#define TEE_IOCTL_UUID_LEN 16 -+ -+/** -+ * struct tee_ioctl_open_session_arg - Open session argument -+ * @uuid: [in] UUID of the Trusted Application -+ * @clnt_uuid: [in] UUID of client -+ * @clnt_login: [in] Login class of client, TEE_IOCTL_LOGIN_* above -+ * @cancel_id: [in] Cancellation id, a unique value to identify this request -+ * @session: [out] Session id -+ * @ret: [out] return value -+ * @ret_origin [out] origin of the return value -+ * @num_params [in] number of parameters following this struct -+ */ -+struct tee_ioctl_open_session_arg { -+ __u8 uuid[TEE_IOCTL_UUID_LEN]; -+ __u8 clnt_uuid[TEE_IOCTL_UUID_LEN]; -+ __u32 clnt_login; -+ __u32 cancel_id; -+ __u32 session; -+ __u32 ret; -+ __u32 ret_origin; -+ __u32 num_params; -+ /* num_params tells the actual number of element in params */ -+ struct tee_ioctl_param params[]; -+}; -+ -+/** -+ * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application -+ * -+ * Takes a struct tee_ioctl_buf_data which contains a struct -+ * tee_ioctl_open_session_arg followed by any array of struct -+ * tee_ioctl_param -+ */ -+#define TEE_IOC_OPEN_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \ -+ struct tee_ioctl_buf_data) -+ -+/** -+ * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted -+ * Application -+ * @func: [in] Trusted Application function, specific to the TA -+ * @session: [in] Session id -+ * @cancel_id: [in] Cancellation id, a unique value to identify this request -+ * @ret: [out] return value -+ * @ret_origin [out] origin of the return value -+ * @num_params [in] number of parameters following this struct -+ */ -+struct tee_ioctl_invoke_arg { -+ __u32 func; -+ __u32 session; -+ __u32 cancel_id; -+ __u32 ret; -+ __u32 ret_origin; -+ __u32 num_params; -+ /* num_params tells the actual number of element in params */ -+ struct tee_ioctl_param params[]; -+}; -+ -+/** -+ * TEE_IOC_INVOKE - Invokes a function in a Trusted Application -+ * -+ * Takes a struct tee_ioctl_buf_data which contains a struct -+ * tee_invoke_func_arg followed by any array of struct tee_param -+ */ -+#define TEE_IOC_INVOKE _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 3, \ -+ struct tee_ioctl_buf_data) -+ -+/** -+ * struct tee_ioctl_cancel_arg - Cancels an open session or invoke ioctl -+ * @cancel_id: [in] Cancellation id, a unique value to identify this request -+ * @session: [in] Session id, if the session is opened, else set to 0 -+ */ -+struct tee_ioctl_cancel_arg { -+ __u32 cancel_id; -+ __u32 session; -+}; -+ -+/** -+ * TEE_IOC_CANCEL - Cancels an open session or invoke -+ */ -+#define TEE_IOC_CANCEL _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 4, \ -+ struct tee_ioctl_cancel_arg) -+ -+/** -+ * struct tee_ioctl_close_session_arg - Closes an open session -+ * @session: [in] Session id -+ */ -+struct tee_ioctl_close_session_arg { -+ __u32 session; -+}; -+ -+/** -+ * TEE_IOC_CLOSE_SESSION - Closes a session -+ */ -+#define TEE_IOC_CLOSE_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 5, \ -+ struct tee_ioctl_close_session_arg) -+ -+/** -+ * struct tee_iocl_supp_recv_arg - Receive a request for a supplicant function -+ * @func: [in] supplicant function -+ * @num_params [in/out] number of parameters following this struct -+ * -+ * @num_params is the number of params that tee-supplicant has room to -+ * receive when input, @num_params is the number of actual params -+ * tee-supplicant receives when output. -+ */ -+struct tee_iocl_supp_recv_arg { -+ __u32 func; -+ __u32 num_params; -+ /* num_params tells the actual number of element in params */ -+ struct tee_ioctl_param params[]; -+}; -+ -+/** -+ * TEE_IOC_SUPPL_RECV - Receive a request for a supplicant function -+ * -+ * Takes a struct tee_ioctl_buf_data which contains a struct -+ * tee_iocl_supp_recv_arg followed by any array of struct tee_param -+ */ -+#define TEE_IOC_SUPPL_RECV _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 6, \ -+ struct tee_ioctl_buf_data) -+ -+/** -+ * struct tee_iocl_supp_send_arg - Send a response to a received request -+ * @ret: [out] return value -+ * @num_params [in] number of parameters following this struct -+ */ -+struct tee_iocl_supp_send_arg { -+ __u32 ret; -+ __u32 num_params; -+ /* num_params tells the actual number of element in params */ -+ struct tee_ioctl_param params[]; -+}; -+ -+/** -+ * TEE_IOC_SUPPL_SEND - Receive a request for a supplicant function -+ * -+ * Takes a struct tee_ioctl_buf_data which contains a struct -+ * tee_iocl_supp_send_arg followed by any array of struct tee_param -+ */ -+#define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \ -+ struct tee_ioctl_buf_data) -+ -+/** -+ * struct tee_ioctl_shm_register_data - Shared memory register argument -+ * @addr: [in] Start address of shared memory to register -+ * @length: [in/out] Length of shared memory to register -+ * @flags: [in/out] Flags to/from registration. -+ * @id: [out] Identifier of the shared memory -+ * -+ * The flags field should currently be zero as input. Updated by the call -+ * with actual flags as defined by TEE_IOCTL_SHM_* above. -+ * This structure is used as argument for TEE_IOC_SHM_REGISTER below. -+ */ -+struct tee_ioctl_shm_register_data { -+ __u64 addr; -+ __u64 length; -+ __u32 flags; -+ __s32 id; -+}; -+ -+/** -+ * TEE_IOC_SHM_REGISTER_FD - register a shared memory from a file descriptor -+ * -+ * Returns a file descriptor on success or < 0 on failure -+ * -+ * The returned file descriptor refers to the shared memory object in kernel -+ * land. The shared memory is freed when the descriptor is closed. -+ */ -+#define TEE_IOC_SHM_REGISTER_FD _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 8, \ -+ struct tee_ioctl_shm_register_fd_data) -+ -+/** -+ * struct tee_ioctl_buf_data - Variable sized buffer -+ * @buf_ptr: [in] A __user pointer to a buffer -+ * @buf_len: [in] Length of the buffer above -+ * -+ * Used as argument for TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE, -+ * TEE_IOC_SUPPL_RECV, and TEE_IOC_SUPPL_SEND below. -+ */ -+struct tee_ioctl_buf_data { -+ __u64 buf_ptr; -+ __u64 buf_len; -+}; -+ -+/** -+ * TEE_IOC_SHM_REGISTER - Register shared memory argument -+ * -+ * Registers shared memory between the user space process and secure OS. -+ * -+ * Returns a file descriptor on success or < 0 on failure -+ * -+ * The shared memory is unregisterred when the descriptor is closed. -+ */ -+#define TEE_IOC_SHM_REGISTER _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 9, \ -+ struct tee_ioctl_shm_register_data) -+/* -+ * Five syscalls are used when communicating with the TEE driver. -+ * open(): opens the device associated with the driver -+ * ioctl(): as described above operating on the file descriptor from open() -+ * close(): two cases -+ * - closes the device file descriptor -+ * - closes a file descriptor connected to allocated shared memory -+ * mmap(): maps shared memory into user space using information from struct -+ * tee_ioctl_shm_alloc_data -+ * munmap(): unmaps previously shared memory -+ */ -+ -+#endif /*__TEE_H*/ -diff --git a/src/tee_bench.h b/src/tee_bench.h -new file mode 100644 -index 0000000..600407f ---- /dev/null -+++ b/src/tee_bench.h -@@ -0,0 +1,77 @@ -+/* -+ * Copyright (c) 2017, Linaro Limited -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef TEE_BENCH_H -+#define TEE_BENCH_H -+ -+#include -+ -+#define PTA_BENCHMARK_UUID \ -+ { 0x0b9a63b0, 0xb4c6, 0x4c85, \ -+ { 0xa2, 0x84, 0xa2, 0x28, 0xef, 0x54, 0x7b, 0x4e } } -+ -+#define BENCHMARK_CMD(id) (0xFA190000 | ((id) & 0xFFFF)) -+#define BENCHMARK_CMD_REGISTER_MEMREF BENCHMARK_CMD(1) -+#define BENCHMARK_CMD_GET_MEMREF BENCHMARK_CMD(2) -+#define BENCHMARK_CMD_UNREGISTER BENCHMARK_CMD(3) -+ -+/* -+ * Cycle count divider is enabled (in PMCR), -+ * CCNT value is incremented every 64th clock cycle -+ */ -+#define TEE_BENCH_DIVIDER 64 -+/* max amount of timestamps per buffer */ -+#define TEE_BENCH_MAX_STAMPS 32 -+#define TEE_BENCH_MAX_MASK (TEE_BENCH_MAX_STAMPS - 1) -+ -+/* OP-TEE susbsystems ids */ -+#define TEE_BENCH_CLIENT 0x10000000 -+#define TEE_BENCH_KMOD 0x20000000 -+#define TEE_BENCH_CORE 0x30000000 -+#define TEE_BENCH_UTEE 0x40000000 -+#define TEE_BENCH_DUMB_TA 0xF0000001 -+ -+/* storing timestamp */ -+struct tee_time_st { -+ uint64_t cnt; /* stores value from CNTPCT register */ -+ uint64_t addr; /* stores value from program counter register */ -+ uint64_t src; /* OP-TEE subsystem id */ -+}; -+ -+/* per-cpu circular buffer for timestamps */ -+struct tee_ts_cpu_buf { -+ uint64_t head; -+ uint64_t tail; -+ struct tee_time_st stamps[TEE_BENCH_MAX_STAMPS]; -+}; -+ -+/* memory layout for shared memory, where timestamps will be stored */ -+struct tee_ts_global { -+ uint64_t cores; -+ struct tee_ts_cpu_buf cpu_buf[]; -+}; -+#endif /* TEE_BENCH_H */ -diff --git a/src/tee_client_api.c b/src/tee_client_api.c -new file mode 100644 -index 0000000..2b07d30 ---- /dev/null -+++ b/src/tee_client_api.c -@@ -0,0 +1,958 @@ -+/* -+ * Copyright (c) 2015-2016, Linaro Limited -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef __aligned -+#define __aligned(x) __attribute__((__aligned__(x))) -+#endif -+#include -+ -+#include "teec_benchmark.h" -+ -+#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -+ -+/* How many device sequence numbers will be tried before giving up */ -+#define TEEC_MAX_DEV_SEQ 10 -+ -+/* Helpers to access memref parts of a struct tee_ioctl_param */ -+#define MEMREF_SHM_ID(p) ((p)->c) -+#define MEMREF_SHM_OFFS(p) ((p)->a) -+#define MEMREF_SIZE(p) ((p)->b) -+ -+/* -+ * Internal flags of TEEC_SharedMemory::internal.flags -+ */ -+#define SHM_FLAG_BUFFER_ALLOCED (1u << 0) -+#define SHM_FLAG_SHADOW_BUFFER_ALLOCED (1u << 1) -+ -+static pthread_mutex_t teec_mutex = PTHREAD_MUTEX_INITIALIZER; -+ -+static void teec_mutex_lock(pthread_mutex_t *mu) -+{ -+ pthread_mutex_lock(mu); -+} -+ -+static void teec_mutex_unlock(pthread_mutex_t *mu) -+{ -+ pthread_mutex_unlock(mu); -+} -+ -+static void *teec_paged_aligned_alloc(size_t sz) -+{ -+ void *p = NULL; -+ -+ if (!posix_memalign(&p, sysconf(_SC_PAGESIZE), sz)) -+ return p; -+ -+ return NULL; -+} -+ -+static int teec_open_dev(const char *devname, const char *capabilities, -+ uint32_t *gen_caps) -+{ -+ int fd = 0; -+ struct tee_ioctl_version_data vers; -+ -+ memset(&vers, 0, sizeof(vers)); -+ -+ fd = open(devname, O_RDWR); -+ if (fd < 0) -+ return -1; -+ -+ if (ioctl(fd, TEE_IOC_VERSION, &vers)) { -+ EMSG("TEE_IOC_VERSION failed"); -+ goto err; -+ } -+ -+ /* We can only handle GP TEEs */ -+ if (!(vers.gen_caps & TEE_GEN_CAP_GP)) -+ goto err; -+ -+ if (capabilities) { -+ if (strcmp(capabilities, "optee-tz") == 0) { -+ if (vers.impl_id != TEE_IMPL_ID_OPTEE) -+ goto err; -+ if (!(vers.impl_caps & TEE_OPTEE_CAP_TZ)) -+ goto err; -+ } else { -+ /* Unrecognized capability requested */ -+ goto err; -+ } -+ } -+ -+ *gen_caps = vers.gen_caps; -+ return fd; -+err: -+ close(fd); -+ return -1; -+} -+ -+static int teec_shm_alloc(int fd, size_t size, int *id) -+{ -+ int shm_fd = 0; -+ struct tee_ioctl_shm_alloc_data data; -+ -+ memset(&data, 0, sizeof(data)); -+ -+ data.size = size; -+ shm_fd = ioctl(fd, TEE_IOC_SHM_ALLOC, &data); -+ if (shm_fd < 0) -+ return -1; -+ *id = data.id; -+ return shm_fd; -+} -+ -+static int teec_shm_register(int fd, void *buf, size_t size, int *id) -+{ -+ int shm_fd = 0; -+ struct tee_ioctl_shm_register_data data; -+ -+ memset(&data, 0, sizeof(data)); -+ -+ data.addr = (uintptr_t)buf; -+ data.length = size; -+ shm_fd = ioctl(fd, TEE_IOC_SHM_REGISTER, &data); -+ if (shm_fd < 0) -+ return -1; -+ *id = data.id; -+ return shm_fd; -+} -+ -+TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx) -+{ -+ char devname[PATH_MAX] = { 0 }; -+ int fd = 0; -+ size_t n = 0; -+ -+ if (!ctx) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ for (n = 0; n < TEEC_MAX_DEV_SEQ; n++) { -+ uint32_t gen_caps = 0; -+ -+ snprintf(devname, sizeof(devname), "/dev/tee%zu", n); -+ fd = teec_open_dev(devname, name, &gen_caps); -+ if (fd >= 0) { -+ ctx->fd = fd; -+ ctx->reg_mem = gen_caps & TEE_GEN_CAP_REG_MEM; -+ ctx->memref_null = gen_caps & TEE_GEN_CAP_MEMREF_NULL; -+ return TEEC_SUCCESS; -+ } -+ } -+ -+ return TEEC_ERROR_ITEM_NOT_FOUND; -+} -+ -+void TEEC_FinalizeContext(TEEC_Context *ctx) -+{ -+ if (ctx) -+ close(ctx->fd); -+} -+ -+ -+static TEEC_Result teec_pre_process_tmpref(TEEC_Context *ctx, -+ uint32_t param_type, TEEC_TempMemoryReference *tmpref, -+ struct tee_ioctl_param *param, -+ TEEC_SharedMemory *shm) -+{ -+ TEEC_Result res = TEEC_ERROR_GENERIC; -+ -+ switch (param_type) { -+ case TEEC_MEMREF_TEMP_INPUT: -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; -+ shm->flags = TEEC_MEM_INPUT; -+ break; -+ case TEEC_MEMREF_TEMP_OUTPUT: -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; -+ shm->flags = TEEC_MEM_OUTPUT; -+ break; -+ case TEEC_MEMREF_TEMP_INOUT: -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; -+ shm->flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT; -+ break; -+ default: -+ return TEEC_ERROR_BAD_PARAMETERS; -+ } -+ shm->size = tmpref->size; -+ -+ if (!tmpref->buffer) { -+ if (tmpref->size) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ if (ctx->memref_null) { -+ /* Null pointer, indicate no shared memory attached */ -+ MEMREF_SHM_ID(param) = TEE_MEMREF_NULL; -+ shm->id = -1; -+ } else { -+ res = TEEC_AllocateSharedMemory(ctx, shm); -+ if (res != TEEC_SUCCESS) -+ return res; -+ MEMREF_SHM_ID(param) = shm->id; -+ } -+ } else { -+ shm->buffer = tmpref->buffer; -+ res = TEEC_RegisterSharedMemory(ctx, shm); -+ if (res != TEEC_SUCCESS) -+ return res; -+ -+ if (shm->shadow_buffer) -+ memcpy(shm->shadow_buffer, tmpref->buffer, -+ tmpref->size); -+ -+ MEMREF_SHM_ID(param) = shm->id; -+ } -+ -+ MEMREF_SIZE(param) = tmpref->size; -+ -+ return TEEC_SUCCESS; -+} -+ -+static TEEC_Result teec_pre_process_whole( -+ TEEC_RegisteredMemoryReference *memref, -+ struct tee_ioctl_param *param) -+{ -+ const uint32_t inout = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT; -+ uint32_t flags = memref->parent->flags & inout; -+ TEEC_SharedMemory *shm = NULL; -+ -+ if (flags == inout) -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; -+ else if (flags & TEEC_MEM_INPUT) -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; -+ else if (flags & TEEC_MEM_OUTPUT) -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; -+ else -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ shm = memref->parent; -+ /* -+ * We're using a shadow buffer in this reference, copy the real buffer -+ * into the shadow buffer if needed. We'll copy it back once we've -+ * returned from the call to secure world. -+ */ -+ if (shm->shadow_buffer && (flags & TEEC_MEM_INPUT)) -+ memcpy(shm->shadow_buffer, shm->buffer, shm->size); -+ -+ MEMREF_SHM_ID(param) = shm->id; -+ MEMREF_SIZE(param) = shm->size; -+ -+ return TEEC_SUCCESS; -+} -+ -+static TEEC_Result teec_pre_process_partial(uint32_t param_type, -+ TEEC_RegisteredMemoryReference *memref, -+ struct tee_ioctl_param *param) -+{ -+ uint32_t req_shm_flags = 0; -+ TEEC_SharedMemory *shm = NULL; -+ -+ switch (param_type) { -+ case TEEC_MEMREF_PARTIAL_INPUT: -+ req_shm_flags = TEEC_MEM_INPUT; -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; -+ break; -+ case TEEC_MEMREF_PARTIAL_OUTPUT: -+ req_shm_flags = TEEC_MEM_OUTPUT; -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; -+ break; -+ case TEEC_MEMREF_PARTIAL_INOUT: -+ req_shm_flags = TEEC_MEM_OUTPUT | TEEC_MEM_INPUT; -+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; -+ break; -+ default: -+ return TEEC_ERROR_BAD_PARAMETERS; -+ } -+ -+ shm = memref->parent; -+ -+ if ((shm->flags & req_shm_flags) != req_shm_flags) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ if ((memref->offset + memref->size < memref->offset) || -+ (memref->offset + memref->size > shm->size)) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ /* -+ * We're using a shadow buffer in this reference, copy the real buffer -+ * into the shadow buffer if needed. We'll copy it back once we've -+ * returned from the call to secure world. -+ */ -+ if (shm->shadow_buffer && param_type != TEEC_MEMREF_PARTIAL_OUTPUT) -+ memcpy((char *)shm->shadow_buffer + memref->offset, -+ (char *)shm->buffer + memref->offset, memref->size); -+ -+ MEMREF_SHM_ID(param) = shm->id; -+ MEMREF_SHM_OFFS(param) = memref->offset; -+ MEMREF_SIZE(param) = memref->size; -+ -+ return TEEC_SUCCESS; -+} -+ -+static TEEC_Result teec_pre_process_operation(TEEC_Context *ctx, -+ TEEC_Operation *operation, -+ struct tee_ioctl_param *params, -+ TEEC_SharedMemory *shms) -+{ -+ TEEC_Result res = TEEC_ERROR_GENERIC; -+ size_t n = 0; -+ -+ memset(shms, 0, sizeof(TEEC_SharedMemory) * -+ TEEC_CONFIG_PAYLOAD_REF_COUNT); -+ -+ for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) -+ shms[n].id = -1; -+ -+ if (!operation) { -+ memset(params, 0, sizeof(struct tee_ioctl_param) * -+ TEEC_CONFIG_PAYLOAD_REF_COUNT); -+ return TEEC_SUCCESS; -+ } -+ -+ for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) { -+ uint32_t param_type = 0; -+ -+ param_type = TEEC_PARAM_TYPE_GET(operation->paramTypes, n); -+ switch (param_type) { -+ case TEEC_NONE: -+ params[n].attr = param_type; -+ break; -+ case TEEC_VALUE_INPUT: -+ case TEEC_VALUE_OUTPUT: -+ case TEEC_VALUE_INOUT: -+ params[n].attr = param_type; -+ params[n].a = operation->params[n].value.a; -+ params[n].b = operation->params[n].value.b; -+ break; -+ case TEEC_MEMREF_TEMP_INPUT: -+ case TEEC_MEMREF_TEMP_OUTPUT: -+ case TEEC_MEMREF_TEMP_INOUT: -+ res = teec_pre_process_tmpref(ctx, param_type, -+ &operation->params[n].tmpref, params + n, -+ shms + n); -+ if (res != TEEC_SUCCESS) -+ return res; -+ break; -+ case TEEC_MEMREF_WHOLE: -+ res = teec_pre_process_whole( -+ &operation->params[n].memref, -+ params + n); -+ if (res != TEEC_SUCCESS) -+ return res; -+ break; -+ case TEEC_MEMREF_PARTIAL_INPUT: -+ case TEEC_MEMREF_PARTIAL_OUTPUT: -+ case TEEC_MEMREF_PARTIAL_INOUT: -+ res = teec_pre_process_partial(param_type, -+ &operation->params[n].memref, params + n); -+ if (res != TEEC_SUCCESS) -+ return res; -+ break; -+ default: -+ return TEEC_ERROR_BAD_PARAMETERS; -+ } -+ } -+ -+ return TEEC_SUCCESS; -+} -+ -+static void teec_post_process_tmpref(uint32_t param_type, -+ TEEC_TempMemoryReference *tmpref, -+ struct tee_ioctl_param *param, -+ TEEC_SharedMemory *shm) -+{ -+ if (param_type != TEEC_MEMREF_TEMP_INPUT) { -+ if (tmpref->buffer && shm->shadow_buffer) -+ memcpy(tmpref->buffer, shm->shadow_buffer, -+ MIN(MEMREF_SIZE(param), tmpref->size)); -+ -+ tmpref->size = MEMREF_SIZE(param); -+ } -+} -+ -+static void teec_post_process_whole(TEEC_RegisteredMemoryReference *memref, -+ struct tee_ioctl_param *param) -+{ -+ TEEC_SharedMemory *shm = memref->parent; -+ -+ if (shm->flags & TEEC_MEM_OUTPUT) { -+ -+ /* -+ * We're using a shadow buffer in this reference, copy back -+ * the shadow buffer into the real buffer now that we've -+ * returned from secure world. -+ */ -+ if (shm->shadow_buffer && MEMREF_SIZE(param) <= shm->size) -+ memcpy(shm->buffer, shm->shadow_buffer, -+ MEMREF_SIZE(param)); -+ -+ memref->size = MEMREF_SIZE(param); -+ } -+} -+ -+static void teec_post_process_partial(uint32_t param_type, -+ TEEC_RegisteredMemoryReference *memref, -+ struct tee_ioctl_param *param) -+{ -+ if (param_type != TEEC_MEMREF_PARTIAL_INPUT) { -+ TEEC_SharedMemory *shm = memref->parent; -+ -+ /* -+ * We're using a shadow buffer in this reference, copy back -+ * the shadow buffer into the real buffer now that we've -+ * returned from secure world. -+ */ -+ if (shm->shadow_buffer && MEMREF_SIZE(param) <= memref->size) -+ memcpy((char *)shm->buffer + memref->offset, -+ (char *)shm->shadow_buffer + memref->offset, -+ MEMREF_SIZE(param)); -+ -+ memref->size = MEMREF_SIZE(param); -+ } -+} -+ -+static void teec_post_process_operation(TEEC_Operation *operation, -+ struct tee_ioctl_param *params, -+ TEEC_SharedMemory *shms) -+{ -+ size_t n = 0; -+ -+ if (!operation) -+ return; -+ -+ for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) { -+ uint32_t param_type = 0; -+ -+ param_type = TEEC_PARAM_TYPE_GET(operation->paramTypes, n); -+ switch (param_type) { -+ case TEEC_VALUE_INPUT: -+ break; -+ case TEEC_VALUE_OUTPUT: -+ case TEEC_VALUE_INOUT: -+ operation->params[n].value.a = params[n].a; -+ operation->params[n].value.b = params[n].b; -+ break; -+ case TEEC_MEMREF_TEMP_INPUT: -+ case TEEC_MEMREF_TEMP_OUTPUT: -+ case TEEC_MEMREF_TEMP_INOUT: -+ teec_post_process_tmpref(param_type, -+ &operation->params[n].tmpref, params + n, -+ shms + n); -+ break; -+ case TEEC_MEMREF_WHOLE: -+ teec_post_process_whole(&operation->params[n].memref, -+ params + n); -+ break; -+ case TEEC_MEMREF_PARTIAL_INPUT: -+ case TEEC_MEMREF_PARTIAL_OUTPUT: -+ case TEEC_MEMREF_PARTIAL_INOUT: -+ teec_post_process_partial(param_type, -+ &operation->params[n].memref, params + n); -+ default: -+ break; -+ } -+ } -+} -+ -+static void teec_free_temp_refs(TEEC_Operation *operation, -+ TEEC_SharedMemory *shms) -+{ -+ size_t n = 0; -+ -+ if (!operation) -+ return; -+ -+ for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) { -+ switch (TEEC_PARAM_TYPE_GET(operation->paramTypes, n)) { -+ case TEEC_MEMREF_TEMP_INPUT: -+ case TEEC_MEMREF_TEMP_OUTPUT: -+ case TEEC_MEMREF_TEMP_INOUT: -+ TEEC_ReleaseSharedMemory(shms + n); -+ break; -+ default: -+ break; -+ } -+ } -+} -+ -+static TEEC_Result ioctl_errno_to_res(int err) -+{ -+ switch (err) { -+ case ENOMEM: -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ case EINVAL: -+ return TEEC_ERROR_BAD_PARAMETERS; -+ default: -+ return TEEC_ERROR_GENERIC; -+ } -+} -+ -+static void uuid_to_octets(uint8_t d[TEE_IOCTL_UUID_LEN], const TEEC_UUID *s) -+{ -+ d[0] = s->timeLow >> 24; -+ d[1] = s->timeLow >> 16; -+ d[2] = s->timeLow >> 8; -+ d[3] = s->timeLow; -+ d[4] = s->timeMid >> 8; -+ d[5] = s->timeMid; -+ d[6] = s->timeHiAndVersion >> 8; -+ d[7] = s->timeHiAndVersion; -+ memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode)); -+} -+ -+static void setup_client_data(struct tee_ioctl_open_session_arg *arg, -+ uint32_t connection_method, -+ const void *connection_data) -+{ -+ arg->clnt_login = connection_method; -+ -+ switch (connection_method) { -+ case TEE_IOCTL_LOGIN_PUBLIC: -+ /* No connection data to pass */ -+ break; -+ case TEE_IOCTL_LOGIN_USER: -+ /* Kernel auto-fills UID and forms client UUID */ -+ break; -+ case TEE_IOCTL_LOGIN_GROUP: -+ /* -+ * Connection data for group login is uint32_t and rest of -+ * clnt_uuid is set as zero. -+ * -+ * Kernel verifies group membership and then forms client UUID. -+ */ -+ memcpy(arg->clnt_uuid, connection_data, sizeof(gid_t)); -+ break; -+ case TEE_IOCTL_LOGIN_APPLICATION: -+ /* -+ * Kernel auto-fills application identifier and forms client -+ * UUID. -+ */ -+ break; -+ case TEE_IOCTL_LOGIN_USER_APPLICATION: -+ /* -+ * Kernel auto-fills application identifier, UID and forms -+ * client UUID. -+ */ -+ break; -+ case TEE_IOCTL_LOGIN_GROUP_APPLICATION: -+ /* -+ * Connection data for group login is uint32_t rest of -+ * clnt_uuid is set as zero. -+ * -+ * Kernel verifies group membership, auto-fills application -+ * identifier and then forms client UUID. -+ */ -+ memcpy(arg->clnt_uuid, connection_data, sizeof(gid_t)); -+ break; -+ default: -+ /* -+ * Unknown login method, don't pass any connection data as we -+ * don't know size. -+ */ -+ break; -+ } -+} -+ -+TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session, -+ const TEEC_UUID *destination, -+ uint32_t connection_method, const void *connection_data, -+ TEEC_Operation *operation, uint32_t *ret_origin) -+{ -+ struct tee_ioctl_open_session_arg *arg = NULL; -+ struct tee_ioctl_param *params = NULL; -+ TEEC_Result res = TEEC_ERROR_GENERIC; -+ uint32_t eorig = 0; -+ int rc = 0; -+ const size_t arg_size = sizeof(struct tee_ioctl_open_session_arg) + -+ TEEC_CONFIG_PAYLOAD_REF_COUNT * -+ sizeof(struct tee_ioctl_param); -+ union { -+ struct tee_ioctl_open_session_arg arg; -+ uint8_t data[arg_size]; -+ } buf; -+ struct tee_ioctl_buf_data buf_data; -+ TEEC_SharedMemory shm[TEEC_CONFIG_PAYLOAD_REF_COUNT]; -+ -+ memset(&buf, 0, sizeof(buf)); -+ memset(&shm, 0, sizeof(shm)); -+ memset(&buf_data, 0, sizeof(buf_data)); -+ -+ if (!ctx || !session) { -+ eorig = TEEC_ORIGIN_API; -+ res = TEEC_ERROR_BAD_PARAMETERS; -+ goto out; -+ } -+ -+ buf_data.buf_ptr = (uintptr_t)&buf; -+ buf_data.buf_len = sizeof(buf); -+ -+ arg = &buf.arg; -+ arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; -+ params = (struct tee_ioctl_param *)(arg + 1); -+ -+ uuid_to_octets(arg->uuid, destination); -+ -+ setup_client_data(arg, connection_method, connection_data); -+ -+ res = teec_pre_process_operation(ctx, operation, params, shm); -+ if (res != TEEC_SUCCESS) { -+ eorig = TEEC_ORIGIN_API; -+ goto out_free_temp_refs; -+ } -+ -+ rc = ioctl(ctx->fd, TEE_IOC_OPEN_SESSION, &buf_data); -+ if (rc) { -+ EMSG("TEE_IOC_OPEN_SESSION failed"); -+ eorig = TEEC_ORIGIN_COMMS; -+ res = ioctl_errno_to_res(errno); -+ goto out_free_temp_refs; -+ } -+ res = arg->ret; -+ eorig = arg->ret_origin; -+ if (res == TEEC_SUCCESS) { -+ session->ctx = ctx; -+ session->session_id = arg->session; -+ } -+ teec_post_process_operation(operation, params, shm); -+ -+out_free_temp_refs: -+ teec_free_temp_refs(operation, shm); -+out: -+ if (ret_origin) -+ *ret_origin = eorig; -+ return res; -+} -+ -+void TEEC_CloseSession(TEEC_Session *session) -+{ -+ struct tee_ioctl_close_session_arg arg; -+ -+ memset(&arg, 0, sizeof(arg)); -+ -+ if (!session) -+ return; -+ -+ arg.session = session->session_id; -+ if (ioctl(session->ctx->fd, TEE_IOC_CLOSE_SESSION, &arg)) -+ EMSG("Failed to close session 0x%x", session->session_id); -+} -+ -+TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, uint32_t cmd_id, -+ TEEC_Operation *operation, uint32_t *error_origin) -+{ -+ struct tee_ioctl_invoke_arg *arg = NULL; -+ struct tee_ioctl_param *params = NULL; -+ TEEC_Result res = TEEC_ERROR_GENERIC; -+ uint32_t eorig = 0; -+ int rc = 0; -+ const size_t arg_size = sizeof(struct tee_ioctl_invoke_arg) + -+ TEEC_CONFIG_PAYLOAD_REF_COUNT * -+ sizeof(struct tee_ioctl_param); -+ union { -+ struct tee_ioctl_invoke_arg arg; -+ uint8_t data[arg_size]; -+ } buf; -+ struct tee_ioctl_buf_data buf_data; -+ TEEC_SharedMemory shm[TEEC_CONFIG_PAYLOAD_REF_COUNT]; -+ -+ memset(&buf, 0, sizeof(buf)); -+ memset(&buf_data, 0, sizeof(buf_data)); -+ memset(&shm, 0, sizeof(shm)); -+ -+ if (!session) { -+ eorig = TEEC_ORIGIN_API; -+ res = TEEC_ERROR_BAD_PARAMETERS; -+ goto out; -+ } -+ -+ bm_timestamp(); -+ -+ buf_data.buf_ptr = (uintptr_t)&buf; -+ buf_data.buf_len = sizeof(buf); -+ -+ arg = &buf.arg; -+ arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; -+ params = (struct tee_ioctl_param *)(arg + 1); -+ -+ arg->session = session->session_id; -+ arg->func = cmd_id; -+ -+ if (operation) { -+ teec_mutex_lock(&teec_mutex); -+ operation->session = session; -+ teec_mutex_unlock(&teec_mutex); -+ } -+ -+ res = teec_pre_process_operation(session->ctx, operation, params, shm); -+ if (res != TEEC_SUCCESS) { -+ eorig = TEEC_ORIGIN_API; -+ goto out_free_temp_refs; -+ } -+ -+ rc = ioctl(session->ctx->fd, TEE_IOC_INVOKE, &buf_data); -+ if (rc) { -+ EMSG("TEE_IOC_INVOKE failed"); -+ eorig = TEEC_ORIGIN_COMMS; -+ res = ioctl_errno_to_res(errno); -+ goto out_free_temp_refs; -+ } -+ -+ res = arg->ret; -+ eorig = arg->ret_origin; -+ teec_post_process_operation(operation, params, shm); -+ -+ bm_timestamp(); -+ -+out_free_temp_refs: -+ teec_free_temp_refs(operation, shm); -+out: -+ if (error_origin) -+ *error_origin = eorig; -+ return res; -+} -+ -+void TEEC_RequestCancellation(TEEC_Operation *operation) -+{ -+ TEEC_Session *session = NULL; -+ struct tee_ioctl_cancel_arg arg; -+ -+ memset(&arg, 0, sizeof(arg)); -+ -+ if (!operation) -+ return; -+ -+ teec_mutex_lock(&teec_mutex); -+ session = operation->session; -+ teec_mutex_unlock(&teec_mutex); -+ -+ if (!session) -+ return; -+ -+ arg.session = session->session_id; -+ arg.cancel_id = 0; -+ -+ if (ioctl(session->ctx->fd, TEE_IOC_CANCEL, &arg)) -+ EMSG("TEE_IOC_CANCEL: %s", strerror(errno)); -+} -+ -+TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) -+{ -+ TEEC_Result res = TEEC_SUCCESS; -+ int fd = 0; -+ size_t s = 0; -+ -+ if (!ctx || !shm) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ if (!shm->buffer) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ s = shm->size; -+ if (!s) -+ s = 8; -+ if (ctx->reg_mem) { -+ fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id); -+ if (fd >= 0) { -+ shm->registered_fd = fd; -+ shm->shadow_buffer = NULL; -+ shm->internal.flags = 0; -+ goto out; -+ } -+ -+ /* -+ * If we're here TEE_IOC_SHM_REGISTER failed, probably -+ * because some read-only memory was supplied and the Linux -+ * kernel doesn't like that at the moment. -+ * -+ * The error could also have some other origin. In any case -+ * we're not making matters worse by trying to allocate and -+ * register a shadow buffer before giving up. -+ */ -+ shm->shadow_buffer = teec_paged_aligned_alloc(s); -+ if (!shm->shadow_buffer) -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ fd = teec_shm_register(ctx->fd, shm->shadow_buffer, s, -+ &shm->id); -+ if (fd >= 0) { -+ shm->registered_fd = fd; -+ shm->internal.flags = SHM_FLAG_SHADOW_BUFFER_ALLOCED; -+ goto out; -+ } -+ -+ if (errno == ENOMEM) -+ res = TEEC_ERROR_OUT_OF_MEMORY; -+ else -+ res = TEEC_ERROR_GENERIC; -+ free(shm->shadow_buffer); -+ shm->shadow_buffer = NULL; -+ return res; -+ } else { -+ fd = teec_shm_alloc(ctx->fd, s, &shm->id); -+ if (fd < 0) -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ -+ shm->shadow_buffer = mmap(NULL, s, PROT_READ | PROT_WRITE, -+ MAP_SHARED, fd, 0); -+ close(fd); -+ if (shm->shadow_buffer == (void *)MAP_FAILED) { -+ shm->id = -1; -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ } -+ shm->registered_fd = -1; -+ shm->internal.flags = 0; -+ } -+ -+out: -+ shm->alloced_size = s; -+ return TEEC_SUCCESS; -+} -+ -+TEEC_Result TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context *ctx, -+ TEEC_SharedMemory *shm, -+ int fd) -+{ -+ int rfd = 0; -+ struct tee_ioctl_shm_register_fd_data data; -+ -+ memset(&data, 0, sizeof(data)); -+ -+ if (!ctx || !shm || fd < 0) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ data.fd = fd; -+ rfd = ioctl(ctx->fd, TEE_IOC_SHM_REGISTER_FD, &data); -+ if (rfd < 0) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ shm->buffer = NULL; -+ shm->shadow_buffer = NULL; -+ shm->registered_fd = rfd; -+ shm->id = data.id; -+ shm->size = data.size; -+ return TEEC_SUCCESS; -+} -+ -+TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) -+{ -+ int fd = 0; -+ size_t s = 0; -+ -+ if (!ctx || !shm) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))) -+ return TEEC_ERROR_BAD_PARAMETERS; -+ -+ s = shm->size; -+ if (!s) -+ s = 8; -+ -+ if (ctx->reg_mem) { -+ shm->buffer = teec_paged_aligned_alloc(s); -+ if (!shm->buffer) -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ -+ fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id); -+ if (fd < 0) { -+ free(shm->buffer); -+ shm->buffer = NULL; -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ } -+ shm->registered_fd = fd; -+ } else { -+ fd = teec_shm_alloc(ctx->fd, s, &shm->id); -+ if (fd < 0) -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ -+ shm->buffer = mmap(NULL, s, PROT_READ | PROT_WRITE, -+ MAP_SHARED, fd, 0); -+ close(fd); -+ if (shm->buffer == (void *)MAP_FAILED) { -+ shm->id = -1; -+ return TEEC_ERROR_OUT_OF_MEMORY; -+ } -+ shm->registered_fd = -1; -+ } -+ -+ shm->shadow_buffer = NULL; -+ shm->alloced_size = s; -+ shm->internal.flags = SHM_FLAG_BUFFER_ALLOCED; -+ return TEEC_SUCCESS; -+} -+ -+void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shm) -+{ -+ if (!shm || shm->id == -1) -+ return; -+ -+ if (shm->shadow_buffer) { -+ if (shm->registered_fd >= 0) { -+ if (shm->internal.flags & -+ SHM_FLAG_SHADOW_BUFFER_ALLOCED) -+ free(shm->shadow_buffer); -+ close(shm->registered_fd); -+ } else { -+ munmap(shm->shadow_buffer, shm->alloced_size); -+ } -+ } else if (shm->buffer) { -+ if (shm->registered_fd >= 0) { -+ if (shm->internal.flags & SHM_FLAG_BUFFER_ALLOCED) -+ free(shm->buffer); -+ close(shm->registered_fd); -+ } else { -+ munmap(shm->buffer, shm->alloced_size); -+ } -+ } else if (shm->registered_fd >= 0) { -+ close(shm->registered_fd); -+ } -+ -+ shm->id = -1; -+ shm->shadow_buffer = NULL; -+ shm->buffer = NULL; -+ shm->registered_fd = -1; -+ shm->internal.flags = 0; -+} -diff --git a/src/tee_client_api.h b/src/tee_client_api.h -new file mode 100644 -index 0000000..1693998 ---- /dev/null -+++ b/src/tee_client_api.h -@@ -0,0 +1,555 @@ -+/* -+ * Copyright (c) 2014, STMicroelectronics International N.V. -+ * All rights reserved. -+ * Copyright (c) 2015, Linaro Limited -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+#ifndef TEE_CLIENT_API_H -+#define TEE_CLIENT_API_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * Defines the number of available memory references in an open session or -+ * invoke command operation payload. -+ */ -+#define TEEC_CONFIG_PAYLOAD_REF_COUNT 4 -+ -+/** -+ * Defines the maximum size of a single shared memory block, in bytes, of both -+ * API allocated and API registered memory. There is no good value to put here -+ * (limits depend on specific config used), so this define does not provide any -+ * restriction in this implementation. -+ */ -+#define TEEC_CONFIG_SHAREDMEM_MAX_SIZE ULONG_MAX -+ -+/** -+ * Flag constants indicating the type of parameters encoded inside the -+ * operation payload (TEEC_Operation), Type is uint32_t. -+ * -+ * TEEC_NONE The Parameter is not used -+ * -+ * TEEC_VALUE_INPUT The Parameter is a TEEC_Value tagged as input. -+ * -+ * TEEC_VALUE_OUTPUT The Parameter is a TEEC_Value tagged as output. -+ * -+ * TEEC_VALUE_INOUT The Parameter is a TEEC_Value tagged as both as -+ * input and output, i.e., for which both the -+ * behaviors of TEEC_VALUE_INPUT and -+ * TEEC_VALUE_OUTPUT apply. -+ * -+ * TEEC_MEMREF_TEMP_INPUT The Parameter is a TEEC_TempMemoryReference -+ * describing a region of memory which needs to be -+ * temporarily registered for the duration of the -+ * Operation and is tagged as input. -+ * -+ * TEEC_MEMREF_TEMP_OUTPUT Same as TEEC_MEMREF_TEMP_INPUT, but the Memory -+ * Reference is tagged as output. The -+ * Implementation may update the size field to -+ * reflect the required output size in some use -+ * cases. -+ * -+ * TEEC_MEMREF_TEMP_INOUT A Temporary Memory Reference tagged as both -+ * input and output, i.e., for which both the -+ * behaviors of TEEC_MEMREF_TEMP_INPUT and -+ * TEEC_MEMREF_TEMP_OUTPUT apply. -+ * -+ * TEEC_MEMREF_WHOLE The Parameter is a Registered Memory Reference -+ * that refers to the entirety of its parent Shared -+ * Memory block. The parameter structure is a -+ * TEEC_MemoryReference. In this structure, the -+ * Implementation MUST read only the parent field -+ * and MAY update the size field when the operation -+ * completes. -+ * -+ * TEEC_MEMREF_PARTIAL_INPUT A Registered Memory Reference structure that -+ * refers to a partial region of its parent Shared -+ * Memory block and is tagged as input. -+ * -+ * TEEC_MEMREF_PARTIAL_OUTPUT Registered Memory Reference structure that -+ * refers to a partial region of its parent Shared -+ * Memory block and is tagged as output. -+ * -+ * TEEC_MEMREF_PARTIAL_INOUT The Registered Memory Reference structure that -+ * refers to a partial region of its parent Shared -+ * Memory block and is tagged as both input and -+ * output, i.e., for which both the behaviors of -+ * TEEC_MEMREF_PARTIAL_INPUT and -+ * TEEC_MEMREF_PARTIAL_OUTPUT apply. -+ */ -+#define TEEC_NONE 0x00000000 -+#define TEEC_VALUE_INPUT 0x00000001 -+#define TEEC_VALUE_OUTPUT 0x00000002 -+#define TEEC_VALUE_INOUT 0x00000003 -+#define TEEC_MEMREF_TEMP_INPUT 0x00000005 -+#define TEEC_MEMREF_TEMP_OUTPUT 0x00000006 -+#define TEEC_MEMREF_TEMP_INOUT 0x00000007 -+#define TEEC_MEMREF_WHOLE 0x0000000C -+#define TEEC_MEMREF_PARTIAL_INPUT 0x0000000D -+#define TEEC_MEMREF_PARTIAL_OUTPUT 0x0000000E -+#define TEEC_MEMREF_PARTIAL_INOUT 0x0000000F -+ -+/** -+ * Flag constants indicating the data transfer direction of memory in -+ * TEEC_Parameter. TEEC_MEM_INPUT signifies data transfer direction from the -+ * client application to the TEE. TEEC_MEM_OUTPUT signifies data transfer -+ * direction from the TEE to the client application. Type is uint32_t. -+ * -+ * TEEC_MEM_INPUT The Shared Memory can carry data from the client -+ * application to the Trusted Application. -+ * TEEC_MEM_OUTPUT The Shared Memory can carry data from the Trusted -+ * Application to the client application. -+ */ -+#define TEEC_MEM_INPUT 0x00000001 -+#define TEEC_MEM_OUTPUT 0x00000002 -+ -+/** -+ * Return values. Type is TEEC_Result -+ * -+ * TEEC_SUCCESS The operation was successful. -+ * TEEC_ERROR_GENERIC Non-specific cause. -+ * TEEC_ERROR_ACCESS_DENIED Access privileges are not sufficient. -+ * TEEC_ERROR_CANCEL The operation was canceled. -+ * TEEC_ERROR_ACCESS_CONFLICT Concurrent accesses caused conflict. -+ * TEEC_ERROR_EXCESS_DATA Too much data for the requested operation was -+ * passed. -+ * TEEC_ERROR_BAD_FORMAT Input data was of invalid format. -+ * TEEC_ERROR_BAD_PARAMETERS Input parameters were invalid. -+ * TEEC_ERROR_BAD_STATE Operation is not valid in the current state. -+ * TEEC_ERROR_ITEM_NOT_FOUND The requested data item is not found. -+ * TEEC_ERROR_NOT_IMPLEMENTED The requested operation should exist but is not -+ * yet implemented. -+ * TEEC_ERROR_NOT_SUPPORTED The requested operation is valid but is not -+ * supported in this implementation. -+ * TEEC_ERROR_NO_DATA Expected data was missing. -+ * TEEC_ERROR_OUT_OF_MEMORY System ran out of resources. -+ * TEEC_ERROR_BUSY The system is busy working on something else. -+ * TEEC_ERROR_COMMUNICATION Communication with a remote party failed. -+ * TEEC_ERROR_SECURITY A security fault was detected. -+ * TEEC_ERROR_SHORT_BUFFER The supplied buffer is too short for the -+ * generated output. -+ * TEEC_ERROR_TARGET_DEAD Trusted Application has panicked -+ * during the operation. -+ */ -+ -+/** -+ * Standard defined error codes. -+ */ -+#define TEEC_SUCCESS 0x00000000 -+#define TEEC_ERROR_STORAGE_NOT_AVAILABLE 0xF0100003 -+#define TEEC_ERROR_GENERIC 0xFFFF0000 -+#define TEEC_ERROR_ACCESS_DENIED 0xFFFF0001 -+#define TEEC_ERROR_CANCEL 0xFFFF0002 -+#define TEEC_ERROR_ACCESS_CONFLICT 0xFFFF0003 -+#define TEEC_ERROR_EXCESS_DATA 0xFFFF0004 -+#define TEEC_ERROR_BAD_FORMAT 0xFFFF0005 -+#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006 -+#define TEEC_ERROR_BAD_STATE 0xFFFF0007 -+#define TEEC_ERROR_ITEM_NOT_FOUND 0xFFFF0008 -+#define TEEC_ERROR_NOT_IMPLEMENTED 0xFFFF0009 -+#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A -+#define TEEC_ERROR_NO_DATA 0xFFFF000B -+#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C -+#define TEEC_ERROR_BUSY 0xFFFF000D -+#define TEEC_ERROR_COMMUNICATION 0xFFFF000E -+#define TEEC_ERROR_SECURITY 0xFFFF000F -+#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010 -+#define TEEC_ERROR_EXTERNAL_CANCEL 0xFFFF0011 -+#define TEEC_ERROR_TARGET_DEAD 0xFFFF3024 -+#define TEEC_ERROR_STORAGE_NO_SPACE 0xFFFF3041 -+ -+/** -+ * Function error origins, of type TEEC_ErrorOrigin. These indicate where in -+ * the software stack a particular return value originates from. -+ * -+ * TEEC_ORIGIN_API The error originated within the TEE Client API -+ * implementation. -+ * TEEC_ORIGIN_COMMS The error originated within the underlying -+ * communications stack linking the rich OS with -+ * the TEE. -+ * TEEC_ORIGIN_TEE The error originated within the common TEE code. -+ * TEEC_ORIGIN_TRUSTED_APP The error originated within the Trusted Application -+ * code. -+ */ -+#define TEEC_ORIGIN_API 0x00000001 -+#define TEEC_ORIGIN_COMMS 0x00000002 -+#define TEEC_ORIGIN_TEE 0x00000003 -+#define TEEC_ORIGIN_TRUSTED_APP 0x00000004 -+ -+/** -+ * Session login methods, for use in TEEC_OpenSession() as parameter -+ * connectionMethod. Type is uint32_t. -+ * -+ * TEEC_LOGIN_PUBLIC No login data is provided. -+ * TEEC_LOGIN_USER Login data about the user running the Client -+ * Application process is provided. -+ * TEEC_LOGIN_GROUP Login data about the group running the Client -+ * Application process is provided. -+ * TEEC_LOGIN_APPLICATION Login data about the running Client Application -+ * itself is provided. -+ * TEEC_LOGIN_USER_APPLICATION Login data about the user and the running -+ * Client Application itself is provided. -+ * TEEC_LOGIN_GROUP_APPLICATION Login data about the group and the running -+ * Client Application itself is provided. -+ */ -+#define TEEC_LOGIN_PUBLIC 0x00000000 -+#define TEEC_LOGIN_USER 0x00000001 -+#define TEEC_LOGIN_GROUP 0x00000002 -+#define TEEC_LOGIN_APPLICATION 0x00000004 -+#define TEEC_LOGIN_USER_APPLICATION 0x00000005 -+#define TEEC_LOGIN_GROUP_APPLICATION 0x00000006 -+ -+/** -+ * Encode the paramTypes according to the supplied types. -+ * -+ * @param p0 The first param type. -+ * @param p1 The second param type. -+ * @param p2 The third param type. -+ * @param p3 The fourth param type. -+ */ -+#define TEEC_PARAM_TYPES(p0, p1, p2, p3) \ -+ ((p0) | ((p1) << 4) | ((p2) << 8) | ((p3) << 12)) -+ -+/** -+ * Get the i_th param type from the paramType. -+ * -+ * @param p The paramType. -+ * @param i The i-th parameter to get the type for. -+ */ -+#define TEEC_PARAM_TYPE_GET(p, i) (((p) >> (i * 4)) & 0xF) -+ -+typedef uint32_t TEEC_Result; -+ -+/** -+ * struct TEEC_Context - Represents a connection between a client application -+ * and a TEE. -+ */ -+typedef struct { -+ /* Implementation defined */ -+ int fd; -+ bool reg_mem; -+ bool memref_null; -+} TEEC_Context; -+ -+/** -+ * This type contains a Universally Unique Resource Identifier (UUID) type as -+ * defined in RFC4122. These UUID values are used to identify Trusted -+ * Applications. -+ */ -+typedef struct { -+ uint32_t timeLow; -+ uint16_t timeMid; -+ uint16_t timeHiAndVersion; -+ uint8_t clockSeqAndNode[8]; -+} TEEC_UUID; -+ -+/** -+ * struct TEEC_SharedMemory - Memory to transfer data between a client -+ * application and trusted code. -+ * -+ * @param buffer The memory buffer which is to be, or has been, shared -+ * with the TEE. -+ * @param size The size, in bytes, of the memory buffer. -+ * @param flags Bit-vector which holds properties of buffer. -+ * The bit-vector can contain either or both of the -+ * TEEC_MEM_INPUT and TEEC_MEM_OUTPUT flags. -+ * -+ * A shared memory block is a region of memory allocated in the context of the -+ * client application memory space that can be used to transfer data between -+ * that client application and a trusted application. The user of this struct -+ * is responsible to populate the buffer pointer. -+ */ -+typedef struct { -+ void *buffer; -+ size_t size; -+ uint32_t flags; -+ /* -+ * Implementation-Defined -+ */ -+ int id; -+ size_t alloced_size; -+ void *shadow_buffer; -+ int registered_fd; -+ union { -+ bool dummy; -+ uint8_t flags; -+ } internal; -+} TEEC_SharedMemory; -+ -+/** -+ * struct TEEC_TempMemoryReference - Temporary memory to transfer data between -+ * a client application and trusted code, only used for the duration of the -+ * operation. -+ * -+ * @param buffer The memory buffer which is to be, or has been shared with -+ * the TEE. -+ * @param size The size, in bytes, of the memory buffer. -+ * -+ * A memory buffer that is registered temporarily for the duration of the -+ * operation to be called. -+ */ -+typedef struct { -+ void *buffer; -+ size_t size; -+} TEEC_TempMemoryReference; -+ -+/** -+ * struct TEEC_RegisteredMemoryReference - use a pre-registered or -+ * pre-allocated shared memory block of memory to transfer data between -+ * a client application and trusted code. -+ * -+ * @param parent Points to a shared memory structure. The memory reference -+ * may utilize the whole shared memory or only a part of it. -+ * Must not be NULL -+ * -+ * @param size The size, in bytes, of the memory buffer. -+ * -+ * @param offset The offset, in bytes, of the referenced memory region from -+ * the start of the shared memory block. -+ * -+ */ -+typedef struct { -+ TEEC_SharedMemory *parent; -+ size_t size; -+ size_t offset; -+} TEEC_RegisteredMemoryReference; -+ -+/** -+ * struct TEEC_Value - Small raw data container -+ * -+ * Instead of allocating a shared memory buffer this structure can be used -+ * to pass small raw data between a client application and trusted code. -+ * -+ * @param a The first integer value. -+ * -+ * @param b The second value. -+ */ -+typedef struct { -+ uint32_t a; -+ uint32_t b; -+} TEEC_Value; -+ -+/** -+ * union TEEC_Parameter - Memory container to be used when passing data between -+ * client application and trusted code. -+ * -+ * Either the client uses a shared memory reference, parts of it or a small raw -+ * data container. -+ * -+ * @param tmpref A temporary memory reference only valid for the duration -+ * of the operation. -+ * -+ * @param memref The entire shared memory or parts of it. -+ * -+ * @param value The small raw data container to use -+ */ -+typedef union { -+ TEEC_TempMemoryReference tmpref; -+ TEEC_RegisteredMemoryReference memref; -+ TEEC_Value value; -+} TEEC_Parameter; -+ -+/** -+ * struct TEEC_Session - Represents a connection between a client application -+ * and a trusted application. -+ */ -+typedef struct { -+ /* Implementation defined */ -+ TEEC_Context *ctx; -+ uint32_t session_id; -+} TEEC_Session; -+ -+/** -+ * struct TEEC_Operation - Holds information and memory references used in -+ * TEEC_InvokeCommand(). -+ * -+ * @param started Client must initialize to zero if it needs to cancel -+ * an operation about to be performed. -+ * @param paramTypes Type of data passed. Use TEEC_PARAM_TYPES macro to -+ * create the correct flags. -+ * 0 means TEEC_NONE is passed for all params. -+ * @param params Array of parameters of type TEEC_Parameter. -+ * @param session Internal pointer to the last session used by -+ * TEEC_InvokeCommand with this operation. -+ * -+ */ -+typedef struct { -+ uint32_t started; -+ uint32_t paramTypes; -+ TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT]; -+ /* Implementation-Defined */ -+ TEEC_Session *session; -+} TEEC_Operation; -+ -+/** -+ * TEEC_InitializeContext() - Initializes a context holding connection -+ * information on the specific TEE, designated by the name string. -+ -+ * @param name A zero-terminated string identifying the TEE to connect to. -+ * If name is set to NULL, the default TEE is connected to. NULL -+ * is the only supported value in this version of the API -+ * implementation. -+ * -+ * @param context The context structure which is to be initialized. -+ * -+ * @return TEEC_SUCCESS The initialization was successful. -+ * @return TEEC_Result Something failed. -+ */ -+TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context); -+ -+/** -+ * TEEC_FinalizeContext() - Destroys a context holding connection information -+ * on the specific TEE. -+ * -+ * This function destroys an initialized TEE context, closing the connection -+ * between the client application and the TEE. This function must only be -+ * called when all sessions related to this TEE context have been closed and -+ * all shared memory blocks have been released. -+ * -+ * @param context The context to be destroyed. -+ */ -+void TEEC_FinalizeContext(TEEC_Context *context); -+ -+/** -+ * TEEC_OpenSession() - Opens a new session with the specified trusted -+ * application. -+ * -+ * @param context The initialized TEE context structure in which -+ * scope to open the session. -+ * @param session The session to initialize. -+ * @param destination A structure identifying the trusted application -+ * with which to open a session. -+ * -+ * @param connectionMethod The connection method to use. -+ * @param connectionData Any data necessary to connect with the chosen -+ * connection method. Not supported, should be set to -+ * NULL. -+ * @param operation An operation structure to use in the session. May -+ * be set to NULL to signify no operation structure -+ * needed. -+ * -+ * @param returnOrigin A parameter which will hold the error origin if -+ * this function returns any value other than -+ * TEEC_SUCCESS. -+ * -+ * @return TEEC_SUCCESS OpenSession successfully opened a new session. -+ * @return TEEC_Result Something failed. -+ * -+ */ -+TEEC_Result TEEC_OpenSession(TEEC_Context *context, -+ TEEC_Session *session, -+ const TEEC_UUID *destination, -+ uint32_t connectionMethod, -+ const void *connectionData, -+ TEEC_Operation *operation, -+ uint32_t *returnOrigin); -+ -+/** -+ * TEEC_CloseSession() - Closes the session which has been opened with the -+ * specific trusted application. -+ * -+ * @param session The opened session to close. -+ */ -+void TEEC_CloseSession(TEEC_Session *session); -+ -+/** -+ * TEEC_InvokeCommand() - Executes a command in the specified trusted -+ * application. -+ * -+ * @param session A handle to an open connection to the trusted -+ * application. -+ * @param commandID Identifier of the command in the trusted application -+ * to invoke. -+ * @param operation An operation structure to use in the invoke command. -+ * May be set to NULL to signify no operation structure -+ * needed. -+ * @param returnOrigin A parameter which will hold the error origin if this -+ * function returns any value other than TEEC_SUCCESS. -+ * -+ * @return TEEC_SUCCESS OpenSession successfully opened a new session. -+ * @return TEEC_Result Something failed. -+ */ -+TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, -+ uint32_t commandID, -+ TEEC_Operation *operation, -+ uint32_t *returnOrigin); -+ -+/** -+ * TEEC_RegisterSharedMemory() - Register a block of existing memory as a -+ * shared block within the scope of the specified context. -+ * -+ * @param context The initialized TEE context structure in which scope to -+ * open the session. -+ * @param sharedMem pointer to the shared memory structure to register. -+ * -+ * @return TEEC_SUCCESS The registration was successful. -+ * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion. -+ * @return TEEC_Result Something failed. -+ */ -+TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context, -+ TEEC_SharedMemory *sharedMem); -+ -+/** -+ * TEEC_AllocateSharedMemory() - Allocate shared memory for TEE. -+ * -+ * @param context The initialized TEE context structure in which scope to -+ * open the session. -+ * @param sharedMem Pointer to the allocated shared memory. -+ * -+ * @return TEEC_SUCCESS The registration was successful. -+ * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion. -+ * @return TEEC_Result Something failed. -+ */ -+TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context, -+ TEEC_SharedMemory *sharedMem); -+ -+/** -+ * TEEC_ReleaseSharedMemory() - Free or deregister the shared memory. -+ * -+ * @param sharedMem Pointer to the shared memory to be freed. -+ */ -+void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory); -+ -+/** -+ * TEEC_RequestCancellation() - Request the cancellation of a pending open -+ * session or command invocation. -+ * -+ * @param operation Pointer to an operation previously passed to open session -+ * or invoke. -+ */ -+void TEEC_RequestCancellation(TEEC_Operation *operation); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/src/tee_client_api_extensions.h b/src/tee_client_api_extensions.h -new file mode 100644 -index 0000000..85298aa ---- /dev/null -+++ b/src/tee_client_api_extensions.h -@@ -0,0 +1,57 @@ -+/* -+ * Copyright (c) 2016, Linaro Limited -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+#ifndef TEE_CLIENT_API_EXTENSIONS_H -+#define TEE_CLIENT_API_EXTENSIONS_H -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * TEEC_RegisterMemoryFileDescriptor() - Register a block of existing memory as -+ * a shared block within the scope of the specified context. -+ * -+ * @param context The initialized TEE context structure in which scope to -+ * open the session. -+ * @param sharedMem pointer to the shared memory structure to register. -+ * @param fd file descriptor of the target memory. -+ * -+ * @return TEEC_SUCCESS The registration was successful. -+ * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion. -+ * @return TEEC_Result Something failed. -+ */ -+TEEC_Result TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context *context, -+ TEEC_SharedMemory *sharedMem, -+ int fd); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* TEE_CLIENT_API_EXTENSIONS_H */ -diff --git a/src/teec_benchmark.h b/src/teec_benchmark.h -new file mode 100644 -index 0000000..17d99ac ---- /dev/null -+++ b/src/teec_benchmark.h -@@ -0,0 +1,37 @@ -+/* -+ * Copyright (c) 2017, Linaro Limited -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef __TEEC_BENCHMARK_H -+#define __TEEC_BENCHMARK_H -+ -+#ifdef CFG_TEE_BENCHMARK -+void bm_timestamp(void); -+#else -+static inline void bm_timestamp(void) {} -+#endif -+ -+#endif /* __TEEC_BENCHMARK_H */ -diff --git a/src/teec_trace.c b/src/teec_trace.c -new file mode 100644 -index 0000000..7194c8c ---- /dev/null -+++ b/src/teec_trace.c -@@ -0,0 +1,141 @@ -+/* -+ * Copyright (c) 2014, STMicroelectronics International N.V. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "teec_trace.h" -+ -+#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -+ -+/* -+ * The length of the prefix is 37, for example it looks like this: -+ * P = Prefix -+ * M = Message -+ * F = Function name -+ * L = Line number -+ * PPPP: MMMMM [FFFFFFFFFFFFFFF : LLLLL] -+ */ -+#define MAX_PRINT_SIZE 256 -+ -+#ifdef TEEC_LOG_FILE -+static void log_to_file(const char *buffer) -+{ -+ FILE *log_file = fopen(TEEC_LOG_FILE, "a"); -+ -+ if (log_file != NULL) { -+ fprintf(log_file, "%s", buffer); -+ fclose(log_file); -+ log_file = NULL; -+ } -+} -+#else -+#define log_to_file(buffer) -+#endif -+ -+static const char * const trace_level_strings[] = { -+ "", "ERR", "INF", "DBG", "FLW" -+}; -+ -+void _dprintf(const char *function, int line, int level, const char *prefix, -+ const char *fmt, ...) -+{ -+ char msg[MAX_PRINT_SIZE]; -+ int n = 0; -+ va_list ap; -+ -+ if (function) { -+ int thread_id = syscall(SYS_gettid); -+ -+ n = snprintf(msg, sizeof(msg), "%s [%d] %s:%s:%d: ", -+ trace_level_strings[level], thread_id, prefix, -+ function, line); -+ if (n < 0) -+ return; -+ } -+ -+ if ((size_t)n < sizeof(msg)) { -+ va_start(ap, fmt); -+ n = vsnprintf(msg + n, sizeof(msg) - n, fmt, ap); -+ va_end(ap); -+ if (n < 0) -+ return; -+ } -+ -+ fprintf(stdout, "%s", msg); -+ log_to_file(msg); -+} -+ -+#if (defined(DEBUGLEVEL_3) || defined(DEBUGLEVEL_true) || defined(DEBUGLEVEL_4)) -+void dump_buffer(const char *bname, const uint8_t *buffer, size_t blen) -+{ -+ fprintf(stderr, "#### %s\n", bname); -+ -+ while (blen > 0) { -+ size_t n = 0; -+ -+ for (n = 0; n < 16; n++) { -+ if (n < blen) -+ fprintf(stderr, "%02x ", (int)buffer[n]); -+ else -+ fprintf(stderr, " "); -+ -+ if (n == 7) -+ fprintf(stderr, " "); -+ } -+ -+ fprintf(stderr, " |"); -+ -+ for (n = 0; n < 16; n++) { -+ if (n < blen) { -+ if (isprint(buffer[n])) -+ fprintf(stderr, "%c", (int)buffer[n]); -+ else -+ fprintf(stderr, "."); -+ } -+ } -+ -+ fprintf(stderr, "|\n"); -+ -+ blen -= MIN(blen, 16); -+ buffer += 16; -+ } -+} -+#else -+void dump_buffer(const char *bname, const uint8_t *buffer, size_t blen) -+{ -+ (void)bname; -+ (void)buffer; -+ (void)blen; -+} -+#endif -diff --git a/src/teec_trace.h b/src/teec_trace.h -new file mode 100644 -index 0000000..b1e37ec ---- /dev/null -+++ b/src/teec_trace.h -@@ -0,0 +1,148 @@ -+/* -+ * Copyright (c) 2014, STMicroelectronics International N.V. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright notice, -+ * this list of conditions and the following disclaimer in the documentation -+ * and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+#ifndef TEEC_TRACE_H -+#define TEEC_TRACE_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#include -+#include -+#include -+#define BINARY_PREFIX "LT" -+ -+#ifndef BINARY_PREFIX -+#error "BINARY_PREFIX not defined" -+#endif -+ -+/* -+ * Trace levels. -+ * -+ * ERROR is used when some kind of error has happened, this is most likely the -+ * print you will use most of the time when you report some kind of error. -+ * -+ * INFO is used when you want to print some 'normal' text to the user. -+ * This is the default level. -+ * -+ * DEBUG is used to print extra information to enter deeply in the module. -+ * -+ * FLOW is used to print the execution flox, typically the in/out of functions. -+ * -+ * */ -+ -+#define TRACE_ERROR 1 -+#define TRACE_INFO 2 -+#define TRACE_DEBUG 3 -+#define TRACE_FLOW 4 -+ -+#if defined(DEBUGLEVEL_0) && !defined(DEBUGLEVEL) -+#define DEBUGLEVEL TRACE_ERROR -+#endif -+ -+#if defined(DEBUGLEVEL_1) && !defined(DEBUGLEVEL) -+#define DEBUGLEVEL TRACE_ERROR -+#endif -+ -+#if defined(DEBUGLEVEL_2) && !defined(DEBUGLEVEL) -+#define DEBUGLEVEL TRACE_INFO -+#endif -+ -+#if defined(DEBUGLEVEL_3) && !defined(DEBUGLEVEL) -+#define DEBUGLEVEL TRACE_DEBUG -+#endif -+ -+#if defined(DEBUGLEVEL_4) && !defined(DEBUGLEVEL) -+#define DEBUGLEVEL TRACE_FLOW -+#endif -+ -+#ifndef DEBUGLEVEL -+/* Default debug level. */ -+#define DEBUGLEVEL TRACE_INFO -+#endif -+ -+/* -+ * This define make sure that parameters are checked in the same manner as it -+ * is done in the normal printf function. -+ */ -+#define __PRINTFLIKE(__fmt, __varargs) __attribute__\ -+ ((__format__(__printf__, __fmt, __varargs))) -+ -+void _dprintf(const char *function, int line, int level, const char *prefix, -+ const char *fmt, ...) __PRINTFLIKE(5, 6); -+ -+#define dprintf(level, x...) do { \ -+ if ((level) <= DEBUGLEVEL) { \ -+ _dprintf(__func__, __LINE__, level, \ -+ BINARY_PREFIX, x); \ -+ } \ -+ } while (0) -+ -+#define EMSG(fmt, ...) dprintf(TRACE_ERROR, fmt "\n", ##__VA_ARGS__) -+#define IMSG(fmt, ...) dprintf(TRACE_INFO, fmt "\n", ##__VA_ARGS__) -+#define DMSG(fmt, ...) dprintf(TRACE_DEBUG, fmt "\n", ##__VA_ARGS__) -+#define FMSG(fmt, ...) dprintf(TRACE_FLOW, fmt "\n", ##__VA_ARGS__) -+ -+#define INMSG(fmt, ...) FMSG("> " fmt, ##__VA_ARGS__) -+#define OUTMSG(fmt, ...) FMSG("< " fmt, ##__VA_ARGS__) -+#define OUTRMSG(r) \ -+ do { \ -+ if (r) \ -+ EMSG("Function returns with [%d]", r); \ -+ OUTMSG("r=[%d]", r); \ -+ return r; \ -+ } while (0) -+ -+#define dprintf_raw(level, x...) do { \ -+ if ((level) <= DEBUGLEVEL) \ -+ _dprintf(0, 0, (level), BINARY_PREFIX, x); \ -+ } while (0) -+ -+#define EMSG_RAW(fmt, ...) dprintf_raw(TRACE_ERROR, fmt, ##__VA_ARGS__) -+#define IMSG_RAW(fmt, ...) dprintf_raw(TRACE_INFO, fmt, ##__VA_ARGS__) -+#define DMSG_RAW(fmt, ...) dprintf_raw(TRACE_DEBUG, fmt, ##__VA_ARGS__) -+#define FMSG_RAW(fmt, ...) dprintf_raw(TRACE_FLOW, fmt, ##__VA_ARGS__) -+ -+/* -+ * This function will hex and ascii dump a buffer. -+ * -+ * Note that this function will only print if debug flag -+ * DEBUGLEVEL is INFO or FLOOD. -+ * -+ * @param bname Information string describing the buffer. -+ * @param buffer Pointer to the buffer. -+ * @param blen Length of the buffer. -+ * -+ * @return void -+ */ -+void dump_buffer(const char *bname, const uint8_t *buffer, size_t blen); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/src/uboot_env.c b/src/uboot_env.c -index d507cac..aa33930 100644 ---- a/src/uboot_env.c -+++ b/src/uboot_env.c -@@ -42,6 +42,9 @@ - #include "md5.h" - #include "uboot_private.h" - -+#include -+#include -+ - /* - * The BLOB includes a random AES-256 key (32 bytes) and a - * Message Authentication Code (MAC) (16 bytes) -@@ -1156,7 +1159,7 @@ static bool machine_is_compatible(char *machine) - } - - #define MAX_HWID_WORDS 4 --static int env_caam_get_keymod(unsigned char output[16]) -+static int env_encryption_get_keymod(unsigned char output[16]) - { - int i; - int len; -@@ -1224,7 +1227,7 @@ static int env_caam_crypt(char *data, unsigned int size, const int enc) - char *buffer; - unsigned char key_modifier[16]; - -- ret = env_caam_get_keymod(key_modifier); -+ ret = env_encryption_get_keymod(key_modifier); - if (ret) - return ret; - -@@ -1271,6 +1274,165 @@ free: - return ret; - } - -+void prepare_tee_session(struct aes_ctx *ctx) -+{ -+ TEEC_Result ret; -+ uint32_t origin; -+ TEEC_UUID uuid = TA_STM32MP_CRYP_UUID; -+ -+ ret = TEEC_InitializeContext(NULL, &ctx->ctx); -+ if (ret != TEEC_SUCCESS) -+ printf("TEEC_InitializeContext failed with code 0x%x", ret); -+ -+ /* Open a session with the TA */ -+ ret = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid, -+ TEEC_LOGIN_PUBLIC, NULL, NULL, &origin); -+ if (ret != TEEC_SUCCESS) -+ printf("TEEC_Opensession failed with code 0x%x origin 0x%x", -+ ret, origin); -+ -+} -+ -+void terminate_tee_session(struct aes_ctx *ctx) -+{ -+ TEEC_CloseSession(&ctx->sess); -+ TEEC_FinalizeContext(&ctx->ctx); -+} -+ -+void prepare_aes(struct aes_ctx *ctx, int encode) -+{ -+ TEEC_Operation op; -+ uint32_t origin; -+ TEEC_Result res; -+ -+ memset(&op, 0, sizeof(op)); -+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, -+ TEEC_VALUE_INPUT, -+ TEEC_VALUE_INPUT, -+ TEEC_NONE); -+ -+ op.params[0].value.a = TA_AES_ALGO_CTR; -+ op.params[1].value.a = AES128_KEY_LENGTH; -+ op.params[2].value.a = encode ? TA_AES_MODE_ENCODE : -+ TA_AES_MODE_DECODE; -+ -+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_PREPARE, -+ &op, &origin); -+ if (res != TEEC_SUCCESS) -+ printf("TEEC_InvokeCommand(PREPARE) failed 0x%x origin 0x%x", -+ res, origin); -+} -+ -+void set_key(struct aes_ctx *ctx, size_t key_sz) -+{ -+ TEEC_Operation op; -+ uint32_t origin; -+ TEEC_Result res; -+ -+ memset(&op, 0, sizeof(op)); -+ -+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, -+ TEEC_NONE, TEEC_NONE, TEEC_NONE); -+ -+ op.params[0].value.a = key_sz; -+ -+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_KEY, -+ &op, &origin); -+ if (res != TEEC_SUCCESS) -+ printf("TEEC_InvokeCommand(SET_KEY) failed 0x%x origin 0x%x", -+ res, origin); -+} -+ -+void set_iv(struct aes_ctx *ctx, char *iv, size_t iv_sz) -+{ -+ TEEC_Operation op; -+ uint32_t origin; -+ TEEC_Result res; -+ -+ memset(&op, 0, sizeof(op)); -+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, -+ TEEC_NONE, TEEC_NONE, TEEC_NONE); -+ op.params[0].tmpref.buffer = iv; -+ op.params[0].tmpref.size = iv_sz; -+ -+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_IV, -+ &op, &origin); -+ if (res != TEEC_SUCCESS) -+ printf("TEEC_InvokeCommand(SET_IV) failed 0x%x origin 0x%x", -+ res, origin); -+} -+ -+void cipher_buffer(struct aes_ctx *ctx, char *in, char *out, size_t sz) -+{ -+ TEEC_Operation op; -+ uint32_t origin; -+ TEEC_Result res; -+ -+ memset(&op, 0, sizeof(op)); -+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, -+ TEEC_MEMREF_TEMP_OUTPUT, -+ TEEC_NONE, TEEC_NONE); -+ op.params[0].tmpref.buffer = in; -+ op.params[0].tmpref.size = sz; -+ op.params[1].tmpref.buffer = out; -+ op.params[1].tmpref.size = sz; -+ -+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_CIPHER, -+ &op, &origin); -+ if (res != TEEC_SUCCESS) -+ printf("TEEC_InvokeCommand(CIPHER) failed 0x%x origin 0x%x", -+ res, origin); -+} -+ -+static int env_ccmp1_crypt(char *data, unsigned int size, const int enc) -+{ -+ int ret, i; -+ uint32_t origin; -+ struct aes_ctx *aes; -+ char *iv, *ciph; -+ TEEC_UUID uuid = TA_STM32MP_CRYP_UUID; -+ unsigned char key_modifier[16]; -+ -+ /* Allocate all the buffer */ -+ iv = calloc(AES_BLOCK_LENGTH, sizeof(char)); -+ ciph = calloc(size+1, sizeof(unsigned int)); -+ -+ if (!iv || !ciph) { -+ printf("%s: can't allocate memory\n", __func__); -+ ret = -ENOMEM; -+ goto err_free_buffs; -+ } -+ -+ /* Get key_modifer for IV */ -+ ret = env_encryption_get_keymod(key_modifier); -+ if (ret) -+ return ret; -+ -+ memcpy(iv, key_modifier, AES_BLOCK_LENGTH); -+ aes = (struct aes_ctx*)malloc(sizeof(struct aes_ctx)); -+ if (aes == NULL) { -+ printf("%s: can't allocate context memory\n", __func__); -+ ret = -ENOMEM; -+ } else { -+ prepare_tee_session(aes); -+ -+ prepare_aes(aes, enc); -+ set_key(aes, AES128_KEY_LENGTH); -+ set_iv(aes, iv, AES_BLOCK_LENGTH); -+ memset(ciph, 0, size); -+ cipher_buffer(aes, data, ciph, size); -+ /* copy ciphered data */ -+ memcpy(data, ciph, size); -+ free(aes); -+ } -+ -+err_free_buffs: -+ free(iv); -+ free(ciph); -+ -+ return ret; -+} -+ - int libuboot_env_store(struct uboot_ctx *ctx) - { - struct var_entry *entry; -@@ -1347,7 +1509,12 @@ int libuboot_env_store(struct uboot_ctx *ctx) - } - - if (ctx->encrypted) { -- ret = env_caam_crypt(data, ctx->usable_size, 1); -+ /* Detect the platform */ -+ if (machine_is_compatible("digi,ccmp15") || -+ machine_is_compatible("digi,ccmp13")) -+ ret = env_ccmp1_crypt(data, ctx->usable_size, 1); -+ else -+ ret = env_caam_crypt(data, ctx->usable_size, 1); - if (ret) { - fprintf(stderr, - "Error: can't encrypt env for flash\n"); -@@ -1420,7 +1587,12 @@ static int libuboot_load(struct uboot_ctx *ctx) - crc = *(uint32_t *)(buf[i] + offsetcrc); - dev->crc = crc32(0, (uint8_t *)data, usable_envsize); - if (ctx->encrypted) { -- ret = env_caam_crypt((char *)data, ctx->usable_size, 0); -+ /* Detect the platform */ -+ if (machine_is_compatible("digi,ccmp15") || -+ machine_is_compatible("digi,ccmp13")) -+ ret = env_ccmp1_crypt((char *)data, ctx->usable_size, 0); -+ else -+ ret = env_caam_crypt((char *)data, ctx->usable_size, 0); - if (ret) { - fprintf(stderr, "Error: can't decrypt environment\n"); - return ret; diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv_%.bbappend b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv_%.bbappend index 5ff1b39e6..3a0ee0f8d 100644 --- a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv_%.bbappend +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv_%.bbappend @@ -15,13 +15,18 @@ FW_CONFIG_FILE:ccmp1 = "${@bb.utils.contains('IMAGE_FEATURES', 'read-only-rootfs 'ubi/fw_env.config_default', \ 'ubi/fw_env.config', d)}" +DEPENDS += "${@oe.utils.conditional('OPTEE_PATCHES', '', '', 'optee-client', d)}" + +OPTEE_PATCHES = "" +OPTEE_PATCHES:ccimx93 = "file://0004-Implement-support-for-environment-encryption-using-O.patch" +OPTEE_PATCHES:ccmp1 = "file://0004-Implement-support-for-environment-encryption-using-O.patch" + SRC_URI += " \ file://${FW_CONFIG_FILE} \ - file://0001-Implement-support-for-environment-encryption-by-CAAM.patch \ - file://0002-Implement-U-Boot-environment-access-functions.patch \ - file://0003-tools-env-add-support-to-set-dynamic-location-of-env.patch \ - file://0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch \ - file://0005-Implement-support-for-environment-encryption-for-CCM.patch \ + file://0001-Implement-U-Boot-environment-access-functions.patch \ + file://0002-tools-env-add-support-to-set-dynamic-location-of-env.patch \ + file://0003-Implement-support-for-environment-encryption-by-CAAM.patch \ + ${@bb.utils.contains('MACHINE_FEATURES', 'optee', '${OPTEE_PATCHES}', '', d)} \ " do_install:append() { From 66780aafc4f7e4e17faa4fcbda67e8007e4c0327 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Tue, 28 May 2024 17:57:31 +0200 Subject: [PATCH 75/91] optee_os: implement Optee-based environment encryption https://onedigi.atlassian.net/browse/DUB-1079 Signed-off-by: Javier Viguera --- ...3-enable-AES_HUK-trusted-application.patch | 714 ++++++++++++++++++ .../optee-imx/optee-os_4.0.0.imx.bb | 1 + 2 files changed, 715 insertions(+) create mode 100644 meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os/0002-core-ccimx93-enable-AES_HUK-trusted-application.patch diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os/0002-core-ccimx93-enable-AES_HUK-trusted-application.patch b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os/0002-core-ccimx93-enable-AES_HUK-trusted-application.patch new file mode 100644 index 000000000..bcb4ec13a --- /dev/null +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os/0002-core-ccimx93-enable-AES_HUK-trusted-application.patch @@ -0,0 +1,714 @@ +From: Javier Viguera +Date: Tue, 14 May 2024 15:33:17 +0200 +Subject: [PATCH] core: ccimx93: enable AES_HUK trusted application + +This provides the support for u-boot environment encryption. + +Signed-off-by: Javier Viguera +--- + core/arch/arm/plat-imx/conf.mk | 2 + + ta/aes_huk/Android.mk | 4 + + ta/aes_huk/Makefile | 13 + + ta/aes_huk/aes_ta.c | 477 ++++++++++++++++++++++++++++ + ta/aes_huk/include/aes_ta.h | 82 +++++ + ta/aes_huk/sub.mk | 3 + + ta/aes_huk/user_ta.mk | 1 + + ta/aes_huk/user_ta_header_defines.h | 48 +++ + 8 files changed, 630 insertions(+) + create mode 100644 ta/aes_huk/Android.mk + create mode 100644 ta/aes_huk/Makefile + create mode 100644 ta/aes_huk/aes_ta.c + create mode 100644 ta/aes_huk/include/aes_ta.h + create mode 100644 ta/aes_huk/sub.mk + create mode 100644 ta/aes_huk/user_ta.mk + create mode 100644 ta/aes_huk/user_ta_header_defines.h + +diff --git a/core/arch/arm/plat-imx/conf.mk b/core/arch/arm/plat-imx/conf.mk +index 5e4c02e27d2e..40d0bb4116dd 100644 +--- a/core/arch/arm/plat-imx/conf.mk ++++ b/core/arch/arm/plat-imx/conf.mk +@@ -456,12 +456,14 @@ endif + ifneq (,$(filter $(PLATFORM_FLAVOR),ccimx93dvk)) + CFG_DDR_SIZE ?= 0x40000000 + CFG_UART_BASE ?= UART6_BASE ++CFG_IN_TREE_EARLY_TAS += aes_huk/c2fad363-5d9f-4fc4-a417-555841e05745 + endif + + ifneq (,$(filter $(PLATFORM_FLAVOR),ccimx93dvk_a0)) + CFG_DDR_SIZE ?= 0x40000000 + CFG_UART_BASE ?= UART6_BASE + $(call force,CFG_SOC_REV_A0,y) ++CFG_IN_TREE_EARLY_TAS += aes_huk/c2fad363-5d9f-4fc4-a417-555841e05745 + endif + + # i.MX6 Solo/SL/SoloX/DualLite/Dual/Quad specific config +diff --git a/ta/aes_huk/Android.mk b/ta/aes_huk/Android.mk +new file mode 100644 +index 000000000000..931f8e4065c9 +--- /dev/null ++++ b/ta/aes_huk/Android.mk +@@ -0,0 +1,4 @@ ++LOCAL_PATH := $(call my-dir) ++ ++local_module := 5dbac793-f574-4871-8ad3-04331ec17f24.ta ++include $(BUILD_OPTEE_MK) +diff --git a/ta/aes_huk/Makefile b/ta/aes_huk/Makefile +new file mode 100644 +index 000000000000..e41d9913e6ae +--- /dev/null ++++ b/ta/aes_huk/Makefile +@@ -0,0 +1,13 @@ ++CFG_TEE_TA_LOG_LEVEL ?= 4 ++CFG_TA_OPTEE_CORE_API_COMPAT_1_1=y ++ ++# The UUID for the Trusted Application ++BINARY=c2fad363-5d9f-4fc4-a417-555841e05745 ++ ++-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk ++ ++ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) ++clean: ++ @echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' ++ @echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' ++endif +diff --git a/ta/aes_huk/aes_ta.c b/ta/aes_huk/aes_ta.c +new file mode 100644 +index 000000000000..036d64b83478 +--- /dev/null ++++ b/ta/aes_huk/aes_ta.c +@@ -0,0 +1,477 @@ ++/* ++ * Copyright (c) 2017, Linaro Limited ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#define AES128_KEY_BIT_SIZE 128 ++#define AES128_KEY_BYTE_SIZE (AES128_KEY_BIT_SIZE / 8) ++#define AES256_KEY_BIT_SIZE 256 ++#define AES256_KEY_BYTE_SIZE (AES256_KEY_BIT_SIZE / 8) ++ ++/* ++ * Ciphering context: each opened session relates to a cipehring operation. ++ * - configure the AES flavour from a command. ++ * - load key from a command (here the key is provided by the REE) ++ * - reset init vector (here IV is provided by the REE) ++ * - cipher a buffer frame (here input and output buffers are non-secure) ++ */ ++struct aes_cipher { ++ uint32_t algo; /* AES flavour */ ++ uint32_t mode; /* Encode or decode */ ++ uint32_t key_size; /* AES key size in byte */ ++ TEE_OperationHandle op_handle; /* AES ciphering operation */ ++ TEE_ObjectHandle key_handle; /* transient object to load the key */ ++}; ++ ++/* ++ * Few routines to convert IDs from TA API into IDs from OP-TEE. ++ */ ++static TEE_Result ta2tee_algo_id(uint32_t param, uint32_t *algo) ++{ ++ switch (param) { ++ case TA_AES_ALGO_ECB: ++ *algo = TEE_ALG_AES_ECB_NOPAD; ++ return TEE_SUCCESS; ++ case TA_AES_ALGO_CBC: ++ *algo = TEE_ALG_AES_CBC_NOPAD; ++ return TEE_SUCCESS; ++ case TA_AES_ALGO_CTR: ++ *algo = TEE_ALG_AES_CTR; ++ return TEE_SUCCESS; ++ default: ++ EMSG("Invalid algo %u", param); ++ return TEE_ERROR_BAD_PARAMETERS; ++ } ++} ++static TEE_Result ta2tee_key_size(uint32_t param, uint32_t *key_size) ++{ ++ switch (param) { ++ case AES128_KEY_BYTE_SIZE: ++ case AES256_KEY_BYTE_SIZE: ++ *key_size = param; ++ return TEE_SUCCESS; ++ default: ++ EMSG("Invalid key size %u", param); ++ return TEE_ERROR_BAD_PARAMETERS; ++ } ++} ++static TEE_Result ta2tee_mode_id(uint32_t param, uint32_t *mode) ++{ ++ switch (param) { ++ case TA_AES_MODE_ENCODE: ++ *mode = TEE_MODE_ENCRYPT; ++ return TEE_SUCCESS; ++ case TA_AES_MODE_DECODE: ++ *mode = TEE_MODE_DECRYPT; ++ return TEE_SUCCESS; ++ default: ++ EMSG("Invalid mode %u", param); ++ return TEE_ERROR_BAD_PARAMETERS; ++ } ++} ++ ++/* ++ * Process command TA_AES_CMD_PREPARE. API in aes_ta.h ++ * ++ * Allocate resources required for the ciphering operation. ++ * During ciphering operation, when expect client can: ++ * - update the key materials (provided by client) ++ * - reset the initial vector (provided by client) ++ * - cipher an input buffer into an output buffer (provided by client) ++ */ ++static TEE_Result alloc_resources(void *session, uint32_t param_types, ++ TEE_Param params[4]) ++{ ++ const uint32_t exp_param_types = ++ TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, ++ TEE_PARAM_TYPE_VALUE_INPUT, ++ TEE_PARAM_TYPE_VALUE_INPUT, ++ TEE_PARAM_TYPE_NONE); ++ struct aes_cipher *sess; ++ TEE_Attribute attr; ++ TEE_Result res; ++ char *key; ++ ++ /* Get ciphering context from session ID */ ++ DMSG("Session %p: get ciphering resources", session); ++ sess = (struct aes_cipher *)session; ++ ++ /* Safely get the invocation parameters */ ++ if (param_types != exp_param_types) ++ return TEE_ERROR_BAD_PARAMETERS; ++ ++ res = ta2tee_algo_id(params[0].value.a, &sess->algo); ++ if (res != TEE_SUCCESS) ++ return res; ++ ++ res = ta2tee_key_size(params[1].value.a, &sess->key_size); ++ if (res != TEE_SUCCESS) ++ return res; ++ ++ res = ta2tee_mode_id(params[2].value.a, &sess->mode); ++ if (res != TEE_SUCCESS) ++ return res; ++ ++ /* ++ * Ready to allocate the resources which are: ++ * - an operation handle, for an AES ciphering of given configuration ++ * - a transient object that will be use to load the key materials ++ * into the AES ciphering operation. ++ */ ++ ++ /* Free potential previous operation */ ++ if (sess->op_handle != TEE_HANDLE_NULL) ++ TEE_FreeOperation(sess->op_handle); ++ ++ /* Allocate operation: AES/CTR, mode and size from params */ ++ res = TEE_AllocateOperation(&sess->op_handle, ++ sess->algo, ++ sess->mode, ++ sess->key_size * 8); ++ if (res != TEE_SUCCESS) { ++ EMSG("Failed to allocate operation"); ++ sess->op_handle = TEE_HANDLE_NULL; ++ goto err; ++ } ++ ++ /* Free potential previous transient object */ ++ if (sess->key_handle != TEE_HANDLE_NULL) ++ TEE_FreeTransientObject(sess->key_handle); ++ ++ /* Allocate transient object according to target key size */ ++ res = TEE_AllocateTransientObject(TEE_TYPE_AES, ++ sess->key_size * 8, ++ &sess->key_handle); ++ if (res != TEE_SUCCESS) { ++ EMSG("Failed to allocate transient object"); ++ sess->key_handle = TEE_HANDLE_NULL; ++ goto err; ++ } ++ ++ /* ++ * When loading a key in the cipher session, set_aes_key() ++ * will reset the operation and load a key. But we cannot ++ * reset and operation that has no key yet (GPD TEE Internal ++ * Core API Specification – Public Release v1.1.1, section ++ * 6.2.5 TEE_ResetOperation). In consequence, we will load a ++ * dummy key in the operation so that operation can be reset ++ * when updating the key. ++ */ ++ key = TEE_Malloc(sess->key_size, 0); ++ if (!key) { ++ res = TEE_ERROR_OUT_OF_MEMORY; ++ goto err; ++ } ++ ++ TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, sess->key_size); ++ ++ res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1); ++ if (res != TEE_SUCCESS) { ++ EMSG("TEE_PopulateTransientObject failed, %x", res); ++ goto err; ++ } ++ ++ res = TEE_SetOperationKey(sess->op_handle, sess->key_handle); ++ if (res != TEE_SUCCESS) { ++ EMSG("TEE_SetOperationKey failed %x", res); ++ goto err; ++ } ++ ++ return res; ++ ++err: ++ if (sess->op_handle != TEE_HANDLE_NULL) ++ TEE_FreeOperation(sess->op_handle); ++ sess->op_handle = TEE_HANDLE_NULL; ++ ++ if (sess->key_handle != TEE_HANDLE_NULL) ++ TEE_FreeTransientObject(sess->key_handle); ++ sess->key_handle = TEE_HANDLE_NULL; ++ ++ return res; ++} ++ ++static TEE_Result derive_unique_key(uint8_t *key, uint16_t key_size, ++ uint8_t *extra, uint16_t extra_size) ++{ ++ TEE_TASessionHandle sess = TEE_HANDLE_NULL; ++ TEE_Param params[TEE_NUM_PARAMS] = { }; ++ TEE_Result res = TEE_ERROR_GENERIC; ++ uint32_t ret_orig = 0; ++ uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, ++ TEE_PARAM_TYPE_MEMREF_OUTPUT, ++ TEE_PARAM_TYPE_NONE, ++ TEE_PARAM_TYPE_NONE); ++ ++ res = TEE_OpenTASession(&(const TEE_UUID)PTA_SYSTEM_UUID, ++ TEE_TIMEOUT_INFINITE, 0, NULL, &sess, ++ &ret_orig); ++ if (res) ++ return res; ++ ++ if (extra && extra_size) { ++ params[0].memref.buffer = extra; ++ params[0].memref.size = extra_size; ++ } ++ ++ params[1].memref.buffer = key; ++ params[1].memref.size = key_size; ++ ++ res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE, ++ PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY, ++ param_types, params, &ret_orig); ++ ++ TEE_CloseTASession(sess); ++ ++ return res; ++} ++ ++/* ++ * Process command TA_AES_CMD_SET_KEY. API in aes_ta.h ++ */ ++static TEE_Result set_aes_key(void *session, uint32_t param_types, ++ TEE_Param params[4]) ++{ ++ const uint32_t exp_param_types = ++ TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, ++ TEE_PARAM_TYPE_NONE, ++ TEE_PARAM_TYPE_NONE, ++ TEE_PARAM_TYPE_NONE); ++ struct aes_cipher *sess; ++ TEE_Attribute attr; ++ TEE_Result res; ++ uint32_t key_sz; ++ uint8_t *key; ++ ++ /* Get ciphering context from session ID */ ++ DMSG("Session %p: load key material", session); ++ sess = (struct aes_cipher *)session; ++ ++ /* Safely get the invocation parameters */ ++ if (param_types != exp_param_types) ++ return TEE_ERROR_BAD_PARAMETERS; ++ ++ key_sz = params[0].value.a; ++ if (key_sz != sess->key_size) { ++ EMSG("Wrong key size %" PRIu32 ", expect %" PRIu32 " bytes", ++ key_sz, sess->key_size); ++ return TEE_ERROR_BAD_PARAMETERS; ++ } ++ ++ /* Request a derivate of the HUK */ ++ key = TEE_Malloc(key_sz, 0); ++ if (!key) ++ return TEE_ERROR_OUT_OF_MEMORY; ++ res = derive_unique_key(key, key_sz, NULL, 0); ++ if (res) { ++ EMSG("derive_unique_key failed: returned %#" PRIx32, res); ++ return res; ++ } ++ ++ /* ++ * Load the key material into the configured operation ++ * - create a secret key attribute with the key material ++ * TEE_InitRefAttribute() ++ * - reset transient object and load attribute data ++ * TEE_ResetTransientObject() ++ * TEE_PopulateTransientObject() ++ * - load the key (transient object) into the ciphering operation ++ * TEE_SetOperationKey() ++ * ++ * TEE_SetOperationKey() requires operation to be in "initial state". ++ * We can use TEE_ResetOperation() to reset the operation but this ++ * API cannot be used on operation with key(s) not yet set. Hence, ++ * when allocating the operation handle, we load a dummy key. ++ * Thus, set_key sequence always reset then set key on operation. ++ */ ++ ++ TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, key_sz); ++ ++ TEE_ResetTransientObject(sess->key_handle); ++ res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1); ++ if (res != TEE_SUCCESS) { ++ EMSG("TEE_PopulateTransientObject failed, %x", res); ++ return res; ++ } ++ ++ TEE_ResetOperation(sess->op_handle); ++ res = TEE_SetOperationKey(sess->op_handle, sess->key_handle); ++ if (res != TEE_SUCCESS) { ++ EMSG("TEE_SetOperationKey failed %x", res); ++ return res; ++ } ++ ++ return res; ++} ++ ++/* ++ * Process command TA_AES_CMD_SET_IV. API in aes_ta.h ++ */ ++static TEE_Result reset_aes_iv(void *session, uint32_t param_types, ++ TEE_Param params[4]) ++{ ++ const uint32_t exp_param_types = ++ TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, ++ TEE_PARAM_TYPE_NONE, ++ TEE_PARAM_TYPE_NONE, ++ TEE_PARAM_TYPE_NONE); ++ struct aes_cipher *sess; ++ size_t iv_sz; ++ char *iv; ++ ++ /* Get ciphering context from session ID */ ++ DMSG("Session %p: reset initial vector", session); ++ sess = (struct aes_cipher *)session; ++ ++ /* Safely get the invocation parameters */ ++ if (param_types != exp_param_types) ++ return TEE_ERROR_BAD_PARAMETERS; ++ ++ iv = params[0].memref.buffer; ++ iv_sz = params[0].memref.size; ++ ++ /* ++ * Init cipher operation with the initialization vector. ++ */ ++ TEE_CipherInit(sess->op_handle, iv, iv_sz); ++ ++ return TEE_SUCCESS; ++} ++ ++/* ++ * Process command TA_AES_CMD_CIPHER. API in aes_ta.h ++ */ ++static TEE_Result cipher_buffer(void *session, uint32_t param_types, ++ TEE_Param params[4]) ++{ ++ const uint32_t exp_param_types = ++ TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, ++ TEE_PARAM_TYPE_MEMREF_OUTPUT, ++ TEE_PARAM_TYPE_NONE, ++ TEE_PARAM_TYPE_NONE); ++ struct aes_cipher *sess; ++ ++ /* Get ciphering context from session ID */ ++ DMSG("Session %p: cipher buffer", session); ++ sess = (struct aes_cipher *)session; ++ ++ /* Safely get the invocation parameters */ ++ if (param_types != exp_param_types) ++ return TEE_ERROR_BAD_PARAMETERS; ++ ++ if (params[1].memref.size < params[0].memref.size) { ++ EMSG("Bad sizes: in %zd, out %zd", params[0].memref.size, ++ params[1].memref.size); ++ return TEE_ERROR_BAD_PARAMETERS; ++ } ++ ++ if (sess->op_handle == TEE_HANDLE_NULL) ++ return TEE_ERROR_BAD_STATE; ++ ++ /* ++ * Process ciphering operation on provided buffers ++ */ ++ return TEE_CipherUpdate(sess->op_handle, ++ params[0].memref.buffer, params[0].memref.size, ++ params[1].memref.buffer, ¶ms[1].memref.size); ++} ++ ++TEE_Result TA_CreateEntryPoint(void) ++{ ++ /* Nothing to do */ ++ return TEE_SUCCESS; ++} ++ ++void TA_DestroyEntryPoint(void) ++{ ++ /* Nothing to do */ ++} ++ ++TEE_Result TA_OpenSessionEntryPoint(uint32_t __unused param_types, ++ TEE_Param __unused params[4], ++ void __unused **session) ++{ ++ struct aes_cipher *sess; ++ ++ /* ++ * Allocate and init ciphering materials for the session. ++ * The address of the structure is used as session ID for ++ * the client. ++ */ ++ sess = TEE_Malloc(sizeof(*sess), 0); ++ if (!sess) ++ return TEE_ERROR_OUT_OF_MEMORY; ++ ++ sess->key_handle = TEE_HANDLE_NULL; ++ sess->op_handle = TEE_HANDLE_NULL; ++ ++ *session = (void *)sess; ++ DMSG("Session %p: newly allocated", *session); ++ ++ return TEE_SUCCESS; ++} ++ ++void TA_CloseSessionEntryPoint(void *session) ++{ ++ struct aes_cipher *sess; ++ ++ /* Get ciphering context from session ID */ ++ DMSG("Session %p: release session", session); ++ sess = (struct aes_cipher *)session; ++ ++ /* Release the session resources */ ++ if (sess->key_handle != TEE_HANDLE_NULL) ++ TEE_FreeTransientObject(sess->key_handle); ++ if (sess->op_handle != TEE_HANDLE_NULL) ++ TEE_FreeOperation(sess->op_handle); ++ TEE_Free(sess); ++} ++ ++TEE_Result TA_InvokeCommandEntryPoint(void *session, ++ uint32_t cmd, ++ uint32_t param_types, ++ TEE_Param params[4]) ++{ ++ switch (cmd) { ++ case TA_AES_CMD_PREPARE: ++ return alloc_resources(session, param_types, params); ++ case TA_AES_CMD_SET_KEY: ++ return set_aes_key(session, param_types, params); ++ case TA_AES_CMD_SET_IV: ++ return reset_aes_iv(session, param_types, params); ++ case TA_AES_CMD_CIPHER: ++ return cipher_buffer(session, param_types, params); ++ default: ++ EMSG("Command ID 0x%x is not supported", cmd); ++ return TEE_ERROR_NOT_SUPPORTED; ++ } ++} +diff --git a/ta/aes_huk/include/aes_ta.h b/ta/aes_huk/include/aes_ta.h +new file mode 100644 +index 000000000000..c07b4bc479ee +--- /dev/null ++++ b/ta/aes_huk/include/aes_ta.h +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (c) 2017, Linaro Limited ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __AES_TA_H__ ++#define __AES_TA_H__ ++ ++/* UUID of the AES example trusted application */ ++#define TA_AES_UUID \ ++ { 0xc2fad363, 0x5d9f, 0x4fc4, \ ++ { 0xa4, 0x17, 0x55, 0x58, 0x41, 0xe0, 0x57, 0x45 } } ++ ++/* ++ * TA_AES_CMD_PREPARE - Allocate resources for the AES ciphering ++ * param[0] (value) a: TA_AES_ALGO_xxx, b: unused ++ * param[1] (value) a: key size in bytes, b: unused ++ * param[2] (value) a: TA_AES_MODE_ENCODE/_DECODE, b: unused ++ * param[3] unused ++ */ ++#define TA_AES_CMD_PREPARE 0 ++ ++#define TA_AES_ALGO_ECB 0 ++#define TA_AES_ALGO_CBC 1 ++#define TA_AES_ALGO_CTR 2 ++ ++#define TA_AES_SIZE_128BIT (128 / 8) ++#define TA_AES_SIZE_256BIT (256 / 8) ++ ++#define TA_AES_MODE_ENCODE 1 ++#define TA_AES_MODE_DECODE 0 ++ ++/* ++ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering ++ * param[0] (memref) key data, size shall equal key length ++ * param[1] unused ++ * param[2] unused ++ * param[3] unused ++ */ ++#define TA_AES_CMD_SET_KEY 1 ++ ++/* ++ * TA_AES_CMD_SET_IV - reset IV ++ * param[0] (memref) initial vector, size shall equal block length ++ * param[1] unused ++ * param[2] unused ++ * param[3] unused ++ */ ++#define TA_AES_CMD_SET_IV 2 ++ ++/* ++ * TA_AES_CMD_CIPHER - Cipher input buffer into output buffer ++ * param[0] (memref) input buffer ++ * param[1] (memref) output buffer (shall be bigger than input buffer) ++ * param[2] unused ++ * param[3] unused ++ */ ++#define TA_AES_CMD_CIPHER 3 ++ ++#endif /* __AES_TA_H */ +diff --git a/ta/aes_huk/sub.mk b/ta/aes_huk/sub.mk +new file mode 100644 +index 000000000000..cfce14e6c119 +--- /dev/null ++++ b/ta/aes_huk/sub.mk +@@ -0,0 +1,3 @@ ++global-incdirs-y += include ++global-incdirs-y += . ++srcs-y += aes_ta.c +diff --git a/ta/aes_huk/user_ta.mk b/ta/aes_huk/user_ta.mk +new file mode 100644 +index 000000000000..d49d309558ba +--- /dev/null ++++ b/ta/aes_huk/user_ta.mk +@@ -0,0 +1 @@ ++user-ta-uuid := c2fad363-5d9f-4fc4-a417-555841e05745 +diff --git a/ta/aes_huk/user_ta_header_defines.h b/ta/aes_huk/user_ta_header_defines.h +new file mode 100644 +index 000000000000..9f944b8b9ab3 +--- /dev/null ++++ b/ta/aes_huk/user_ta_header_defines.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (c) 2017, Linaro Limited ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * The name of this file must not be modified ++ */ ++ ++#ifndef USER_TA_HEADER_DEFINES_H ++#define USER_TA_HEADER_DEFINES_H ++ ++#include ++ ++#define TA_UUID TA_AES_UUID ++ ++#define TA_FLAGS TA_FLAG_EXEC_DDR ++#define TA_STACK_SIZE (2 * 1024) ++#define TA_DATA_SIZE (32 * 1024) ++ ++#define TA_CURRENT_TA_EXT_PROPERTIES \ ++ { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \ ++ "Example of TA using an AES sequence" }, \ ++ { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } } ++ ++#endif /*USER_TA_HEADER_DEFINES_H*/ diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os_4.0.0.imx.bb b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os_4.0.0.imx.bb index c4f613481..67d5a5ccf 100644 --- a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os_4.0.0.imx.bb +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-security/optee-imx/optee-os_4.0.0.imx.bb @@ -9,6 +9,7 @@ SRC_URI = " \ git://github.com/nxp-imx/imx-optee-os.git;protocol=https;branch=${SRCBRANCH} \ file://0007-allow-setting-sysroot-for-clang.patch \ file://0001-core-imx-support-ccimx93-dvk.patch \ + file://0002-core-ccimx93-enable-AES_HUK-trusted-application.patch \ " SRCBRANCH = "lf-6.1.55_2.2.0" # Tag: lf-6.1.55-2.2.0 From 584b263614c2292384b99c9d6be1c501e6902616 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Tue, 28 May 2024 17:58:01 +0200 Subject: [PATCH 76/91] meta-digi: enable u-boot env encryption support on ccimx93 https://onedigi.atlassian.net/browse/DUB-1079 Signed-off-by: Javier Viguera --- meta-digi-dey/classes/trustfence.bbclass | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index d8db03b7d..bed0364cd 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -26,7 +26,6 @@ TRUSTFENCE_SIGN_KEYS_PATH ?= "default" TRUSTFENCE_DEK_PATH ?= "default" TRUSTFENCE_DEK_PATH:ccmp1 ?= "0" TRUSTFENCE_ENCRYPT_ENVIRONMENT ?= "1" -TRUSTFENCE_ENCRYPT_ENVIRONMENT:ccimx93 ?= "0" TRUSTFENCE_SRK_REVOKE_MASK ?= "0x0" TRUSTFENCE_KEY_INDEX ?= "0" TRUSTFENCE_SIGN_ARTIFACTS = "1" @@ -222,7 +221,7 @@ python () { if (d.getVar("TRUSTFENCE_ENCRYPT_ENVIRONMENT") == "1"): if (d.getVar("DEY_SOC_VENDOR") == "NXP"): - d.appendVar("UBOOT_TF_CONF", "CONFIG_ENV_AES=y CONFIG_ENV_AES_CAAM_KEY=y ") + d.appendVar("UBOOT_TF_CONF", "CONFIG_ENV_AES=y CONFIG_ENV_AES_CAAM_KEY=y CONFIG_ENV_ENCRYPT=y ") elif (d.getVar("DEY_SOC_VENDOR") == "STM"): d.appendVar("UBOOT_TF_CONF", "CONFIG_ENV_AES_CCMP1=y ") From ecad5dba32c5cf958cc79c788b90d8302a4e9ea0 Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Mon, 3 Jun 2024 09:06:07 +0200 Subject: [PATCH 77/91] uuu: fix incorrect command for trustfence update from uuu The command trustfence update doesn't require the partition argument. Besides of that, remove extra fi on the cc8m platforms. Signed-off-by: Francisco Gil --- .../ccimx6qpsbc/install_linux_fw_uuu.sh | 4 ++-- .../u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 4 ++-- .../u-boot-dey/ccimx8m/install_linux_fw_uuu.sh | 15 +++++++-------- .../u-boot-dey/ccimx8x/install_linux_fw_uuu.sh | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index db5f31316..ff7a40188 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -68,9 +68,9 @@ part_update() uuu fb: ucmd setenv fastboot_buffer $initrd_addr uuu fb: download -f "${3}" uuu fb: ucmd setenv dek_size $filesize - uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else - uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} + uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} fi else if [ "${1}" = "bootloader" ]; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index ccd0b05c6..113dbc4c5 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -68,9 +68,9 @@ part_update() uuu fb: ucmd setenv fastboot_buffer $initrd_addr uuu fb: download -f "${3}" uuu fb: ucmd setenv dek_size $filesize - uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else - uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} + uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} fi else if [ "${1}" = "bootloader" ]; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index 6e93187c6..a6151082b 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -64,14 +64,13 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" if [ -n "${DEK_BLOB_KEY}" ]; then - uuu fb: ucmd setenv uboot_size $filesize - uuu fb: ucmd setenv fastboot_buffer $initrd_addr - uuu fb: download -f "${3}" - uuu fb: ucmd setenv dek_size $filesize - uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} - else - uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} - fi + uuu fb: ucmd setenv uboot_size $filesize + uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: download -f "${3}" + uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + else + uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} fi else if [ "${1}" = "bootloader" ]; then diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index 760cfd8e4..9fb6fb0f5 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -68,9 +68,9 @@ part_update() uuu fb: ucmd setenv fastboot_buffer $initrd_addr uuu fb: download -f "${3}" uuu fb: ucmd setenv dek_size $filesize - uuu fb: ucmd trustfence update "${1}" ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else - uuu fb: ucmd trustfence update "${1}" ram \${fastboot_buffer} \${fastboot_bytes} + uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} fi else if [ "${1}" = "bootloader" ]; then From 37f5db42ac6d2a6d7e5fd886b6a9d79eb3583d5c Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Tue, 21 May 2024 16:06:36 +0200 Subject: [PATCH 78/91] tsn: add basic Time sensitive networking (TSN) This commit adds some basic TSN support to DEY. It includes the kernel configuration fragment with the IEEE 802.1 support and the some user space tools necessary to configure the network. https://onedigi.atlassian.net/browse/DEL-9026 Signed-off-by: Mike Engel --- meta-digi-arm/conf/machine/ccimx93-dvk.conf | 1 + .../linux/linux-dey/tsn_conf.cfg | 27 +++++++++++++++++++ .../recipes-kernel/linux/linux-dey_6.1.bb | 1 + .../packagegroups/packagegroup-dey-network.bb | 2 ++ 4 files changed, 31 insertions(+) create mode 100644 meta-digi-arm/recipes-kernel/linux/linux-dey/tsn_conf.cfg diff --git a/meta-digi-arm/conf/machine/ccimx93-dvk.conf b/meta-digi-arm/conf/machine/ccimx93-dvk.conf index 8dea1961a..1c125a626 100644 --- a/meta-digi-arm/conf/machine/ccimx93-dvk.conf +++ b/meta-digi-arm/conf/machine/ccimx93-dvk.conf @@ -25,6 +25,7 @@ KERNEL_DEVICETREE ?= " \ digi/_ov_som_bt-dtm_ccimx93.dtbo \ digi/_ov_som_npu_ccimx93.dtbo \ digi/_ov_som_wifi_ccimx93.dtbo \ + ${@bb.utils.contains('DISTRO_FEATURES', 'tsn', 'digi/_ov_board_eqos-tsn_ccimx93-dvk.dtbo', '', d)} \ " # Wireless external module diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey/tsn_conf.cfg b/meta-digi-arm/recipes-kernel/linux/linux-dey/tsn_conf.cfg new file mode 100644 index 000000000..cdc21fd88 --- /dev/null +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey/tsn_conf.cfg @@ -0,0 +1,27 @@ +.......................................................................... +. WARNING +. +. This file is a kernel configuration fragment, and not a full kernel +. configuration file. The final kernel configuration is made up of +. an assembly of processed fragments, each of which is designed to +. capture a specific part of the final configuration (e.g. platform +. configuration, feature configuration, and board specific hardware +. configuration). For more information on kernel configuration, please +. consult the product documentation. +. +.......................................................................... +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_CBS=m +CONFIG_NET_SCH_ETF=m +CONFIG_NET_SCH_TAPRIO=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_GATE=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_FSL_ENETC_QOS=y diff --git a/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb b/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb index cba404b1f..44bc97220 100644 --- a/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb +++ b/meta-digi-arm/recipes-kernel/linux/linux-dey_6.1.bb @@ -20,6 +20,7 @@ NXP_RT_PATCHES = " \ SRC_URI:append = " \ ${@bb.utils.contains('DISTRO_FEATURES', 'rt', '${NXP_RT_PATCHES}', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'tsn', 'file://tsn_conf.cfg', '', d)} \ " SRCREV = "${AUTOREV}" diff --git a/meta-digi-dey/recipes-connectivity/packagegroups/packagegroup-dey-network.bb b/meta-digi-dey/recipes-connectivity/packagegroups/packagegroup-dey-network.bb index 2936d8aa1..1b6112ce2 100644 --- a/meta-digi-dey/recipes-connectivity/packagegroups/packagegroup-dey-network.bb +++ b/meta-digi-dey/recipes-connectivity/packagegroups/packagegroup-dey-network.bb @@ -35,4 +35,6 @@ RDEPENDS:${PN} = "\ ${VIRTUAL-RUNTIME_network-utils} \ ${VIRTUAL-RUNTIME_snmp-manager} \ ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '', '${VIRTUAL-RUNTIME_ntp-client}', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'tsn', 'iproute2-tc', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'tsn', 'linuxptp', '', d)} \ " From d07e68b5a274b24e52083c8995bc7877ce8d7812 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Mon, 3 Jun 2024 17:00:58 +0200 Subject: [PATCH 79/91] imx-boot: apply patches to fix CVE-2023-39902 on i.MX8M platforms The patches have been backported from the lf-6.1.36-2.1.0 release of imx-mkimage. https://onedigi.atlassian.net/browse/DUB-1081 Signed-off-by: Gabriel Valcazar --- ...Generate-hash-of-FIT-FDT-structure-t.patch | 207 ++++++++++++++++++ ...Reserve-new-IVT-CSF-for-FIT-FDT-sign.patch | 179 +++++++++++++++ .../imx-mkimage/imx-boot_1.0.bbappend | 2 + 3 files changed, 388 insertions(+) create mode 100644 meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0003-LFU-573-1-imx8m-Generate-hash-of-FIT-FDT-structure-t.patch create mode 100644 meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0004-LFU-573-2-imx8m-Reserve-new-IVT-CSF-for-FIT-FDT-sign.patch diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0003-LFU-573-1-imx8m-Generate-hash-of-FIT-FDT-structure-t.patch b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0003-LFU-573-1-imx8m-Generate-hash-of-FIT-FDT-structure-t.patch new file mode 100644 index 000000000..685c7e140 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0003-LFU-573-1-imx8m-Generate-hash-of-FIT-FDT-structure-t.patch @@ -0,0 +1,207 @@ +From: Ye Li +Date: Mon, 3 Jul 2023 17:31:32 +0800 +Subject: [PATCH] LFU-573-1 imx8m: Generate hash of FIT FDT structure to SPL + image + +Generate the hash of FIT FDT structure by SHA256 and append it +to end of SPL image (after DDR FW). +SPL will get the hash from the position to verify the FIT FDT +structure in loaded FIT image. + +Signed-off-by: Ye Li +(cherry picked from commit 2f2d426f03ebbcf7a9c28cf53680cd5777e70ea1) +--- + iMX8M/mkimage_imx8.c | 109 ++++++++++++++++++++++++++++++++++++++++++- + iMX8M/soc.mak | 14 ++++-- + 2 files changed, 117 insertions(+), 6 deletions(-) + +diff --git a/iMX8M/mkimage_imx8.c b/iMX8M/mkimage_imx8.c +index 54828d1..f8484d0 100644 +--- a/iMX8M/mkimage_imx8.c ++++ b/iMX8M/mkimage_imx8.c +@@ -366,6 +366,31 @@ copy_file (int ifd, const char *datafile, int pad, int offset, int datafile_offs + (void) close (dfd); + } + ++static void append_data(char *filename, uint8_t *data, int size) ++{ ++ int dfd, ret; ++ ++ if ((dfd = open(filename, O_RDWR|O_BINARY)) < 0) { ++ fprintf (stderr, "Can't open %s: %s\n", ++ filename, strerror(errno)); ++ exit (EXIT_FAILURE); ++ } ++ ++ ret = lseek(dfd, 0, SEEK_END); ++ if (ret < 0) { ++ fprintf(stderr, "%s: lseek error %s\n", ++ __func__, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ if (write(dfd, data, size) != size) { ++ fprintf (stderr, "Write error %s\n", ++ strerror(errno)); ++ exit (EXIT_FAILURE); ++ } ++ (void) close (dfd); ++} ++ ++ + enum imximage_fld_types { + CFG_INVALID = -1, + CFG_COMMAND, +@@ -861,6 +886,77 @@ void generate_sld_with_ivt(char * input_file, uint32_t ep, char *out_file) + close(input_fd); + } + ++#define HASH_MAX_LEN 32 ++static void calc_fitimage_hash(char* filename, uint8_t *hash) ++{ ++ int sld_fd; ++ FILE *fp = NULL; ++ char sha_command[512]; ++ char *digest_type = "sha256sum"; ++ char hash_char[2 * HASH_MAX_LEN + 1]; ++ int digest_length = 64; ++ ++ uimage_header_t image_header; ++ uint32_t fit_size; ++ ++ sld_fd = open(filename, O_RDONLY | O_BINARY); ++ if (sld_fd < 0) { ++ fprintf(stderr, "%s: Can't open: %s\n", ++ filename, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (read(sld_fd, (char *)&image_header, sizeof(uimage_header_t)) != sizeof(uimage_header_t)) { ++ fprintf (stderr, "generate_ivt_for_fit read failed: %s\n", ++ strerror(errno)); ++ exit (EXIT_FAILURE); ++ } ++ ++ if (be32_to_cpu(image_header.ih_magic) != FDT_MAGIC){ ++ fprintf (stderr, "generate_ivt_for_fit error: not a FIT file\n"); ++ exit (EXIT_FAILURE); ++ } ++ ++ fit_size = fdt_totalsize(&image_header); ++ ++ fprintf(stderr, "fit_size: %u\n", fit_size); ++ ++ sprintf(sha_command, "dd if=\'%s\' of=tmp_pad bs=%d count=1;\ ++ %s tmp_pad; rm -f tmp_pad;", ++ filename, fit_size, digest_type); ++ ++ memset(hash, 0, HASH_MAX_LEN); ++ ++ fp = popen(sha_command, "r"); ++ if (fp == NULL) { ++ fprintf(stderr, "Failed to run command hash\n" ); ++ exit(EXIT_FAILURE); ++ } ++ ++ if(fgets(hash_char, digest_length + 1, fp) == NULL) { ++ fprintf(stderr, "Failed to hash file: %s\n", filename); ++ exit(EXIT_FAILURE); ++ } ++ ++ for(int i = 0; i < strlen(hash_char)/2; i++){ ++ sscanf(hash_char + 2*i, "%02hhx", &hash[i]); ++ } ++ ++ pclose(fp); ++ (void) close (sld_fd); ++} ++ ++void dump_fit_hash(uint8_t *hash, int size) ++{ ++ int i; ++ ++ fprintf(stderr, "FIT hash: "); ++ for (i = 0; i < size; i++) { ++ fprintf(stderr, "%x", hash[i]); ++ } ++ fprintf(stderr, "\n"); ++} ++ + /* Return this IVT offset in the final output file */ + int generate_ivt_for_fit(int fd, int fit_offset, uint32_t ep, uint32_t *fit_load_addr) + { +@@ -943,6 +1039,8 @@ int main(int argc, char **argv) + uimage_header_t uimage_hdr; + uint32_t version = ROM_V1; + ++ uint8_t fit_hash[HASH_MAX_LEN]; ++ + static struct option long_options[] = + { + {"loader", required_argument, NULL, 'i'}, +@@ -1146,6 +1244,15 @@ int main(int argc, char **argv) + exit(1); + } + ++ if (sld_img && using_fit) { ++ calc_fitimage_hash(sld_img, fit_hash); ++ ++ /* Append hash to ap_img */ ++ append_data(ap_img, fit_hash, HASH_MAX_LEN); ++ ++ dump_fit_hash(fit_hash, HASH_MAX_LEN); ++ } ++ + if (version == ROM_V2) { + + /* On V2, flexspi IVT offset is 0, image offset is 0x1000 */ +@@ -1638,7 +1745,7 @@ int main(int argc, char **argv) + } + + /* The FLEXSPI configuration parameters will add to flash.bin by script, so need add 0x1000 offset to every offset prints */ +- if ((version == ROM_V2 && rom_image_offset == IVT_OFFSET_FLEXSPI) || ++ if ((version == ROM_V2 && rom_image_offset == IVT_OFFSET_FLEXSPI) || + (version == ROM_V1 && ivt_offset == IVT_OFFSET_FLEXSPI)) { + header_image_off += IVT_OFFSET_FLEXSPI; + dcd_off += IVT_OFFSET_FLEXSPI; +diff --git a/iMX8M/soc.mak b/iMX8M/soc.mak +index 6b3a01f..a30523b 100644 +--- a/iMX8M/soc.mak ++++ b/iMX8M/soc.mak +@@ -101,8 +101,9 @@ u-boot-spl-ddr.bin: u-boot-spl.bin $(lpddr4_imem_1d) $(lpddr4_dmem_1d) $(lpddr4_ + @objcopy -I binary -O binary --pad-to 0x8000 --gap-fill=0x0 $(lpddr4_imem_1d) lpddr4_pmu_train_1d_imem_pad.bin + @objcopy -I binary -O binary --pad-to 0x4000 --gap-fill=0x0 $(lpddr4_dmem_1d) lpddr4_pmu_train_1d_dmem_pad.bin + @objcopy -I binary -O binary --pad-to 0x8000 --gap-fill=0x0 $(lpddr4_imem_2d) lpddr4_pmu_train_2d_imem_pad.bin ++ @objcopy -I binary -O binary --pad-to 0x4000 --gap-fill=0x0 $(lpddr4_dmem_2d) lpddr4_pmu_train_2d_dmem_pad.bin + @cat lpddr4_pmu_train_1d_imem_pad.bin lpddr4_pmu_train_1d_dmem_pad.bin > lpddr4_pmu_train_1d_fw.bin +- @cat lpddr4_pmu_train_2d_imem_pad.bin $(lpddr4_dmem_2d) > lpddr4_pmu_train_2d_fw.bin ++ @cat lpddr4_pmu_train_2d_imem_pad.bin lpddr4_pmu_train_2d_dmem_pad.bin > lpddr4_pmu_train_2d_fw.bin + @dd if=u-boot-spl.bin of=u-boot-spl-pad.bin bs=4 conv=sync + @cat u-boot-spl-pad.bin lpddr4_pmu_train_1d_fw.bin lpddr4_pmu_train_2d_fw.bin > u-boot-spl-ddr.bin + @rm -f u-boot-spl-pad.bin lpddr4_pmu_train_1d_fw.bin lpddr4_pmu_train_2d_fw.bin lpddr4_pmu_train_1d_imem_pad.bin lpddr4_pmu_train_1d_dmem_pad.bin lpddr4_pmu_train_2d_imem_pad.bin +@@ -116,8 +117,9 @@ u-boot-spl-ddr4.bin: u-boot-spl.bin $(ddr4_imem_1d) $(ddr4_dmem_1d) $(ddr4_imem_ + @objcopy -I binary -O binary --pad-to 0x8000 --gap-fill=0x0 $(ddr4_imem_1d) ddr4_imem_1d_pad.bin + @objcopy -I binary -O binary --pad-to 0x4000 --gap-fill=0x0 $(ddr4_dmem_1d) ddr4_dmem_1d_pad.bin + @objcopy -I binary -O binary --pad-to 0x8000 --gap-fill=0x0 $(ddr4_imem_2d) ddr4_imem_2d_pad.bin ++ @objcopy -I binary -O binary --pad-to 0x4000 --gap-fill=0x0 $(ddr4_dmem_2d) ddr4_dmem_2d_pad.bin + @cat ddr4_imem_1d_pad.bin ddr4_dmem_1d_pad.bin > ddr4_1d_fw.bin +- @cat ddr4_imem_2d_pad.bin $(ddr4_dmem_2d) > ddr4_2d_fw.bin ++ @cat ddr4_imem_2d_pad.bin ddr4_dmem_2d_pad.bin > ddr4_2d_fw.bin + @dd if=u-boot-spl.bin of=u-boot-spl-pad.bin bs=4 conv=sync + @cat u-boot-spl-pad.bin ddr4_1d_fw.bin ddr4_2d_fw.bin > u-boot-spl-ddr4.bin + @rm -f u-boot-spl-pad.bin ddr4_1d_fw.bin ddr4_2d_fw.bin ddr4_imem_1d_pad.bin ddr4_dmem_1d_pad.bin ddr4_imem_2d_pad.bin +@@ -127,10 +129,12 @@ ddr3_dmem_1d = ddr3_dmem_1d$(DDR_FW_VERSION).bin + + u-boot-spl-ddr3l.bin: u-boot-spl.bin $(ddr3_imem_1d) $(ddr3_dmem_1d) + @objcopy -I binary -O binary --pad-to 0x8000 --gap-fill=0x0 $(ddr3_imem_1d) ddr3_imem_1d.bin_pad.bin +- @cat ddr3_imem_1d.bin_pad.bin $(ddr3_dmem_1d) > ddr3_pmu_train_fw.bin ++ @objcopy -I binary -O binary --pad-to 0x4000 --gap-fill=0x0 $(ddr3_dmem_1d) ddr3_dmem_1d.bin_pad.bin ++ @cat ddr3_imem_1d.bin_pad.bin ddr3_dmem_1d.bin_pad.bin > ddr3_pmu_train_fw.bin ++ @dd if=/dev/zero of=ddr3_fw_zero_pad.bin bs=1 count=49152 conv=sync + @dd if=u-boot-spl.bin of=u-boot-spl-pad.bin bs=4 conv=sync +- @cat u-boot-spl-pad.bin ddr3_pmu_train_fw.bin > u-boot-spl-ddr3l.bin +- @rm -f u-boot-spl-pad.bin ddr3_pmu_train_fw.bin ddr3_imem_1d.bin_pad.bin ++ @cat u-boot-spl-pad.bin ddr3_pmu_train_fw.bin ddr3_fw_zero_pad.bin > u-boot-spl-ddr3l.bin ++ @rm -f u-boot-spl-pad.bin ddr3_pmu_train_fw.bin ddr3_imem_1d.bin_pad.bin ddr3_fw_zero_pad.bin + + u-boot-atf.bin: u-boot.bin bl31.bin + @cp bl31.bin u-boot-atf.bin diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0004-LFU-573-2-imx8m-Reserve-new-IVT-CSF-for-FIT-FDT-sign.patch b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0004-LFU-573-2-imx8m-Reserve-new-IVT-CSF-for-FIT-FDT-sign.patch new file mode 100644 index 000000000..54a2d385e --- /dev/null +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/files/0004-LFU-573-2-imx8m-Reserve-new-IVT-CSF-for-FIT-FDT-sign.patch @@ -0,0 +1,179 @@ +From: Ye Li +Date: Thu, 27 Jul 2023 09:52:33 +0800 +Subject: [PATCH] LFU-573-2 imx8m: Reserve new IVT+CSF for FIT FDT signature + +Without using FIT FDT hash, we also allow user to sign FIT FDT structure, +so that FIT image can upgrade individually. The option needs +CONFIG_IMX_SPL_FIT_FDT_SIGNATURE enabled in SPL. + +imx-mkimage will insert the new IVT for FIT FDT signature by default +and reserve the CSF (0x2000) for the FIT FDT signature. + +Signed-off-by: Ye Li +(cherry picked from commit 5a0faefc223e51e088433663b6e7d6fbce89bf59) +--- + iMX8M/mkimage_imx8.c | 30 +++++++++++++++++++++++++++++- + iMX8M/print_fit_hab.sh | 4 ++-- + iMX8M/soc.mak | 17 +++++++++-------- + 3 files changed, 40 insertions(+), 11 deletions(-) + +diff --git a/iMX8M/mkimage_imx8.c b/iMX8M/mkimage_imx8.c +index f8484d0..c2a6c29 100644 +--- a/iMX8M/mkimage_imx8.c ++++ b/iMX8M/mkimage_imx8.c +@@ -999,7 +999,7 @@ int generate_ivt_for_fit(int fd, int fit_offset, uint32_t ep, uint32_t *fit_load + } + + /* ep is the u-boot entry. SPL loads the FIT before the u-boot address. 0x2000 is for CSF_SIZE */ +- load_addr = (ep - (fit_size + CSF_SIZE) - 512 - ++ load_addr = (ep - (fit_size + 2 * CSF_SIZE) - 512 - + align_len) & ~align_len; + + flash_header_v2_t ivt_header = { { 0xd1, 0x2000, 0x40 }, +@@ -1013,6 +1013,24 @@ int generate_ivt_for_fit(int fd, int fit_offset, uint32_t ep, uint32_t *fit_load + exit(EXIT_FAILURE); + } + ++ ret = lseek(fd, fit_offset + fit_size + CSF_SIZE, SEEK_SET); ++ if (ret < 0) { ++ fprintf(stderr, "%s: lseek error %s\n", ++ __func__, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ flash_header_v2_t fdt_ivt_header = { { 0xd1, 0x2000, 0x40 }, ++ load_addr, 0, 0, 0, ++ (load_addr + fit_size + CSF_SIZE ), ++ (load_addr + fit_size + CSF_SIZE + 0x20), ++ 0 }; ++ ++ if (write(fd, &fdt_ivt_header, sizeof(flash_header_v2_t)) != sizeof(flash_header_v2_t)) { ++ fprintf(stderr, "FIT FDT IVT writing error on fit image\n"); ++ exit(EXIT_FAILURE); ++ } ++ + *fit_load_addr = load_addr; + + return fit_offset + fit_size; +@@ -1229,6 +1247,11 @@ int main(int argc, char **argv) + fprintf(stderr, " fit hab block: \t0x%x 0x%x 0x%x\n", + sld_load_addr, sld_src_off, sld_csf_off - sld_src_off); + ++ fprintf(stderr, " fit-fdt_csf_off \t0x%x\n", ++ sld_csf_off + CSF_SIZE); ++ fprintf(stderr, " fit-fdt hab block: \t0x%x 0x%x 0x%x\n", ++ sld_load_addr, sld_src_off, sld_csf_off + CSF_SIZE - sld_src_off); ++ + exit(0); + } + +@@ -1769,6 +1792,11 @@ int main(int argc, char **argv) + fprintf(stderr, " sld hab block: \t0x%x 0x%x 0x%x\n", + sld_load_addr, sld_header_off, sld_csf_off - sld_header_off); + ++ fprintf(stderr, " fit-fdt csf_off \t0x%x\n", ++ sld_csf_off + CSF_SIZE); ++ fprintf(stderr, " fit-fdt hab block: \t0x%x 0x%x 0x%x\n", ++ sld_load_addr, sld_header_off, sld_csf_off + CSF_SIZE - sld_header_off); ++ + return 0; + } + +diff --git a/iMX8M/print_fit_hab.sh b/iMX8M/print_fit_hab.sh +index 6f1a22d..d1e344a 100755 +--- a/iMX8M/print_fit_hab.sh ++++ b/iMX8M/print_fit_hab.sh +@@ -24,10 +24,10 @@ fi + + if [ "$BOOT_DEV" = "flexspi" ] || [ ${fit_off} == 0 ]; then + # We dd flash.bin to 0 offset for flexspi +- let uboot_sign_off=$((fit_off + 0x3000)) ++ let uboot_sign_off=$((fit_off + $FIT_DATA_POS)) + else + # We dd flash.bin to 33KB "0x8400" offset, so need minus 0x8400 +- let uboot_sign_off=$((fit_off - 0x8000 - ivt_off + 0x3000)) ++ let uboot_sign_off=$((fit_off - 0x8000 - ivt_off + $FIT_DATA_POS)) + fi + + let uboot_size=$(stat --printf="%s" $BL33) +diff --git a/iMX8M/soc.mak b/iMX8M/soc.mak +index a30523b..d4946dc 100644 +--- a/iMX8M/soc.mak ++++ b/iMX8M/soc.mak +@@ -84,6 +84,7 @@ VERSION = v1 + CAPSULE_GUID = 296119cf-dd70-43de-8ac8-a7051f312577 + endif + ++FIT_EXTERNAL_POSITION = 0x5000 + + FW_DIR = imx-boot/imx-boot-tools/$(PLAT) + +@@ -158,7 +159,7 @@ u-boot.itb: $(dtb) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb) + BL32=$(TEE) DEK_BLOB_LOAD_ADDR=$(DEK_BLOB_LOAD_ADDR) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) ../$(SOC_DIR)/mkimage_fit_atf.sh $(dtb) > u-boot.its +- mkimage -E -p 0x3000 -f u-boot.its u-boot.itb ++ mkimage -E -p $(FIT_EXTERNAL_POSITION) -f u-boot.its u-boot.itb + @rm -f u-boot.its + + dtb_ddr3l = valddr3l.dtb +@@ -170,7 +171,7 @@ u-boot-ddr3l.itb: $(dtb_ddr3l) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb_ddr3l) + DEK_BLOB_LOAD_ADDR=$(DEK_BLOB_LOAD_ADDR) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) ../$(SOC_DIR)/mkimage_fit_atf.sh $(dtb_ddr3l) > u-boot-ddr3l.its +- mkimage -E -p 0x3000 -f u-boot-ddr3l.its u-boot-ddr3l.itb ++ mkimage -E -p $(FIT_EXTERNAL_POSITION) -f u-boot-ddr3l.its u-boot-ddr3l.itb + @rm -f u-boot.its $(dtb_ddr3l) + + dtb_ddr3l_evk = evkddr3l.dtb +@@ -182,7 +183,7 @@ u-boot-ddr3l-evk.itb: $(dtb_ddr3l_evk) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb_ddr3l_evk) + DEK_BLOB_LOAD_ADDR=$(DEK_BLOB_LOAD_ADDR) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) ../$(SOC_DIR)/mkimage_fit_atf.sh $(dtb_ddr3l_evk) > u-boot-ddr3l-evk.its +- mkimage -E -p 0x3000 -f u-boot-ddr3l-evk.its u-boot-ddr3l-evk.itb ++ mkimage -E -p $(FIT_EXTERNAL_POSITION) -f u-boot-ddr3l-evk.its u-boot-ddr3l-evk.itb + @rm -f u-boot.its $(dtb_ddr3l_evk) + + dtb_ddr4 = valddr4.dtb +@@ -194,7 +195,7 @@ u-boot-ddr4.itb: $(dtb_ddr4) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb_ddr4) + DEK_BLOB_LOAD_ADDR=$(DEK_BLOB_LOAD_ADDR) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) ../$(SOC_DIR)/mkimage_fit_atf.sh $(dtb_ddr4) > u-boot-ddr4.its +- mkimage -E -p 0x3000 -f u-boot-ddr4.its u-boot-ddr4.itb ++ mkimage -E -p $(FIT_EXTERNAL_POSITION) -f u-boot-ddr4.its u-boot-ddr4.itb + @rm -f u-boot.its $(dtb_ddr4) + + dtb_ddr4_evk = evkddr4.dtb +@@ -206,7 +207,7 @@ u-boot-ddr4-evk.itb: $(dtb_ddr4_evk) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb_ddr4_evk) + DEK_BLOB_LOAD_ADDR=$(DEK_BLOB_LOAD_ADDR) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) ../$(SOC_DIR)/mkimage_fit_atf.sh $(dtb_ddr4_evk) > u-boot-ddr4-evk.its +- mkimage -E -p 0x3000 -f u-boot-ddr4-evk.its u-boot-ddr4-evk.itb ++ mkimage -E -p $(FIT_EXTERNAL_POSITION) -f u-boot-ddr4-evk.its u-boot-ddr4-evk.itb + @rm -f u-boot.its $(dtb_ddr4_evk) + + ifeq ($(HDMI),yes) +@@ -326,20 +327,20 @@ print_fit_hab: u-boot-nodtb.bin bl31.bin $(dtb) + ./$(PAD_IMAGE) $(TEE) 2>&1 | tee $(MKIMAGE_LOG) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb) +- { echo $@; TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) VERSION=$(VERSION) ../$(SOC_DIR)/print_fit_hab.sh $(PRINT_FIT_HAB_OFFSET) $(dtb) 2>&1; } | tee -a $(MKIMAGE_LOG) ++ { echo $@; FIT_DATA_POS=$(FIT_EXTERNAL_POSITION) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) VERSION=$(VERSION) ../$(SOC_DIR)/print_fit_hab.sh $(PRINT_FIT_HAB_OFFSET) $(dtb) 2>&1; } | tee -a $(MKIMAGE_LOG) + + print_fit_hab_ddr4: u-boot-nodtb.bin bl31.bin $(dtb_ddr4_evk) + ./$(PAD_IMAGE) $(TEE) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb_ddr4_evk) +- TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) VERSION=$(VERSION) ../$(SOC_DIR)/print_fit_hab.sh $(PRINT_FIT_HAB_OFFSET) $(dtb_ddr4_evk) ++ FIT_DATA_POS=$(FIT_EXTERNAL_POSITION) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) VERSION=$(VERSION) ../$(SOC_DIR)/print_fit_hab.sh $(PRINT_FIT_HAB_OFFSET) $(dtb_ddr4_evk) + @rm -f $(dtb_ddr4_evk) + + print_fit_hab_flexspi: u-boot-nodtb.bin bl31.bin $(dtb) + ./$(PAD_IMAGE) $(TEE) + ./$(PAD_IMAGE) bl31.bin + ./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb) +- TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) VERSION=$(VERSION) BOOT_DEV="flexspi" ../$(SOC_DIR)/print_fit_hab.sh $(PRINT_FIT_HAB_OFFSET) $(dtb) ++ FIT_DATA_POS=$(FIT_EXTERNAL_POSITION) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) VERSION=$(VERSION) BOOT_DEV="flexspi" ../$(SOC_DIR)/print_fit_hab.sh $(PRINT_FIT_HAB_OFFSET) $(dtb) + @rm -f $(dtb) + + nightly : diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend index c83f09161..fad1a49d0 100644 --- a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-mkimage/imx-boot_1.0.bbappend @@ -5,6 +5,8 @@ FILESEXTRAPATHS:prepend := "${THISDIR}/files:" SRC_URI:append:ccimx8m = " \ file://0001-imx8m-soc.mak-preserve-dtbs-after-build.patch \ file://0002-imx8m-soc.mak-capture-commands-output-into-a-log-fil.patch \ + file://0003-LFU-573-1-imx8m-Generate-hash-of-FIT-FDT-structure-t.patch \ + file://0004-LFU-573-2-imx8m-Reserve-new-IVT-CSF-for-FIT-FDT-sign.patch \ " SRC_URI:append:ccimx93 = " \ From c157313de1d1d61cf771000a5952bcf602e0f8cc Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Wed, 5 Jun 2024 12:11:28 +0200 Subject: [PATCH 80/91] ccmp15: remove Cortex-M4 overlay from DEVICETREE list This commit removes the Cortex-M4 overlay because the M4 has been enabled now in the DTSI file. https://onedigi.atlassian.net/browse/DEL-9056 Signed-off-by: Mike Engel --- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index ebeb091e9..704edbe68 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -51,7 +51,6 @@ STM32MP_KERNEL_DEVICETREE:ccmp15-dvk += " \ _ov_board_v2_ccmp15-dvk.dtbo \ _ov_som_bt_ccmp15.dtbo \ _ov_som_bt_test_ccmp15.dtbo \ - _ov_som_m4_ccmp15.dtbo \ _ov_som_wifi_ccmp15.dtbo \ " # Set DTB load address to U-Boot fdt_addr_r From 0d085e3062b24dbf78ae260a8d7aa64423f2f3b3 Mon Sep 17 00:00:00 2001 From: Gonzalo Ruiz Date: Mon, 3 Jun 2024 16:58:45 +0200 Subject: [PATCH 81/91] ccmp15: add overlay for NHD-3.5-640480EF-MSXP MIPI display https://onedigi.atlassian.net/browse/DEL-9036 Signed-off-by: Gonzalo Ruiz --- meta-digi-arm/conf/machine/ccmp15-dvk.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/meta-digi-arm/conf/machine/ccmp15-dvk.conf b/meta-digi-arm/conf/machine/ccmp15-dvk.conf index 704edbe68..d871e1c6e 100644 --- a/meta-digi-arm/conf/machine/ccmp15-dvk.conf +++ b/meta-digi-arm/conf/machine/ccmp15-dvk.conf @@ -46,6 +46,7 @@ STM32MP_KERNEL_DEVICETREE:ccmp15-dvk += " \ _ov_board_mikroe-accel2-click_ccmp15-dvk.dtbo \ _ov_board_mikroe-gyro-click_ccmp15-dvk.dtbo \ _ov_board_mikroe-i2c-to-spi-click_ccmp15-dvk.dtbo \ + _ov_board_nhd-3-5-640480ef-msxp-mipi-dsi_ccmp15-dvk.dtbo \ _ov_board_sv4e-mipi-analyzer_ccmp15-dvk.dtbo \ _ov_board_v1_ccmp15-dvk.dtbo \ _ov_board_v2_ccmp15-dvk.dtbo \ From 970c0cac508f6826ce155a4a4a1aaef6d36841b9 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Wed, 12 Jun 2024 15:31:23 +0200 Subject: [PATCH 82/91] trustfence: ccimx93: implement missing secure console functionality Unlike the rest of the NXP platforms, in u-boot, the ccimx93 allows configuring a GPIO name to activate the console when secure console is enabled. Those u-boot options were not translated to the trustfence code in meta-digi. https://onedigi.atlassian.net/browse/DEL-9063 Signed-off-by: Javier Viguera --- meta-digi-dey/classes/trustfence.bbclass | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index bed0364cd..eaff8f0b0 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -150,6 +150,12 @@ python () { elif d.getVar("TRUSTFENCE_CONSOLE_GPIO_ENABLE"): if (d.getVar("DEY_SOC_VENDOR") == "NXP"): d.appendVar("UBOOT_TF_CONF", "CONFIG_CONSOLE_ENABLE_GPIO=y CONFIG_CONSOLE_ENABLE_GPIO_NR=%s " % d.getVar("TRUSTFENCE_CONSOLE_GPIO_ENABLE")) + if d.getVar("TRUSTFENCE_CONSOLE_GPIO_ENABLE_NAME"): + d.appendVar("UBOOT_TF_CONF", 'CONFIG_CONSOLE_ENABLE_GPIO_NAME="%s" ' % d.getVar("TRUSTFENCE_CONSOLE_GPIO_ENABLE_NAME")) + if d.getVar("TRUSTFENCE_CONSOLE_GPIO_ENABLE_ACTIVE_LOW"): + d.appendVar("UBOOT_TF_CONF", "CONFIG_CONSOLE_ENABLE_GPIO_ACTIVE_LOW=y ") + else: + d.appendVar("UBOOT_TF_CONF", '"# CONFIG_CONSOLE_ENABLE_GPIO_ACTIVE_LOW is not set" ') elif (d.getVar("DEY_SOC_VENDOR") == "STM"): d.appendVar("UBOOT_TF_CONF", 'CONFIG_CONSOLE_ENABLE_GPIO=y CONFIG_CONSOLE_ENABLE_GPIO_NAME="%s" ' % d.getVar("TRUSTFENCE_CONSOLE_GPIO_ENABLE_NAME")) From 8633a4ed49081c3e5750f3a87d9bf1497a95770d Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Wed, 12 Jun 2024 15:31:43 +0200 Subject: [PATCH 83/91] imx-atf: prevent console output when TF secure console is enabled https://onedigi.atlassian.net/browse/DEL-9063 Signed-off-by: Javier Viguera --- .../freescale-layer/recipes-bsp/imx-atf/imx-atf_%.bbappend | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-atf/imx-atf_%.bbappend b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-atf/imx-atf_%.bbappend index 91dd55397..bf02767c5 100644 --- a/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-atf/imx-atf_%.bbappend +++ b/meta-digi-arm/dynamic-layers/freescale-layer/recipes-bsp/imx-atf/imx-atf_%.bbappend @@ -15,6 +15,8 @@ SRC_URI:append:ccimx93 = " \ BOOT_TOOLS = "imx-boot-tools" +EXTRA_OEMAKE += "${@oe.utils.conditional('TRUSTFENCE_CONSOLE_DISABLE', '1', 'LOG_LEVEL=0', '', d)}" + # Build ATF for imx93 SOC revision A0 do_compile:append:ccimx93() { oe_runmake SOC_REV_A0=1 BUILD_BASE=build-A0 clean From 0a5274e06f4df9c41e03e522ee8e90635406eeed Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Thu, 13 Jun 2024 13:21:58 +0200 Subject: [PATCH 84/91] firmware installation scripts: correct usage of u-boot variables Some variables in the script belong to u-boot, not to the shell running the script. Escape those variables so the shell does not expand them. Signed-off-by: Francisco Gil --- .../u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh | 6 +++--- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 6 +++--- .../u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh | 6 +++--- .../u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh | 6 +++--- .../u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index ff7a40188..17949a556 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -64,10 +64,10 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" if [ -n "${DEK_BLOB_FILE}" ]; then - uuu fb: ucmd setenv uboot_size $filesize - uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: ucmd setenv uboot_size \${filesize} + uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" - uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd setenv dek_size \${filesize} uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index 113dbc4c5..4d3f636c7 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -64,10 +64,10 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" if [ -n "${DEK_BLOB_FILE}" ]; then - uuu fb: ucmd setenv uboot_size $filesize - uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: ucmd setenv uboot_size \${filesize} + uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" - uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd setenv dek_size \${filesize} uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh index 446ccc150..01afb32fc 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh @@ -76,10 +76,10 @@ part_update() uuu fb: download -f "${2}" if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "uboot" ]; then if [ -n "${DEK_BLOB_FILE}" ]; then - uuu fb: ucmd setenv uboot_size $filesize - uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: ucmd setenv uboot_size \${filesize} + uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${4}" - uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd setenv dek_size \${filesize} uuu "fb[-t ${3}]:" ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else uuu "fb[-t ${3}]:" ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index a6151082b..00b1e6a34 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -64,10 +64,10 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" if [ -n "${DEK_BLOB_KEY}" ]; then - uuu fb: ucmd setenv uboot_size $filesize - uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: ucmd setenv uboot_size \${filesize} + uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" - uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd setenv dek_size \${filesize} uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index 9fb6fb0f5..bf8b59c92 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -64,10 +64,10 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" if [ -n "${DEK_BLOB_KEY}" ]; then - uuu fb: ucmd setenv uboot_size $filesize - uuu fb: ucmd setenv fastboot_buffer $initrd_addr + uuu fb: ucmd setenv uboot_size \${filesize} + uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" - uuu fb: ucmd setenv dek_size $filesize + uuu fb: ucmd setenv dek_size \${filesize} uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} else uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} From 86b97c888af7d221b9488aa28ce1610a708fc641 Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Thu, 13 Jun 2024 14:15:07 +0200 Subject: [PATCH 85/91] ccimx93: uuu: add support to flash trustfence artifacts https://onedigi.atlassian.net/browse/DEL-9058 Signed-off-by: Francisco Gil --- .../ccimx93/install_linux_fw_uuu.sh | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh index c6213dff3..1e458c625 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh @@ -39,8 +39,11 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." + echo " -k Update includes dek blob file." + echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -u U-Boot filename." + echo " -t Install Trustfence artifacts." echo " Auto-determined by variant if not provided." echo " -U Update redundant bootloader partition." @@ -51,6 +54,7 @@ show_usage() # Params: # 1. partition # 2. file +# 3. dek blob file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -59,10 +63,23 @@ part_update() echo "=====================================================================================" echo "\033[0m" - if [ "${1}" = "bootloader" ] || [ "${1}" = "bootloader_redundant" ]; then - uuu fb: flash "${1}" "${2}" + if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then + uuu fb: download -f "${2}" + if [ -n "${DEK_BLOB_KEY}" ]; then + uuu fb: ucmd setenv uboot_size \${filesize} + uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} + uuu fb: download -f "${3}" + uuu fb: ucmd setenv dek_size \${filesize} + uuu fb: ucmd trustfence update ram \${loadaddr} \${uboot_size} \${initrd_addr} \${dek_size} + else + uuu fb: ucmd trustfence update ram \${fastboot_buffer} \${fastboot_bytes} + fi else - uuu fb: flash -raw2sparse "${1}" "${2}" + if [ "${1}" = "bootloader" ] || [ "${1}" = "bootloader_redundant" ]; then + uuu fb: flash "${1}" "${2}" + else + uuu fb: flash -raw2sparse "${1}" "${2}" + fi fi } @@ -75,15 +92,18 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:nu:U' c +# -k +while getopts 'bdhti:nu:Uk:' c do case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; + k) DEK_BLOB_KEY=${OPTARG} ;; n) NOWAIT=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; + t) TRUSTFENCE=true ;; U) INSTALL_REDUNDANT_UBOOT=true ;; esac done @@ -112,7 +132,7 @@ if [ -z "${INSTALL_UBOOT_FILENAME}" ]; then som_hv="$(((hwid_2 & 0x78) >> 3))" [ "${som_hv}" -lt "2" ] && SOCREV="-A0" fi - INSTALL_UBOOT_FILENAME="imx-boot-##MACHINE##${SOCREV}.bin" + INSTALL_UBOOT_FILENAME="imx-boot-##SIGNED##-##MACHINE##${SOCREV}.bin" fi # remove redirect @@ -230,7 +250,7 @@ uuu fb: ucmd setenv fastboot_buffer \${loadaddr} uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_KEY}" if [ "${INSTALL_REDUNDANT_UBOOT}" = true ]; then part_update bootloader_redundant "${INSTALL_UBOOT_FILENAME}" fi @@ -313,6 +333,10 @@ fi if [ -f ${COMPRESSED_ROOTFS_IMAGE} ] && [ -f ${INSTALL_ROOTFS_FILENAME} ]; then rm -f "${INSTALL_ROOTFS_FILENAME}" fi +# Set the dboot_kernel_var to fitimage if Trustfence is enabled +if [ "${TRUSTFENCE}" = "true" ] || echo "$INSTALL_UBOOT_FILENAME" | grep -q -e "signed" -e "encrypted"; then + uuu fb: ucmd setenv dboot_kernel_var fitimage +fi if [ "${DUALBOOT}" != true ]; then # Configure u-boot to boot into recovery mode From 87ec014630e656ed58c727577195e25f0556aeb3 Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Thu, 13 Jun 2024 14:23:22 +0200 Subject: [PATCH 86/91] ccmp1X: uuu: add support to flash trustfence artifacts https://onedigi.atlassian.net/browse/DEL-9058 Signed-off-by: Francisco Gil --- .../u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh index 969b1b054..f84b44625 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh @@ -50,6 +50,7 @@ show_usage() echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." echo " -n No wait. Skips 10 seconds delay to stop script." + echo " -t Install Trustfence artifacts." exit 2 } @@ -93,6 +94,7 @@ do h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; n) NOWAIT=true ;; + t) TRUSTFENCE=true ;; esac done @@ -312,6 +314,11 @@ else uuu fb: ucmd saveenv fi +# Set the dboot_kernel_var to fitimage if Trustfence is enabled +if [ "${TRUSTFENCE}" = "true" ] || echo "$INSTALL_UBOOT_FILENAME" | grep -q -e "signed"; then + uuu fb: ucmd setenv dboot_kernel_var fitimage + uuu fb: ucmd saveenv +fi # Set the rootfstype if squashfs if [ "${SQUASHFS}" = true ]; then uuu fb: ucmd setenv rootfstype squashfs From 85b0895297bd553a22e7b23c64942b915e0f75ac Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Fri, 14 Jun 2024 11:11:15 +0200 Subject: [PATCH 87/91] install script: remove extra "-" in not signed/encrypted images By default is trying to install an artifact imx-boot-- if trustfence is not enabled. Signed-off-by: Francisco Gil --- meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc index aa0f7e391..6ccfd5c15 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey.inc @@ -98,7 +98,7 @@ build_uboot_scripts() { sed -i -e 's,##SIGNED_TFA##,_signed,g' ${TMP_INSTALL_SCR} fi else - sed -i -e 's,##SIGNED##,,g' ${TMP_INSTALL_SCR} + sed -i -e 's,-##SIGNED##,,g' -e 's,##SIGNED##,,g' ${TMP_INSTALL_SCR} if [ "${DEY_SOC_VENDOR}" = "STM" ]; then sed -i -e 's,##SIGNED_TFA##,,g' ${TMP_INSTALL_SCR} fi From d86648f791a9dfbf0019d17c64368f7b20d59e2c Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Mon, 17 Jun 2024 09:59:13 +0200 Subject: [PATCH 88/91] install scripts: capitalize F from TrustFence Signed-off-by: Francisco Gil --- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 2 +- .../u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh | 2 +- .../u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh | 2 +- .../u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh | 2 +- .../u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh | 2 +- .../recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index 4d3f636c7..d5e35171e 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -42,7 +42,7 @@ show_usage() echo " -k Update includes dek blob file." echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." - echo " -t Install Trustfence artifacts." + echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh index 01afb32fc..f3154a965 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh @@ -42,7 +42,7 @@ show_usage() echo " -k Update includes dek blob file." echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." - echo " -t Install Trustfence artifacts." + echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index 00b1e6a34..7b3f723d6 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -42,7 +42,7 @@ show_usage() echo " -k Update includes dek blob file." echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." - echo " -t Install Trustfence artifacts." + echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index bf8b59c92..b3cfb229d 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -42,7 +42,7 @@ show_usage() echo " -k Update includes dek blob file." echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." - echo " -t Install Trustfence artifacts." + echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." echo " Auto-determined by variant if not provided." exit 2 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh index 1e458c625..8c945f43f 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh @@ -43,7 +43,7 @@ show_usage() echo " (requires -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -u U-Boot filename." - echo " -t Install Trustfence artifacts." + echo " -t Install TrustFence artifacts." echo " Auto-determined by variant if not provided." echo " -U Update redundant bootloader partition." diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh index f84b44625..70468cdd4 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccmp1/install_linux_fw_uuu.sh @@ -50,7 +50,7 @@ show_usage() echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." echo " -n No wait. Skips 10 seconds delay to stop script." - echo " -t Install Trustfence artifacts." + echo " -t Install TrustFence artifacts." exit 2 } From 828f5da09b0044d0d8fa1d3e40c59b96ec4e2a27 Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Mon, 17 Jun 2024 10:00:43 +0200 Subject: [PATCH 89/91] install script: allow -k parameter to be used without arguments There is a corner case that wasn't cover by the script, if you use the script using a -k -t the "-t" would be the name of the dek.bin. This new implementation solves the issue. Signed-off-by: Francisco Gil --- .../u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh | 9 ++++++++- .../u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 9 ++++++++- .../u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh | 9 ++++++++- .../u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh | 9 ++++++++- .../u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh | 9 ++++++++- .../u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh | 9 ++++++++- 6 files changed, 48 insertions(+), 6 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index 17949a556..091be4fa4 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -90,8 +90,15 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -while getopts 'bdhi:k:ntu:' c +while getopts ':bdhi:k:ntu:' c do + if [ "${c}" = ":" ]; then + c="${OPTARG}" + unset OPTARG + elif echo "${OPTARG}" | grep -qs '^-'; then + OPTIND="$((OPTIND-1))" + unset OPTARG + fi case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index d5e35171e..214fb4e6f 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -91,8 +91,15 @@ echo "############################################################" # -i # -u # -k -while getopts 'bdhi:k:ntu:' c +while getopts ':bdhi:k:ntu:' c do + if [ "${c}" = ":" ]; then + c="${OPTARG}" + unset OPTARG + elif echo "${OPTARG}" | grep -qs '^-'; then + OPTIND="$((OPTIND-1))" + unset OPTARG + fi case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh index f3154a965..4df6795e7 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh @@ -99,8 +99,15 @@ echo "############################################################" # -i # -u # -k -while getopts 'bdhi:k:ntu:' c +while getopts ':bdhi:k:ntu:' c do + if [ "${c}" = ":" ]; then + c="${OPTARG}" + unset OPTARG + elif echo "${OPTARG}" | grep -qs '^-'; then + OPTIND="$((OPTIND-1))" + unset OPTARG + fi case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index 7b3f723d6..9d61627b2 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -91,8 +91,15 @@ echo "############################################################" # -i # -u # -k -while getopts 'bdhi:k:ntu:' c +while getopts ':bdhi:k:ntu:' c do + if [ "${c}" = ":" ]; then + c="${OPTARG}" + unset OPTARG + elif echo "${OPTARG}" | grep -qs '^-'; then + OPTIND="$((OPTIND-1))" + unset OPTARG + fi case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index b3cfb229d..c49db40a8 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -91,8 +91,15 @@ echo "############################################################" # -i # -u # -k -while getopts 'bdhi:k:ntu:' c +while getopts ':bdhi:k:ntu:' c do + if [ "${c}" = ":" ]; then + c="${OPTARG}" + unset OPTARG + elif echo "${OPTARG}" | grep -qs '^-'; then + OPTIND="$((OPTIND-1))" + unset OPTARG + fi case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh index 8c945f43f..16a9315bd 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh @@ -93,8 +93,15 @@ echo "############################################################" # -i # -u # -k -while getopts 'bdhti:nu:Uk:' c +while getopts ':bdhti:nu:Uk:' c do + if [ "${c}" = ":" ]; then + c="${OPTARG}" + unset OPTARG + elif echo "${OPTARG}" | grep -qs '^-'; then + OPTIND="$((OPTIND-1))" + unset OPTARG + fi case $c in b) BOOTCOUNT=true ;; d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; From 7e493b74ae9daafbf2cbd8a835e4821aac8d3f09 Mon Sep 17 00:00:00 2001 From: Francisco Gil Date: Mon, 17 Jun 2024 12:05:12 +0200 Subject: [PATCH 90/91] install script: enable trustfence if -k is selected Also use the name DEK_FILE for all the files. Signed-off-by: Francisco Gil --- .../u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh | 13 +++++++------ .../u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh | 14 +++++++------- .../u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh | 14 +++++++------- .../u-boot-dey/ccimx8m/install_linux_fw_uuu.sh | 14 +++++++------- .../u-boot-dey/ccimx8x/install_linux_fw_uuu.sh | 14 +++++++------- .../u-boot-dey/ccimx93/install_linux_fw_uuu.sh | 14 +++++++------- 6 files changed, 42 insertions(+), 41 deletions(-) diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh index 091be4fa4..a0359a376 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6qpsbc/install_linux_fw_uuu.sh @@ -39,8 +39,8 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." - echo " -k Update includes dek blob file." - echo " (requires -t)." + echo " -k Update includes dek file." + echo " (implies -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -t Install Trustfence artifacts." echo " -u U-Boot filename." @@ -52,7 +52,7 @@ show_usage() # Params: # 1. partition # 2. file -# 3. dek blob file when updating an encrypted bootloader +# 3. dek file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -63,7 +63,7 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" - if [ -n "${DEK_BLOB_FILE}" ]; then + if [ -n "${DEK_FILE}" ]; then uuu fb: ucmd setenv uboot_size \${filesize} uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" @@ -90,6 +90,7 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u +# -k while getopts ':bdhi:k:ntu:' c do if [ "${c}" = ":" ]; then @@ -104,7 +105,7 @@ do d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; - k) DEK_BLOB_FILE=${OPTARG} ;; + k) DEK_FILE=${OPTARG} ;; n) NOWAIT=true ;; t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; @@ -269,7 +270,7 @@ fi uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_FILE}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_FILE}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh index 214fb4e6f..a818ad60b 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6sbc/install_linux_fw_uuu.sh @@ -39,8 +39,8 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." - echo " -k Update includes dek blob file." - echo " (requires -t)." + echo " -k Update includes dek file." + echo " (implies -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." @@ -52,7 +52,7 @@ show_usage() # Params: # 1. partition # 2. file -# 3. dek blob file when updating an encrypted bootloader +# 3. dek file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -63,7 +63,7 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" - if [ -n "${DEK_BLOB_FILE}" ]; then + if [ -n "${DEK_FILE}" ]; then uuu fb: ucmd setenv uboot_size \${filesize} uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" @@ -90,7 +90,7 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -# -k +# -k while getopts ':bdhi:k:ntu:' c do if [ "${c}" = ":" ]; then @@ -105,7 +105,7 @@ do d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; - k) DEK_BLOB_FILE=${OPTARG} ;; + k) DEK_FILE=${OPTARG} && TRUSTFENCE=true ;; n) NOWAIT=true ;; t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; @@ -289,7 +289,7 @@ fi uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_FILE}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_FILE}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh index 4df6795e7..4d5c36083 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx6ul/install_linux_fw_uuu.sh @@ -39,8 +39,8 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." - echo " -k Update includes dek blob file." - echo " (requires -t)." + echo " -k Update includes dek file." + echo " (implies -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." @@ -56,7 +56,7 @@ show_usage() # Description: # - downloads image to RAM # - runs 'update' command from RAM -# 4. dek blob file when updating an encrypted u-boot +# 4. dek file when updating an encrypted u-boot part_update() { echo "\033[36m" @@ -75,7 +75,7 @@ part_update() fi uuu fb: download -f "${2}" if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "uboot" ]; then - if [ -n "${DEK_BLOB_FILE}" ]; then + if [ -n "${DEK_FILE}" ]; then uuu fb: ucmd setenv uboot_size \${filesize} uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${4}" @@ -98,7 +98,7 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -# -k +# -k while getopts ':bdhi:k:ntu:' c do if [ "${c}" = ":" ]; then @@ -113,7 +113,7 @@ do d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; - k) DEK_BLOB_FILE=${OPTARG} ;; + k) DEK_FILE=${OPTARG} && TRUSTFENCE=true ;; n) NOWAIT=true ;; t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; @@ -286,7 +286,7 @@ uuu fb: ucmd setenv fastboot_buffer \${loadaddr} uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "uboot" "${INSTALL_UBOOT_FILENAME}" 5000 "${DEK_BLOB_FILE}" +part_update "uboot" "${INSTALL_UBOOT_FILENAME}" 5000 "${DEK_FILE}" # Set 'bootcmd' for the second part of the script that will # - Reset environment to defaults diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh index 9d61627b2..f6fbdcd81 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8m/install_linux_fw_uuu.sh @@ -39,8 +39,8 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." - echo " -k Update includes dek blob file." - echo " (requires -t)." + echo " -k Update includes dek file." + echo " (implies -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." @@ -52,7 +52,7 @@ show_usage() # Params: # 1. partition # 2. file -# 3. dek blob file when updating an encrypted bootloader +# 3. dek file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -63,7 +63,7 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" - if [ -n "${DEK_BLOB_KEY}" ]; then + if [ -n "${DEK_FILE}" ]; then uuu fb: ucmd setenv uboot_size \${filesize} uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" @@ -90,7 +90,7 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -# -k +# -k while getopts ':bdhi:k:ntu:' c do if [ "${c}" = ":" ]; then @@ -105,7 +105,7 @@ do d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; - k) DEK_BLOB_KEY=${OPTARG} ;; + k) DEK_FILE=${OPTARG} && TRUSTFENCE=true ;; n) NOWAIT=true ;; t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; @@ -241,7 +241,7 @@ uuu fb: ucmd setenv fastboot_buffer \${loadaddr} uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_KEY}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_FILE}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh index c49db40a8..88b258932 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx8x/install_linux_fw_uuu.sh @@ -39,8 +39,8 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." - echo " -k Update includes dek blob file." - echo " (requires -t)." + echo " -k Update includes dek file." + echo " (implies -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -t Install TrustFence artifacts." echo " -u U-Boot filename." @@ -52,7 +52,7 @@ show_usage() # Params: # 1. partition # 2. file -# 3. dek blob file when updating an encrypted bootloader +# 3. dek file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -63,7 +63,7 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" - if [ -n "${DEK_BLOB_KEY}" ]; then + if [ -n "${DEK_FILE}" ]; then uuu fb: ucmd setenv uboot_size \${filesize} uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" @@ -90,7 +90,7 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -# -k +# -k while getopts ':bdhi:k:ntu:' c do if [ "${c}" = ":" ]; then @@ -105,7 +105,7 @@ do d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; - k) DEK_BLOB_KEY=${OPTARG} ;; + k) DEK_FILE=${OPTARG} && TRUSTFENCE=true ;; n) NOWAIT=true ;; t) TRUSTFENCE=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; @@ -248,7 +248,7 @@ uuu fb: ucmd setenv fastboot_buffer \${loadaddr} uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_KEY}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_FILE}" # Set MMC to boot from BOOT1 partition uuu fb: ucmd mmc partconf 0 1 1 1 diff --git a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh index 16a9315bd..be9f15de5 100644 --- a/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh +++ b/meta-digi-arm/recipes-bsp/u-boot/u-boot-dey/ccimx93/install_linux_fw_uuu.sh @@ -39,8 +39,8 @@ show_usage() echo " -i Image name that prefixes the image filenames, such as 'dey-image-qt', " echo " 'dey-image-webkit', 'core-image-base'..." echo " Defaults to '##DEFAULT_IMAGE_NAME##' if not provided." - echo " -k Update includes dek blob file." - echo " (requires -t)." + echo " -k Update includes dek file." + echo " (implies -t)." echo " -n No wait. Skips 10 seconds delay to stop script." echo " -u U-Boot filename." echo " -t Install TrustFence artifacts." @@ -54,7 +54,7 @@ show_usage() # Params: # 1. partition # 2. file -# 3. dek blob file when updating an encrypted bootloader +# 3. dek file when updating an encrypted bootloader part_update() { echo "\033[36m" @@ -65,7 +65,7 @@ part_update() if [ "${TRUSTFENCE}" = "true" ] && [ "${1}" = "bootloader" ]; then uuu fb: download -f "${2}" - if [ -n "${DEK_BLOB_KEY}" ]; then + if [ -n "${DEK_FILE}" ]; then uuu fb: ucmd setenv uboot_size \${filesize} uuu fb: ucmd setenv fastboot_buffer \${initrd_addr} uuu fb: download -f "${3}" @@ -92,7 +92,7 @@ echo "############################################################" # -b, -d, -n (booleans) # -i # -u -# -k +# -k while getopts ':bdhti:nu:Uk:' c do if [ "${c}" = ":" ]; then @@ -107,7 +107,7 @@ do d) INSTALL_DUALBOOT=true && BOOTCOUNT=true ;; h) show_usage ;; i) IMAGE_NAME=${OPTARG} ;; - k) DEK_BLOB_KEY=${OPTARG} ;; + k) DEK_FILE=${OPTARG} && TRUSTFENCE=true ;; n) NOWAIT=true ;; u) INSTALL_UBOOT_FILENAME=${OPTARG} ;; t) TRUSTFENCE=true ;; @@ -257,7 +257,7 @@ uuu fb: ucmd setenv fastboot_buffer \${loadaddr} uuu fb: ucmd setenv forced_update 1 # Update U-Boot -part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_BLOB_KEY}" +part_update "bootloader" "${INSTALL_UBOOT_FILENAME}" "${DEK_FILE}" if [ "${INSTALL_REDUNDANT_UBOOT}" = true ]; then part_update bootloader_redundant "${INSTALL_UBOOT_FILENAME}" fi From 11ee0251d0b644ac5f82bd7330a767ef18086bd5 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Mon, 17 Jun 2024 15:20:01 +0200 Subject: [PATCH 91/91] trustfence: ccimx93: disable boot artifacts encryption by default Encrypting boot artifacts impacts the device's boot time, so disable them by default. It is still possible to enable it in the project's config file by setting the TRUSTFENCE_DEK_PATH option. Signed-off-by: Javier Viguera --- meta-digi-dey/classes/trustfence.bbclass | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/meta-digi-dey/classes/trustfence.bbclass b/meta-digi-dey/classes/trustfence.bbclass index eaff8f0b0..ba99025bb 100644 --- a/meta-digi-dey/classes/trustfence.bbclass +++ b/meta-digi-dey/classes/trustfence.bbclass @@ -23,8 +23,7 @@ TRUSTFENCE_CONSOLE_DISABLE ?= "0" # Default secure boot configuration TRUSTFENCE_SIGN ?= "1" TRUSTFENCE_SIGN_KEYS_PATH ?= "default" -TRUSTFENCE_DEK_PATH ?= "default" -TRUSTFENCE_DEK_PATH:ccmp1 ?= "0" +TRUSTFENCE_DEK_PATH ?= "${TF_DEK_PATH}" TRUSTFENCE_ENCRYPT_ENVIRONMENT ?= "1" TRUSTFENCE_SRK_REVOKE_MASK ?= "0x0" TRUSTFENCE_KEY_INDEX ?= "0" @@ -45,6 +44,11 @@ TRUSTFENCE_READ_ONLY_ROOTFS ?= "${@bb.utils.contains("IMAGE_FEATURES", "read-onl # NOTHING TO CUSTOMIZE BELOW THIS LINE # +# Platform specific defaults +TF_DEK_PATH = "default" +TF_DEK_PATH:ccimx93 = "0" +TF_DEK_PATH:ccmp1 = "0" + # NXP-based sign a FIT-format boot artifact TRUSTFENCE_SIGN_FIT_NXP = "0" TRUSTFENCE_SIGN_FIT_NXP:ccimx93 = "${TRUSTFENCE_SIGN_ARTIFACTS}"