diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ac617bad336d..70716a1768c4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -32,7 +32,7 @@ config/boards/bananapim2pro.conf @igorpecovnik config/boards/bananapim2s.conf @jeanrhum @pyavitz config/boards/bananapim2zero.csc @mhawkins-consultant config/boards/bananapim3.csc @AaronNGray -config/boards/bananapim4berry.csc @The-going +config/boards/bananapim4berry.conf @The-going config/boards/bananapim4zero.conf @pyavitz config/boards/bananapim5.conf @igorpecovnik config/boards/bananapim64.csc @devdotnetorg @@ -55,6 +55,7 @@ config/boards/helios4.conf @Heisath config/boards/helios64.conf @prahal config/boards/hinlink-h28k.csc @sputnik2019 config/boards/hinlink-ht2.csc @hoochiwetech +config/boards/imb3588.conf @JackHuang021 config/boards/indiedroid-nova.csc @lanefu config/boards/inovato-quadra.conf @NicoD-SBC config/boards/jethubj100.conf @adeepn @@ -121,7 +122,7 @@ config/boards/orangepizeroplus.csc @schwar3kat config/boards/phytiumpi.conf @chainsx config/boards/pine64.conf @PanderMusubi config/boards/pinebook-pro.csc @TRSx80 @ahoneybun -config/boards/pocketbeagle2.csc @Grippy98 +config/boards/pocketbeagle2.conf @Grippy98 config/boards/pocketchip-sd.csc @TheSnowfield config/boards/qcom-robotics-rb5.conf @FantasyGmm config/boards/qemu-uboot-arm64.csc @rpardini @@ -188,7 +189,7 @@ config/kernel/linux-meson64-*.config @NicoD-SBC @SteeManMI @Tonymac32 @adeepn @ config/kernel/linux-mvebu-*.config @Heisath config/kernel/linux-odroidxu4-*.config @joekhoobyar config/kernel/linux-phytium-embedded-*.config @chainsx -config/kernel/linux-rk35xx-*.config @CodeChenL @ColorfulRhino @HeyMeco @SeeleVolleri @SuperKali @Tonymac32 @ZazaBR @alexl83 @amazingfate @catalinii @chainsx @efectn @fridtjof @ginkage @hoochiwetech @hqnicolas @krachlatte @lanefu @linhz0hz @mahdichi @mattx433 @monkaBlyat @prahal @rpardini @schwar3kat @sputnik2019 @vamzii +config/kernel/linux-rk35xx-*.config @CodeChenL @ColorfulRhino @HeyMeco @JackHuang021 @SeeleVolleri @SuperKali @Tonymac32 @ZazaBR @alexl83 @amazingfate @andyshrk @catalinii @chainsx @efectn @fridtjof @ginkage @hoochiwetech @hqnicolas @krachlatte @lanefu @linhz0hz @mahdichi @mattx433 @monkaBlyat @prahal @rpardini @schwar3kat @sputnik2019 @vamzii config/kernel/linux-rockchip-*.config @paolosabatino config/kernel/linux-rockchip64-*.config @150balbes @ColorfulRhino @HeyMeco @JohnTheCoolingFan @SuperKali @TRSx80 @TheSnowfield @Tonymac32 @ZazaBR @ahoneybun @alexl83 @amazingfate @andyshrk @brentr @catalinii @clee @efectn @fridtjof @hqnicolas @igorpecovnik @joekhoobyar @krachlatte @lanefu @linhz0hz @mlegenovic @paolosabatino @prahal @redrathnure @rpardini @schwar3kat @sicXnull @tdleiyao @torte71 @utlark @vamzii config/kernel/linux-sm8250-*.config @FantasyGmm @amazingfate @@ -207,11 +208,11 @@ config/kernel/linux-wsl2-x86-*.config @rpardini patch/atf/atf-arm64/ @PeterChrz @rpardini patch/atf/atf-bcm2711/ @PanderMusubi @teknoid patch/atf/atf-genio/ @HeyMeco -patch/atf/atf-imx8m/ @schmiedelm +patch/atf/atf-imx8/ @schmiedelm patch/atf/atf-k3-beagle/ @Grippy98 patch/atf/atf-k3/ @Grippy98 @glneo patch/atf/atf-phytium-embedded/ @chainsx -patch/atf/atf-rockchip64/ @ColorfulRhino @TRSx80 @ahoneybun @andyshrk @clee @joekhoobyar @paolosabatino @prahal +patch/atf/atf-rockchip64/ @ColorfulRhino @SuperKali @TRSx80 @Tonymac32 @ahoneybun @andyshrk @clee @joekhoobyar @paolosabatino @prahal patch/atf/atf-sm8250/ @FantasyGmm @amazingfate patch/atf/atf-sm8550/ @FantasyGmm patch/atf/atf-spacemit/ @pyavitz @@ -239,7 +240,7 @@ patch/kernel/archive/wsl2-arm64-*/ @rpardini patch/kernel/archive/wsl2-x86-*/ @rpardini patch/kernel/genio-1200-*/ @HeyMeco patch/kernel/phytium-embedded-*/ @chainsx -patch/kernel/rk35xx-vendor-*/ @CodeChenL @ColorfulRhino @HeyMeco @SeeleVolleri @SuperKali @Tonymac32 @ZazaBR @alexl83 @amazingfate @catalinii @chainsx @efectn @fridtjof @ginkage @hoochiwetech @hqnicolas @krachlatte @lanefu @linhz0hz @mahdichi @mattx433 @monkaBlyat @prahal @rpardini @schwar3kat @sputnik2019 @vamzii +patch/kernel/rk35xx-vendor-*/ @CodeChenL @ColorfulRhino @HeyMeco @JackHuang021 @SeeleVolleri @SuperKali @Tonymac32 @ZazaBR @alexl83 @amazingfate @andyshrk @catalinii @chainsx @efectn @fridtjof @ginkage @hoochiwetech @hqnicolas @krachlatte @lanefu @linhz0hz @mahdichi @mattx433 @monkaBlyat @prahal @rpardini @schwar3kat @sputnik2019 @vamzii patch/kernel/starfive2-*/ @libiunc patch/kernel/sun55iw3-syterkit-*/ @chainsx patch/kernel/thead-*/ @chainsx @@ -248,7 +249,7 @@ patch/u-boot/legacy/ @chainsx @joekhoobyar @juanlufont @lanefu patch/u-boot/legacy/u-boot-clearfog/ @Heisath patch/u-boot/legacy/u-boot-helios4/ @Heisath patch/u-boot/legacy/u-boot-khadas-edge2-rk3588/ @efectn -patch/u-boot/legacy/u-boot-radxa-rk35xx/ @CodeChenL @HeyMeco @SeeleVolleri @SuperKali @Tonymac32 @ZazaBR @alexl83 @amazingfate @catalinii @chainsx @efectn @fridtjof @ginkage @hoochiwetech @hqnicolas @krachlatte @linhz0hz @mahdichi @mattx433 @monkaBlyat @prahal @rpardini @schwar3kat @sputnik2019 @tdleiyao @vamzii +patch/u-boot/legacy/u-boot-radxa-rk35xx/ @CodeChenL @HeyMeco @JackHuang021 @SeeleVolleri @SuperKali @Tonymac32 @ZazaBR @alexl83 @amazingfate @catalinii @chainsx @efectn @fridtjof @ginkage @hoochiwetech @hqnicolas @krachlatte @linhz0hz @mahdichi @mattx433 @monkaBlyat @prahal @rpardini @schwar3kat @sputnik2019 @tdleiyao @vamzii patch/u-boot/legacy/u-boot-spacemit-k1/ @pyavitz patch/u-boot/u-boot-beagle/ @Grippy98 patch/u-boot/u-boot-k3-beagle/ @Grippy98 @@ -270,17 +271,17 @@ patch/u-boot/v2023.10/ @adeepn patch/u-boot/v2024.01/ @Tonymac32 @rpardini patch/u-boot/v2024.01/board_orangepi5/ @efectn patch/u-boot/v2024.04-rock5b-radxa/ @amazingfate @linhz0hz -patch/u-boot/v2024.04/ @Tonymac32 @chraac @igorpecovnik @pyavitz @utlark +patch/u-boot/v2024.04/ @Tonymac32 @chraac @pyavitz @utlark patch/u-boot/v2024.07-coolpi-cm5/ @andyshrk patch/u-boot/v2024.07/ @adeepn @igorpecovnik @monkaBlyat patch/u-boot/v2024.07/board_station-m1/ @150balbes -patch/u-boot/v2024.10/ @HeyMeco @alexl83 @brentr @fridtjof +patch/u-boot/v2024.10/ @HeyMeco @alexl83 @brentr @fridtjof @pyavitz patch/u-boot/v2024.10/board_bigtreetech-cb2/ @JohnTheCoolingFan patch/u-boot/v2025-sunxi/ @The-going patch/u-boot/v2025.01-rc3-coolpi-cm5/ @andyshrk patch/u-boot/v2025.01/ @ColorfulRhino @efectn @jeanrhum @joekhoobyar @paolosabatino @pyavitz @rpardini @torte71 patch/u-boot/v2025.01/board_h96-tvbox-3566/ @hqnicolas -patch/u-boot/v2025.04/ @IsMrX @NicoD-SBC @SuperKali @TheSnowfield @Tonymac32 @ZazaBR @amazingfate @andyshrk @catalinii @mlegenovic @rpardini @vamzii +patch/u-boot/v2025.04/ @IsMrX @NicoD-SBC @SuperKali @TheSnowfield @Tonymac32 @ZazaBR @amazingfate @andyshrk @catalinii @igorpecovnik @mlegenovic @rpardini @vamzii sources/families/bcm2711.conf @PanderMusubi @teknoid sources/families/genio.conf @HeyMeco sources/families/imx8m.conf @schmiedelm @@ -298,7 +299,7 @@ sources/families/mvebu.conf @Heisath sources/families/odroidxu4.conf @joekhoobyar sources/families/phytium-embedded.conf @chainsx sources/families/rk35xx.conf @CodeChenL @ZazaBR @amazingfate @andyshrk @catalinii @hoochiwetech @hqnicolas @krachlatte @mattx433 @sputnik2019 @tdleiyao @vamzii -sources/families/rockchip-rk3588.conf @ColorfulRhino @HeyMeco @SeeleVolleri @SuperKali @Tonymac32 @alexl83 @amazingfate @andyshrk @chainsx @efectn @fridtjof @ginkage @lanefu @linhz0hz @mahdichi @monkaBlyat @prahal @rpardini @schwar3kat +sources/families/rockchip-rk3588.conf @ColorfulRhino @HeyMeco @JackHuang021 @SeeleVolleri @SuperKali @Tonymac32 @alexl83 @amazingfate @andyshrk @chainsx @efectn @fridtjof @ginkage @lanefu @linhz0hz @mahdichi @monkaBlyat @prahal @rpardini @schwar3kat sources/families/rockchip.conf @paolosabatino sources/families/rockchip64.conf @150balbes @JohnTheCoolingFan @TRSx80 @TheSnowfield @Tonymac32 @ahoneybun @andyshrk @brentr @clee @hqnicolas @igorpecovnik @joekhoobyar @mlegenovic @paolosabatino @prahal @redrathnure @rpardini @sicXnull @torte71 @utlark sources/families/sm8250.conf @FantasyGmm @amazingfate diff --git a/.github/workflows/pr-kernel-security-analysis.yml b/.github/workflows/pr-kernel-security-analysis.yml index 22d099ebd174..2b1d44cf120d 100644 --- a/.github/workflows/pr-kernel-security-analysis.yml +++ b/.github/workflows/pr-kernel-security-analysis.yml @@ -34,7 +34,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@480f49412651059a414a6a5c96887abb1877de8a # v46.0.3 + uses: tj-actions/changed-files@4140eb99d2cced9bfd78375c2088371853262f79 # v46.0.3 - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/pr-lint-scripts.yml b/.github/workflows/pr-lint-scripts.yml index 5be2d472aac7..d5a5b8eb53a8 100644 --- a/.github/workflows/pr-lint-scripts.yml +++ b/.github/workflows/pr-lint-scripts.yml @@ -30,7 +30,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@480f49412651059a414a6a5c96887abb1877de8a # v46.0.3 + uses: tj-actions/changed-files@4140eb99d2cced9bfd78375c2088371853262f79 # v46.0.3 - name: List all changed files run: | diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 97ec1fb0bad8..ed8967510b52 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,7 +33,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@v2.4.1 + uses: ossf/scorecard-action@v2.4.2 with: results_file: results.sarif results_format: sarif diff --git a/README.md b/README.md index db45442d4f37..6791fbb0082d 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ Function | Armbian | Yocto | Buildroot | ├── config-example.conf User: example user config file ├── customize-image.sh User: script will execute just before closing the image    ├── atf User: ARM trusted firmware +    ├── extensions User: Extend build system with specific functionality    ├── kernel User: Linux kernel per kernel family    ├── misc User: various    └── u-boot User: universal boot loader patches diff --git a/config/boards/bananapim4berry.csc b/config/boards/bananapim4berry.conf similarity index 53% rename from config/boards/bananapim4berry.csc rename to config/boards/bananapim4berry.conf index 29cbf66733f9..a3078fbb4469 100644 --- a/config/boards/bananapim4berry.csc +++ b/config/boards/bananapim4berry.conf @@ -13,23 +13,14 @@ BOOT_LOGO="desktop" KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" -PACKAGE_LIST_BOARD="rfkill bluetooth bluez bluez-tools" +PACKAGE_LIST_BOARD="rfkill bluetooth bluez bluez-tools hostapd" function post_family_tweaks_bsp__bananapi_module_conf() { mkdir -p "${destination}"/etc/modprobe.d/ - display_alert "$BOARD" "Configuring rlt8821cu wifi module" "info" + display_alert "$BOARD" "Configuring rtl8821cu wifi module" "info" - cat <<-EOF > "${destination}"/etc/modprobe.d/8821cu.conf - # https://github.com/morrownr/8821cu-20210916/blob/main/8821cu.conf - # - # To see all options that are available: - # - # for f in /sys/module/8821cu/parameters/*;do echo "\$(basename \$f): \$(sudo cat \$f)";done - # - blacklist rtw88_8821cu - # - options 8821cu rtw_led_ctrl=2 - EOF + cp -f "${SRC}"/packages/bsp/wifi-rtl8821cu/etc/modprobe.d/8821cu.conf \ + "${destination}"/etc/modprobe.d/8821cu.conf } diff --git a/config/boards/beaglebone-ai64.conf b/config/boards/beaglebone-ai64.conf index 6b4b1479f5f3..5b5fd5835a08 100644 --- a/config/boards/beaglebone-ai64.conf +++ b/config/boards/beaglebone-ai64.conf @@ -16,3 +16,5 @@ KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="generic" +OPTEE_ARGS="" +OPTEE_PLATFORM="k3-j721e" diff --git a/config/boards/beagleplay.conf b/config/boards/beagleplay.conf index a1f65e692afb..86fe9afb370e 100644 --- a/config/boards/beagleplay.conf +++ b/config/boards/beagleplay.conf @@ -15,3 +15,5 @@ KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="lite" +OPTEE_ARGS="CFG_TEE_CORE_LOG_LEVEL=1" +OPTEE_PLATFORM="k3-am62x" diff --git a/config/boards/beagley-ai.csc b/config/boards/beagley-ai.csc index 943732b22191..3090a857d6e8 100644 --- a/config/boards/beagley-ai.csc +++ b/config/boards/beagley-ai.csc @@ -13,6 +13,8 @@ KERNEL_TARGET="current" KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="lite" +OPTEE_ARGS="" +OPTEE_PLATFORM="k3-am62x" # Use these branches until BeagleY-AI goes upstream function post_family_config_branch_current__beagley_ai_use_beagle_kernel_uboot() { diff --git a/config/boards/cainiao-cniot-core.csc b/config/boards/cainiao-cniot-core.csc new file mode 100644 index 000000000000..1518c1c8b0d5 --- /dev/null +++ b/config/boards/cainiao-cniot-core.csc @@ -0,0 +1,90 @@ +# Amlogic A311D 2GB RAM 16GB eMMC GBE USB3 RTL8822CS WiFi/BT +BOARD_NAME="CAINIAO CNIoT-CORE" +BOARDFAMILY="meson-g12b" +BOARD_MAINTAINER="" +BOOTCONFIG="cainiao-cniot-core_defconfig" +KERNEL_TARGET="current,edge" +KERNEL_TEST_TARGET="current" +MODULES_BLACKLIST="simpledrm" # SimpleDRM conflicts with Panfrost on the CAINIAO CNIoT-CORE +FULL_DESKTOP="yes" +SERIALCON="ttyAML0" +BOOT_LOGO="desktop" +BOOT_FDT_FILE="amlogic/meson-g12b-a311d-cainiao-cniot-core.dtb" +# playback via HDMI: aplay -D plughw:CNIoTCORE,0 /usr/share/sounds/alsa/Front_Center.wav +# playback via internal speaker: aplay -D plughw:CNIoTCORE,1 /usr/share/sounds/alsa/Front_Center.wav +ASOUND_STATE="asound.state.cainiao-cniot-core" + +BOOTBRANCH_BOARD="tag:v2025.04" +BOOTPATCHDIR="v2025.04" # This has a patch that adds support for CAINIAO CNIoT-CORE. + +function post_family_config__use_repacked_fip() { + declare -g UBOOT_TARGET_MAP="u-boot.bin" + unset write_uboot_platform + + function write_uboot_platform() { + dd if="$1/u-boot.bin" of="$2" bs=512 seek=1 conv=fsync 2>&1 + } +} + +function fetch_sources_tools__get_vendor_fip_and_gxlimg_source() { + fetch_from_repo "https://github.com/retro98boy/cainiao-cniot-core-linux.git" "cainiao-cniot-core-linux" "commit:30273c25aeabf75f609cff2c4fa7264335c295a8" + fetch_from_repo "https://github.com/repk/gxlimg.git" "gxlimg" "commit:0d0e5ba9cf396d1338067e8dc37a8bcd2e6874f1" +} + +function build_host_tools__install_gxlimg() { + # Compile and install only if git commit hash changed + cd "${SRC}/cache/sources/gxlimg" || exit + # need to check if /usr/local/bin/gxlimg to detect new Docker containers with old cached sources + if [[ ! -f .commit_id || $(git rev-parse @ 2> /dev/null) != $(< .commit_id) || ! -f /usr/local/bin/gxlimg ]]; then + display_alert "Compiling" "gxlimg" "info" + run_host_command_logged make distclean + run_host_command_logged make + install -Dm0755 gxlimg /usr/local/bin/gxlimg + git rev-parse @ 2> /dev/null > .commit_id + fi +} + +function post_uboot_custom_postprocess__repack_vendor_fip_with_mainline_uboot() { + display_alert "${BOARD}" "Repacking vendor FIP with mainline u-boot.bin" "info" + + BLOBS_DIR="${SRC}/cache/sources/cainiao-cniot-core-linux" + EXTRACT_DIR="${BLOBS_DIR}/extract" + AML_ENCRYPT="${SRC}/cache/sources/amlogic-boot-fip/khadas-vim3/aml_encrypt_g12b" + + if [ ! -f "$AML_ENCRYPT" ]; then + display_alert "${BOARD}" "amlogic-boot-fip/khadas-vim3/aml_encrypt_g12b not exist" "err" + exit 1 + fi + + mv u-boot.bin raw-u-boot.bin + rm -f "${EXTRACT_DIR}/bl33.enc" + # The current version of gxlimg has a problem with the handling of bl3x, + # which may cause the produced fip to fail to boot. + # see https://github.com/repk/gxlimg/issues/19 + # run_host_command_logged gxlimg -t bl3x -s raw-u-boot.bin "${EXTRACT_DIR}/bl33.enc" + run_host_x86_binary_logged "$AML_ENCRYPT" --bl3sig \ + --input raw-u-boot.bin \ + --output "${EXTRACT_DIR}/bl33.enc" \ + --level v3 --type bl33 + run_host_command_logged gxlimg \ + -t fip \ + --bl2 "${EXTRACT_DIR}/bl2.sign" \ + --ddrfw "${EXTRACT_DIR}/ddr4_1d.fw" \ + --ddrfw "${EXTRACT_DIR}/ddr4_2d.fw" \ + --ddrfw "${EXTRACT_DIR}/ddr3_1d.fw" \ + --ddrfw "${EXTRACT_DIR}/piei.fw" \ + --ddrfw "${EXTRACT_DIR}/lpddr4_1d.fw" \ + --ddrfw "${EXTRACT_DIR}/lpddr4_2d.fw" \ + --ddrfw "${EXTRACT_DIR}/diag_lpddr4.fw" \ + --ddrfw "${EXTRACT_DIR}/aml_ddr.fw" \ + --ddrfw "${EXTRACT_DIR}/lpddr3_1d.fw" \ + --bl30 "${EXTRACT_DIR}/bl30.enc" \ + --bl31 "${EXTRACT_DIR}/bl31.enc" \ + --bl33 "${EXTRACT_DIR}/bl33.enc" \ + --rev v3 u-boot.bin + + if [ ! -s u-boot.bin ]; then + display_alert "${BOARD}" "FIP repack produced empty u-boot.bin" "err" + exit 1 + fi +} diff --git a/config/boards/coolpi-genbook.csc b/config/boards/coolpi-genbook.csc index 6227dd41346e..14175dca0cc6 100644 --- a/config/boards/coolpi-genbook.csc +++ b/config/boards/coolpi-genbook.csc @@ -5,7 +5,7 @@ BOARD_MAINTAINER="andyshrk" BOARD_FIRMWARE_INSTALL="-full" BOOT_SOC="rk3588" BOOTCONFIG="coolpi-cm5-genbook-rk3588_defconfig" -KERNEL_TARGET="edge" +KERNEL_TARGET="edge,vendor" FULL_DESKTOP="yes" BOOT_LOGO="desktop" BOOT_FDT_FILE="rockchip/rk3588-coolpi-cm5-genbook.dtb" @@ -15,13 +15,13 @@ BOOT_SPI_RKSPI_LOADER="yes" IMAGE_PARTITION_TABLE="gpt" # Mainline U-Boot -function post_family_config_branch_edge__coolpi-genbook_use_mainline_uboot() { +function post_family_config__coolpi-genbook_use_mainline_uboot() { display_alert "$BOARD" "mainline (next branch) u-boot overrides for $BOARD / $BRANCH" "info" declare -g BOOTSOURCE="https://github.com/u-boot/u-boot.git" # Mainline U-Boot unset BOOTBRANCH declare -g BOOTPATCHDIR="v2025.01-rc3-coolpi-cm5" - declare -g BOOTBRANCH_BOARD="tag:v2025.01" + declare -g BOOTBRANCH_BOARD="tag:v2025.04" declare -g UBOOT_TARGET_MAP="BL31=${RKBIN_DIR}/${BL31_BLOB} ROCKCHIP_TPL=${RKBIN_DIR}/${DDR_BLOB};;u-boot-rockchip.bin u-boot-rockchip-spi.bin" unset uboot_custom_postprocess write_uboot_platform write_uboot_platform_mtd # disable stuff from rockchip64_common; we're using binman here which does all the work already diff --git a/config/boards/gateway-gz80x.conf b/config/boards/gateway-gz80x.conf index 0a05cb82d075..d5c819f9a69a 100644 --- a/config/boards/gateway-gz80x.conf +++ b/config/boards/gateway-gz80x.conf @@ -5,8 +5,8 @@ BOARD_MAINTAINER="pyavitz" BOOTCONFIG="amper_gateway_am-gz80x_defconfig" KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" -BOOTBRANCH_BOARD="tag:v2025.01" -BOOTPATCHDIR="v2025.01" +BOOTBRANCH_BOARD="tag:v2024.10" +BOOTPATCHDIR="v2024.10" BOOT_FDT_FILE="amlogic/meson-axg-amper-gateway-am-gz80x.dtb" SRC_EXTLINUX="yes" SRC_CMDLINE="console=ttyAML0,115200n8 clk_ignore_unused loglevel=7" diff --git a/config/boards/helios4.conf b/config/boards/helios4.conf index dd4709e65f41..f3b4e241fa38 100644 --- a/config/boards/helios4.conf +++ b/config/boards/helios4.conf @@ -13,4 +13,5 @@ KERNEL_TEST_TARGET="current" function post_family_config__helios4_extra_packages() { add_packages_to_image "fancontrol" + add_packages_to_image "ethtool" } diff --git a/config/boards/imb3588.conf b/config/boards/imb3588.conf new file mode 100644 index 000000000000..7dda8a81530b --- /dev/null +++ b/config/boards/imb3588.conf @@ -0,0 +1,14 @@ +# Rockchip RK3588 SoC with 4/8/16GB RAM, 16GBB/32GB/64GB/128GB EMMC, m.2 SATA, USB3, USB2, 2xGbE, WIFI6, BT5.1, LCDS, MIPI, eDP, HDMI +BOARD_NAME="IMB3588" +BOARDFAMILY="rockchip-rk3588" +BOARD_MAINTAINER="JackHuang021" +BOOTCONFIG="imb3588_defconfig" +BOOT_SOC="rk3588" +KERNEL_TARGET="vendor" +FULL_DESKTOP="yes" +BOOT_LOGO="desktop" +BOOT_FDT_FILE="rockchip/rk3588-yx-imb3588.dtb" +BOOT_SCENARIO="spl-blobs" +BOOT_SUPPORT_SPI="yes" +BOOT_SPI_RKSPI_LOADER="yes" +IMAGE_PARTITION_TABLE="gpt" diff --git a/config/boards/khadas-edge2.conf b/config/boards/khadas-edge2.conf index d64f74aca554..b7068d5048d5 100644 --- a/config/boards/khadas-edge2.conf +++ b/config/boards/khadas-edge2.conf @@ -33,7 +33,7 @@ function post_family_config__uboot_kedge2() { display_alert "$BOARD" "Configuring ($BOARD) u-boot" "info" declare -g BOOTSOURCE='https://github.com/khadas/u-boot.git' - declare -g BOOTBRANCH='branch:khadas-edges-v2017.09' + declare -g BOOTBRANCH="commit:df276095a29a02f8e7ce4f451770c06486106594" declare -g BOOTPATCHDIR="legacy/u-boot-khadas-edge2-rk3588" declare -g BOOTCONFIG="khadas-edge2-rk3588s_defconfig" declare -g SRC_EXTLINUX="yes" # For now, use extlinux. Thanks Monka diff --git a/config/boards/khadas-vim3.conf b/config/boards/khadas-vim3.conf index e9b3b7a07cad..70a127d354e3 100644 --- a/config/boards/khadas-vim3.conf +++ b/config/boards/khadas-vim3.conf @@ -12,7 +12,7 @@ BOOT_LOGO="desktop" BOOT_FDT_FILE="amlogic/meson-g12b-a311d-khadas-vim3.dtb" # there is also a s922x dtb, but vim3 is a311d only ASOUND_STATE="asound.state.khadas-vim3" -BOOTBRANCH_BOARD="tag:v2025.04-rc5" +BOOTBRANCH_BOARD="tag:v2025.04" BOOTPATCHDIR="v2025.04" # this has 'board_khadas-vim3' which has a patch to boot USB/NVMe/SCSI first declare -g KHADAS_OOWOW_BOARD_ID="VIM3" # for use with EXT=output-image-oowow diff --git a/config/boards/mixtile-blade3.csc b/config/boards/mixtile-blade3.csc index 408b232c10f0..7f74e2481bee 100644 --- a/config/boards/mixtile-blade3.csc +++ b/config/boards/mixtile-blade3.csc @@ -12,8 +12,13 @@ declare -g UEFI_EDK2_BOARD_ID="blade3" # This _only_ used for uefi-edk2-rk3588 e # Vendor u-boot; use the default family (rockchip-rk3588) u-boot. See config/sources/families/rockchip-rk3588.conf function post_family_config__vendor_uboot_mekotronics() { - display_alert "$BOARD" "Configuring $BOARD vendor u-boot" "info" + display_alert "$BOARD" "Configuring $BOARD vendor u-boot (using Radxa's older next-dev-v2024.03)" "info" declare -g BOOTDELAY=1 # build injects this into u-boot config. we can then get into UMS mode and avoid the whole rockusb/rkdeveloptool thing + + # Override the stuff from rockchip-rk3588 family; Meko's have a patch for stable MAC address that breaks with Radxa's next-dev-v2024.10+ + declare -g BOOTSOURCE='https://github.com/radxa/u-boot.git' + declare -g BOOTBRANCH='branch:next-dev-v2024.03' # NOT next-dev-v2024.10 + declare -g BOOTPATCHDIR="legacy/u-boot-radxa-rk35xx" } function post_family_config_branch_edge__different_dtb_for_edge() { diff --git a/config/boards/nanopct6.conf b/config/boards/nanopct6.conf index d979ff51d007..2dc95c3cd2d0 100644 --- a/config/boards/nanopct6.conf +++ b/config/boards/nanopct6.conf @@ -30,16 +30,22 @@ function post_family_tweaks__nanopct6_naming_audios() { } # Mainline u-boot -function post_family_config_branch_edge__nanopct6_use_mainline_uboot() { - display_alert "$BOARD" "mainline (next branch) u-boot overrides for $BOARD / $BRANCH" "info" +function post_family_config__nanopct6_use_mainline_uboot() { + [[ "${BRANCH}" == "vendor" ]] && return 0 # Not for 'vendor' branch, which uses 2017.09 vendor u-boot from Radxa + + display_alert "$BOARD" "u-boot overrides for $BOARD / $BRANCH" "info" + + # To reuse ATF code in rockchip64_common, let's change the BOOT_SCENARIO and call prepare_boot_configuration() again + BOOT_SCENARIO="tpl-blob-atf-mainline" + prepare_boot_configuration declare -g BOOTCONFIG="nanopc-t6-rk3588_defconfig" declare -g BOOTDELAY=1 # Wait for UART interrupt to enter UMS/RockUSB mode etc declare -g BOOTSOURCE="https://github.com/u-boot/u-boot.git" # We ❤️ Mainline - declare -g BOOTBRANCH="tag:v2025.04-rc1" + declare -g BOOTBRANCH="tag:v2025.04" declare -g BOOTPATCHDIR="v2025.04" declare -g BOOTDIR="u-boot-${BOARD}" # do not share u-boot directory - declare -g UBOOT_TARGET_MAP="BL31=${RKBIN_DIR}/${BL31_BLOB} ROCKCHIP_TPL=${RKBIN_DIR}/${DDR_BLOB};;u-boot-rockchip.bin u-boot-rockchip-spi.bin" + declare -g UBOOT_TARGET_MAP="BL31=bl31.elf ROCKCHIP_TPL=${RKBIN_DIR}/${DDR_BLOB};;u-boot-rockchip.bin u-boot-rockchip-spi.bin" unset uboot_custom_postprocess write_uboot_platform write_uboot_platform_mtd # disable stuff from rockchip64_common; we're using binman here which does all the work already # Just use the binman-provided u-boot-rockchip.bin, which is ready-to-go @@ -55,12 +61,13 @@ function post_family_config_branch_edge__nanopct6_use_mainline_uboot() { # U-boot 2025.04+ can detect and set fdtfile automatically across T6 and T6-LTS boards. # So if using mainline u-boot, unset BOOT_FDT_FILE to let u-boot handle it. # That way, both variants can boot from the same image; lets keep the -lts board file for vendor kernel/u-boot. -function post_family_config_branch_edge__t6_and_t6_lts_auto_dtb_name_via_uboot_detection() { +function post_family_config__t6_and_t6_lts_auto_dtb_name_via_uboot_detection() { + [[ "${BRANCH}" == "vendor" ]] && return 0 # Not for 'vendor' branch, which uses 2017.09 vendor u-boot from Radxa unset BOOT_FDT_FILE } function pre_config_uboot_target__nanoptc6_patch_uboot_dtsi_for_ums() { - [[ "${BRANCH}" != "edge" ]] && return 0 + [[ "${BRANCH}" == "vendor" ]] && return 0 # Not for 'vendor' branch, which uses 2017.09 vendor u-boot from Radxa display_alert "u-boot for ${BOARD}" "u-boot: add to u-boot dtsi for UMS" "info" # avoid a patch, just append to the dtsi file cat <<- EOD >> arch/arm/dts/rk3588-nanopc-t6-u-boot.dtsi # Append to the t6 u-boot dtsi file with stuff for enabling gadget/otg/peripheral mode @@ -69,6 +76,9 @@ function pre_config_uboot_target__nanoptc6_patch_uboot_dtsi_for_ums() { &usbdp_phy0 { status = "okay"; }; &usb_host0_xhci { dr_mode = "peripheral"; maximum-speed = "high-speed"; status = "okay"; }; EOD + # Append to the t6 u-boot dtsi file with stuff for enabling gadget/otg/peripheral mode + # Append to the t6 u-boot dtsi file with stuff for enabling gadget/otg/peripheral mode + # Append to the t6 u-boot dtsi file with stuff for enabling gadget/otg/peripheral mode } @@ -85,7 +95,7 @@ function pre_config_uboot_target__nanopct6_patch_rockchip_common_boot_order() { } function post_config_uboot_target__extra_configs_for_nanopct6_mainline_environment_in_spi() { - [[ "${BRANCH}" != "edge" ]] && return 0 + [[ "${BRANCH}" == "vendor" ]] && return 0 # Not for 'vendor' branch, which uses 2017.09 vendor u-boot from Radxa display_alert "u-boot for ${BOARD}/${BRANCH}" "u-boot: enable board-specific configs (env in SPI)" "info" run_host_command_logged scripts/config --enable CONFIG_DM_PMIC_FAN53555 @@ -134,7 +144,7 @@ function post_config_uboot_target__extra_configs_for_nanopct6_mainline_environme # Include fw_setenv, configured to point to the correct spot on the SPI Flash PACKAGE_LIST_BOARD="libubootenv-tool" # libubootenv-tool provides fw_printenv and fw_setenv, for talking to U-Boot environment function post_family_tweaks__config_nanopct6_fwenv() { - [[ "${BRANCH}" != "edge" ]] && return 0 + [[ "${BRANCH}" == "vendor" ]] && return 0 # Not for 'vendor' branch, which uses 2017.09 vendor u-boot from Radxa display_alert "Configuring fw_printenv and fw_setenv" "for ${BOARD} and u-boot ${BOOTBRANCH}" "info" # Addresses below come from CONFIG_ENV_OFFSET and CONFIG_ENV_SIZE in defconfig cat <<- 'FW_ENV_CONFIG' > "${SDCARD}"/etc/fw_env.config diff --git a/config/boards/nanopi-r3s-lts.conf b/config/boards/nanopi-r3s-lts.conf new file mode 100644 index 000000000000..e7c637bd386a --- /dev/null +++ b/config/boards/nanopi-r3s-lts.conf @@ -0,0 +1,30 @@ +# Rockchip RK3566 quad core 2GB RAM eMMC 2x GbE USB3 HDMI +BOARD_NAME="NanoPi R3S LTS" +BOARDFAMILY="rk35xx" +BOARD_MAINTAINER="pyavitz" +BOOTCONFIG="nanopi-r3s-lts-rk3566_defconfig" +KERNEL_TARGET="current,edge" +KERNEL_TEST_TARGET="current,edge" +BOOT_FDT_FILE="rockchip/rk3566-nanopi-r3s-lts.dtb" +IMAGE_PARTITION_TABLE="gpt" +BOOT_SCENARIO="spl-blobs" + + +function post_family_config__use_mainline_uboot() { + if [[ "$BRANCH" != "current" && "$BRANCH" != "edge" ]]; then + return 0 + fi + unset BOOTFS_TYPE # mainline u-boot can boot ext4 directly + BOOTCONFIG="nanopi-r3s-lts-rk3566_defconfig" + BOOTSOURCE="https://github.com/u-boot/u-boot" + BOOTBRANCH="tag:v2025.04" + BOOTPATCHDIR="v2025.04" + + UBOOT_TARGET_MAP="BL31=$RKBIN_DIR/$BL31_BLOB ROCKCHIP_TPL=$RKBIN_DIR/$DDR_BLOB;;u-boot-rockchip.bin" + + unset uboot_custom_postprocess write_uboot_platform write_uboot_platform_mtd + + function write_uboot_platform() { + dd if=$1/u-boot-rockchip.bin of=$2 seek=64 conv=notrunc status=none + } +} diff --git a/config/boards/odroidhc4.conf b/config/boards/odroidhc4.conf index b3bfc9e1db19..c9a29357e9f2 100644 --- a/config/boards/odroidhc4.conf +++ b/config/boards/odroidhc4.conf @@ -2,7 +2,7 @@ BOARD_NAME="Odroid HC4" BOARDFAMILY="meson-sm1" BOARD_MAINTAINER="igorpecovnik" -BOOTCONFIG="odroid-c4_defconfig" # for the SD card; but also 'odroid-hc4_defconfig', see below at pre_config_uboot_target +BOOTCONFIG="odroid-hc4_defconfig" KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" MODULES_BLACKLIST="simpledrm" # SimpleDRM conflicts with Panfrost @@ -12,8 +12,8 @@ BOOT_FDT_FILE="amlogic/meson-sm1-odroid-hc4.dtb" PACKAGE_LIST_BOARD="lm-sensors fancontrol" # SPI, sensors, manual fan control via 'pwmconfig' # Newer u-boot for the HC4. There's patches in `board_odroidhc4` for the defconfigs used in the UBOOT_TARGET_MAP below. -BOOTBRANCH_BOARD="tag:v2024.04" -BOOTPATCHDIR="v2024.04" +BOOTBRANCH_BOARD="tag:v2025.04" +BOOTPATCHDIR="v2025.04" # We build u-boot twice: C4 config for SD cards, and HC4 (with SATA/PCI/SPI) config for SPI. UBOOT_TARGET_MAP=" @@ -39,22 +39,6 @@ function post_uboot_custom_postprocess__odroid_hc4_uboot() { uboot_g12_postprocess "${SRC}"/cache/sources/amlogic-boot-fip/odroid-hc4 g12a } -# switch defconfig according to target, so we can still use the same post_config_uboot_target for both. -function pre_config_uboot_target__odroidhc4_defconfig_per_target() { - case "${target_make}" in - "armbian_target=spi "*) - BOOTCONFIG="odroid-hc4_defconfig" - ;; - "armbian_target=sd "*) - BOOTCONFIG="odroid-c4_defconfig" - ;; - *) - exit_with_error "Unknown target_make: '${target_make}', unknown BOOTCONFIG." - ;; - esac - display_alert "setting BOOTCONFIG for target" "${target_make}: '${BOOTCONFIG}'" "info" -} - # Enable extra u-boot .config options, this way we avoid patching defconfig function post_config_uboot_target__extra_configs_for_odroid_hc4() { display_alert "u-boot for ${BOARD}" "u-boot: enable preboot & pci+usb start in preboot" "info" diff --git a/config/boards/orangepi5-ultra.csc b/config/boards/orangepi5-ultra.csc index f5c389fdd40b..7fda2c1591dd 100644 --- a/config/boards/orangepi5-ultra.csc +++ b/config/boards/orangepi5-ultra.csc @@ -1,4 +1,4 @@ -# Rockchip RK3588 octa core whatever fixme +# Rockchip RK3588 octa core 4/8/16GB RAM SoC SPI NVMe 2x USB2 2x USB3 HDMI HDMI-in BOARD_NAME="Orange Pi 5 Ultra" BOARDFAMILY="rockchip-rk3588" BOARD_MAINTAINER="" @@ -16,15 +16,6 @@ IMAGE_PARTITION_TABLE="gpt" #enable_extension "bcmdhd" BCMDHD_TYPE="sdio" -# for testing purpose only. needs adaption to mainline once this makes it into 6.15 or .16 -function post_family_config_branch_edge__orangepi5-ultra_use_custom_source() { - KERNEL_MAJOR_MINOR="6.14" # Major and minor versions of this kernel. - KERNELSOURCE='https://github.com/jimmyhon/linux.git' - KERNELBRANCH='branch:integrate-6.15' - KERNELPATCHDIR='integrate-6.15' - EXTRAWIFI=no # due to absence of our own fixups 3rd party wifi drivers break -} - function post_family_tweaks__orangepi5ultra_naming_audios() { display_alert "$BOARD" "Renaming orangepi5ultra audios" "info" diff --git a/config/boards/pocketbeagle2.csc b/config/boards/pocketbeagle2.conf similarity index 83% rename from config/boards/pocketbeagle2.csc rename to config/boards/pocketbeagle2.conf index 89cec36df409..44b98f72324f 100644 --- a/config/boards/pocketbeagle2.csc +++ b/config/boards/pocketbeagle2.conf @@ -13,8 +13,9 @@ KERNEL_TEST_TARGET="edge" SERIALCON="ttyS2" ATF_BOARD="lite" SRC_EXTLINUX="yes" -SRC_CMDLINE="console=ttyS2,115200n8" +SRC_CMDLINE="root=/dev/mmcblk1p2 rootwait console=ttyS2,115200n8" BOOT_FDT_FILE="ti/k3-am6232-pocketbeagle2.dtb" +OPTEE_PLATFORM="k3-am62x" #Until PB2 goes upstream, use this branch function post_family_config_branch_edge__pocketbeagle2_use_beagle_kernel_uboot() { @@ -22,9 +23,9 @@ function post_family_config_branch_edge__pocketbeagle2_use_beagle_kernel_uboot() declare -g KERNELSOURCE="https://github.com/beagleboard/linux" # BeagleBoard kernel declare -g KERNEL_MAJOR_MINOR="6.12" - declare -g KERNELBRANCH="branch:v6.12.13-ti-arm64-r24" + declare -g KERNELBRANCH="branch:v6.12.24-ti-arm64-r42" declare -g LINUXFAMILY="k3-beagle" # Separate kernel package from the regular `k3` family declare -g BOOTSOURCE="https://github.com/beagleboard/u-boot" # BeagleBoard u-boot - declare -g BOOTBRANCH="branch:v2025.01-pocketbeagle2" + declare -g BOOTBRANCH="branch:v2025.04-pocketbeagle2" } diff --git a/config/boards/quartz64a.csc b/config/boards/quartz64a.csc index c1f638824846..b4a5b265df5f 100644 --- a/config/boards/quartz64a.csc +++ b/config/boards/quartz64a.csc @@ -16,9 +16,9 @@ function post_family_config__quartz64_a_use_mainline_uboot() { display_alert "$BOARD" "Using mainline U-Boot for $BOARD / $BRANCH" "info" declare -g BOOTSOURCE="https://github.com/u-boot/u-boot.git" # We ❤️ Mainline U-Boot - declare -g BOOTBRANCH="tag:v2024.07" - declare -g BOOTPATCHDIR="v2024.07/board_${BOARD}" - # Don't set BOOTDIR, allow shared U-Boot source directory for disk space efficiency + declare -g BOOTBRANCH="tag:v2025.04" + declare -g BOOTPATCHDIR="v2025.04" + declare -g BOOTDELAY=1 # Wait for UART interrupt to enter UMS/RockUSB mode etc declare -g UBOOT_TARGET_MAP="BL31=${RKBIN_DIR}/${BL31_BLOB} ROCKCHIP_TPL=${RKBIN_DIR}/${DDR_BLOB};;u-boot-rockchip.bin" @@ -30,3 +30,65 @@ function post_family_config__quartz64_a_use_mainline_uboot() { dd "if=$1/u-boot-rockchip.bin" "of=$2" bs=32k seek=1 conv=notrunc status=none } } + +# Quartz64a's OTG port is the BLACK one, on top of the USB3 port. Use an USB-A cable; not all cables work. +function pre_config_uboot_target__quartz64a_patch_uboot_dtsi_for_ums() { + display_alert "u-boot for ${BOARD}" "u-boot: add to u-boot dtsi for UMS" "info" # avoid a patch, just append to the dtsi file + cat <<- UBOOT_BOARD_DTSI_OTG >> arch/arm/dts/rk3566-quartz64-a-u-boot.dtsi + &usb_host0_xhci { dr_mode = "otg"; }; + UBOOT_BOARD_DTSI_OTG +} + +# "rockchip-common: boot SD card first, then NVMe, then SATA, then USB, then mmc" +# On quartz64a, mmc0 is the eMMC, mmc1 is the SD card slot +function pre_config_uboot_target__quartz64a_patch_rockchip_common_boot_order() { + declare -a rockchip_uboot_targets=("mmc1" "nvme" "scsi" "usb" "mmc0" "pxe" "dhcp" "spi") # for future make-this-generic delight + display_alert "u-boot for ${BOARD}/${BRANCH}" "u-boot: adjust boot order to '${rockchip_uboot_targets[*]}'" "info" + sed -i -e "s/#define BOOT_TARGETS.*/#define BOOT_TARGETS \"${rockchip_uboot_targets[*]}\"/" include/configs/rockchip-common.h + regular_git diff -u include/configs/rockchip-common.h || true +} + +# A better equivalent to patching a defconfig, do changes to .config via code. +# For UMS/RockUSB to work in u-boot, &usb_host0_xhci { dr_mode = "otg" } is required. See 0002-board-rockchip-ODROID-M1-override-kernel-DT-for-xhci-otg-dr_mode.patch +function post_config_uboot_target__extra_configs_for_quartz64a() { + [[ "${BRANCH}" == "edge" || "${BRANCH}" == "current" ]] || return 0 + + display_alert "u-boot for ${BOARD}" "u-boot: enable preboot & flash leds in preboot" "info" + run_host_command_logged scripts/config --enable CONFIG_USE_PREBOOT + run_host_command_logged scripts/config --set-str CONFIG_PREBOOT "'echo armbian leds; led diy-led on; led work-led on; sleep 0.1; led diy-led off; led work-led off; sleep 0.1; led diy-led on;'" # double quote + + display_alert "u-boot for ${BOARD}" "u-boot: enable EFI debugging command" "info" + run_host_command_logged scripts/config --enable CMD_EFIDEBUG + run_host_command_logged scripts/config --enable CMD_NVEDIT_EFI + + display_alert "u-boot for ${BOARD}" "u-boot: enable more compression support" "info" + run_host_command_logged scripts/config --enable CONFIG_LZO + run_host_command_logged scripts/config --enable CONFIG_BZIP2 + run_host_command_logged scripts/config --enable CONFIG_ZSTD + + display_alert "u-boot for ${BOARD}" "u-boot: enable gpio LED support" "info" + run_host_command_logged scripts/config --enable CONFIG_LED + run_host_command_logged scripts/config --enable CONFIG_LED_GPIO + + display_alert "u-boot for ${BOARD}" "u-boot: enable networking cmds" "info" + run_host_command_logged scripts/config --enable CONFIG_CMD_NFS + run_host_command_logged scripts/config --enable CONFIG_CMD_WGET + run_host_command_logged scripts/config --enable CONFIG_CMD_DNS + run_host_command_logged scripts/config --enable CONFIG_PROT_TCP + run_host_command_logged scripts/config --enable CONFIG_PROT_TCP_SACK + + display_alert "u-boot for ${BOARD}" "u-boot: enable more cmdline commands" "info" # for extra compat with eg HAOS + run_host_command_logged scripts/config --enable CONFIG_CMD_SQUASHFS + run_host_command_logged scripts/config --enable CONFIG_CMD_SETEXPR + run_host_command_logged scripts/config --enable CONFIG_CMD_FILEENV # added via cmd-fileenv-read-string-from-file-into-env.patch + run_host_command_logged scripts/config --enable CONFIG_CMD_CAT + run_host_command_logged scripts/config --enable CONFIG_CMD_XXD + + display_alert "u-boot for ${BOARD}/${BRANCH}" "u-boot: enabling UMS/RockUSB Gadget functionality" "info" + declare -a enable_configs=("CONFIG_CMD_USB_MASS_STORAGE" "CONFIG_USB_GADGET" "USB_GADGET_DOWNLOAD" "CONFIG_USB_FUNCTION_ROCKUSB" "CONFIG_USB_FUNCTION_ACM" "CONFIG_CMD_ROCKUSB" "CONFIG_CMD_USB_MASS_STORAGE") + for config in "${enable_configs[@]}"; do + run_host_command_logged scripts/config --enable "${config}" + done + # Auto-enabled by the above, force off... + run_host_command_logged scripts/config --disable USB_FUNCTION_FASTBOOT +} diff --git a/config/boards/sk-am62b.conf b/config/boards/sk-am62b.conf index ac99b9a14baa..b6e16a56da54 100644 --- a/config/boards/sk-am62b.conf +++ b/config/boards/sk-am62b.conf @@ -13,3 +13,5 @@ KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="lite" +OPTEE_ARGS="CFG_TEE_CORE_LOG_LEVEL=1" +OPTEE_PLATFORM="k3-am62x" diff --git a/config/boards/sk-am64b.conf b/config/boards/sk-am64b.conf index d9cdbdf6d9fd..153f34c1bdb1 100644 --- a/config/boards/sk-am64b.conf +++ b/config/boards/sk-am64b.conf @@ -14,3 +14,5 @@ KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="lite" +OPTEE_ARGS="" +OPTEE_PLATFORM="k3-am64x" diff --git a/config/boards/sk-am68.conf b/config/boards/sk-am68.conf index d731dc1e50d5..dada63fac49d 100644 --- a/config/boards/sk-am68.conf +++ b/config/boards/sk-am68.conf @@ -14,3 +14,5 @@ KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="generic" ATF_K3_USART_OFFSET="K3_USART=0x8" +OPTEE_ARGS="CFG_CONSOLE_UART=0x8" +OPTEE_PLATFORM="k3-j784s4" diff --git a/config/boards/sk-am69.conf b/config/boards/sk-am69.conf index 9a46b214f055..bb3eeda78146 100644 --- a/config/boards/sk-am69.conf +++ b/config/boards/sk-am69.conf @@ -14,3 +14,5 @@ KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="j784s4" ATF_K3_USART_OFFSET="K3_USART=0x8" +OPTEE_ARGS="CFG_CONSOLE_UART=0x8" +OPTEE_PLATFORM="k3-j784s4" diff --git a/config/boards/sk-tda4vm.conf b/config/boards/sk-tda4vm.conf index 7236a1e0c162..f3b8348813ba 100644 --- a/config/boards/sk-tda4vm.conf +++ b/config/boards/sk-tda4vm.conf @@ -16,3 +16,5 @@ KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" SERIALCON="ttyS2" ATF_BOARD="generic" +OPTEE_ARGS="" +OPTEE_PLATFORM="k3-j721e" diff --git a/config/boards/smart-am40.csc b/config/boards/smart-am40.csc index ae0ee4dd7c88..d3bede5e651d 100644 --- a/config/boards/smart-am40.csc +++ b/config/boards/smart-am40.csc @@ -5,13 +5,13 @@ BOARD_MAINTAINER="" BOOTCONFIG="am40-rk3399_defconfig" KERNEL_TARGET="current,edge" KERNEL_TEST_TARGET="current" -MODULES_CURRENT="extcon_usbc_virtual_pd" -MODULES_EDGE="extcon_usbc_virtual_pd" +MODULES_CURRENT="extcon-usbc-virtual-pd" +MODULES_EDGE="extcon-usbc-virtual-pd" FULL_DESKTOP="yes" BOOT_LOGO="desktop" BOOT_FDT_FILE="rockchip/rk3399-am40.dtb" -BOOTBRANCH_BOARD="tag:v2024.10" -BOOTPATCHDIR="v2024.10" +BOOTBRANCH_BOARD="tag:v2025.04" +BOOTPATCHDIR="v2025.04" BOOT_SCENARIO="binman" SRC_EXTLINUX="yes" SRC_CMDLINE="console=ttyS2,1500000 console=tty0" diff --git a/config/boards/thinkpad-x13s.conf b/config/boards/thinkpad-x13s.conf index 58c2676e55f5..c84b3e9638ea 100644 --- a/config/boards/thinkpad-x13s.conf +++ b/config/boards/thinkpad-x13s.conf @@ -27,8 +27,8 @@ enable_extension "grub-with-dtb" # important, puts the whole DTB handling in pla declare -g BOARD_FIRMWARE_INSTALL="-full" function post_family_config_branch_sc8280xp__jhovolds_wip_kernel() { - declare -g KERNEL_MAJOR_MINOR="6.14" # Major and minor versions of this kernel. - declare -g KERNELBRANCH='branch:wip/sc8280xp-6.14' # @TODO: this is down to 31 patches, from hundreds back in the day. Considering merging this with default arm64 uefi kernel + declare -g KERNEL_MAJOR_MINOR="6.15" # Major and minor versions of this kernel. + declare -g KERNELBRANCH='branch:wip/sc8280xp-6.15' # @TODO: this is up to 47 patches, from 28 around 6.13; wait a bit until speculating about merging with uefi-arm64 declare -g KERNELSOURCE='https://github.com/jhovold/linux.git' declare -g LINUXCONFIG="linux-${ARCH}-${BRANCH}" # for this board: linux-arm64-sc8280xp display_alert "Set up jhovold's kernel ${KERNELBRANCH} for" "${BOARD}" "info" diff --git a/config/boards/tinkerboard-2.csc b/config/boards/tinkerboard-2.csc index dbe12a6318ad..d01674aaed3b 100644 --- a/config/boards/tinkerboard-2.csc +++ b/config/boards/tinkerboard-2.csc @@ -9,8 +9,8 @@ FULL_DESKTOP="yes" BOOT_LOGO="desktop" BOOT_FDT_FILE="rockchip/rk3399-tinker-2.dtb" SERIALCON="ttyS2" -BOOT_SCENARIO="spl-blobs" # 'blobless' also works; but some RAM issues found; see rk33/rk3399_ddr_800MHz_v1.27.bin in rockchip64_common.inc +BOOT_SCENARIO="binman" # 'blobless' also works; but some RAM issues found; see rk33/rk3399_ddr_800MHz_v1.27.bin in rockchip64_common.inc BOARD_FIRMWARE_INSTALL="-full" # Install full firmware, for rtl8822ce firmware and others -BOOTBRANCH="tag:v2021.07" # v2021.07 ... +BOOTBRANCH="tag:v2025.04" # v2025.04 ... BOOTPATCHDIR='legacy/u-boot-tinkerboard2' # ... with _only_ the patches we need for TB2, not the default rockchip64 DDR_BLOB="rk33/rk3399_ddr_800MHz_v1.27.bin" # Different blob for TB2 diff --git a/config/bootscripts/boot-mvebu.cmd b/config/bootscripts/boot-mvebu.cmd index 9b9b1fd54351..399508926cdc 100644 --- a/config/bootscripts/boot-mvebu.cmd +++ b/config/bootscripts/boot-mvebu.cmd @@ -3,187 +3,539 @@ # Please edit /boot/armbianEnv.txt to set supported parameters # -setenv load_addr "0x00300000" -setenv fdt_addr_r "0x02040000" # max size 256 KiB (=dtb+dto+fdt_extrasize) -setenv kernel_addr_r "0x02080000" # max size 16 MiB -setenv ramdisk_addr_r "0x03080000" +# NOTE +# If you intend to use 'outside' of 'global' variables from U-Boot, make sure that you do not change them! +# The boot logic will attempt a list of 'boot_targets' that all might rely on (environment) variables that +# have been set by U-Boot, either compile-time or as part of U-Boot's default 'bootcmd'. +# Any variable that this bootscript uses needs to be set explicitly and not conflict with any pre-set variables. +# Variables that we might change will be saved in preset_x and variables we use will be copied into l_x. -# default values -setenv overlay_error "false" -setenv rootdev "/dev/mmcblk0p1" -setenv rootfstype "ext4" -setenv verbosity "1" +# default environment variables +setenv align_overlap_oboe_avoidance "on" +setenv align_to "0x00001000" +setenv console "both" +setenv docker_optimizations "on" +setenv earlycon "off" setenv emmc_fix "off" -setenv spi_workaround "off" -setenv ethaddr "00:50:43:84:fb:2f" setenv eth1addr "00:50:43:25:fb:84" setenv eth2addr "00:50:43:84:25:2f" setenv eth3addr "00:50:43:0d:19:18" +setenv ethaddr "00:50:43:84:fb:2f" setenv exit_on_critical_errors "on" setenv fdt_extrasize "0x00010000" -setenv align_to "0x00001000" -setenv align_overlap_oboe_avoidance "on" -setenv align_addr_next 'if test "${align_overlap_oboe_avoidance}" = "on" ; then setexpr addr_next ${addr_next} + 1 ; fi ; setexpr modulo ${addr_next} % ${align_to} ; if itest ${modulo} -gt 0 ; then setexpr addr_next ${addr_next} / ${align_to} ; setexpr addr_next ${addr_next} + 1 ; setexpr addr_next ${addr_next} * ${align_to} ; fi' +setenv kver +setenv load_addr_calc +setenv overlay_error "false" +setenv preset_fdtdir "${fdtdir}" +setenv preset_fdtfile "${fdtfile}" +setenv preset_kernel_comp_addr_r "${kernel_comp_addr_r}" +setenv preset_kernel_comp_size "${kernel_comp_size}" +setenv rootdev "/dev/mmcblk${devnum}p${distro_bootpart}" +setenv rootfstype "ext4" +setenv spi_workaround "off" +setenv vendor "marvell" +setenv verbosity "1" + +# load addresses +setenv load_addr "0x00300000" +setenv fdt_addr_r "0x02040000" # max size 256 KiB (=dtb+dto+fdt_extrasize) +setenv kernel_addr_r "0x02080000" # max size 16 MiB +setenv ramdisk_addr_r "0x03080000" -if setexpr setexpr 1 + 1 ; then - setenv setexpr "available" +# environment run variables +setenv func_align_addr_next ' + test "${align_overlap_oboe_avoidance}" = "on" && setexpr l_addr_next ${l_addr_next} + 1 ; + setexpr modulo ${l_addr_next} % ${align_to} ; + if itest ${modulo} -gt 0 ; then + setexpr l_addr_next ${l_addr_next} / ${align_to} ; + setexpr l_addr_next ${l_addr_next} + 1 ; + setexpr l_addr_next ${l_addr_next} * ${align_to} ; + fi' +setenv func_inform 'test "${verbosity}" = "" || itest ${verbosity} -gt 0 && echo "${l_message}"' +setenv func_warn 'echo "** WARNING: ${l_message}"' +setenv func_critical_error ' + echo "!! CRITICAL: ${l_message}" ; + if test "${exit_on_critical_errors}" = "on" ; then + false ; + else + true ; + fi' + +# set some defaults in case there are no pre-sets +if test "${envfile}" = "" ; then + setenv l_envfile 'armbianEnv.txt' else - echo "** Command `setexpr` not available - using configured load addresses" + setenv l_envfile "${envfile}" fi -echo "Boot script loaded from ${devtype}" +echo "Boot script loaded from ${devtype} ${devnum}:${distro_bootpart}." + +# load (merge) on-disk environment +setenv l_file "${prefix}${l_envfile}" +if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${l_file} ; then + if env import -t ${load_addr} ${filesize} ; then + setenv l_message "Loaded/imported environment ${l_file} to/from ${load_addr}." + run func_inform + else + setenv l_message "Could not import environment ${l_file} - using default environment!" + run func_warn + fi + else + setenv l_message "Could not load environment ${l_file} - using default environment!" + run func_warn + fi +fi -setenv something "environment ${prefix}armbianEnv.txt from ${devtype} to ${load_addr}" -echo "Loading ${something} ..." -if load ${devtype} ${devnum} ${load_addr} ${prefix}armbianEnv.txt; then - env import -t ${load_addr} ${filesize} +# compose kernel commandline options (bootargs) +setenv consoleargs +if test "${console}" = "display" || test "${console}" = "both" ; then + setenv consoleargs "console=tty1" +fi +if test "${console}" = "serial" || test "${console}" = "both" ; then + setenv consoleargs "console=ttyS0,115200 ${consoleargs}" +fi +if test "${earlycon}" = "on" ; then + setenv consoleargs "earlycon ${consoleargs}" +fi +if test "${bootlogo}" = "true" ; then + setenv consoleargs "splash plymouth.ignore-serial-consoles ${consoleargs}" else - echo "** Could not load ${something} - using default environment" + setenv consoleargs "splash=verbose ${consoleargs}" fi -setenv bootargs "console=ttyS0,115200 root=${rootdev} rootwait rootfstype=${rootfstype} ubootdev=${devtype} scandelay loglevel=${verbosity} usb-storage.quirks=${usbstoragequirks} ${extraargs}" +part uuid ${devtype} ${devnum}:${distro_bootpart} l_ubootpart -setenv something "DT ${prefix}dtb/${fdtfile} from ${devtype} to ${fdt_addr_r}" -echo "Loading ${something} ..." -if load ${devtype} ${devnum} ${fdt_addr_r} ${prefix}dtb/${fdtfile} ; then -else - echo "!! CRITICAL - Could not load ${something}" - if test "${exit_on_critical_errors}" = "on" ; then - exit - fi +setenv bootargs "root=${rootdev} rootfstype=${rootfstype} rootwait ${consoleargs} consoleblank=0 loglevel=${verbosity} ubootpart=${l_ubootpart} usb-storage.quirks=${usbstoragequirks} ${extraargs} ${extraboardargs}" + +if test "${docker_optimizations}" = "on" ; then + setenv bootargs "${bootargs} cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory" fi -setenv fdt_filesize ${filesize} -fdt addr ${fdt_addr_r} -fdt resize ${fdt_extrasize} +if test "${vendor}" = "allwinner" ; then + if test "${disp_mem_reserves}" = "off" ; then + setenv bootargs "${bootargs} sunxi_ve_mem_reserve=0 sunxi_g2d_mem_reserve=0 sunxi_fb_mem_reserve=16" + fi +fi +if test "${vendor}" = "marvell" ; then + # nothing here yet +fi +if test "${vendor}" = "rockchip" ; then + # nothing here yet +fi -for overlay_file in ${overlays}; do - setenv something "kernel provided DT overlay ${overlay_prefix}-${overlay_file}.dtbo from ${devtype} to ${load_addr}" - echo "Loading ${something} ..." - if load ${devtype} ${devnum} ${load_addr} ${prefix}dtb/overlay/${overlay_prefix}-${overlay_file}.dtbo; then - fdt apply ${load_addr} || setenv overlay_error "true" +# check if we are requested (or are able to) use load address calculation +if test "${load_addr_calc}" = "" ; then + if setexpr load_addr_calc 1 + 1 ; then + setenv load_addr_calc 'on' else - echo "** Could not load ${something}" + setenv load_addr_calc 'off' fi -done +fi +if test "${load_addr_calc}" != "on" ; then + setenv load_addr_calc 'off' + + setenv l_message "Using fixed load addresses." + run func_inform + setenv l_message " fdt_addr_r: ${fdt_addr_r}" + run func_inform + setenv l_message " kernel_addr_r: ${kernel_addr_r}" + run func_inform + setenv l_message " ramdisk_addr_r: ${ramdisk_addr_r}" + run func_inform +fi -for overlay_file in ${user_overlays}; do - setenv something "user provided DT overlay ${overlay_file}.dtbo from ${devtype} to ${load_addr}" - echo "Loading ${something}" - if load ${devtype} ${devnum} ${load_addr} ${prefix}overlay-user/${overlay_file}.dtbo; then - fdt apply ${load_addr} || setenv overlay_error "true" +if test "${kver}" != "" ; then + setenv l_message "Using version override ${kver} for image loading." + run func_inform +fi + +# set a default kernel image type in case 'setexpr' not available +if test "${cpu}" = "armv8" ; then + # aarch64 uses a flat kernel image + setenv l_kernel_image_type "flat" + setenv l_bootfile "Image${kver}" +else + if test "${cpu}" = "armv7" ; then + # aarch32 mostly uses compressed kernel image + setenv l_kernel_image_type "compressed" + setenv l_bootfile "zImage${kver}" else - echo "** Could not load ${something}" + # per default use compressed kernel image + setenv l_kernel_image_type "compressed" + setenv l_bootfile "zImage${kver}" fi -done +fi -if test "${overlay_error}" = "true"; then - echo "** Error applying DT overlays" - setenv something "original DT ${prefix}dtb/${fdtfile} from ${devtype} to ${fdt_addr_r}" - echo "Restoring ${something} ..." - if load ${devtype} ${devnum} ${fdt_addr_r} ${prefix}dtb/${fdtfile} ; then - fdt addr ${fdt_addr_r} - fdt resize ${fdt_extrasize} +setenv l_ramdiskfile "uInitrd${kver}" + +# $fdtdir: +# some boards use "${prefix}dtb/" others use "${prefix}dtb/${vendor}/" as base location for the DT files +# user can also override by specifying an fdtdir=... in armbianEnv.txt +# try any U-Boot built-in (or pre-set) fdtdir as last resort +# $fdtfile: +# some boards use a "filename.dts" others use "${vendor}/filename.dts" +# user can also override by specifying an fdtfile=... in armbianEnv.txt +# strip any leading path components and try any U-Boot built-in (or pre-set) fdtfile as last resort + +setenv l_fdtfile_basename +setexpr l_fdtfile_basename sub ".*/" "" "${fdtfile}" +if test "${l_fdtfile_basename}" = "" ; then + setenv l_fdtfile_basename "${fdtfile}" +fi + +setenv l_fdtdir "${fdtdir}" +setenv l_fdtfile "${l_fdtfile_basename}" +if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true +else + setenv l_fdtdir "${prefix}dtb${kver}/${vendor}" + setenv l_fdtfile "${l_fdtfile_basename}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true else - echo "!! CRITICAL - Could not restore ${something}" - if test "${exit_on_critical_errors}" = "on" ; then - exit + setenv l_fdtdir "${prefix}dtb${kver}" + setenv l_fdtfile "${l_fdtfile_basename}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true + else + setenv l_fdtdir "${fdtdir}" + setenv l_fdtfile "${fdtfile}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true + else + setenv l_fdtdir "${preset_fdtdir}" + setenv l_fdtfile "${preset_fdtfile}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true + else + false + fi + fi fi fi +fi +if itest $? -ne 0 ; then + setenv l_message "Cannot find DT!" + run func_critical_error || exit +fi + +# load the device tree blob +setenv l_file "${l_fdtdir}/${l_fdtfile}" +if load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${l_file} ; then + setenv l_message "Loaded DT ${l_file} to ${fdt_addr_r}." + run func_inform + + setenv l_fdt_filesize ${filesize} + fdt addr ${fdt_addr_r} + fdt resize ${fdt_extrasize} else - if test -e ${devtype} ${devnum} ${prefix}dtb/overlay/${overlay_prefix}-fixup.scr; then - setenv something "kernel provided DT fixup script (${overlay_prefix}-fixup.scr) from ${devtype} to ${load_addr}" - echo "Loading ${something} ..." - if load ${devtype} ${devnum} ${load_addr} ${prefix}dtb/overlay/${overlay_prefix}-fixup.scr ; then - source ${load_addr} + setenv l_message "Could not load DT ${l_file}!" + run func_critical_error || exit +fi + +# process "overlays=..." from $l_envfile +if test "${overlays}" != "" ; then + setenv l_message "Loading kernel provided DT overlay(s) from ${l_fdtdir}/overlay to ${load_addr} .." + run func_inform + + # as some families offer overlays with different (or no) prefixes, try to guess the most commonly seen ones + # just changing overlay_prefix= will not work for all available overlays, as some have prefixes and some do not + + setenv each_overlay + for each_overlay in ${overlays} ; do + setenv l_overlay_prefix "${overlay_prefix}" + setenv l_file "${l_fdtdir}/overlay/${l_overlay_prefix}-${each_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + true else - echo "** Could not load ${something}" + setenv l_overlay_prefix "${vendor}" + setenv l_file "${l_fdtdir}/overlay/${l_overlay_prefix}-${each_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + setenv l_message "Found DT overlay ${l_overlay_prefix}-${each_overlay} instead of ${overlay_prefix}-${each_overlay} in ${l_fdtdir}/overlay!" + run func_warn + setenv l_message "Consider setting overlay_prefix=${l_overlay_prefix} in your ${l_envfile}." + run func_inform + true + else + setenv l_overlay_prefix "${vendor}-${soc}" + setenv l_file "${l_fdtdir}/overlay/${l_overlay_prefix}-${each_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + setenv l_message "Found DT overlay ${l_overlay_prefix}-${each_overlay} instead of ${overlay_prefix}-${each_overlay} in ${l_fdtdir}/overlay!" + run func_warn + setenv l_message "Consider setting overlay_prefix=${l_overlay_prefix} in your ${l_envfile}." + run func_inform + true + else + false + fi + fi fi - fi - if test -e ${devtype} ${devnum} ${prefix}fixup.scr; then - setenv something "user provided fixup script (fixup.scr) from ${devtype} to ${load_addr}" - echo "Loading ${something} ..." - if load ${devtype} ${devnum} ${load_addr} ${prefix}fixup.scr ; then - source ${load_addr} + if itest $? -eq 0 ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${l_file} ; then + if fdt apply ${load_addr} ; then + setenv l_message "Applied DT overlay ${each_overlay} (${l_file})." + run func_inform + else + setenv overlay_error "true" + setenv l_message "Could NOT apply DT overlay ${each_overlay} (${l_file})!" + run func_warn + fi + else + setenv l_message "Could NOT load DT overlay ${each_overlay} (${l_file})!" + run func_warn + fi + else + setenv l_message "Could NOT find DT overlay ${each_overlay}!" + run func_warn + fi + done +fi + +# process "user_overlays=..." from $l_envfile +if test "${user_overlays}" != "" ; then + setenv l_message "Loading user provided DT overlay(s) from ${prefix}overlay-user to ${load_addr} .." + run func_inform + + setenv each_user_overlay + for each_user_overlay in ${user_overlays} ; do + setenv l_file "${prefix}overlay-user/${each_user_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${l_file} ; then + if fdt apply ${load_addr} ; then + setenv l_message "Applied user DT overlay ${each_user_overlay} (${l_file})." + run func_inform + else + setenv overlay_error "true" + setenv l_message "Could NOT apply user DT overlay ${each_user_overlay} (${l_file})!" + run func_warn + fi + else + setenv l_message "Could NOT load user DT overlay ${each_user_overlay} (${l_file})!" + run func_warn + fi else - echo "** Could not load ${something}" + setenv l_message "Could NOT find user DT overlay ${each_user_overlay} (${l_file})!" + run func_warn fi + done +fi +if test "${overlay_error}" = "true" ; then + setenv l_message "Could not apply DT overlays!" + run func_warn + + setenv l_file "${l_fdtdir}/${l_fdtfile}" + if load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${l_file} ; then + setenv l_message "Loaded original DT ${l_file} to ${fdt_addr_r}." + run func_inform + + setenv l_fdt_filesize ${filesize} + fdt addr ${fdt_addr_r} + fdt resize ${fdt_extrasize} + else + setenv l_message "Could not load original DT ${l_file}!" + run func_critical_error || exit + fi +else + # process any available DT fixup scripts + setenv l_fixup_scripts "${prefix}fixup.scr" + if test "${overlay_prefix}" != "" ; then + setenv l_fixup_scripts "${l_fdtdir}/overlay/${overlay_prefix}-fixup.scr ${l_fixup_scripts}" fi + if test "${vendor}" != "" ; then + if test "${vendor}" != "${overlay_prefix}" ; then + setenv l_fixup_scripts "${l_fdtdir}/overlay/${vendor}-fixup.scr ${l_fixup_scripts}" + fi + fi + + setenv each_fixup_script + for each_fixup_script in ${l_fixup_scripts} ; do + if test -e ${devtype} ${devnum}:${distro_bootpart} ${each_fixup_script} ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${each_fixup_script} ; then + if source ${load_addr} ; then + setenv l_message "Loaded/sourced fixup script ${each_fixup_script} to/at ${load_addr}." + run func_inform + else + setenv l_message "Fixup script ${each_fixup_script} returned an error!" + run func_warn + fi + else + setenv l_message "Could not load fixup script ${each_fixup_script}!" + run func_warn + fi + fi + done fi # eMMC fix if test "${emmc_fix}" = "on"; then - echo "Applying eMMC compatibility fix to the DT" + echo "Applying eMMC compatibility fix to the DT." fdt rm /soc/internal-regs/sdhci@d8000/ cd-gpios fdt set /soc/internal-regs/sdhci@d8000/ non-removable fi # SPI - SATA workaround if test "${spi_workaround}" = "on"; then - echo "Applying SPI workaround to the DT" + echo "Applying SPI workaround to the DT." fdt set /soc/internal-regs/sata@e0000 status "disabled" fdt set /soc/internal-regs/sata@a8000 status "disabled" fdt set /soc/spi@10680 status "okay" fdt set /soc/spi@10680/spi-flash@0 status "okay" fi -echo "Trimming DT ..." +# resize (trim) device tree after all overlays have been applied and fixup scripts have been run fdt resize -if test "${setexpr}" = "available" ; then - fdt header get fdt_totalsize totalsize - if test "${fdt_totalsize}" = "" ; then - echo "** Command `fdt header` does not support `get ` - calculating DT size" +# determine the load address for the kernel image +if test "${load_addr_calc}" = "on" ; then + # get the total size of the DT + setenv l_fdt_totalsize + fdt header get l_fdt_totalsize totalsize + + if test "${l_fdt_totalsize}" = "" ; then + # could not get the total size of the DT so calculate it instead + setenv l_message "Calculating DT size." + run func_inform # 'fdt resize' will align upwards to 4k address boundary - setexpr fdt_totalsize ${fdt_filesize} / 0x1000 - setexpr fdt_totalsize ${fdt_totalsize} + 1 - setexpr fdt_totalsize ${fdt_totalsize} * 0x1000 + setexpr l_fdt_totalsize ${l_fdt_filesize} / 0x1000 + setexpr l_fdt_totalsize ${l_fdt_totalsize} + 1 + setexpr l_fdt_totalsize ${l_fdt_totalsize} * 0x1000 if test "${fdt_extrasize}" != "" ; then - # add 'extrasize' before aligning - setexpr fdt_totalsize ${fdt_totalsize} + ${fdt_extrasize} + setexpr l_fdt_totalsize ${l_fdt_totalsize} + ${fdt_extrasize} fi fi - setexpr addr_next ${fdt_addr_r} + ${fdt_totalsize} - run align_addr_next - setenv kernel_addr_r ${addr_next} + + setexpr l_addr_next ${fdt_addr_r} + ${l_fdt_totalsize} + run func_align_addr_next + + setenv l_kernel_addr_r ${l_addr_next} +else + setenv l_kernel_addr_r ${kernel_addr_r} fi -setenv something "kernel ${prefix}zImage from ${devtype} to ${kernel_addr_r}" -echo "Loading ${something} ..." -if load ${devtype} ${devnum} ${kernel_addr_r} ${prefix}zImage ; then +setenv l_file "${prefix}${l_bootfile}" +if load ${devtype} ${devnum}:${distro_bootpart} ${l_kernel_addr_r} ${l_file} ; then + if test "${load_addr_calc}" = "on" ; then + setenv kernel_comp_size ${filesize} + fi + + setenv l_message "Loaded ${l_kernel_image_type} kernel image ${l_file} to ${l_kernel_addr_r}." + run func_inform else - echo "!! CRITICAL - Could not load ${something}" - if test "${exit_on_critical_errors}" = "on" ; then - exit + if test "${load_addr_calc}" = "on" ; then + setenv kernel_comp_addr_r "${preset_kernel_comp_addr_r}" + setenv kernel_comp_size "${preset_kernel_comp_size}" fi + setenv l_message "Could not load ${l_kernel_image_type} kernel image ${l_file}!" + run func_critical_error || exit fi -if test "${setexpr}" = "available" ; then - setexpr addr_next ${kernel_addr_r} + ${filesize} - run align_addr_next - setenv ramdisk_addr_r ${addr_next} +# determine the load address for the initial ramdisk +if test "${load_addr_calc}" = "on" ; then + # vmlinux image + 0x38 contain magic (le-double) 'ARMd' + setexpr l_ptr ${l_kernel_addr_r} + 0x00000038 + setexpr.w l_magic_lsw *${l_ptr} + + setexpr l_ptr ${l_kernel_addr_r} + 0x0000003a + setexpr.w l_magic_msw *${l_ptr} + + if test "${l_magic_msw}${l_magic_lsw}" != "" && itest "${l_magic_msw}${l_magic_lsw}" -eq 0x644d5241 ; then + setenv l_kernel_image_type "flat" + else + setenv l_kernel_image_type "compressed" + fi + + if test "${l_kernel_image_type}" = "flat" ; then + # vmlinux image + 0x10 contains image_size + setexpr l_ptr ${l_kernel_addr_r} + 0x00000010 + setexpr.l l_image_size *${l_ptr} + + setenv l_message "Using ${l_kernel_image_type} kernel image image_size 0x${l_image_size} bytes to calculate initial ramdisk load address." + run func_inform + + # vmlinux image + 0x08 contains text_offset + setexpr l_ptr ${l_kernel_addr_r} + 0x00000008 + setexpr.l l_text_offset *${l_ptr} + + setenv l_message "Using ${l_kernel_image_type} kernel image text_offset 0x${l_text_offset} bytes to offset initial ramdisk load address." + run func_inform + + setexpr l_addr_next ${l_kernel_addr_r} + ${l_image_size} + run func_align_addr_next + + # take into account that U-Boot's booti_setup() might relocate the kernel image + setexpr l_addr_next ${l_addr_next} + ${l_text_offset} + else + setexpr l_addr_next ${l_kernel_addr_r} + ${filesize} + run func_align_addr_next + + setenv l_message "Using ${l_kernel_image_type} kernel image filesize 0x${filesize} bytes to calculate initial ramdisk load address." + run func_inform + fi + + setenv l_ramdisk_addr_r ${l_addr_next} +else + setenv l_ramdisk_addr_r ${ramdisk_addr_r} fi -setenv something "initial ramdisk ${prefix}uInitrd from ${devtype} to ${ramdisk_addr_r}" -echo "Loading ${something} ..." -if load ${devtype} ${devnum} ${ramdisk_addr_r} ${prefix}uInitrd ; then +setenv l_file "${prefix}${l_ramdiskfile}" +if load ${devtype} ${devnum}:${distro_bootpart} ${l_ramdisk_addr_r} ${l_file} ; then + if test "${load_addr_calc}" = "on" ; then + setexpr l_addr_next ${l_ramdisk_addr_r} + ${filesize} + run func_align_addr_next + + setenv kernel_comp_addr_r ${l_addr_next} + fi + + setenv l_message "Loaded initial ramdisk ${l_file} to ${l_ramdisk_addr_r}." + run func_inform else - echo "!! CRITICAL - Could not load ${something}" - if test "${exit_on_critical_errors}" = "on" ; then - exit + if test "${load_addr_calc}" = "on" ; then + setenv kernel_comp_addr_r "${preset_kernel_comp_addr_r}" + setenv kernel_comp_size "${preset_kernel_comp_size}" fi + setenv l_message "Could not load initial ramdisk ${l_file}!" + run func_critical_error || exit fi -setenv something "kernel from ${kernel_addr_r}" -echo "Booting ${something} ..." -if bootz ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r} ; then +# attempt to prepare for kernel address space randomization +if kaslrseed ; then else - echo "!! CRITICAL - Could not boot ${something}" - if test "${exit_on_critical_errors}" = "on" ; then - exit + setenv l_message "Not able to prepare for KASLR." + run func_inform +fi + +setenv l_message "Kernel commandline arguments:" +run func_inform + +setenv each_bootarg +for each_bootarg in ${bootargs} ; do + setenv l_message " ${each_bootarg}" + run func_inform +done + +if test "${l_kernel_image_type}" = "flat" ; then + booti ${l_kernel_addr_r} ${l_ramdisk_addr_r} ${fdt_addr_r} +else + if test "${l_kernel_image_type}" = "compressed" ; then + bootz ${l_kernel_addr_r} ${l_ramdisk_addr_r} ${fdt_addr_r} + else + # default booting command + bootz ${l_kernel_addr_r} ${l_ramdisk_addr_r} ${fdt_addr_r} fi fi +# booting failed, restore environment variables that are not unique +# to this bootmeth +if test "${load_addr_calc}" = "on" ; then + # restore original presets + setenv kernel_comp_addr_r "${preset_kernel_comp_addr_r}" + setenv kernel_comp_size "${preset_kernel_comp_size}" +fi + +setenv l_message "Could not boot kernel!" +run func_critical_error || exit + # Recompile with: # mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr diff --git a/config/desktop/trixie/environments/cinnamon/config_base/packages b/config/desktop/trixie/environments/cinnamon/config_base/packages index f850058b3ab5..9a2286f92de6 100644 --- a/config/desktop/trixie/environments/cinnamon/config_base/packages +++ b/config/desktop/trixie/environments/cinnamon/config_base/packages @@ -78,8 +78,6 @@ openprinting-ppds p7zip-full pamix pasystray -pavucontrol -pavumeter polkitd pkexec #printer-driver-all diff --git a/config/desktop/trixie/environments/xfce/config_base/packages b/config/desktop/trixie/environments/xfce/config_base/packages index b4dca91d6e83..3dc823bc8641 100644 --- a/config/desktop/trixie/environments/xfce/config_base/packages +++ b/config/desktop/trixie/environments/xfce/config_base/packages @@ -65,8 +65,6 @@ orca p7zip-full pamix pasystray -pavucontrol -pavumeter polkitd pkexec #printer-driver-all diff --git a/config/kernel/linux-k3-beagle-edge.config b/config/kernel/linux-k3-beagle-edge.config index 58b4249536b3..d77a874d9ff4 100644 --- a/config/kernel/linux-k3-beagle-edge.config +++ b/config/kernel/linux-k3-beagle-edge.config @@ -1,7 +1,6 @@ # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_AUDIT=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BPF_SYSCALL=y @@ -17,6 +16,8 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_PIDS=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_HUGETLB=y @@ -25,6 +26,8 @@ CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_PERF=y CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y @@ -89,7 +92,10 @@ CONFIG_JUMP_LABEL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_THROTTLING=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_ZSWAP=y +CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_COMPAT_BRK is not set CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y @@ -101,33 +107,69 @@ CONFIG_CMA_AREAS=20 CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_XFRM_USER=m CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y +CONFIG_INET_ESP=m CONFIG_IPV6=m CONFIG_NETFILTER=y CONFIG_BRIDGE_NETFILTER=m -CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_ZONES=y CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_TABLES=y +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_REJECT_NETDEV=m CONFIG_NETFILTER_XT_MARK=m CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m CONFIG_NETFILTER_XT_TARGET_LOG=m CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m CONFIG_NETFILTER_XT_MATCH_IPVS=m CONFIG_IP_VS=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_FILTER=m +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_NFCT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=y CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_BRIDGE=m @@ -149,6 +191,7 @@ CONFIG_NET_SCH_TAPRIO=m CONFIG_NET_SCH_MQPRIO=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_CGROUP=m CONFIG_NET_CLS_FLOWER=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_GACT=m @@ -156,6 +199,7 @@ CONFIG_NET_ACT_MIRRED=m CONFIG_NET_ACT_GATE=m CONFIG_QRTR_SMD=m CONFIG_QRTR_TUN=m +CONFIG_CGROUP_NET_PRIO=y CONFIG_CAN=m CONFIG_BT=m CONFIG_BT_HIDP=m @@ -195,12 +239,10 @@ CONFIG_FW_LOADER_USER_HELPER=y CONFIG_MHI_BUS_PCI_GENERIC=m CONFIG_ARM_SCMI_PROTOCOL=y CONFIG_IMX_SCMI_BBM_EXT=y -CONFIG_IMX_SCMI_MISC_EXT=y CONFIG_GOOGLE_FIRMWARE=y CONFIG_GOOGLE_CBMEM=m CONFIG_GOOGLE_COREBOOT_TABLE=m CONFIG_EFI_CAPSULE_LOADER=y -CONFIG_IMX_SCMI_MISC_DRV=y CONFIG_GNSS=m CONFIG_GNSS_MTK_SERIAL=m CONFIG_MTD=y @@ -219,6 +261,10 @@ CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=m CONFIG_MTD_HYPERBUS=m CONFIG_HBMC_AM654=m +CONFIG_OF_OVERLAY=y +CONFIG_ZRAM=m +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM_MEMORY_TRACKING=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_VIRTIO_BLK=y @@ -245,11 +291,15 @@ CONFIG_BLK_DEV_DM=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m CONFIG_NETDEVICES=y +CONFIG_DUMMY=m CONFIG_MACVLAN=m CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_VXLAN=m CONFIG_TUN=y CONFIG_VETH=m CONFIG_VIRTIO_NET=y +CONFIG_NETKIT=y CONFIG_MHI_NET=m # CONFIG_NET_VENDOR_ALACRITECH is not set # CONFIG_NET_VENDOR_AMAZON is not set @@ -347,6 +397,7 @@ CONFIG_IWLMVM=m CONFIG_MWIFIEX=m CONFIG_MWIFIEX_SDIO=m CONFIG_MWIFIEX_PCIE=m +CONFIG_MT7601U=m CONFIG_MT7921E=m CONFIG_RSI_91X=m CONFIG_WL18XX=m @@ -355,6 +406,7 @@ CONFIG_WWAN=m CONFIG_MHI_WWAN_CTRL=m CONFIG_MHI_WWAN_MBIM=m CONFIG_INPUT_MATRIXKMAP=y +CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_ADC=m CONFIG_KEYBOARD_GPIO=y @@ -417,6 +469,7 @@ CONFIG_SPI_OMAP24XX=m CONFIG_SPI_SPIDEV=m CONFIG_PINCTRL=y CONFIG_PINCTRL_DA9062=m +CONFIG_PINCTRL_MCP23S08=m CONFIG_PINCTRL_RK805=m CONFIG_PINCTRL_SINGLE=y CONFIG_GPIO_SYSFS=y @@ -522,6 +575,8 @@ CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX412=m CONFIG_VIDEO_OV5640=m CONFIG_VIDEO_OV5645=m +CONFIG_AUXDISPLAY=y +CONFIG_SEG_LED_GPIO=m CONFIG_DRM=m CONFIG_DRM_I2C_CH7006=m CONFIG_DRM_I2C_SIL164=m @@ -698,6 +753,7 @@ CONFIG_LEDS_PCA9532=m CONFIG_LEDS_GPIO=y CONFIG_LEDS_PWM=y CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_PWM_MULTICOLOR=m CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_DISK=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y @@ -772,6 +828,8 @@ CONFIG_EXTCON_PTN5150=m CONFIG_EXTCON_USB_GPIO=y CONFIG_MEMORY=y CONFIG_IIO=y +CONFIG_MMA8452=m +CONFIG_AD7291=m CONFIG_MAX9611=m CONFIG_TI_ADS1015=m CONFIG_TI_AM335X_ADC=m @@ -782,6 +840,7 @@ CONFIG_IIO_ST_MAGN_3AXIS=m CONFIG_MPL3115=m CONFIG_PWM=y CONFIG_PWM_ADP5585=m +CONFIG_PWM_GPIO=m CONFIG_PWM_TIECAP=m CONFIG_PWM_TIEHRPWM=m CONFIG_RESET_CONTROLLER=y @@ -822,7 +881,7 @@ CONFIG_HTE=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y -CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y @@ -847,10 +906,13 @@ CONFIG_NFS_V4_2=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y +CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_ENCRYPTED_KEYS=y +CONFIG_KEY_DH_OPERATIONS=y CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y CONFIG_CRYPTO_USER=y CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_DH=m CONFIG_CRYPTO_CURVE25519=m CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_ANSI_CPRNG=y diff --git a/config/kernel/linux-rockchip-edge.config b/config/kernel/linux-rockchip-edge.config index 03d738cedee9..3123323555c0 100644 --- a/config/kernel/linux-rockchip-edge.config +++ b/config/kernel/linux-rockchip-edge.config @@ -86,7 +86,6 @@ CONFIG_ZSWAP=y CONFIG_ZSWAP_DEFAULT_ON=y CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y -CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_COMPAT_BRK is not set CONFIG_KSM=y CONFIG_CMA=y @@ -777,10 +776,11 @@ CONFIG_RTL8XXXU=m CONFIG_RTW88=m CONFIG_RTW88_8822BU=m CONFIG_RTW88_8822CU=m +CONFIG_RTW88_8723DS=m +CONFIG_RTW88_8723CS=m CONFIG_RTW88_8723DU=m CONFIG_RTW88_8821CU=m CONFIG_RTW89=m -CONFIG_RTL8723DS=m CONFIG_RTL8192EU=m CONFIG_RTL8189ES=m CONFIG_ZD1211RW=m @@ -1245,11 +1245,6 @@ CONFIG_HID_ICADE=m CONFIG_HID_TWINHAN=m CONFIG_HID_KENSINGTON=m CONFIG_HID_LCPOWER=m -CONFIG_HID_LOGITECH=m -CONFIG_HID_LOGITECH_DJ=m -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y CONFIG_HID_MAGICMOUSE=m CONFIG_HID_MALTRON=m CONFIG_HID_MICROSOFT=m @@ -1535,7 +1530,6 @@ CONFIG_FB_TFT_TLS8204=m CONFIG_FB_TFT_UC1611=m CONFIG_FB_TFT_UC1701=m CONFIG_FB_TFT_UPD161704=m -CONFIG_RTL8723CS=m CONFIG_COMMON_CLK_MAX9485=m CONFIG_COMMON_CLK_RK808=y CONFIG_COMMON_CLK_SCMI=m @@ -1692,7 +1686,6 @@ CONFIG_SQUASHFS_EMBEDDED=y CONFIG_PSTORE=y CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_RAM=y -CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_EROFS_FS=m # CONFIG_EROFS_FS_ZIP is not set @@ -1726,7 +1719,6 @@ CONFIG_CIFS_POSIX=y CONFIG_CIFS_FSCACHE=y CONFIG_CIFS_COMPRESSION=y CONFIG_SMB_SERVER=m -CONFIG_SMB_SERVER_KERBEROS5=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y @@ -1799,8 +1791,6 @@ CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG=y CONFIG_CRYPTO_DEV_VIRTIO=m CONFIG_CRYPTO_DEV_SAFEXCEL=m CONFIG_CRYPTO_DEV_CCREE=m -CONFIG_CRC4=m -CONFIG_CRC7=m CONFIG_DMA_CMA=y CONFIG_IRQ_POLL=y CONFIG_PRINTK_TIME=y @@ -1812,7 +1802,6 @@ CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0 # CONFIG_SLUB_DEBUG is not set CONFIG_DETECT_HUNG_TASK=y CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y -# CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y CONFIG_STACKTRACE=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 diff --git a/config/kernel/linux-rockchip64-current.config b/config/kernel/linux-rockchip64-current.config index d40a695cbce9..d053d09976d9 100644 --- a/config/kernel/linux-rockchip64-current.config +++ b/config/kernel/linux-rockchip64-current.config @@ -2694,7 +2694,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_LIB_KUNIT_TEST=m CONFIG_RTC_DRV_AS3722=m CONFIG_RTC_DRV_DS1307=y -CONFIG_RTC_DRV_HYM8563=y +CONFIG_RTC_DRV_HYM8563=m CONFIG_RTC_DRV_MAX77686=y CONFIG_RTC_DRV_RK808=m CONFIG_RTC_DRV_ISL12026=m diff --git a/config/kernel/linux-rockchip64-edge.config b/config/kernel/linux-rockchip64-edge.config index a49c47a827cb..582379a0dfa1 100644 --- a/config/kernel/linux-rockchip64-edge.config +++ b/config/kernel/linux-rockchip64-edge.config @@ -798,6 +798,7 @@ CONFIG_TUN_VNET_CROSS_LE=y CONFIG_VETH=m CONFIG_VIRTIO_NET=m CONFIG_NLMON=m +CONFIG_NETKIT=y CONFIG_NET_VRF=m CONFIG_MHI_NET=m CONFIG_ATM_DUMMY=m @@ -1932,6 +1933,7 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m CONFIG_VIDEO_ROCKCHIP_RGA=m CONFIG_VIDEO_SYNOPSYS_HDMIRX=m +CONFIG_VIDEO_SYNOPSYS_HDMIRX_LOAD_DEFAULT_EDID=y CONFIG_VIDEO_HANTRO=m CONFIG_SMS_SDIO_DRV=m CONFIG_VIDEO_HI556=m @@ -2694,7 +2696,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_LIB_KUNIT_TEST=m CONFIG_RTC_DRV_AS3722=m CONFIG_RTC_DRV_DS1307=y -CONFIG_RTC_DRV_HYM8563=y +CONFIG_RTC_DRV_HYM8563=m CONFIG_RTC_DRV_MAX77686=y CONFIG_RTC_DRV_RK808=m CONFIG_RTC_DRV_ISL12026=m diff --git a/config/kernel/linux-spacemit-current.config b/config/kernel/linux-spacemit-current.config index 264a2d11f411..47589e1f1a3a 100644 --- a/config/kernel/linux-spacemit-current.config +++ b/config/kernel/linux-spacemit-current.config @@ -959,10 +959,18 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_SOC_SPACEMIT=y +CONFIG_SPACEMIT_CARD=y +CONFIG_SPACEMIT_PCM=y +CONFIG_SPACEMIT_I2S=y +CONFIG_SPACEMIT_HDMIAUDIO=y +CONFIG_SND_SOC_AC97_CODEC=m CONFIG_SND_SOC_ES7210=y CONFIG_SND_SOC_ES8156=y CONFIG_SND_SOC_ES8326=y CONFIG_SND_SIMPLE_CARD=y +CONFIG_SND_AUDIO_GRAPH_CARD=m +CONFIG_SND_AUDIO_GRAPH_CARD2=m +CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE=m CONFIG_UHID=y CONFIG_HID_MULTITOUCH=y CONFIG_USB_HIDDEV=y diff --git a/config/kernel/linux-sunxi64-edge.config b/config/kernel/linux-sunxi64-edge.config index f35b00632b1d..ed3926ea88a0 100644 --- a/config/kernel/linux-sunxi64-edge.config +++ b/config/kernel/linux-sunxi64-edge.config @@ -929,6 +929,7 @@ CONFIG_WWAN_HWSIM=m CONFIG_MHI_WWAN_CTRL=m CONFIG_MHI_WWAN_MBIM=m CONFIG_NETDEVSIM=m +CONFIG_INPUT=y CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_PSAUX=y CONFIG_INPUT_JOYDEV=m @@ -1159,6 +1160,7 @@ CONFIG_W1_SLAVE_DS2433=m CONFIG_W1_SLAVE_DS250X=m CONFIG_W1_SLAVE_DS28E04=m CONFIG_W1_SLAVE_DS28E17=m +CONFIG_POWER_SUPPLY=y CONFIG_POWER_RESET_ATC260X=m CONFIG_POWER_RESET_SYSCON=y CONFIG_IP5XXX_POWER=m @@ -1943,6 +1945,8 @@ CONFIG_SND_VIRTIO=m CONFIG_HID_BATTERY_STRENGTH=y CONFIG_HIDRAW=y CONFIG_UHID=m +CONFIG_HID=y +CONFIG_HID_SUPPORT=y CONFIG_HID_A4TECH=m CONFIG_HID_ACCUTOUCH=m CONFIG_HID_ACRUX=m @@ -2026,6 +2030,8 @@ CONFIG_HID_SEMITEK=m CONFIG_HID_SIGMAMICRO=m CONFIG_HID_SONY=m CONFIG_SONY_FF=y +CONFIG_HID_PLAYSTATION=m +CONFIG_PLAYSTATION_FF=y CONFIG_HID_SPEEDLINK=m CONFIG_HID_STEAM=m CONFIG_HID_STEELSERIES=m @@ -2054,6 +2060,7 @@ CONFIG_HID_ALPS=m CONFIG_HID_MCP2221=m CONFIG_HID_PID=y CONFIG_USB_HIDDEV=y +CONFIG_USB_HID=y CONFIG_I2C_HID_OF=m CONFIG_I2C_HID_OF_ELAN=m CONFIG_I2C_HID_OF_GOODIX=m @@ -2211,7 +2218,8 @@ CONFIG_MMC_HSQ=m CONFIG_MMC_LITEX=m CONFIG_SCSI_UFSHCD=m CONFIG_LEDS_CLASS=y -CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_CLASS_MULTICOLOR=y +CONFIG_NEW_LEDS=y CONFIG_LEDS_AN30259A=m CONFIG_LEDS_CR0014114=m CONFIG_LEDS_EL15203000=m diff --git a/config/sources/families/bcm2711.conf b/config/sources/families/bcm2711.conf index bf9fb536eabe..ca3ba158507a 100644 --- a/config/sources/families/bcm2711.conf +++ b/config/sources/families/bcm2711.conf @@ -37,8 +37,8 @@ case "${BRANCH}" in edge) declare -g EXTRAWIFI="no" declare -g KERNELSOURCE='https://github.com/raspberrypi/linux' - declare -g KERNEL_MAJOR_MINOR="6.14" # Major and minor versions of this kernel. For mainline caching. - declare -g KERNELBRANCH="branch:rpi-6.14.y" + declare -g KERNEL_MAJOR_MINOR="6.15" # Major and minor versions of this kernel. For mainline caching. + declare -g KERNELBRANCH="branch:rpi-6.15.y" ;; esac @@ -181,6 +181,12 @@ function post_family_tweaks_bsp__add_hooks_to_move_kernel_initrd_and_dtb() { run_host_command_logged chmod a+x "${destination}"/etc/initramfs/post-update.d/zzz-update-initramfs } +function post_family_tweaks_bsp__rpi_firmware() { + display_alert "$BOARD" "Installing firmware" "info" + git clone https://github.com/pyavitz/firmware.git --depth=1 -q "${destination}"/lib/firmware/updates/brcm + rm -fdr "${destination}"/lib/firmware/updates/brcm/{.git,README.md} +} + function post_family_tweaks_bsp__add_x11_config() { display_alert "rpi5b" "Adding X11 configuration" "info" run_host_command_logged mkdir -p "${destination}"/etc/X11/xorg.conf.d/ @@ -255,6 +261,26 @@ function pre_install_distribution_specific__add_rpi_packages() { fi } +function pre_install_distribution_specific__unblock_rfkill() { + # Create a systemd service to unblock rfkill + cat > "${SDCARD}/etc/systemd/system/unblock-rfkill.service" <<- EOT + [Unit] + Description=Unblock rfkill manually (no rfkill binary) + After=multi-user.target + + [Service] + Type=oneshot + ExecStart=/bin/bash -c 'for f in /sys/class/rfkill/*/state; do echo 1 > "\$f"; done' + RemainAfterExit=true + + [Install] + WantedBy=multi-user.target + EOT + # Enable the service to run at boot + display_alert "Enabling unblock-rfkill service" "bcm2711" "info" + chroot_sdcard systemctl enable unblock-rfkill.service +} + # Our default paritioning system is leaving esp on. Rpi3 is the only board that have issues with this. # Removing the ESP flag from the boot partition should allow the image to boot on both the RPi3 and RPi4. function pre_umount_final_image__remove_esp() { diff --git a/config/sources/families/imx8m.conf b/config/sources/families/imx8m.conf index 4804cf1666ec..ca699ba89d3e 100644 --- a/config/sources/families/imx8m.conf +++ b/config/sources/families/imx8m.conf @@ -23,7 +23,7 @@ case $BOARD in ATFSOURCE='https://github.com/tq-systems/atf' # required for ram ATFBRANCH="branch:TQM-lf_v2.10" BOOTSOURCE='https://github.com/tq-systems/u-boot-tqmaxx.git' # u-boot mainlining is hard and has low-priority - BOOTBRANCH='branch:TQMa8-v2020.04_imx_5.4.70_2.3.0' + BOOTBRANCH='commit:90aea55d842b6c3c978530532e16110123995002' BOOTPATCHDIR="u-boot-tqma" # could be removed when distro boot patches are integrated ;; esac diff --git a/config/sources/families/include/imx8_common.inc b/config/sources/families/include/imx8_common.inc index dbff3d421037..37659306214b 100644 --- a/config/sources/families/include/imx8_common.inc +++ b/config/sources/families/include/imx8_common.inc @@ -11,11 +11,12 @@ ARCH="arm64" KERNEL_IMAGE_TYPE="Image" OVERLAY_DIR="/boot/dtb/freescale/overlay" SRC_EXTLINUX="yes" # use extlinux as default -IMX_FIRMWARE="${IMX_FIRMWARE:-"firmware-imx-8.12"}" +IMX_FIRMWARE="${IMX_FIRMWARE:-"firmware-imx-8.26-d4c33ab"}" # ATF_PLAT musst set in board # ATF_UART_BASE musst set in board # MAP = target_make,target_patchdir,target_files # use xxx:xxx to rename files after build +ATFPATCHDIR='atf-imx8' ATF_TARGET_MAP="PLAT=${ATF_PLAT} IMX_BOOT_UART_BASE=${ATF_UART_BASE} bl31;;build/imx8mp/release/bl31.bin" UBOOT_TARGET_MAP="flash.bin;;flash.bin" diff --git a/config/sources/families/include/meson64_common.inc b/config/sources/families/include/meson64_common.inc index fa9d580ef825..b7d51832c019 100644 --- a/config/sources/families/include/meson64_common.inc +++ b/config/sources/families/include/meson64_common.inc @@ -39,7 +39,7 @@ case $BRANCH in declare -g KERNEL_MAJOR_MINOR="6.12" ;; edge) - declare -g KERNEL_MAJOR_MINOR="6.14" + declare -g KERNEL_MAJOR_MINOR="6.15" ;; esac diff --git a/config/sources/families/include/rockchip64_common.inc b/config/sources/families/include/rockchip64_common.inc index ce0e09ce44ae..cfc7d77d9b42 100644 --- a/config/sources/families/include/rockchip64_common.inc +++ b/config/sources/families/include/rockchip64_common.inc @@ -33,7 +33,7 @@ case $BRANCH in ;; edge) - declare -g KERNEL_MAJOR_MINOR="6.14" + declare -g KERNEL_MAJOR_MINOR="6.15" declare -g LINUXFAMILY=rockchip64 declare -g LINUXCONFIG='linux-rockchip64-'$BRANCH ;; @@ -166,7 +166,7 @@ prepare_boot_configuration() { ATFSOURCE='https://github.com/ARM-software/arm-trusted-firmware' ATF_COMPILER='aarch64-linux-gnu-' ATFDIR='arm-trusted-firmware' - ATFBRANCH='tag:v2.12.0' + ATFBRANCH='tag:v2.13.0' ATF_USE_GCC='> 6.3' ATF_TARGET_MAP="M0_CROSS_COMPILE=arm-linux-gnueabi- PLAT=$BOOT_SOC bl31;;build/$BOOT_SOC/release/bl31/bl31.elf:bl31.elf" ATF_TOOLCHAIN2="arm-linux-gnueabi-:< 10.0" diff --git a/config/sources/families/include/sunxi64_common.inc b/config/sources/families/include/sunxi64_common.inc index 60f13316b0ff..f4a7a34fb174 100644 --- a/config/sources/families/include/sunxi64_common.inc +++ b/config/sources/families/include/sunxi64_common.inc @@ -31,12 +31,12 @@ case $BRANCH in current) declare -g KERNEL_MAJOR_MINOR="6.12" # Major and minor versions of this kernel. - declare -g KERNELBRANCH="tag:v6.12.23" + declare -g KERNELBRANCH="tag:v6.12.30" ;; edge) - declare -g KERNEL_MAJOR_MINOR="6.14" # Major and minor versions of this kernel. - declare -g KERNELBRANCH="tag:v6.14.5" + declare -g KERNEL_MAJOR_MINOR="6.15" # Major and minor versions of this kernel. + declare -g KERNELBRANCH="tag:v6.15" ;; esac diff --git a/config/sources/families/include/sunxi_common.inc b/config/sources/families/include/sunxi_common.inc index 56430d14ba02..074291e04e20 100644 --- a/config/sources/families/include/sunxi_common.inc +++ b/config/sources/families/include/sunxi_common.inc @@ -32,12 +32,12 @@ case $BRANCH in current) declare -g KERNEL_MAJOR_MINOR="6.12" # Major and minor versions of this kernel. - declare -g KERNELBRANCH="tag:v6.12.23" + declare -g KERNELBRANCH="tag:v6.12.30" ;; edge) - declare -g KERNEL_MAJOR_MINOR="6.14" # Major and minor versions of this kernel. - declare -g KERNELBRANCH="tag:v6.14.5" + declare -g KERNEL_MAJOR_MINOR="6.15" # Major and minor versions of this kernel. + declare -g KERNELBRANCH="tag:v6.15" ;; esac diff --git a/config/sources/families/include/uefi_common.inc b/config/sources/families/include/uefi_common.inc index f8e956fc34b4..3947a50e94fa 100644 --- a/config/sources/families/include/uefi_common.inc +++ b/config/sources/families/include/uefi_common.inc @@ -41,7 +41,7 @@ case "${BRANCH}" in ;; edge) - declare -g KERNEL_MAJOR_MINOR="6.14" + declare -g KERNEL_MAJOR_MINOR="6.15" ;; esac diff --git a/config/sources/families/k3.conf b/config/sources/families/k3.conf index cbe2dd24ea7e..f3287022371f 100644 --- a/config/sources/families/k3.conf +++ b/config/sources/families/k3.conf @@ -10,10 +10,13 @@ declare -g ARCH="arm64" declare -g LINUXFAMILY="k3" declare -g OVERLAY_DIR="/boot/dtb/ti/overlay" -declare -g ATFBRANCH="tag:v2.12.0" -declare -g BOOTBRANCH="tag:v2025.01" +declare -g KERNELSOURCE="https://github.com/TexasInstruments-Sandbox/ti-linux-kernel" +declare -g ATFSOURCE="https://github.com/TexasInstruments/arm-trusted-firmware" +declare -g BOOTSOURCE="https://git.ti.com/cgit/ti-u-boot/ti-u-boot" + declare -g BOOTSCRIPT="boot-k3.cmd:uEnv.txt" +declare -g SPD_OPTEED="SPD=opteed" declare -g INSTALL_HEADERS="yes" @@ -21,24 +24,35 @@ case "${BRANCH}" in current) - declare -g KERNELSOURCE="https://github.com/TexasInstruments-Sandbox/ti-linux-kernel" - declare -g KERNEL_MAJOR_MINOR="6.6" - declare -g KERNELBRANCH="branch:ti-linux-6.6.y" + declare -g CORESDK_TAG="tag:11.00.09" + declare -g KERNEL_MAJOR_MINOR="6.12" + declare -g KERNELBRANCH="${CORESDK_TAG}" + declare -g KERNEL_DESCRIPTION="Texas Instruments currently supported SDK (vendor) kernel" + declare -g ATFBRANCH="commit:b11beb2b6bd30b75c4bfb0e9925c0e72f16ca53f" + declare -g OPTEE_BRANCH="tag:4.6.0" + declare -g TI_LINUX_FIRMWARE_BRANCH="${CORESDK_TAG}" + declare -g BOOTBRANCH="${CORESDK_TAG}" ;; edge) + declare -g CORESDK_TAG="tag:11.00.12" declare -g KERNEL_MAJOR_MINOR="6.12" - declare -g KERNELBRANCH='branch:linux-6.12.y' + declare -g KERNELBRANCH="${CORESDK_TAG}" + declare -g ATFBRANCH="commit:b45324936bbba464b0623c83cd5aa53e1cd4cbdb" + declare -g OPTEE_BRANCH="tag:4.6.0" + declare -g TI_LINUX_FIRMWARE_BRANCH="${CORESDK_TAG}" + declare -g BOOTBRANCH="${CORESDK_TAG}" EXTRAWIFI="no" + declare -g KERNEL_DESCRIPTION="Edge branch of TI Linux SDK" ;; esac ATF_PLAT="k3" -ATF_TARGET_MAP="PLAT=$ATF_PLAT TARGET_BOARD=$ATF_BOARD DEBUG=1 ${ATF_K3_USART_OFFSET} bl31;;build/$ATF_PLAT/$ATF_BOARD/debug/bl31.bin:bl31.bin" +ATF_TARGET_MAP="PLAT=$ATF_PLAT TARGET_BOARD=$ATF_BOARD ${SPD_OPTEED} ${ATF_K3_USART_OFFSET} bl31;;build/$ATF_PLAT/$ATF_BOARD/release/bl31.bin:bl31.bin" -UBOOT_TARGET_MAP="BL31=bl31.bin TEE=bl31.bin BINMAN_INDIRS=${SRC}/cache/sources/ti-linux-firmware all;;tiboot3.bin ${SYSFW_FILE:+sysfw.itb} tispl.bin u-boot.img" +UBOOT_TARGET_MAP="BL31=bl31.bin TEE=${SRC}/cache/sources/optee-os/out/arm-plat-k3/core/tee-raw.bin BINMAN_INDIRS=${SRC}/cache/sources/ti-linux-firmware all;;tiboot3.bin ${SYSFW_FILE:+sysfw.itb} tispl.bin u-boot.img" # To match what our current SDK produces BOOT_FS_LABEL="boot" @@ -46,12 +60,12 @@ ROOT_FS_LABEL="root" function add_host_dependencies__k3_python3_dep() { display_alert "Preparing K3 U-Boot host-side dependencies" "${EXTENSION}" "info" - declare -g EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} python3-yaml python3-jsonschema yamllint" + declare -g EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} python3-yaml python3-jsonschema yamllint python3-cryptography python3-pyelftools python3-setuptools" } function compile_k3_bootgen() { # Source code checkout - (fetch_from_repo "https://github.com/TexasInstruments-Sandbox/ti-linux-firmware" "ti-linux-firmware" "branch:ti-linux-firmware") + (fetch_from_repo "https://github.com/TexasInstruments-Sandbox/ti-linux-firmware" "ti-linux-firmware" ${TI_LINUX_FIRMWARE_BRANCH}) pushd ${SRC}/cache/sources/u-boot-worktree/${BOOTDIR}/${BOOTBRANCH##*:} || exit @@ -61,8 +75,16 @@ function compile_k3_bootgen() { popd } +function compile_k3_optee() { + (fetch_from_repo "https://github.com/OP-TEE/optee_os.git" "optee-os" ${OPTEE_BRANCH}) + pushd ${SRC}/cache/sources/optee-os || exit + run_host_command_logged make -j$(nproc) CROSS_COMPILE=arm-linux-gnueabihf- CFG_ARM64_core=y PLATFORM=${OPTEE_PLATFORM} ${OPTEE_ARGS} + popd +} + function pre_config_uboot_target__build_first_stage() { # Compile first stage bootloader + compile_k3_optee compile_k3_bootgen cp ${SRC}/cache/sources/u-boot-worktree/${BOOTDIR}/${BOOTBRANCH##*:}/build-r5/${TIBOOT3_FILE} tiboot3.bin diff --git a/config/sources/families/meson-g12b.conf b/config/sources/families/meson-g12b.conf index a6d0c5159645..22f56683ab2e 100644 --- a/config/sources/families/meson-g12b.conf +++ b/config/sources/families/meson-g12b.conf @@ -24,6 +24,9 @@ function uboot_custom_postprocess() { elif [[ $BOARD == khadas-vim3 ]]; then # do nothing. VIM3 has its own post_uboot_custom_postprocess hook, directly in the board file. : + elif [[ $BOARD == cainiao-cniot-core ]]; then + # do nothing. CAINIAO CNIoT-CORE has its own post_uboot_custom_postprocess hook, directly in the board file. + : elif [[ $BOARD == radxa-zero2 ]]; then uboot_g12_postprocess "$SRC"/cache/sources/amlogic-boot-fip/radxa-zero2 g12b elif [[ $BOARD == bananapim2s ]]; then diff --git a/config/sources/families/rockchip.conf b/config/sources/families/rockchip.conf index d3923093f586..498dd1c03e0c 100644 --- a/config/sources/families/rockchip.conf +++ b/config/sources/families/rockchip.conf @@ -56,7 +56,7 @@ case $BRANCH in edge) - declare -g KERNEL_MAJOR_MINOR="6.14" # Major and minor versions of this kernel. + declare -g KERNEL_MAJOR_MINOR="6.15" # Major and minor versions of this kernel. ;; esac diff --git a/config/sources/mainline-kernel.conf.sh b/config/sources/mainline-kernel.conf.sh index a2ddd7ae2dde..24bdd605641f 100644 --- a/config/sources/mainline-kernel.conf.sh +++ b/config/sources/mainline-kernel.conf.sh @@ -7,8 +7,8 @@ # Shared versioning logic for Armbian mainline kernels. function mainline_kernel_decide_version__upstream_release_candidate_number() { [[ -n "${KERNELBRANCH}" ]] && return 0 # if already set, don't touch it; that way other hooks can run in any order - if [[ "${KERNEL_MAJOR_MINOR}" == "6.15" ]]; then # @TODO: roll over to next MAJOR.MINOR and MAJOR.MINOR-rc1 when it is released - declare -g KERNELBRANCH="tag:v6.15-rc1" + if [[ "${KERNEL_MAJOR_MINOR}" == "6.16" ]]; then # @TODO: roll over to next MAJOR.MINOR and MAJOR.MINOR-rc1 when it is released + declare -g KERNELBRANCH="tag:v6.16-rc1" display_alert "mainline-kernel: upstream release candidate" "Using KERNELBRANCH='${KERNELBRANCH}' for KERNEL_MAJOR_MINOR='${KERNEL_MAJOR_MINOR}'" "info" fi } diff --git a/extensions/apa.sh b/extensions/apa.sh index 19e394f7245c..20330c26e231 100644 --- a/extensions/apa.sh +++ b/extensions/apa.sh @@ -5,7 +5,7 @@ function extension_prepare_config__apa() { } function custom_apt_repo__add_apa() { - run_host_command_logged echo "deb [signed-by=${APT_SIGNING_KEY_FILE}] https://github.armbian.com/apa current main" "|" tee "${SDCARD}"/etc/apt/sources.list.d/armbian-apa.list + run_host_command_logged echo "deb [signed-by=${APT_SIGNING_KEY_FILE}] http://github.armbian.com/apa current main" "|" tee "${SDCARD}"/etc/apt/sources.list.d/armbian-apa.list } function post_armbian_repo_customize_image__install_from_apa() { diff --git a/extensions/armbian-config.sh b/extensions/armbian-config.sh index dc850c52fb62..bdad0d25616c 100644 --- a/extensions/armbian-config.sh +++ b/extensions/armbian-config.sh @@ -5,7 +5,7 @@ function custom_apt_repo__add_armbian-github-repo() { cat <<- EOF > "${SDCARD}"/etc/apt/sources.list.d/armbian-config.sources Types: deb - URIs: https://github.armbian.com/configng + URIs: http://github.armbian.com/configng Suites: stable Components: main Signed-By: ${APT_SIGNING_KEY_FILE} diff --git a/extensions/grub.sh b/extensions/grub.sh index 563e70b4d209..bab94d514476 100644 --- a/extensions/grub.sh +++ b/extensions/grub.sh @@ -247,6 +247,13 @@ pre_umount_final_image__900_export_kernel_and_initramfs() { } configure_grub() { + display_alert "Extension: ${EXTENSION}: Configuring GRUB" "UEFI GRUB; SERIALCON=${SERIALCON}" "info" + + # If SERIALCON is _not_ tty1 or tty0, include a console=tty0 first. + if [[ "${SERIALCON}" != "tty1" && "${SERIALCON}" != "tty0" ]]; then + GRUB_CMDLINE_LINUX_DEFAULT+=" console=tty0" + fi + [[ -n "$SERIALCON" ]] && GRUB_CMDLINE_LINUX_DEFAULT+=" console=${SERIALCON}" @@ -266,7 +273,7 @@ configure_grub() { run_host_command_logged chmod -v +x "${MOUNT}"/usr/share/desktop-base/grub_background.sh fi - display_alert "Extension: ${EXTENSION}: GRUB EFI kernel cmdline" "${GRUB_CMDLINE_LINUX_DEFAULT} distro=${UEFI_GRUB_DISTRO_NAME} timeout=${UEFI_GRUB_TIMEOUT}" "" + display_alert "Extension: ${EXTENSION}: GRUB EFI kernel cmdline" "cmdline '${GRUB_CMDLINE_LINUX_DEFAULT}' distro=${UEFI_GRUB_DISTRO_NAME} timeout=${UEFI_GRUB_TIMEOUT}" "" cat <<- grubCfgFrag >> "${MOUNT}"/etc/default/grub.d/98-armbian.cfg GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT}" GRUB_TIMEOUT_STYLE=menu # Show the menu with Kernel options (Armbian or -generic)... diff --git a/extensions/linux-source-package.sh b/extensions/linux-source-package.sh new file mode 100644 index 000000000000..135b0747e7c5 --- /dev/null +++ b/extensions/linux-source-package.sh @@ -0,0 +1,57 @@ +function extension_prepare_config__linux_source_package_extension() { + display_alert "Packaging kernel source enabled. This will enforce ARTIFACT_IGNORE_CACHE=yes in order to prepare the source code." "${EXTENSION}" "info" + declare -g ARTIFACT_IGNORE_CACHE=yes # enforce building from scratch + declare -g KERNEL_GIT=shallow # download necessary branch only +} + +function add_host_dependencies__add_fakeroot() { + display_alert "Adding packages to host dependencies" "${EXTENSION}" "info" + EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} fakeroot" +} + +function armbian_kernel_config__create_ksrc_package() { + if [[ -f .config ]]; then + + display_alert "Packaging kernel source..." "${EXTENSION}" "info" + declare kernel_work_dir="${SRC}/cache/sources/${LINUXSOURCEDIR}" + declare CHOSEN_KSRC=linux-source-${BRANCH}-${LINUXFAMILY} + + ts=$(date +%s) + local sources_pkg_dir tmp_src_dir + tmp_src_dir=$(mktemp -d) + trap "ret=\$?; rm -rf \"${tmp_src_dir}\" ; exit \$ret" 0 1 2 3 15 + sources_pkg_dir=${tmp_src_dir}/${CHOSEN_KSRC}_${REVISION}_all + mkdir -p "${sources_pkg_dir}"/usr/src/ \ + "${sources_pkg_dir}"/usr/share/doc/linux-source-${version}-${LINUXFAMILY} \ + "${sources_pkg_dir}"/DEBIAN + + cp "${SRC}/config/kernel/${LINUXCONFIG}.config" "default_${LINUXCONFIG}.config" + xz < ${kernel_work_dir}/.config > "${sources_pkg_dir}/usr/src/${LINUXCONFIG}_${version}_${REVISION}_config.xz" + + display_alert "Compressing sources for the linux-source package" "${EXTENSION}" "info" + tar cp --directory="$kernel_work_dir" --exclude='.git' --owner=root . | + pv -p -b -r -s "$(du -sb "$kernel_work_dir" --exclude='.git' | cut -f1)" | + xz -T0 -1 > "${sources_pkg_dir}/usr/src/linux-source-${version}-${LINUXFAMILY}.tar.xz" + cp ${kernel_work_dir}/COPYING "${sources_pkg_dir}/usr/share/doc/linux-source-${version}-${LINUXFAMILY}/LICENSE" + + cat <<- EOF > "${sources_pkg_dir}"/DEBIAN/control + Package: linux-source-${version}-${BRANCH}-${LINUXFAMILY} + Version: ${version}-${BRANCH}-${LINUXFAMILY}+${REVISION} + Architecture: all + Maintainer: $MAINTAINER <$MAINTAINERMAIL> + Section: kernel + Priority: optional + Depends: binutils, coreutils, linux-base + Provides: linux-source, linux-source-${REVISION}-${LINUXFAMILY} + Recommends: gcc, make + Description: This package provides the source code for the Linux kernel $REVISION + EOF + + fakeroot dpkg-deb -b -z0 "${sources_pkg_dir}" "${sources_pkg_dir}.deb" + rsync --remove-source-files -rq "${sources_pkg_dir}.deb" "${DEB_STORAGE}/" + + te=$(date +%s) + display_alert "Make the linux-source package" "$(($te - $ts)) sec." "info" + rm -rf "${tmp_src_dir}" + fi +} \ No newline at end of file diff --git a/extensions/network/config-networkd/netplan/10-dhcp-all-interfaces.yaml b/extensions/network/config-networkd/netplan/10-dhcp-all-interfaces.yaml index 5bd2b3d35a76..97eeb2477412 100644 --- a/extensions/network/config-networkd/netplan/10-dhcp-all-interfaces.yaml +++ b/extensions/network/config-networkd/netplan/10-dhcp-all-interfaces.yaml @@ -14,3 +14,15 @@ network: dhcp4: yes dhcp6: yes ipv6-privacy: yes # Enabled by default on most current systems, but networkd currently doesn't enable IPv6 privacy by default, see https://man.archlinux.org/man/systemd.network.5 + all-lan-interfaces: # include interfaces that are renamed to 'lanX' by udev, e.g. nanopi-r2s + match: + name: "lan[0-9]*" + dhcp4: yes + dhcp6: yes + ipv6-privacy: yes # Enabled by default on most current systems, but networkd currently doesn't enable IPv6 privacy by default, see https://man.archlinux.org/man/systemd.network.5 + all-wan-interfaces: # include interfaces that are renamed to 'wanX' by udev, e.g. nanopi-r1 + match: + name: "wan[0-9]*" + dhcp4: yes + dhcp6: yes + ipv6-privacy: yes # Enabled by default on most current systems, but networkd currently doesn't enable IPv6 privacy by default, see https://man.archlinux.org/man/systemd.network.5 diff --git a/lib/functions/artifacts/artifacts-obtain.sh b/lib/functions/artifacts/artifacts-obtain.sh index 1a60f4867ce6..497856b8d2d7 100644 --- a/lib/functions/artifacts/artifacts-obtain.sh +++ b/lib/functions/artifacts/artifacts-obtain.sh @@ -397,7 +397,7 @@ function build_artifact_for_image() { function pack_artifact_to_local_cache() { if [[ "${artifact_type}" == "deb-tar" ]]; then - declare -a files_to_tar=() + wait_for_disk_sync "before pack_artifact_to_local_cache for deb-tar" run_host_command_logged tar -C "${artifact_base_dir}" -cf "${artifact_final_file}" "${artifact_map_debs[@]}" display_alert "Created deb-tar artifact" "deb-tar: ${artifact_final_file}" "info" fi diff --git a/lib/functions/compilation/armbian-kernel.sh b/lib/functions/compilation/armbian-kernel.sh index 4a12670f4155..8b45e6749838 100644 --- a/lib/functions/compilation/armbian-kernel.sh +++ b/lib/functions/compilation/armbian-kernel.sh @@ -367,8 +367,14 @@ function armbian_kernel_config__restore_enable_gpio_sysfs() { # function kernel_config_set_m() { declare module="$1" - display_alert "Enabling kernel module" "${module}=m" "debug" - run_host_command_logged ./scripts/config --module "$module" + state=$(./scripts/config --state "$module") + + if [ "$state" == "y" ]; then + display_alert "${module} is already enabled as built-in" + else + display_alert "Enabling kernel module" "${module}=m" "debug" + run_host_command_logged ./scripts/config --module "$module" + fi } function kernel_config_set_y() { diff --git a/lib/functions/compilation/kernel-debs.sh b/lib/functions/compilation/kernel-debs.sh index 631c6d52657d..0be710024f00 100644 --- a/lib/functions/compilation/kernel-debs.sh +++ b/lib/functions/compilation/kernel-debs.sh @@ -458,9 +458,8 @@ function kernel_package_callback_linux_headers() { # In order for the cleanup to be correct for tools, we need to pass the VMLINUX_BTF variable, # which contains the real path to the newly compiled vmlinux file. declare make_bitbucket="&> /dev/null" - [[ "${DEBUG}" == "yes" ]] && make_bitbucket="" - run_host_command_logged cd "${headers_target_dir}" "&&" make "ARCH=${SRC_ARCH}" "M=scripts" clean "${make_bitbucket}" - run_host_command_logged cd "${headers_target_dir}/tools" "&&" make "ARCH=${SRC_ARCH}" "VMLINUX_BTF=${kernel_work_dir}/vmlinux" clean "${make_bitbucket}" + run_host_command_logged cd "${headers_target_dir}" "&&" make "ARCH=${SRC_ARCH}" "M=scripts" clean "${make_bitbucket}" "||" make "ARCH=${SRC_ARCH}" "M=scripts" clean + run_host_command_logged cd "${headers_target_dir}/tools" "&&" make "ARCH=${SRC_ARCH}" "VMLINUX_BTF=${kernel_work_dir}/vmlinux" clean "${make_bitbucket}" "||" make "ARCH=${SRC_ARCH}" "VMLINUX_BTF=${kernel_work_dir}/vmlinux" clean # Trim down on the tools dir a bit after cleaning. rm -rf "${headers_target_dir}/tools/perf" "${headers_target_dir}/tools/testing" diff --git a/lib/functions/compilation/patch/drivers_network.sh b/lib/functions/compilation/patch/drivers_network.sh index d4c52df54e8f..3e60118a4d91 100644 --- a/lib/functions/compilation/patch/drivers_network.sh +++ b/lib/functions/compilation/patch/drivers_network.sh @@ -41,7 +41,7 @@ driver_rtl8189ES() { if linux-version compare "${version}" ge 3.14; then # Attach to specific commit (was "branch:master") - local rtl8189esver='commit:fcf2a5746e6fe11d9d71337ee5dac6cf43423a97' # Commit date: Feb 24, 2025 (please update when updating commit ref) + local rtl8189esver='commit:7b43c5c7971eabea263dc2b6cc0928b84323f310' # Commit date: 2025-04-30 (please update when updating commit ref) display_alert "Adding" "Wireless drivers for Realtek 8189ES chipsets ${rtl8189esver}" "info" @@ -87,7 +87,7 @@ driver_rtl8189FS() { if linux-version compare "${version}" ge 3.14; then # Attach to specific commit (was "branch:rtl8189fs") - local rtl8189fsver='commit:3f34f380715b88e4a3ef049b3a60e2fc69ccc9bd' # Commit date: Feb 25, 2025 (please update when updating commit ref) + local rtl8189fsver='commit:06e89edce6817616d963414825dccf87094a7e54' # Commit date: 2025-05-04 (please update when updating commit ref) display_alert "Adding" "Wireless drivers for Realtek 8189FS chipsets ${rtl8189fsver}" "info" @@ -133,7 +133,7 @@ driver_rtl8192EU() { if linux-version compare "${version}" ge 3.14; then # Attach to specific commit (was "branch:realtek-4.4.x") - local rtl8192euver='commit:e6721468a4e48cf2199c212fa13c086e3705bcb3' # Commit date: Feb 16, 2025 (please update when updating commit ref) + local rtl8192euver='commit:27aa922c298f2be240eec6c2e8636fe865ece195' # Commit date: 2025-05-04 (please update when updating commit ref) display_alert "Adding" "Wireless drivers for Realtek 8192EU chipsets ${rtl8192euver}" "info" @@ -175,11 +175,11 @@ driver_rtl8811_rtl8812_rtl8814_rtl8821() { if linux-version compare "${version}" ge 3.14; then # Attach to specific commit (is branch:v5.6.4.2) - local rtl8812auver="commit:c3fb89a2f7066f4bf4e4d9d85d84f9791f14c83e" # Commit date: Mar 30, 2025 (please update when updating commit ref) + local rtl8812auver="commit:fd80508096699705ec9eb95c7a5c970fa6c2ecdc" # Commit date: 2025-05-03 (please update when updating commit ref) display_alert "Adding" "Wireless drivers for Realtek 8811, 8812, 8814 and 8821 chipsets ${rtl8812auver}" "info" - fetch_from_repo "$GITHUB_SOURCE/aircrack-ng/rtl8812au" "rtl8812au" "${rtl8812auver}" "yes" # https://github.com/aircrack-ng/rtl8812au + fetch_from_repo "$GITHUB_SOURCE/domin144/rtl8812au" "rtl8812au" "${rtl8812auver}" "yes" # https://github.com/aircrack-ng/rtl8812au cd "$kerneldir" || exit # Brief detour. Turns out that HardKernel's vendor odroidxu4 kernel already has this driver @@ -245,6 +245,8 @@ driver_xradio_xr819() { >> "$kerneldir/drivers/net/wireless/Makefile" sed -i '/source "drivers\/net\/wireless\/ti\/Kconfig"/a source "drivers\/net\/wireless\/xradio\/Kconfig"' \ "$kerneldir/drivers/net/wireless/Kconfig" + + process_patch_file "${SRC}/patch/misc/xradio-Switching-from-del_timer_sync-to-timer_delete_sync.patch" "applying" fi } @@ -254,7 +256,7 @@ driver_rtl8811CU_rtl8821C() { if linux-version compare "${version}" ge 3.14; then # Attach to specific commit (is branch:main) - local rtl8811cuver="commit:132dcf025806a436b9a95fb4af24eacfd07222f5" # Commit date: Feb 19, 2024 (please update when updating commit ref) + local rtl8811cuver="commit:d74134a1c68f59f2b80cdd6c6afb8c1a8a687cbf" # Commit date: 2025-05-08 (please update when updating commit ref) display_alert "Adding" "Wireless drivers for Realtek RTL8811CU and RTL8821C chipsets ${rtl8811cuver}" "info" @@ -296,7 +298,7 @@ driver_rtl88x2bu() { if linux-version compare "${version}" ge 5.0; then # Attach to specific commit (is branch:main) - local rtl88x2buver="commit:bd8baa17dc0c07510a7a56c52410a81c363b85ae" # Commit date: Feb 21, 2024 (please update when updating commit ref) + local rtl88x2buver="commit:1ee13286e0b212c22946aa8d51aa7d84cb876cd4" # Commit date: 2025-05-06 (please update when updating commit ref) display_alert "Adding" "Wireless drivers for Realtek 88x2bu chipsets ${rtl88x2buver}" "info" @@ -524,6 +526,13 @@ driver_uwe5622() { process_patch_file "${SRC}/patch/misc/wireless-uwe5622/uwe5622-fix-spanning-writes.patch" "applying" fi + if linux-version compare "${version}" ge 6.15; then + if [[ "$LINUXFAMILY" == sunxi* ]]; then + process_patch_file "${SRC}/patch/misc/wireless-uwe5622/uwe5622-fix-timer-api-changes-for-6.15-only-sunxi.patch" "applying" + else + process_patch_file "${SRC}/patch/misc/wireless-uwe5622/uwe5622-v6.15-timer-api-changes.patch" "applying" + fi + fi fi } @@ -625,11 +634,11 @@ driver_rtl8723DS() { if linux-version compare "${version}" ge 5.0; then # Attach to specific commit (was "branch:master") - local rtl8723dsver='commit:ac64712f6767565bc3560e6ae412b780b07bc84c' # Commit date: Feb 16, 2025 (please update when updating commit ref) + local rtl8723dsver='commit:86e3c4d2203b7f977d36a17c24efe0549afc6e31' # Commit date: 2025-05-14 (please update when updating commit ref) display_alert "Adding" "Wireless drivers for Realtek 8723DS chipsets ${rtl8723dsver}" "info" - fetch_from_repo "$GITHUB_SOURCE/lwfinger/rtl8723ds" "rtl8723ds" "${rtl8723dsver}" "yes" # https://github.com/lwfinger/rtl8723ds + fetch_from_repo "$GITHUB_SOURCE/armbian/rtl8723ds" "rtl8723ds" "${rtl8723dsver}" "yes" # https://github.com/armbian/rtl8723ds cd "$kerneldir" || exit rm -rf "$kerneldir/drivers/net/wireless/rtl8723ds" mkdir -p "$kerneldir/drivers/net/wireless/rtl8723ds/" diff --git a/lib/functions/configuration/change-tracking.sh b/lib/functions/configuration/change-tracking.sh index 6a6e8e8681b5..38c169aaea9f 100644 --- a/lib/functions/configuration/change-tracking.sh +++ b/lib/functions/configuration/change-tracking.sh @@ -41,7 +41,7 @@ function track_config_variables() { } function track_general_config_variables() { - track_config_variables "${1}" BOARDFAMILY KERNELSOURCE KERNEL_MAJOR_MINOR KERNELBRANCH LINUXFAMILY LINUXCONFIG KERNELPATCHDIR KERNEL_PATCH_ARCHIVE_BASE + track_config_variables "${1}" BOARDFAMILY KERNELSOURCE KERNEL_MAJOR_MINOR KERNELBRANCH KERNEL_DESCRIPTION LINUXFAMILY LINUXCONFIG KERNELPATCHDIR KERNEL_PATCH_ARCHIVE_BASE array_values="yes" track_config_variables "${1}" KERNEL_DRIVERS_SKIP track_config_variables "${1}" BOOTSOURCE BOOTSOURCEDIR BOOTBRANCH BOOTPATCHDIR BOOTDIR BOOTCONFIG BOOTBRANCH_BOARD BOOTPATCHDIR_BOARD track_config_variables "${1}" ATFSOURCEDIR ATFDIR ATFBRANCH CRUSTSOURCEDIR CRUSTDIR CRUSTBRANCH LINUXSOURCEDIR diff --git a/lib/functions/configuration/interactive.sh b/lib/functions/configuration/interactive.sh index 3e9cc552b0de..c16dced63e15 100644 --- a/lib/functions/configuration/interactive.sh +++ b/lib/functions/configuration/interactive.sh @@ -176,43 +176,96 @@ function interactive_config_ask_board_list() { done } +function get_kernel_info_for_branch() { + local search_branch="$1" + local conf_file="${SRC}/config/sources/families/${BOARDFAMILY}.conf" + + awk -v branch="$search_branch" ' + BEGIN { found=0; major_minor=""; desc="" } + /^[[:space:]]*[a-zA-Z0-9_-]+\)/ { + if ($0 ~ "^[[:space:]]*" branch "\\)") { + found=1 + next + } else if (found) { + exit + } + } + found && /declare[[:space:]]+-g[[:space:]]+KERNEL_MAJOR_MINOR=/ { + if (match($0, /"([^"]+)"/, arr)) { + major_minor=arr[1] + } + } + found && /declare[[:space:]]+-g[[:space:]]+KERNEL_DESCRIPTION=/ { + if (match($0, /"([^"]+)"/, arr)) { + desc=arr[1] + } + } + END { + print major_minor "|" desc + } + ' "$conf_file" +} + function interactive_config_ask_branch() { - # if BRANCH not set, display selection menu - if [[ -n $BRANCH ]]; then - display_alert "Already set BRANCH, skipping interactive" "${BRANCH}" "debug" - return 0 - fi - declare -a options=() - # Loop over the kernel targets and add them to the options array. They're comma separated. - declare one_kernel_target - for one_kernel_target in $(echo "${KERNEL_TARGET}" | tr "," "\n"); do - case $one_kernel_target in - "current") - options+=("current" "Recommended. Usually an LTS kernel") - ;; - "legacy") - options+=("legacy" "Old stable / Legacy / Vendor kernel") - ;; - "edge") - options+=("edge" "Bleeding edge / latest possible") - ;; - "cloud") - options+=("cloud" "Cloud optimised minimal LTS kernel") - ;; - *) - options+=("${one_kernel_target}" "Experimental ${one_kernel_target} kernel / for Developers") - ;; - esac - done + if [[ -n $BRANCH ]]; then + display_alert "Already set BRANCH, skipping interactive" "${BRANCH}" "debug" + return 0 + fi - dialog_if_terminal_set_vars --title "Choose a kernel" --backtitle "$backtitle" --colors \ - --menu "Select the target kernel branch.\nSelected BOARD='${BOARD}'\nExact kernel versions depend on selected board and its family." \ - $TTY_Y $TTY_X $((TTY_Y - 8)) "${options[@]}" + declare -a options=() + declare one_kernel_target - set_interactive_config_value BRANCH "${DIALOG_RESULT}" + for one_kernel_target in $(echo "${KERNEL_TARGET}" | tr "," "\n"); do - [[ -z ${BRANCH} ]] && exit_with_error "No kernel branch selected" - return 0 + + local version="" + local description="" + + local info + info="$(get_kernel_info_for_branch "$one_kernel_target")" + version="${info%%|*}" + description="${info#*|}" + + # Fallback if description is empty + if [[ -z "$description" ]]; then + case "$one_kernel_target" in + current) + description="Recommended. Usually an LTS kernel" + ;; + legacy) + description="Old stable / Legacy kernel" + ;; + edge) + description="Bleeding edge / latest possible" + ;; + cloud) + description="Cloud optimized minimal LTS kernel" + ;; + vendor) + description="Vendor BSP kernel" + ;; + *) + description="Experimental ${one_kernel_target} kernel / for Developers" + ;; + esac + fi + + # Append version if found + if [[ -n "$version" ]]; then + description="${description} (${version})" + fi + + options+=("${one_kernel_target}" "${description}") + done + + dialog_if_terminal_set_vars --title "Choose a kernel" --backtitle "$backtitle" --colors \ + --menu "Select the target kernel branch.\nSelected BOARD='${BOARD}'\nExact kernel versions depend on selected board and its family." \ + $TTY_Y $TTY_X $((TTY_Y - 8)) "${options[@]}" + + set_interactive_config_value BRANCH "${DIALOG_RESULT}" + + [[ -z ${BRANCH} ]] && exit_with_error "No kernel branch selected" + return 0 } function interactive_config_ask_release() { diff --git a/lib/functions/general/extensions.sh b/lib/functions/general/extensions.sh index 439d7a78c064..280e2fa9d8d8 100644 --- a/lib/functions/general/extensions.sh +++ b/lib/functions/general/extensions.sh @@ -562,6 +562,42 @@ function enable_all_extensions_builtin_and_user() { done } +# This looks up and enables extensions containing function hooks passed in as arguments. +# The reasoning is simple: during Dockerfile build, we wanna have all the hostdeps defined, even if we're not gonna use them. +function enable_extensions_with_hostdeps_builtin_and_user() { + declare -a searched_hook_names=("${@}") #eg: "add_host_dependencies" "host_dependencies_known" + declare -a grep_args=() + for hook_name in "${searched_hook_names[@]}"; do + grep_args+=("-e" "^function ${hook_name}__") + done + + declare -a extension_list=() + declare -a ext_dirs=("${SRC}/extensions" "${USERPATCHES_PATH}/extensions") + declare -a ignore_extensions=("sample-extension") + + # Extensions are files of the format /extension_name.sh or /extension_name/extension_name.sh + for ext_dir in "${ext_dirs[@]}"; do + if [[ -d "${ext_dir}" ]]; then + declare -a ext_list_dir=() + mapfile -t ext_list_dir < <(find "${ext_dir}" -maxdepth 2 -type f -name "*.sh" -print0 | xargs -0 grep -l "${grep_args[@]}") + extension_list+=("${ext_list_dir[@]}") + fi + done + + # loop over the files found; remove the prefix + for extension_file in "${extension_list[@]}"; do + extension_file="${extension_file#${SRC}/}" + extension_file="${extension_file%.sh}" + extension_name="${extension_file##*/}" + # skip, if extension_name is in the ignore_extensions array + if [[ " ${ignore_extensions[*]} " == *" ${extension_name} "* ]]; then + continue + fi + # enable the extensions, quietly. + enable_extension_quiet="yes" enable_extension "${extension_name}" + done +} + # Fancy placeholder for future ideas. allow any core function to be hooked. maybe with "voters" infrastructure? function do_with_hooks() { "$@" diff --git a/lib/functions/host/docker.sh b/lib/functions/host/docker.sh index 736acbe2a447..a3f5cbb46561 100644 --- a/lib/functions/host/docker.sh +++ b/lib/functions/host/docker.sh @@ -247,12 +247,14 @@ function docker_cli_prepare_dockerfile() { # initialize the extension manager; enable all extensions; only once.. if [[ "${docker_prepare_cli_skip_exts:-no}" != "yes" ]]; then display_alert "Docker launcher" "enabling all extensions looking for Docker dependencies" "info" - enable_all_extensions_builtin_and_user + declare -i seconds_before_extensions=$SECONDS + enable_extensions_with_hostdeps_builtin_and_user "add_host_dependencies" "host_dependencies_known" initialize_extension_manager + display_alert "Docker launcher" "enabled extensions in $((SECONDS - seconds_before_extensions)) seconds" "debug" fi declare -a -g host_dependencies=() - host_release="${DOCKER_WANTED_RELEASE}" early_prepare_host_dependencies + host_release="${DOCKER_WANTED_RELEASE}" early_prepare_host_dependencies # hooks: add_host_dependencies // host_dependencies_known display_alert "Pre-game host dependencies for host_release '${DOCKER_WANTED_RELEASE}'" "${host_dependencies[*]}" "debug" # This includes apt install equivalent to install_host_dependencies() @@ -407,6 +409,13 @@ function docker_cli_prepare_launch() { "--env" "GITHUB_SHA=${GITHUB_SHA}" "--env" "GITHUB_WORKFLOW=${GITHUB_WORKFLOW}" "--env" "GITHUB_WORKSPACE=${GITHUB_WORKSPACE}" + + # Pass proxy args + "--env" "http_proxy=${http_proxy:-${HTTP_PROXY}}" + "--env" "https_proxy=${https_proxy:-${HTTPS_PROXY}}" + "--env" "HTTP_PROXY=${HTTP_PROXY}" + "--env" "HTTPS_PROXY=${HTTPS_PROXY}" + "--env" "APT_PROXY_ADDR=${APT_PROXY_ADDR}" ) # This env var is used super early (in entrypoint.sh), so set it as an env to current value. diff --git a/lib/functions/host/prepare-host.sh b/lib/functions/host/prepare-host.sh index 8affa5407188..f378e3e59e29 100644 --- a/lib/functions/host/prepare-host.sh +++ b/lib/functions/host/prepare-host.sh @@ -203,7 +203,7 @@ function adaptative_prepare_host_dependencies() { udev # causes initramfs rebuild, but is usually pre-installed. uuid-dev zlib1g-dev - gcc-arm-linux-gnueabi # necessary for rockchip64 (and maybe other too) ATF compilation + gcc-arm-linux-gnueabi # necessary for rockchip64 (and maybe other too) ATF compilation # by-category below file tree expect # logging utilities; expect is needed for 'unbuffer' command @@ -228,6 +228,12 @@ function adaptative_prepare_host_dependencies() { # Needed for some u-boot's, lest "tools/mkeficapsule.c:21:10: fatal error: gnutls/gnutls.h" host_dependencies+=("libgnutls28-dev") + # Some versions of U-Boot do not require/import 'python3-setuptools' properly, so add them explicitly. + if [[ 'tag:v2022.04' == "${BOOTBRANCH:-}" || 'tag:v2022.07' == "${BOOTBRANCH:-}" ]]; then + display_alert "Adding package to 'host_dependencies'" "python3-setuptools" "info" + host_dependencies+=("python3-setuptools") + fi + ### Python2 -- required for some older u-boot builds # Debian newer than 'bookworm' and Ubuntu newer than 'lunar'/'mantic' does not carry python2 anymore; in this case some u-boot's might fail to build. # Last versions to support python2 were Debian 'bullseye' and Ubuntu 'jammy' diff --git a/lib/functions/image/rootfs-to-image.sh b/lib/functions/image/rootfs-to-image.sh index bae3a0b84c2e..3bc9c7c08bb2 100644 --- a/lib/functions/image/rootfs-to-image.sh +++ b/lib/functions/image/rootfs-to-image.sh @@ -215,7 +215,7 @@ function move_images_to_final_destination() { done else display_alert "Moving artefacts using rsync to final destination" "${version}" "info" - run_host_command_logged rsync -av --sparse --no-owner --no-group --remove-source-files "${DESTIMG}/${version}"* "${FINALDEST}" + run_host_command_logged rsync -av --no-owner --no-group --remove-source-files "${DESTIMG}/${version}"* "${FINALDEST}" run_host_command_logged rm -rfv --one-file-system "${DESTIMG}" fi return 0 diff --git a/lib/functions/logging/runners.sh b/lib/functions/logging/runners.sh index 3643b0c8b0ad..a99b866e4d0c 100644 --- a/lib/functions/logging/runners.sh +++ b/lib/functions/logging/runners.sh @@ -37,8 +37,15 @@ function chroot_sdcard_apt_get_remove() { DONT_MAINTAIN_APT_CACHE="yes" chroot_sdcard_apt_get remove "$@" } +function chroot_sdcard_custom_with_apt_logic() { + declare command="${1}" + shift + chroot_command="${command}" chroot_sdcard_apt_get "$@" +} + function chroot_sdcard_apt_get() { acng_check_status_or_restart # make sure apt-cacher-ng is running OK. + declare apt_get_command="${chroot_command:-"apt-get"}" declare default_apt_logging="-qq" if [[ "${SHOW_DEBUG}" == "yes" ]]; then default_apt_logging="" @@ -83,7 +90,7 @@ function chroot_sdcard_apt_get() { prelude_clean_env=("env" "-i") fi - local_apt_deb_cache_prepare "before 'apt-get $*'" # sets LOCAL_APT_CACHE_INFO + local_apt_deb_cache_prepare "before '${apt_get_command} $*'" # sets LOCAL_APT_CACHE_INFO if [[ "${LOCAL_APT_CACHE_INFO[USE]}" == "yes" ]]; then # prepare and mount apt cache dir at /var/cache/apt/archives in the SDCARD. skip_error_info="yes" run_host_command_logged mkdir -pv "${LOCAL_APT_CACHE_INFO[SDCARD_DEBS_DIR]}" "${LOCAL_APT_CACHE_INFO[SDCARD_LISTS_DIR]}" @@ -104,9 +111,14 @@ function chroot_sdcard_apt_get() { display_alert "Extra envs for apt:" "${extra_envs[*]@Q}" "debug" local chroot_apt_result=1 - chroot_sdcard "${prelude_clean_env[@]}" "${extra_envs[@]}" apt-get "${apt_params[@]}" "$@" && chroot_apt_result=0 + if [[ "${apt_get_command}" == "apt-get" ]]; then + chroot_sdcard "${prelude_clean_env[@]}" "${extra_envs[@]}" apt-get "${apt_params[@]}" "$@" && chroot_apt_result=0 + else + # custom case: does not pass the apt parameters; but envs are passed normally. + chroot_sdcard "${prelude_clean_env[@]}" "${extra_envs[@]}" "${apt_get_command}" "$@" && chroot_apt_result=0 + fi - local_apt_deb_cache_prepare "after 'apt-get $*'" # sets LOCAL_APT_CACHE_INFO + local_apt_deb_cache_prepare "after '${apt_get_command} $*'" # sets LOCAL_APT_CACHE_INFO if [[ "${LOCAL_APT_CACHE_INFO[USE]}" == "yes" ]]; then display_alert "Unmounting apt deb cache dir" "${LOCAL_APT_CACHE_INFO[SDCARD_DEBS_DIR]}" "debug" run_host_command_logged umount "${LOCAL_APT_CACHE_INFO[SDCARD_DEBS_DIR]}" diff --git a/lib/functions/main/config-prepare.sh b/lib/functions/main/config-prepare.sh index 05573d493561..1a3f1e52121b 100644 --- a/lib/functions/main/config-prepare.sh +++ b/lib/functions/main/config-prepare.sh @@ -166,7 +166,11 @@ function config_early_init() { display_alert "Starting single build process" "${BOARD:-"no BOARD set"}" "info" - declare -g -a KERNEL_DRIVERS_SKIP=() # Prepare array to be filled in by board/family/extensions + # Do not initialize an empty array if it exists. + if [ "${KERNEL_DRIVERS_SKIP[*]}" == "" ]; then + # Prepare array to be filled in by board/family/extensions + declare -g -a KERNEL_DRIVERS_SKIP=() + fi silent="yes" track_general_config_variables "after config_early_init" # don't log anything, just init the change tracking diff --git a/lib/functions/rootfs/customize.sh b/lib/functions/rootfs/customize.sh index f861b64cadf5..42119716b97d 100644 --- a/lib/functions/rootfs/customize.sh +++ b/lib/functions/rootfs/customize.sh @@ -20,8 +20,10 @@ function customize_image() { If you need repos, please consider `post_armbian_repo_customize_image` or `post_repo_customize_image`. PRE_CUSTOMIZE_IMAGE - cp "$USERPATCHES_PATH"/customize-image.sh "${SDCARD}"/tmp/customize-image.sh - chmod +x "${SDCARD}"/tmp/customize-image.sh + if [[ -f "$USERPATCHES_PATH"/customize-image.sh ]]; then + cp "$USERPATCHES_PATH"/customize-image.sh "${SDCARD}"/tmp/customize-image.sh + chmod +x "${SDCARD}"/tmp/customize-image.sh + fi mkdir -p "${SDCARD}"/tmp/overlay # util-linux >= 2.27 required diff --git a/lib/functions/rootfs/distro-specific.sh b/lib/functions/rootfs/distro-specific.sh index f9c54b06f197..8bd537219424 100644 --- a/lib/functions/rootfs/distro-specific.sh +++ b/lib/functions/rootfs/distro-specific.sh @@ -161,9 +161,13 @@ function create_sources_list_and_deploy_repo_key() { display_alert "Adding Armbian repository and authentication key" "${when} :: /etc/apt/sources.list.d/armbian.sources" "info" mkdir -p "${basedir}"/usr/share/keyrings # change to binary form - APT_SIGNING_KEY_FILE="/usr/share/keyrings/armbian.gpg" + APT_SIGNING_KEY_FILE="/usr/share/keyrings/armbian-archive-keyring.gpg" gpg --dearmor < "${SRC}"/config/armbian.key > "${basedir}${APT_SIGNING_KEY_FILE}" + # lets link to the old file as armbian-config uses it and we can't set there to new file + # we user force linking as some old caches still exists + chroot "${basedir}" /bin/bash -c "ln -fs armbian-archive-keyring.gpg /usr/share/keyrings/armbian.gpg" + # lets keep old way for old distributions if [[ "${RELEASE}" =~ (focal|bullseye) ]]; then cp "${SRC}"/config/armbian.key "${basedir}" @@ -192,7 +196,7 @@ function create_sources_list_and_deploy_repo_key() { fi cat <<- EOF > "${basedir}"/etc/apt/sources.list.d/armbian.sources Types: deb - URIs: https://${armbian_mirror} + URIs: http://${armbian_mirror} Suites: $RELEASE Components: ${components[*]} Signed-By: ${APT_SIGNING_KEY_FILE} diff --git a/packages/blobs/asound.state/asound.state.cainiao-cniot-core b/packages/blobs/asound.state/asound.state.cainiao-cniot-core new file mode 100644 index 000000000000..4714671c1ef8 --- /dev/null +++ b/packages/blobs/asound.state/asound.state.cainiao-cniot-core @@ -0,0 +1,621 @@ +state.CNIoTCORE { + control.1 { + iface MIXER + name 'TOACODEC Lane Select' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 3' + } + } + control.2 { + iface MIXER + name 'ACODEC Playback Channel Mode' + value Stereo + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Stereo + item.1 Mono + } + } + control.3 { + iface MIXER + name 'ACODEC Playback Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.4 { + iface MIXER + name 'ACODEC Playback Volume' + value.0 255 + value.1 255 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + dbmin -9999999 + dbmax 0 + dbvalue.0 0 + dbvalue.1 0 + } + } + control.5 { + iface MIXER + name 'ACODEC Ramp Rate' + value Fast + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Fast + item.1 Slow + } + } + control.6 { + iface MIXER + name 'ACODEC Volume Ramp Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.7 { + iface MIXER + name 'ACODEC Mute Ramp Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.8 { + iface MIXER + name 'ACODEC Unmute Ramp Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.9 { + iface MIXER + name 'TDMOUT_C Lane 0 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.10 { + iface MIXER + name 'TDMOUT_C Lane 1 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.11 { + iface MIXER + name 'TDMOUT_C Lane 2 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.12 { + iface MIXER + name 'TDMOUT_C Lane 3 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.13 { + iface MIXER + name 'TDMOUT_C Gain Enable Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.14 { + iface MIXER + name 'TDMOUT_B Lane 0 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.15 { + iface MIXER + name 'TDMOUT_B Lane 1 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.16 { + iface MIXER + name 'TDMOUT_B Lane 2 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.17 { + iface MIXER + name 'TDMOUT_B Lane 3 Volume' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + } + } + control.18 { + iface MIXER + name 'TDMOUT_B Gain Enable Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.19 { + iface PCM + device 7 + name 'Playback Channel Map' + value.0 0 + value.1 0 + value.2 0 + value.3 0 + value.4 0 + value.5 0 + value.6 0 + value.7 0 + comment { + access 'read volatile' + type INTEGER + count 8 + range '0 - 36' + } + } + control.20 { + iface PCM + device 7 + name 'IEC958 Playback Mask' + value ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + comment { + access read + type IEC958 + count 1 + } + } + control.21 { + iface PCM + device 7 + name 'IEC958 Playback Default' + value '0400000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + comment { + access 'read write' + type IEC958 + count 1 + } + } + control.22 { + iface PCM + device 7 + name ELD + value '100008006d10000100000000000000003669c2ac4d414732373451205144204532097f070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + comment { + access 'read volatile' + type BYTES + count 128 + } + } + control.23 { + iface MIXER + name 'FRDDR_A SRC 1 EN Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.24 { + iface MIXER + name 'FRDDR_A SRC 2 EN Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.25 { + iface MIXER + name 'FRDDR_A SRC 3 EN Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.26 { + iface MIXER + name 'FRDDR_A SINK 1 SEL' + value 'OUT 1' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.27 { + iface MIXER + name 'FRDDR_A SINK 2 SEL' + value 'OUT 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.28 { + iface MIXER + name 'FRDDR_A SINK 3 SEL' + value 'OUT 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.29 { + iface MIXER + name 'FRDDR_B SRC 1 EN Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.30 { + iface MIXER + name 'FRDDR_B SRC 2 EN Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.31 { + iface MIXER + name 'FRDDR_B SRC 3 EN Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.32 { + iface MIXER + name 'FRDDR_B SINK 1 SEL' + value 'OUT 2' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.33 { + iface MIXER + name 'FRDDR_B SINK 2 SEL' + value 'OUT 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.34 { + iface MIXER + name 'FRDDR_B SINK 3 SEL' + value 'OUT 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.35 { + iface MIXER + name 'FRDDR_C SRC 1 EN Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.36 { + iface MIXER + name 'FRDDR_C SRC 2 EN Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.37 { + iface MIXER + name 'FRDDR_C SRC 3 EN Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.38 { + iface MIXER + name 'FRDDR_C SINK 1 SEL' + value 'OUT 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.39 { + iface MIXER + name 'FRDDR_C SINK 2 SEL' + value 'OUT 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.40 { + iface MIXER + name 'FRDDR_C SINK 3 SEL' + value 'OUT 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'OUT 0' + item.1 'OUT 1' + item.2 'OUT 2' + item.3 'OUT 3' + item.4 'OUT 4' + item.5 'OUT 5' + item.6 'OUT 6' + item.7 'OUT 7' + } + } + control.41 { + iface MIXER + name 'TOHDMITX I2S SRC' + value 'I2S B' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'I2S A' + item.1 'I2S B' + item.2 'I2S C' + } + } + control.42 { + iface MIXER + name 'TOHDMITX Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.43 { + iface MIXER + name 'TOHDMITX SPDIF SRC' + value 'SPDIF A' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'SPDIF A' + item.1 'SPDIF B' + } + } + control.44 { + iface MIXER + name 'TOACODEC SRC' + value 'I2S C' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'I2S A' + item.1 'I2S B' + item.2 'I2S C' + } + } + control.45 { + iface MIXER + name 'TOACODEC OUT EN Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.46 { + iface MIXER + name 'ACODEC Right DAC Sel' + value Right + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Right + item.1 Left + } + } + control.47 { + iface MIXER + name 'ACODEC Left DAC Sel' + value Left + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Left + item.1 Right + } + } + control.48 { + iface MIXER + name 'TDMOUT_C SRC SEL' + value 'IN 1' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'IN 0' + item.1 'IN 1' + item.2 'IN 2' + } + } + control.49 { + iface MIXER + name 'TDMOUT_B SRC SEL' + value 'IN 0' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'IN 0' + item.1 'IN 1' + item.2 'IN 2' + } + } +} diff --git a/packages/bsp/common/usr/lib/armbian/armbian-allwinner-battery b/packages/bsp/common/usr/lib/armbian/armbian-allwinner-battery index 5d18d017fbf8..85cf35c788f3 100755 --- a/packages/bsp/common/usr/lib/armbian/armbian-allwinner-battery +++ b/packages/bsp/common/usr/lib/armbian/armbian-allwinner-battery @@ -11,11 +11,11 @@ function getboardtemp() { if [ -f /etc/armbianmonitor/datasources/soctemp ]; then read raw_temp /dev/null - if [ ! -z $(echo "$raw_temp" | grep -o "^[1-9][0-9]*\.\?[0-9]*$") ] && (( $(echo "${raw_temp} < 200" |bc -l) )); then - # Allwinner legacy kernels output degree C + if [[ "$raw_temp" =~ ^[1-9][0-9]*\.?[0-9]*$ ]] && awk "BEGIN {exit !($raw_temp < 200)}"; then + # Allwinner legacy kernels output degree C board_temp=${raw_temp} else - board_temp=$(awk '{printf("%d",$1/1000)}' <<<${raw_temp}) + board_temp=$(awk '{printf("%d",$1/1000)}' <<<"${raw_temp}") fi elif [ -f /etc/armbianmonitor/datasources/pmictemp ]; then # fallback to PMIC temperature diff --git a/packages/bsp/common/usr/lib/armbian/armbian-firstlogin b/packages/bsp/common/usr/lib/armbian/armbian-firstlogin index 195d811f9117..fca30573f80f 100755 --- a/packages/bsp/common/usr/lib/armbian/armbian-firstlogin +++ b/packages/bsp/common/usr/lib/armbian/armbian-firstlogin @@ -687,15 +687,30 @@ if [[ -f /root/.not_logged_in_yet && -n $(tty) ]]; then systemctl start systemd-networkd-wait-online fi - # enable hiDPI support - if [[ "$(cut -d, -f1 < /sys/class/graphics/fb0/virtual_size 2> /dev/null)" -gt 1920 ]]; then - # lightdm - [[ -f /etc/lightdm/slick-greeter.conf ]] && echo "enable-hidpi = on" >> /etc/lightdm/slick-greeter.conf - # xfce - [[ -f /etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml ]] && sed -i 's||g' /etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml - - # framebuffer console larger font - setfont /usr/share/consolefonts/Uni3-TerminusBold32x16.psf.gz + # Enable HiDPI support only if the framebuffer size is detectable + FB_VIRTUAL_SIZE="/sys/class/graphics/fb0/virtual_size" + HIDPI_THRESHOLD="1920" + if [[ -r "$FB_VIRTUAL_SIZE" ]]; then + fb_virtual_width=$(cut -d, -f1 < "$FB_VIRTUAL_SIZE" 2>/dev/null) + if [[ "$fb_virtual_width" =~ ^[0-9]+$ && "$fb_virtual_width" -gt "${HIDPI_THRESHOLD}" ]]; then + # Enable HiDPI in LightDM slick-greeter + if [[ -f /etc/lightdm/slick-greeter.conf ]]; then + if ! grep -q "^enable-hidpi *= *on" /etc/lightdm/slick-greeter.conf; then + echo "enable-hidpi = on" >> /etc/lightdm/slick-greeter.conf + fi + fi + + # Set XFCE scaling factor in skeleton config + XFCE_XSETTINGS="/etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml" + if [[ -f "$XFCE_XSETTINGS" ]]; then + sed -i 's|\(\)|\12\2|' "$XFCE_XSETTINGS" + fi + + # Set a larger console font for framebuffer + if [[ -f /usr/share/consolefonts/Uni3-TerminusBold32x16.psf.gz ]]; then + setfont /usr/share/consolefonts/Uni3-TerminusBold32x16.psf.gz + fi + fi fi clear diff --git a/packages/bsp/mvebu/helios4/helios4-wol.service b/packages/bsp/mvebu/helios4/helios4-wol.service index 965eb74f5e88..469a32c0536d 100644 --- a/packages/bsp/mvebu/helios4/helios4-wol.service +++ b/packages/bsp/mvebu/helios4/helios4-wol.service @@ -4,7 +4,7 @@ After=network-online.target Wants=network-online.target [Service] -ExecStart=/sbin/ethtool -s eth0 wol g +ExecStart=/bin/sh -c '/bin/ls -1 /sys/class/net/ | /bin/grep -E "^(eth|en[do])[0-9]+" | /bin/xargs -n1 -I{} /sbin/ethtool -s "{}" wol g' Type=oneshot [Install] diff --git a/packages/bsp/wifi-rtl8821cu/etc/modprobe.d/8821cu.conf b/packages/bsp/wifi-rtl8821cu/etc/modprobe.d/8821cu.conf new file mode 100644 index 000000000000..569c2e6abb06 --- /dev/null +++ b/packages/bsp/wifi-rtl8821cu/etc/modprobe.d/8821cu.conf @@ -0,0 +1,207 @@ +# /etc/modprobe.d/8821cu.conf +# +# source: https://github.com/morrownr/8821cu-20210916/blob/main/8821cu.conf +# +# Purpose: Allow easy access to specific driver options. +# +# Note: pull-request: wireless-next-2022-12-12 +# wireless-next patches for v6.2 +# wifi: rtw88: Add rtw8821cu chipset support +# +# The following line blacklists (deactivates) the above in-kernel driver. +blacklist rtw88_8821cu +# +# Edit the following line to change, add or delete options: +options 8821cu rtw_led_ctrl=1 rtw_power_mgnt=1 rtw_RFE_type=7 rtw_country_code=US +# +# Note: The above `options` line is a good default for managed mode. Below is +# an example for AP mode. Modify as required after reading the documentation: +#options 8821cu rtw_drv_log_level=1 rtw_led_ctrl=1 rtw_vht_enable=2 rtw_power_mgnt=1 rtw_beamform_cap=1 rtw_dfs_region_domain=1 +# +# After editing is complete, save this file (if using nano: Ctrl + x, y, Enter) +# and reboot to activate the changes. +# +# Important: Some adapters based on the rtl8821cu chipset may require the +# `rtw_RFE_type` option to be set. If wifi or bluetooth does not work +# after driver installation, see the appropriate section in the below +# documentation. This issue has not been seen on wifi only adapters. +# +# Documentation: +# +# ----- +# +# Log options ( rtw_drv_log_level ) +# +# 0 = NONE (default) +# 1 = ALWAYS +# 2 = ERROR +# 3 = WARNING +# 4 = INFO +# 5 = DEBUG +# 6 = MAX +# +# Note: You can save a log file that only includes RTW log entries by running +# the following in a terminal: +# +# sudo ./save-log.sh +# +# Note: A log option greater than 1 must be set. The name of the log +# file will be `rtw.log`. +# +# ----- +# +# LED options ( rtw_led_ctrl ) +# +# 0 = Always off +# 1 = Normal blink (default) +# 2 = Always on +# +# ----- +# +# VHT options ( rtw_vht_enable ) +# +# 0 = Disable +# 1 = Enable (default) +# 2 = Force auto enable (use only for 5 GHz AP mode) +# +# Notes: +# - A non-default setting can degrade performance greatly in managed mode. +# - Option 2 allows 80 MHz channel width for 5GHz AP mode, such as when +# you are using hostapd. +# +# ----- +# +# Power options ( rtw_power_mgnt ) +# +# 0 = Disable power saving +# 1 = Power saving on, minPS (default) +# 2 = Power saving on, maxPS (not recommended for AP mode) +# +# ----- +# +# Beamforming options ( rtw_beamform_cap ) +# +# 1 = SU Beamformer (recommended for AP mode) +# 2 = SU Beamformee +# 3 = SU Beamformer and SU Beamformee +# 10= SU Beamformee and MU Beamformee (default) +# 11= SU Beamformer and SU Beamformee and MU Beamformee +# +# Note: MU Beamformer is not supported. +# +# From the source code: +# +# /* /os_dep/linux/os_intfs.c +# * +# * BIT0: Enable VHT SU Beamformer +# * BIT1: Enable VHT SU Beamformee +# * BIT2: Enable VHT MU Beamformer, depend on VHT SU Beamformer (not supported) +# * BIT3: Enable VHT MU Beamformee, depend on VHT SU Beamformee +# */ +# +# ----- +# +# USB options: ( rtw_switch_usb_mode ) +# +# Note: This option is not supported on this chipset. This chipset is USB2 only. +# +# ----- +# +# DFS Options ( rtw_dfs_region_domain ) +# +# 0 = NONE (default) +# 1 = FCC +# 2 = MKK +# 3 = ETSI +# +# Notes: +# - Activates DFS channels in AP mode. +# - DFS FCC 80 MHz channels for hostapd: 52(58), 100(106), 116(122) and 132(138) +# - For more information: https://en.wikipedia.org/wiki/List_of_WLAN_channels +# +# Note: An AP needs to listen on a DFS channel for a period of 60 seconds +# before transmitting on the channel. If any radar pulses are detected, +# the AP cannot use that channel and will have to try a different channel. +# +# ----- +# +# Wireless Mode options ( rtw_wireless_mode ) +# +# 1 = 2.4GHz 802.11b +# 2 = 2.4GHz 802.11g +# 3 = 2.4GHz 802.11b/g +# 4 = 5GHz 802.11a +# 8 = 2.4Hz 802.11n +# 11 = 2.4GHz 802.11b/g/n +# 16 = 5GHz 802.11n +# 20 = 5GHz 802.11a/n +# 64 = 5GHz 802.11ac +# 84 = 5GHz 802.11a/n/ac +# 95 = 2.4GHz 802.11b/g/n 5GHz 802.11a/n/ac (default) +# +# ----- +# +# Country Code options ( rtw_country_code ) +# +# Note: Allows the Country Code to be set in cases where it is unable to +# be obtained otherwise. +# +# URL: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 +# +# Example for the US: rtw_country_code=US +# Example for Panama: rtw_country_code=PA +# Example for Norway: rtw_country_code=NO +# Example for Kuwait: rtw_country_code=KW +# Example for Taiwan: rtw_country_code=TW +# +# ----- +# +# Select RFE type ( rtw_RFE_type ) +# +# 0 = (2-Ant, DPDT), (2G_WLG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) +# 1 = (1-Ant, SPDT@Ant1), (2G_WLG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) +# 2 = (1-Ant, SPDT@Ant1) , (2G_BTG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) +# 3 = (1-Ant, DPDT@Ant2), (2G_WLG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) +# 4 = (1-Ant, DPDT@Ant2), (2G_BTG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) +# 5 = (2-Ant), (2G_WLG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) +# 6 = (2-Ant), (2G_WLG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) +# 7 = (1-Ant), (2G_BTG, iPA, iLNA, iSW), (5G, iPA, iLNA, iSW) (try this setting first) +# 64 = this appears to be the default on adapters that do not support bluetooth +# +# Note: RFE Type is used to set antenna isolation and the BT coexistence +# mechanism. Some adapters require this setting and some do not. It may be +# necessary to try different settings to determine which setting is optimal +# for your adapter. +# +# ----- +# +# To see all options that are available: +# +# $ ls /sys/module/8821cu/parameters/ +# +# ----- +# +# To see the values that are in use: +# +# $ grep [[:alnum:]] /sys/module/8821cu/parameters/* +# or +# $ for f in /sys/module/8821cu/parameters/*;do echo "$(basename $f): $(sudo cat $f)";done +# ----- +# +# hostapd setup information for rtl8821cu +# Note: The best settings can vary but the following may be a good place to start. +# +# /etc/modprobe.d/8821cu.conf +# options 8821cu rtw_drv_log_level=0 rtw_led_ctrl=0 rtw_vht_enable=2 rtw_power_mgnt=1 rtw_dfs_region_domain=1 +# +# Note: The best setting for `rtw_dfs_region_domain=` will depend on your location. +# +# /etc/hostapd/hostapd.conf +# +# hw ht capab: 0x862 +# ht_capab=[HT40+][HT40-][SHORT-GI-20][SHORT-GI-40][MAX-AMSDU-7935] +# +# hw vht capab: 0x03c00022 +# vht_capab=[MAX-MPDU-11454][SHORT-GI-80][HTC-VHT][MAX-A-MPDU-LEN-EXP7] +# +# ----- diff --git a/patch/atf/atf-imx8/0001-fix-needed-by-armbian-build-system.patch b/patch/atf/atf-imx8/0001-fix-needed-by-armbian-build-system.patch new file mode 100644 index 000000000000..9d1f16f1c50f --- /dev/null +++ b/patch/atf/atf-imx8/0001-fix-needed-by-armbian-build-system.patch @@ -0,0 +1,30 @@ +From 230e25fbcd0a36dfaaa8f3b9f0ad7d9cd0500736 Mon Sep 17 00:00:00 2001 +From: Martin Schmiedel +Date: Wed, 28 May 2025 14:02:39 +0200 +Subject: [PATCH] fix needed by armbian build system + +remove possibly contained gcc linker flags + +Signed-off-by: Martin Schmiedel +--- + Makefile | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Makefile b/Makefile +index ea5701347..7a4ff1244 100644 +--- a/Makefile ++++ b/Makefile +@@ -343,6 +343,10 @@ GCC_V_OUTPUT := $(shell $(CC) -v 2>&1) + + TF_LDFLAGS += -z noexecstack + ++# remove possibly contained gcc linker flags we use the linker directly ++gcc_linker_flags = -Wl,--no-warn-rwx-segment ++TF_LDFLAGS := $(filter-out $(gcc_linker_flags), $(TF_LDFLAGS)) ++ + # LD = armlink + ifneq ($(findstring armlink,$(notdir $(LD))),) + TF_LDFLAGS += --diag_error=warning --lto_level=O1 +-- +2.43.0 + diff --git a/patch/atf/atf-rockchip64/enable-logging.patch b/patch/atf/atf-rockchip64/enable-logging.patch deleted file mode 100644 index f327c1d3a24a..000000000000 --- a/patch/atf/atf-rockchip64/enable-logging.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h -index ba83242..8d6ecfb 100644 ---- a/plat/rockchip/rk3399/rk3399_def.h -+++ b/plat/rockchip/rk3399/rk3399_def.h -@@ -17,7 +17,7 @@ - /************************************************************************** - * UART related constants - **************************************************************************/ --#define RK3399_BAUDRATE 115200 -+#define RK3399_BAUDRATE 1500000 - #define RK3399_UART_CLOCK 24000000 - - /****************************************************************************** -diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c -index c4a0359..22d07e0 100644 ---- a/plat/rockchip/common/bl31_plat_setup.c -+++ b/plat/rockchip/common/bl31_plat_setup.c -@@ -61,10 +61,13 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, - - params_early_setup(arg1); - -- if (rockchip_get_uart_base() != 0) -+ if (rockchip_get_uart_base() != 0) { - console_16550_register(rockchip_get_uart_base(), - rockchip_get_uart_clock(), - rockchip_get_uart_baudrate(), &console); -+ console_set_scope(&console, -+ CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); -+ } - - VERBOSE("bl31_setup\n"); diff --git a/patch/kernel/archive/imx8m-6.12/0003-TQMa8MPXL-LDO5-Fix.patch b/patch/kernel/archive/imx8m-6.12/0003-TQMa8MPXL-LDO5-Fix.patch new file mode 100644 index 000000000000..86dd3c0927d9 --- /dev/null +++ b/patch/kernel/archive/imx8m-6.12/0003-TQMa8MPXL-LDO5-Fix.patch @@ -0,0 +1,259 @@ +From 17f6e064d93013f2aaca40e9f44bf2c5b45652eb Mon Sep 17 00:00:00 2001 +From: Martin Schmiedel +Date: Thu, 5 Jun 2025 13:11:40 +0200 +Subject: [PATCH] TQMa8MPXL LDO5 Fix + +Signed-off-by: Martin Schmiedel +Signed-off-by: Markus Niebel +--- + .../imx8mp-tqma8mpql-mba8mp-ras314.dts | 13 ++--- + .../freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 13 ++--- + .../boot/dts/freescale/imx8mp-tqma8mpql.dtsi | 48 +++++++++++++++---- + 3 files changed, 53 insertions(+), 21 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +index d7fd9d36f824..f7346b3d35fe 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +@@ -467,6 +467,10 @@ &pwm4 { + status = "okay"; + }; + ++®_usdhc2_vqmmc { ++ status = "okay"; ++}; ++ + &sai5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai5>; +@@ -876,8 +880,7 @@ pinctrl_usdhc2: usdhc2grp { + , + , + , +- , +- ; ++ ; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { +@@ -886,8 +889,7 @@ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + , + , + , +- , +- ; ++ ; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { +@@ -896,8 +898,7 @@ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + , + , + , +- , +- ; ++ ; + }; + + pinctrl_usdhc2_gpio: usdhc2-gpiogrp { +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +index ae64731266f3..e7c16a7ee6c2 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +@@ -603,6 +603,10 @@ &pwm3 { + status = "okay"; + }; + ++®_usdhc2_vqmmc { ++ status = "okay"; ++}; ++ + &sai3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai3>; +@@ -982,8 +986,7 @@ pinctrl_usdhc2: usdhc2grp { + , + , + , +- , +- ; ++ ; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { +@@ -992,8 +995,7 @@ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + , + , + , +- , +- ; ++ ; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { +@@ -1002,8 +1004,7 @@ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + , + , + , +- , +- ; ++ ; + }; + + pinctrl_usdhc2_gpio: usdhc2-gpiogrp { +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi +index 3ddc5aaa7c5f..05a518209b59 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi +@@ -16,13 +16,26 @@ memory@40000000 { + reg = <0x0 0x40000000 0 0x80000000>; + }; + +- /* identical to buck4_reg, but should never change */ +- reg_vcc3v3: regulator-vcc3v3 { +- compatible = "regulator-fixed"; +- regulator-name = "VCC3V3"; +- regulator-min-microvolt = <3300000>; ++ reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc { ++ compatible = "regulator-gpio"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_reg_usdhc2_vqmmc>; ++ regulator-name = "V_SD2"; ++ regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; +- regulator-always-on; ++ gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1>, ++ <3300000 0x0>; ++ vin-supply = <&ldo5_reg>; ++ status = "disabled"; ++ }; ++ ++ reg_5v_in: regulator-5v-in { ++ compatible = "regulator-fixed"; ++ regulator-name = "V_5V_IN"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-boot-on; + }; + }; + +@@ -80,6 +93,7 @@ buck1_reg: BUCK1 { + regulator-name = "BUCK1"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <950000>; ++ vin-supply = <®_5v_in>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; +@@ -90,6 +104,7 @@ buck2_reg: BUCK2 { + regulator-name = "BUCK2"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1000000>; ++ vin-supply = <®_5v_in>; + regulator-boot-on; + regulator-always-on; + nxp,dvs-run-voltage = <950000>; +@@ -102,6 +117,7 @@ buck4_reg: BUCK4 { + regulator-name = "BUCK4"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; ++ vin-supply = <®_5v_in>; + regulator-boot-on; + regulator-always-on; + }; +@@ -111,6 +127,7 @@ buck5_reg: BUCK5 { + regulator-name = "BUCK5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; ++ vin-supply = <®_5v_in>; + regulator-boot-on; + regulator-always-on; + }; +@@ -120,6 +137,7 @@ buck6_reg: BUCK6 { + regulator-name = "BUCK6"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; ++ vin-supply = <®_5v_in>; + regulator-boot-on; + regulator-always-on; + }; +@@ -129,6 +147,7 @@ ldo1_reg: LDO1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; ++ vin-supply = <®_5v_in>; + regulator-boot-on; + regulator-always-on; + }; +@@ -138,6 +157,7 @@ ldo3_reg: LDO3 { + regulator-name = "LDO3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; ++ vin-supply = <®_5v_in>; + regulator-boot-on; + regulator-always-on; + }; +@@ -147,6 +167,7 @@ ldo4_reg: LDO4 { + regulator-name = "LDO4"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; ++ vin-supply = <®_5v_in>; + }; + + /* VCC SD IO - switched using SD2 VSELECT */ +@@ -154,6 +175,7 @@ ldo5_reg: LDO5 { + regulator-name = "LDO5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; ++ vin-supply = <®_5v_in>; + }; + }; + }; +@@ -168,17 +190,21 @@ at24c02: eeprom@53 { + read-only; + reg = <0x53>; + pagesize = <16>; +- vcc-supply = <®_vcc3v3>; ++ vcc-supply = <&buck4_reg>; + }; + + m24c64: eeprom@57 { + compatible = "atmel,24c64"; + reg = <0x57>; + pagesize = <32>; +- vcc-supply = <®_vcc3v3>; ++ vcc-supply = <&buck4_reg>; + }; + }; + ++&usdhc2 { ++ vqmmc-supply = <®_usdhc2_vqmmc>; ++}; ++ + &usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; +@@ -188,7 +214,7 @@ &usdhc3 { + non-removable; + no-sd; + no-sdio; +- vmmc-supply = <®_vcc3v3>; ++ vmmc-supply = <&buck4_reg>; + vqmmc-supply = <&buck5_reg>; + status = "okay"; + }; +@@ -228,6 +254,10 @@ pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { + fsl,pins = ; + }; + ++ pinctrl_reg_usdhc2_vqmmc: regusdhc2vqmmcgrp { ++ fsl,pins = ; ++ }; ++ + pinctrl_usdhc3: usdhc3grp { + fsl,pins = , + , +-- +2.43.0 + diff --git a/patch/kernel/archive/meson64-6.12/dt/meson-g12b-a311d-cainiao-cniot-core.dts b/patch/kernel/archive/meson64-6.12/dt/meson-g12b-a311d-cainiao-cniot-core.dts new file mode 100644 index 000000000000..b310fc52f330 --- /dev/null +++ b/patch/kernel/archive/meson64-6.12/dt/meson-g12b-a311d-cainiao-cniot-core.dts @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + * Copyright (c) 2025 retro98boy + */ + +/dts-v1/; + +#include "meson-g12b-a311d.dtsi" +#include +#include +#include +#include + +/ { + compatible = "CAINIAO,CNIoT-CORE", "amlogic,a311d", "amlogic,g12b"; + model = "CAINIAO CNIoT-CORE"; + + aliases { + serial0 = &uart_AO; + ethernet0 = ðmac; + rtc99 = &vrtc; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + fan0: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + cooling-levels = <0 120 170 220>; + pwms = <&pwm_cd 1 40000 1>; + tach-gpio = <&gpio GPIOA_4 GPIO_ACTIVE_HIGH>; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + poll-interval = <100>; + + pwr-btn { + label = "pwr-btn"; + linux,code = ; + gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>; + }; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 2>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + poll-interval = <100>; + + button-recovery { + label = "Recovery"; + linux,code = ; + press-threshold-microvolt = <10000>; + }; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; /* In the vendor DTS, this is BOOT_10, but the actual test result is BOOT_12. */ + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; + + ht6872: ht6872 { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>; + VCC-supply = <&vdd_amp>; + sound-name-prefix = "HT6872"; + status = "okay"; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + clocks = <&wifi32k>; + clock-names = "ext_clock"; + }; + + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ + }; + + dc_in: regulator-dc-in { + compatible = "regulator-fixed"; + regulator-name = "dc_in"; + regulator-always-on; + regulator-boot-on; + }; + + /* important to usb hub */ + amp_power: regulator-amp-power { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio GPIOH_8 GPIO_ACTIVE_HIGH>; + regulator-name = "amp_power"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + vddao_1v8: regulator-vddao-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vddao_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + vddcpu_a: regulator-vddcpu-a { + compatible = "pwm-regulator"; + regulator-name = "VDDCPU_A"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + pwm-supply = <&dc_in>; + pwms = <&pwm_ab 0 1250 0>; + pwm-dutycycle-range = <100 0>; + regulator-boot-on; + regulator-always-on; + }; + + vddcpu_b: regulator-vddcpu-b { + compatible = "pwm-regulator"; + regulator-name = "VDDCPU_B"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + pwm-supply = <&dc_in>; + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + regulator-boot-on; + regulator-always-on; + }; + + vsys_3v3: regulator-vsys-3v3 { + compatible = "regulator-fixed"; + regulator-name = "vsys_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + usb_pwr: regulator-usb-pwr { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>; /* always keep usb hub reset pin high */ + regulator-name = "usb_pwr"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + /* + * The Type-C port on the host is switched with the four USB contacts on the side of the host via GPIOA_14. + * Since the Type-C port on the host is either used for power supply or blocked by the dock, + * switching USB 2.0 access to the four contacts on the side of the host is a better choice. + * To use the Type-C port for data transmission, + * you only need to set GPIOA_14 in the node below to a high level. + */ + usb_switch: regulator-usb-switch { + compatible = "regulator-fixed"; + enable-active-low; + gpio = <&gpio GPIOA_14 GPIO_ACTIVE_LOW>; + regulator-name = "usb_switch"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + vdd_amp: regulator-vdd-amp { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio GPIOH_7 GPIO_ACTIVE_HIGH>; + regulator-name = "vdd_amp"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "CNIoT-CORE"; + audio-widgets = "Line", "Lineout"; + audio-aux-devs = <&tdmout_b>, <&tdmout_c>, <&ht6872>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", + "TDMOUT_B IN 2", "FRDDR_C OUT 1", + "TDM_B Playback", "TDMOUT_B OUT", + "TDMOUT_C IN 0", "FRDDR_A OUT 2", + "TDMOUT_C IN 1", "FRDDR_B OUT 2", + "TDMOUT_C IN 2", "FRDDR_C OUT 2", + "TDM_C Playback", "TDMOUT_C OUT", + "HT6872 INL", "ACODEC LOLP", + "HT6872 INR", "ACODEC LORP", + "Lineout", "HT6872 OUTL", + "Lineout", "HT6872 OUTR"; + + clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-3 { + sound-dai = <&tdmif_b>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-tx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; + }; + }; + + dai-link-4 { + sound-dai = <&tdmif_c>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&toacodec TOACODEC_IN_C>; + }; + }; + + /* hdmi glue */ + dai-link-5 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + + /* acodec glue */ + dai-link-6 { + sound-dai = <&toacodec TOACODEC_OUT>; + + codec { + sound-dai = <&acodec>; + }; + }; + }; +}; + +&acodec { + AVDD-supply = <&vddao_1v8>; + status = "okay"; +}; + +&arb { + status = "okay"; +}; + +&clkc_audio { + status = "okay"; +}; + +&cecb_AO { + pinctrl-0 = <&cec_ao_b_h_pins>; + pinctrl-names = "default"; + status = "okay"; + hdmi-phandle = <&hdmi_tx>; +}; + +&cpu0 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu100 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu101 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu102 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu103 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu_thermal { + trips { + cpu_active: cpu-active { + temperature = <60000>; /* millicelsius */ + hysteresis = <5000>; /* millicelsius */ + type = "active"; + }; + }; + + cooling-maps { + map2 { + trip = <&cpu_active>; + cooling-device = <&fan0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; +}; + +ðmac { + pinctrl-0 = <ð_pins>, <ð_rgmii_pins>; + pinctrl-names = "default"; + status = "okay"; + phy-mode = "rgmii"; + phy-handle = <&rtl8211f>; + amlogic,tx-delay-ns = <2>; +}; + +&ext_mdio { + rtl8211f: rtl8211f@0 { + reg = <0>; + max-speed = <1000>; + + reset-assert-us = <10000>; + reset-deassert-us = <80000>; + reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; + + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_14 */ + interrupts = ; /* tested by voltmeter */ + }; +}; + +&frddr_a { + status = "okay"; +}; + +&frddr_b { + status = "okay"; +}; + +&frddr_c { + status = "okay"; +}; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + +&npu { + status = "okay"; +}; + +&pwm_ab { + status = "okay"; + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; +}; + +&pwm_cd { + status = "okay"; + pinctrl-0 = <&pwm_d_a_pins>; + pinctrl-names = "default"; +}; + +&pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; + pinctrl-names = "default"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddao_1v8>; +}; + +&sd_emmc_a { + status = "okay"; + pinctrl-0 = <&sdio_pins>; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + #address-cells = <1>; + #size-cells = <0>; + + bus-width = <4>; + max-frequency = <100000000>; + cap-sdio-irq; + cap-sd-highspeed; + non-removable; + + /* WiFi firmware requires power in suspend */ + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + vmmc-supply = <&vsys_3v3>; + vqmmc-supply = <&vddao_1v8>; + + rtl8822cs: wifi@1 { + reg = <1>; + /* + * tested by voltmeter + * WL_REG_ON GPIOX_6 + * WL_WAKE_HOST GPIOX_5 + */ + }; +}; + +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_8b_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + + max-frequency = <200000000>; + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vsys_3v3>; + vqmmc-supply = <&vddao_1v8>; +}; + +/* + * GPIOH_4 is connected to 6 WS2812 LEDs. + * Reusing GPIOH_4 as SPI MOSI to control the WS2812 offers superior performance compared to the GPIO method. + */ +&spicc1_pins { + mux { + groups = "spi1_mosi"; + }; +}; + +/* Controlling WS2812 LEDs via spidev in user space. */ +&spicc1 { + status = "okay"; + pinctrl-0 = <&spicc1_pins>; + pinctrl-names = "default"; + + spidev@0 { + compatible = "rohm,dh2228fv"; + reg = <0>; + spi-max-frequency = <3340000>; + }; +}; + +&tdmif_b { + status = "okay"; +}; + +&tdmif_c { + status = "okay"; +}; + +&tdmout_b { + status = "okay"; +}; + +&tdmout_c { + status = "okay"; +}; + +&toacodec { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; + +&uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; + uart-has-rtscts; + + bluetooth { + compatible = "realtek,rtl8822cs-bt"; + enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; /* tested by voltmeter */ + host-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>; /* tested by voltmeter */ + device-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; /* tested by voltmeter */ + }; +}; + +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; +}; + +&usb2_phy0 { + phy-supply = <&_power>; +}; + +&usb2_phy1 { + phy-supply = <&usb_switch>; +}; + +&usb3_pcie_phy { + phy-supply = <&usb_pwr>; +}; + +&usb { + status = "okay"; + dr_mode = "host"; +}; diff --git a/patch/kernel/archive/meson64-6.12/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch b/patch/kernel/archive/meson64-6.12/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch index b3de0ee701ef..9c88f042ccd9 100644 --- a/patch/kernel/archive/meson64-6.12/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch +++ b/patch/kernel/archive/meson64-6.12/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch @@ -1,7 +1,7 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From e1e66c32b7a9ce7cf52922fe073c4bff40054599 Mon Sep 17 00:00:00 2001 From: Yuntian Zhang Date: Thu, 13 Jan 2022 21:34:10 +0800 -Subject: pinctrl: meson: Add several missing pinmux for pwm functions +Subject: [PATCH] pinctrl: meson: Add several missing pinmux for pwm functions The following pin definitions are mentioned in A311D Quick Reference Manual and S922X Public Datasheet, but not in S905Y2 @@ -11,15 +11,15 @@ They are currently exposed in Radxa Zero 2's GPIO header. Signed-off-by: Yuntian Zhang --- - arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 34 ++++++++++ - drivers/pinctrl/meson/pinctrl-meson-g12a.c | 14 +++- - 2 files changed, 45 insertions(+), 3 deletions(-) + arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 42 +++++++++++++++++++++ + drivers/pinctrl/meson/pinctrl-meson-g12a.c | 16 ++++++-- + 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi -index 111111111111..222222222222 100644 +index 86e6ceb31..b2f9a09b2 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi -@@ -149,3 +149,37 @@ &pmu { +@@ -149,3 +149,45 @@ &pmu { &npu { power-domains = <&pwrc PWRC_G12A_NNA_ID>; }; @@ -56,12 +56,20 @@ index 111111111111..222222222222 100644 + bias-disable; + }; + }; ++ ++ pwm_d_a_pins: pwm-d-a { ++ mux { ++ groups = "pwm_d_a"; ++ function = "pwm_d"; ++ bias-disable; ++ }; ++ }; +}; diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c -index 111111111111..222222222222 100644 +index e2788bfc5..c94360afc 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c +++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c -@@ -271,17 +271,21 @@ static const unsigned int eth_act_led_pins[] = { GPIOZ_15 }; +@@ -268,17 +268,22 @@ static const unsigned int eth_act_led_pins[] = { GPIOZ_15 }; static const unsigned int pwm_a_pins[] = { GPIOX_6 }; /* pwm_b */ @@ -80,20 +88,22 @@ index 111111111111..222222222222 100644 static const unsigned int pwm_d_x3_pins[] = { GPIOX_3 }; static const unsigned int pwm_d_x6_pins[] = { GPIOX_6 }; +static const unsigned int pwm_d_z_pins[] = { GPIOZ_2 }; ++static const unsigned int pwm_d_a_pins[] = { GPIOA_4 }; /* pwm_e */ static const unsigned int pwm_e_pins[] = { GPIOX_16 }; -@@ -594,6 +598,9 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { +@@ -591,6 +596,10 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { GROUP(bt565_a_din5, 2), GROUP(bt565_a_din6, 2), GROUP(bt565_a_din7, 2), + GROUP(pwm_b_z, 5), + GROUP(pwm_c_z, 5), + GROUP(pwm_d_z, 2), ++ GROUP(pwm_d_a, 3), GROUP(tsin_b_valid_z, 3), GROUP(tsin_b_sop_z, 3), GROUP(tsin_b_din0_z, 3), -@@ -726,6 +733,7 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { +@@ -723,6 +732,7 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { GROUP(uart_c_rts, 2), GROUP(iso7816_clk_h, 1), GROUP(iso7816_data_h, 1), @@ -101,7 +111,7 @@ index 111111111111..222222222222 100644 GROUP(pwm_f_h, 4), GROUP(cec_ao_a_h, 4), GROUP(cec_ao_b_h, 5), -@@ -1066,15 +1074,15 @@ static const char * const pwm_a_groups[] = { +@@ -1058,15 +1068,15 @@ static const char * const pwm_a_groups[] = { }; static const char * const pwm_b_groups[] = { @@ -116,10 +126,10 @@ index 111111111111..222222222222 100644 static const char * const pwm_d_groups[] = { - "pwm_d_x3", "pwm_d_x6", -+ "pwm_d_x3", "pwm_d_x6", "pwm_d_z", ++ "pwm_d_x3", "pwm_d_x6", "pwm_d_z", "pwm_d_a", }; static const char * const pwm_e_groups[] = { -- -Armbian +2.49.0 diff --git a/patch/kernel/archive/meson64-6.14/0000.patching_config.yaml b/patch/kernel/archive/meson64-6.15/0000.patching_config.yaml similarity index 100% rename from patch/kernel/archive/meson64-6.14/0000.patching_config.yaml rename to patch/kernel/archive/meson64-6.15/0000.patching_config.yaml diff --git a/patch/kernel/archive/meson64-6.14/board-bananapi-cm4-cm4io.patch b/patch/kernel/archive/meson64-6.15/board-bananapi-cm4-cm4io.patch similarity index 97% rename from patch/kernel/archive/meson64-6.14/board-bananapi-cm4-cm4io.patch rename to patch/kernel/archive/meson64-6.15/board-bananapi-cm4-cm4io.patch index 3990b4e33737..6eff7071bdc8 100644 --- a/patch/kernel/archive/meson64-6.14/board-bananapi-cm4-cm4io.patch +++ b/patch/kernel/archive/meson64-6.15/board-bananapi-cm4-cm4io.patch @@ -62,7 +62,7 @@ index 111111111111..222222222222 100644 chosen { stdout-path = "serial0:115200n8"; }; -@@ -369,8 +378,7 @@ &uart_A { +@@ -365,8 +374,7 @@ &uart_A { bluetooth { compatible = "realtek,rtl8822cs-bt"; @@ -89,7 +89,7 @@ diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi b/arch/arm index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi -@@ -303,8 +303,10 @@ &sd_emmc_a { +@@ -299,8 +299,10 @@ &sd_emmc_a { #size-cells = <0>; bus-width = <4>; @@ -101,7 +101,7 @@ index 111111111111..222222222222 100644 non-removable; disable-wp; -@@ -312,10 +314,13 @@ &sd_emmc_a { +@@ -308,10 +310,13 @@ &sd_emmc_a { /* WiFi firmware requires power in suspend */ keep-power-in-suspend; diff --git a/patch/kernel/archive/meson64-6.14/board-bananapi-m2s.patch b/patch/kernel/archive/meson64-6.15/board-bananapi-m2s.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-bananapi-m2s.patch rename to patch/kernel/archive/meson64-6.15/board-bananapi-m2s.patch diff --git a/patch/kernel/archive/meson64-6.14/board-bananapim5-001-sd-use-270-mmc-clock-phase-via-dt.patch b/patch/kernel/archive/meson64-6.15/board-bananapim5-001-sd-use-270-mmc-clock-phase-via-dt.patch similarity index 95% rename from patch/kernel/archive/meson64-6.14/board-bananapim5-001-sd-use-270-mmc-clock-phase-via-dt.patch rename to patch/kernel/archive/meson64-6.15/board-bananapim5-001-sd-use-270-mmc-clock-phase-via-dt.patch index a7fc8f521eca..7fb54929f29e 100644 --- a/patch/kernel/archive/meson64-6.14/board-bananapim5-001-sd-use-270-mmc-clock-phase-via-dt.patch +++ b/patch/kernel/archive/meson64-6.15/board-bananapim5-001-sd-use-270-mmc-clock-phase-via-dt.patch @@ -22,7 +22,7 @@ index 111111111111..222222222222 100644 / { adc-keys { -@@ -394,6 +395,8 @@ &sd_emmc_b { +@@ -392,6 +393,8 @@ &sd_emmc_b { cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; vmmc-supply = <&tflash_vdd>; vqmmc-supply = <&vddio_c>; @@ -31,7 +31,7 @@ index 111111111111..222222222222 100644 }; /* eMMC */ -@@ -413,6 +416,8 @@ &sd_emmc_c { +@@ -411,6 +414,8 @@ &sd_emmc_c { mmc-pwrseq = <&emmc_pwrseq>; vmmc-supply = <&vddao_3v3>; vqmmc-supply = <&emmc_1v8>; diff --git a/patch/kernel/archive/meson64-6.14/board-bananapim5-002-add-wifi-bt-support.patch b/patch/kernel/archive/meson64-6.15/board-bananapim5-002-add-wifi-bt-support.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-bananapim5-002-add-wifi-bt-support.patch rename to patch/kernel/archive/meson64-6.15/board-bananapim5-002-add-wifi-bt-support.patch diff --git a/patch/kernel/archive/meson64-6.14/board-bananapism1-add-uart_A-and-AO_B.patch b/patch/kernel/archive/meson64-6.15/board-bananapism1-add-uart_A-and-AO_B.patch similarity index 98% rename from patch/kernel/archive/meson64-6.14/board-bananapism1-add-uart_A-and-AO_B.patch rename to patch/kernel/archive/meson64-6.15/board-bananapism1-add-uart_A-and-AO_B.patch index 4f79c487b3e9..6ce9d0eba915 100644 --- a/patch/kernel/archive/meson64-6.14/board-bananapism1-add-uart_A-and-AO_B.patch +++ b/patch/kernel/archive/meson64-6.15/board-bananapism1-add-uart_A-and-AO_B.patch @@ -69,7 +69,7 @@ index 111111111111..222222222222 100644 ethernet0 = ðmac; }; -@@ -426,6 +427,12 @@ &uart_AO { +@@ -424,6 +425,12 @@ &uart_AO { pinctrl-names = "default"; }; diff --git a/patch/kernel/archive/meson64-6.14/board-khadas-vim3-fix-missing-i2c3-nod.patch b/patch/kernel/archive/meson64-6.15/board-khadas-vim3-fix-missing-i2c3-nod.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-khadas-vim3-fix-missing-i2c3-nod.patch rename to patch/kernel/archive/meson64-6.15/board-khadas-vim3-fix-missing-i2c3-nod.patch diff --git a/patch/kernel/archive/meson64-6.14/board-khadas-vims-add-rtc-vrtc-aliases.patch b/patch/kernel/archive/meson64-6.15/board-khadas-vims-add-rtc-vrtc-aliases.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-khadas-vims-add-rtc-vrtc-aliases.patch rename to patch/kernel/archive/meson64-6.15/board-khadas-vims-add-rtc-vrtc-aliases.patch diff --git a/patch/kernel/archive/meson64-6.14/board-nanopi-k2-add-uartC-alias.patch b/patch/kernel/archive/meson64-6.15/board-nanopi-k2-add-uartC-alias.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-nanopi-k2-add-uartC-alias.patch rename to patch/kernel/archive/meson64-6.15/board-nanopi-k2-add-uartC-alias.patch diff --git a/patch/kernel/archive/meson64-6.14/board-nanopi-k2-enable-emmc.patch b/patch/kernel/archive/meson64-6.15/board-nanopi-k2-enable-emmc.patch similarity index 93% rename from patch/kernel/archive/meson64-6.14/board-nanopi-k2-enable-emmc.patch rename to patch/kernel/archive/meson64-6.15/board-nanopi-k2-enable-emmc.patch index 6405bd43ccf6..ed994da9dd2f 100644 --- a/patch/kernel/archive/meson64-6.14/board-nanopi-k2-enable-emmc.patch +++ b/patch/kernel/archive/meson64-6.15/board-nanopi-k2-enable-emmc.patch @@ -12,7 +12,7 @@ diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/b index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts -@@ -362,7 +362,7 @@ &sd_emmc_b { +@@ -360,7 +360,7 @@ &sd_emmc_b { /* eMMC */ &sd_emmc_c { @@ -21,7 +21,7 @@ index 111111111111..222222222222 100644 pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; pinctrl-1 = <&emmc_clk_gate_pins>; pinctrl-names = "default", "clk-gate"; -@@ -372,8 +372,6 @@ &sd_emmc_c { +@@ -370,8 +370,6 @@ &sd_emmc_c { non-removable; disable-wp; cap-mmc-highspeed; diff --git a/patch/kernel/archive/meson64-6.14/board-odroid-sm1-reset.patch b/patch/kernel/archive/meson64-6.15/board-odroid-sm1-reset.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-odroid-sm1-reset.patch rename to patch/kernel/archive/meson64-6.15/board-odroid-sm1-reset.patch diff --git a/patch/kernel/archive/meson64-6.14/board-odroidc2-add-uartA-uartC.patch b/patch/kernel/archive/meson64-6.15/board-odroidc2-add-uartA-uartC.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-odroidc2-add-uartA-uartC.patch rename to patch/kernel/archive/meson64-6.15/board-odroidc2-add-uartA-uartC.patch diff --git a/patch/kernel/archive/meson64-6.14/board-odroidc2-enable-SPI.patch b/patch/kernel/archive/meson64-6.15/board-odroidc2-enable-SPI.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-odroidc2-enable-SPI.patch rename to patch/kernel/archive/meson64-6.15/board-odroidc2-enable-SPI.patch diff --git a/patch/kernel/archive/meson64-6.14/board-odroidc2-enable-scpi-dvfs.patch b/patch/kernel/archive/meson64-6.15/board-odroidc2-enable-scpi-dvfs.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-odroidc2-enable-scpi-dvfs.patch rename to patch/kernel/archive/meson64-6.15/board-odroidc2-enable-scpi-dvfs.patch diff --git a/patch/kernel/archive/meson64-6.14/board-odroidc2-usb-hub-disable-autosuspend-for-Genesys-Logic-.patch b/patch/kernel/archive/meson64-6.15/board-odroidc2-usb-hub-disable-autosuspend-for-Genesys-Logic-.patch similarity index 95% rename from patch/kernel/archive/meson64-6.14/board-odroidc2-usb-hub-disable-autosuspend-for-Genesys-Logic-.patch rename to patch/kernel/archive/meson64-6.15/board-odroidc2-usb-hub-disable-autosuspend-for-Genesys-Logic-.patch index d249e170ce19..d1a146d691a2 100644 --- a/patch/kernel/archive/meson64-6.14/board-odroidc2-usb-hub-disable-autosuspend-for-Genesys-Logic-.patch +++ b/patch/kernel/archive/meson64-6.15/board-odroidc2-usb-hub-disable-autosuspend-for-Genesys-Logic-.patch @@ -19,7 +19,7 @@ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 111111111111..222222222222 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -5977,7 +5977,7 @@ static const struct usb_device_id hub_id_table[] = { +@@ -5975,7 +5975,7 @@ static const struct usb_device_id hub_id_table[] = { | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = USB_VENDOR_GENESYS_LOGIC, .bInterfaceClass = USB_CLASS_HUB, diff --git a/patch/kernel/archive/meson64-6.14/board-odroidhc4-enable-fan1_input.patch b/patch/kernel/archive/meson64-6.15/board-odroidhc4-enable-fan1_input.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-odroidhc4-enable-fan1_input.patch rename to patch/kernel/archive/meson64-6.15/board-odroidhc4-enable-fan1_input.patch diff --git a/patch/kernel/archive/meson64-6.14/board-odroidn2plus-Add-missing-CPU-opp.patch b/patch/kernel/archive/meson64-6.15/board-odroidn2plus-Add-missing-CPU-opp.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-odroidn2plus-Add-missing-CPU-opp.patch rename to patch/kernel/archive/meson64-6.15/board-odroidn2plus-Add-missing-CPU-opp.patch diff --git a/patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-add-aliases-for-serial-i2c-and-spi.patch b/patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-add-aliases-for-serial-i2c-and-spi.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-add-aliases-for-serial-i2c-and-spi.patch rename to patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-add-aliases-for-serial-i2c-and-spi.patch diff --git a/patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-add-support-for-the-usb-c-controller.patch b/patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-add-support-for-the-usb-c-controller.patch similarity index 98% rename from patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-add-support-for-the-usb-c-controller.patch rename to patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-add-support-for-the-usb-c-controller.patch index 1263cda9ab91..af9ae2b23041 100644 --- a/patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-add-support-for-the-usb-c-controller.patch +++ b/patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-add-support-for-the-usb-c-controller.patch @@ -87,7 +87,7 @@ index 111111111111..222222222222 100644 &pwm_AO_cd { pinctrl-0 = <&pwm_ao_d_e_pins>; pinctrl-names = "default"; -@@ -417,3 +457,11 @@ &uart_AO { +@@ -413,3 +453,11 @@ &uart_AO { &usb { status = "okay"; }; diff --git a/patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-slow-down-sdio-for-working-emmc.patch b/patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-slow-down-sdio-for-working-emmc.patch similarity index 95% rename from patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-slow-down-sdio-for-working-emmc.patch rename to patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-slow-down-sdio-for-working-emmc.patch index 76ee25bd6031..3e6be05222c0 100644 --- a/patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-slow-down-sdio-for-working-emmc.patch +++ b/patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-slow-down-sdio-for-working-emmc.patch @@ -11,7 +11,7 @@ diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts b/arch/arm64/ index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts -@@ -413,7 +413,7 @@ &sd_emmc_c { +@@ -409,7 +409,7 @@ &sd_emmc_c { cap-mmc-highspeed; mmc-ddr-1_8v; mmc-hs200-1_8v; diff --git a/patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-slow-down-sdio-for-working-wifi.patch b/patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-slow-down-sdio-for-working-wifi.patch similarity index 96% rename from patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-slow-down-sdio-for-working-wifi.patch rename to patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-slow-down-sdio-for-working-wifi.patch index 6ced91999b8c..d7aea9f2b106 100644 --- a/patch/kernel/archive/meson64-6.14/board-radxa-zero-dts-slow-down-sdio-for-working-wifi.patch +++ b/patch/kernel/archive/meson64-6.15/board-radxa-zero-dts-slow-down-sdio-for-working-wifi.patch @@ -15,7 +15,7 @@ diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts b/arch/arm64/ index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts -@@ -365,7 +365,7 @@ &sd_emmc_a { +@@ -361,7 +361,7 @@ &sd_emmc_a { bus-width = <4>; cap-sd-highspeed; diff --git a/patch/kernel/archive/meson64-6.14/board-t95z-add-rc-remote-keymap.patch b/patch/kernel/archive/meson64-6.15/board-t95z-add-rc-remote-keymap.patch similarity index 94% rename from patch/kernel/archive/meson64-6.14/board-t95z-add-rc-remote-keymap.patch rename to patch/kernel/archive/meson64-6.15/board-t95z-add-rc-remote-keymap.patch index 873e7917efbb..5ffff22915b4 100644 --- a/patch/kernel/archive/meson64-6.14/board-t95z-add-rc-remote-keymap.patch +++ b/patch/kernel/archive/meson64-6.15/board-t95z-add-rc-remote-keymap.patch @@ -34,7 +34,7 @@ diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentat index 111111111111..222222222222 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml -@@ -1461,6 +1461,8 @@ patternProperties: +@@ -1471,6 +1471,8 @@ patternProperties: description: Sundance DSP Inc. "^sunplus,.*": description: Sunplus Technology Co., Ltd. @@ -47,8 +47,8 @@ diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefi index 111111111111..222222222222 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile -@@ -108,6 +108,7 @@ obj-$(CONFIG_RC_MAP) += \ - rc-reddo.o \ +@@ -109,6 +109,7 @@ obj-$(CONFIG_RC_MAP) += \ + rc-siemens-gigaset-rc20.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ + rc-sunvell-t95z-plus.o \ @@ -140,8 +140,8 @@ diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 111111111111..222222222222 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h -@@ -315,6 +315,7 @@ struct rc_map *rc_map_get(const char *name); - #define RC_MAP_REDDO "rc-reddo" +@@ -316,6 +316,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_SIEMENS_GIGASET_RC20 "rc-siemens-gigaset-rc20" #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" +#define RC_MAP_SUNVELL_T95Z_PLUS "rc-sunvell-t95z-plus" diff --git a/patch/kernel/archive/meson64-6.14/driver-power-meson64-reset.patch b/patch/kernel/archive/meson64-6.15/driver-power-meson64-reset.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/driver-power-meson64-reset.patch rename to patch/kernel/archive/meson64-6.15/driver-power-meson64-reset.patch diff --git a/patch/kernel/archive/meson64-6.14/drv-spi-spidev-remove-warnings.patch b/patch/kernel/archive/meson64-6.15/drv-spi-spidev-remove-warnings.patch similarity index 94% rename from patch/kernel/archive/meson64-6.14/drv-spi-spidev-remove-warnings.patch rename to patch/kernel/archive/meson64-6.15/drv-spi-spidev-remove-warnings.patch index 1863bd8d8f15..7c50ec76471f 100644 --- a/patch/kernel/archive/meson64-6.14/drv-spi-spidev-remove-warnings.patch +++ b/patch/kernel/archive/meson64-6.15/drv-spi-spidev-remove-warnings.patch @@ -20,7 +20,7 @@ index 111111111111..222222222222 100644 { .name = /* cisco */ "spi-petra" }, { .name = /* dh */ "dhcom-board" }, { .name = /* elgin */ "jg10309-01" }, -@@ -734,6 +735,7 @@ static int spidev_of_check(struct device *dev) +@@ -735,6 +736,7 @@ static int spidev_of_check(struct device *dev) } static const struct of_device_id spidev_dt_ids[] = { diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-axg-amper-gateway-am-gz80x.dts b/patch/kernel/archive/meson64-6.15/dt/meson-axg-amper-gateway-am-gz80x.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-axg-amper-gateway-am-gz80x.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-axg-amper-gateway-am-gz80x.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-axg-amper-gateway-gz80x.dtsi b/patch/kernel/archive/meson64-6.15/dt/meson-axg-amper-gateway-gz80x.dtsi similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-axg-amper-gateway-gz80x.dtsi rename to patch/kernel/archive/meson64-6.15/dt/meson-axg-amper-gateway-gz80x.dtsi diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12-enable-spinor.dtsi b/patch/kernel/archive/meson64-6.15/dt/meson-g12-enable-spinor.dtsi similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12-enable-spinor.dtsi rename to patch/kernel/archive/meson64-6.15/dt/meson-g12-enable-spinor.dtsi diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12a-radxa-zero-spidev.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12a-radxa-zero-spidev.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12a-radxa-zero-spidev.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12a-radxa-zero-spidev.dts diff --git a/patch/kernel/archive/meson64-6.15/dt/meson-g12b-a311d-cainiao-cniot-core.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-a311d-cainiao-cniot-core.dts new file mode 100644 index 000000000000..b310fc52f330 --- /dev/null +++ b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-a311d-cainiao-cniot-core.dts @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + * Copyright (c) 2025 retro98boy + */ + +/dts-v1/; + +#include "meson-g12b-a311d.dtsi" +#include +#include +#include +#include + +/ { + compatible = "CAINIAO,CNIoT-CORE", "amlogic,a311d", "amlogic,g12b"; + model = "CAINIAO CNIoT-CORE"; + + aliases { + serial0 = &uart_AO; + ethernet0 = ðmac; + rtc99 = &vrtc; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + fan0: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + cooling-levels = <0 120 170 220>; + pwms = <&pwm_cd 1 40000 1>; + tach-gpio = <&gpio GPIOA_4 GPIO_ACTIVE_HIGH>; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + poll-interval = <100>; + + pwr-btn { + label = "pwr-btn"; + linux,code = ; + gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>; + }; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 2>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1710000>; + poll-interval = <100>; + + button-recovery { + label = "Recovery"; + linux,code = ; + press-threshold-microvolt = <10000>; + }; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; /* In the vendor DTS, this is BOOT_10, but the actual test result is BOOT_12. */ + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; + + ht6872: ht6872 { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>; + VCC-supply = <&vdd_amp>; + sound-name-prefix = "HT6872"; + status = "okay"; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + clocks = <&wifi32k>; + clock-names = "ext_clock"; + }; + + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ + }; + + dc_in: regulator-dc-in { + compatible = "regulator-fixed"; + regulator-name = "dc_in"; + regulator-always-on; + regulator-boot-on; + }; + + /* important to usb hub */ + amp_power: regulator-amp-power { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio GPIOH_8 GPIO_ACTIVE_HIGH>; + regulator-name = "amp_power"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + vddao_1v8: regulator-vddao-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vddao_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + vddcpu_a: regulator-vddcpu-a { + compatible = "pwm-regulator"; + regulator-name = "VDDCPU_A"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + pwm-supply = <&dc_in>; + pwms = <&pwm_ab 0 1250 0>; + pwm-dutycycle-range = <100 0>; + regulator-boot-on; + regulator-always-on; + }; + + vddcpu_b: regulator-vddcpu-b { + compatible = "pwm-regulator"; + regulator-name = "VDDCPU_B"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + pwm-supply = <&dc_in>; + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + regulator-boot-on; + regulator-always-on; + }; + + vsys_3v3: regulator-vsys-3v3 { + compatible = "regulator-fixed"; + regulator-name = "vsys_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + usb_pwr: regulator-usb-pwr { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>; /* always keep usb hub reset pin high */ + regulator-name = "usb_pwr"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + /* + * The Type-C port on the host is switched with the four USB contacts on the side of the host via GPIOA_14. + * Since the Type-C port on the host is either used for power supply or blocked by the dock, + * switching USB 2.0 access to the four contacts on the side of the host is a better choice. + * To use the Type-C port for data transmission, + * you only need to set GPIOA_14 in the node below to a high level. + */ + usb_switch: regulator-usb-switch { + compatible = "regulator-fixed"; + enable-active-low; + gpio = <&gpio GPIOA_14 GPIO_ACTIVE_LOW>; + regulator-name = "usb_switch"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + vdd_amp: regulator-vdd-amp { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio GPIOH_7 GPIO_ACTIVE_HIGH>; + regulator-name = "vdd_amp"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_in>; + }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "CNIoT-CORE"; + audio-widgets = "Line", "Lineout"; + audio-aux-devs = <&tdmout_b>, <&tdmout_c>, <&ht6872>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", + "TDMOUT_B IN 2", "FRDDR_C OUT 1", + "TDM_B Playback", "TDMOUT_B OUT", + "TDMOUT_C IN 0", "FRDDR_A OUT 2", + "TDMOUT_C IN 1", "FRDDR_B OUT 2", + "TDMOUT_C IN 2", "FRDDR_C OUT 2", + "TDM_C Playback", "TDMOUT_C OUT", + "HT6872 INL", "ACODEC LOLP", + "HT6872 INR", "ACODEC LORP", + "Lineout", "HT6872 OUTL", + "Lineout", "HT6872 OUTR"; + + clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-3 { + sound-dai = <&tdmif_b>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-tx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; + }; + }; + + dai-link-4 { + sound-dai = <&tdmif_c>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&toacodec TOACODEC_IN_C>; + }; + }; + + /* hdmi glue */ + dai-link-5 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + + /* acodec glue */ + dai-link-6 { + sound-dai = <&toacodec TOACODEC_OUT>; + + codec { + sound-dai = <&acodec>; + }; + }; + }; +}; + +&acodec { + AVDD-supply = <&vddao_1v8>; + status = "okay"; +}; + +&arb { + status = "okay"; +}; + +&clkc_audio { + status = "okay"; +}; + +&cecb_AO { + pinctrl-0 = <&cec_ao_b_h_pins>; + pinctrl-names = "default"; + status = "okay"; + hdmi-phandle = <&hdmi_tx>; +}; + +&cpu0 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu100 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu101 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu102 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu103 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu_thermal { + trips { + cpu_active: cpu-active { + temperature = <60000>; /* millicelsius */ + hysteresis = <5000>; /* millicelsius */ + type = "active"; + }; + }; + + cooling-maps { + map2 { + trip = <&cpu_active>; + cooling-device = <&fan0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; +}; + +ðmac { + pinctrl-0 = <ð_pins>, <ð_rgmii_pins>; + pinctrl-names = "default"; + status = "okay"; + phy-mode = "rgmii"; + phy-handle = <&rtl8211f>; + amlogic,tx-delay-ns = <2>; +}; + +&ext_mdio { + rtl8211f: rtl8211f@0 { + reg = <0>; + max-speed = <1000>; + + reset-assert-us = <10000>; + reset-deassert-us = <80000>; + reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; + + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_14 */ + interrupts = ; /* tested by voltmeter */ + }; +}; + +&frddr_a { + status = "okay"; +}; + +&frddr_b { + status = "okay"; +}; + +&frddr_c { + status = "okay"; +}; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + +&npu { + status = "okay"; +}; + +&pwm_ab { + status = "okay"; + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; +}; + +&pwm_cd { + status = "okay"; + pinctrl-0 = <&pwm_d_a_pins>; + pinctrl-names = "default"; +}; + +&pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; + pinctrl-names = "default"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddao_1v8>; +}; + +&sd_emmc_a { + status = "okay"; + pinctrl-0 = <&sdio_pins>; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + #address-cells = <1>; + #size-cells = <0>; + + bus-width = <4>; + max-frequency = <100000000>; + cap-sdio-irq; + cap-sd-highspeed; + non-removable; + + /* WiFi firmware requires power in suspend */ + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + vmmc-supply = <&vsys_3v3>; + vqmmc-supply = <&vddao_1v8>; + + rtl8822cs: wifi@1 { + reg = <1>; + /* + * tested by voltmeter + * WL_REG_ON GPIOX_6 + * WL_WAKE_HOST GPIOX_5 + */ + }; +}; + +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_8b_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + + max-frequency = <200000000>; + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vsys_3v3>; + vqmmc-supply = <&vddao_1v8>; +}; + +/* + * GPIOH_4 is connected to 6 WS2812 LEDs. + * Reusing GPIOH_4 as SPI MOSI to control the WS2812 offers superior performance compared to the GPIO method. + */ +&spicc1_pins { + mux { + groups = "spi1_mosi"; + }; +}; + +/* Controlling WS2812 LEDs via spidev in user space. */ +&spicc1 { + status = "okay"; + pinctrl-0 = <&spicc1_pins>; + pinctrl-names = "default"; + + spidev@0 { + compatible = "rohm,dh2228fv"; + reg = <0>; + spi-max-frequency = <3340000>; + }; +}; + +&tdmif_b { + status = "okay"; +}; + +&tdmif_c { + status = "okay"; +}; + +&tdmout_b { + status = "okay"; +}; + +&tdmout_c { + status = "okay"; +}; + +&toacodec { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; + +&uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; + uart-has-rtscts; + + bluetooth { + compatible = "realtek,rtl8822cs-bt"; + enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; /* tested by voltmeter */ + host-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>; /* tested by voltmeter */ + device-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; /* tested by voltmeter */ + }; +}; + +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; +}; + +&usb2_phy0 { + phy-supply = <&_power>; +}; + +&usb2_phy1 { + phy-supply = <&usb_switch>; +}; + +&usb3_pcie_phy { + phy-supply = <&usb_pwr>; +}; + +&usb { + status = "okay"; + dr_mode = "host"; +}; diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12b-a311d-khadas-vim3-spidev.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-a311d-khadas-vim3-spidev.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12b-a311d-khadas-vim3-spidev.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12b-a311d-khadas-vim3-spidev.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12b-a311d-khadas-vim3-spinor.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-a311d-khadas-vim3-spinor.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12b-a311d-khadas-vim3-spinor.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12b-a311d-khadas-vim3-spinor.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12b-odroid-n2-plus-spidev.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-odroid-n2-plus-spidev.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12b-odroid-n2-plus-spidev.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12b-odroid-n2-plus-spidev.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12b-odroid-n2-plus-spinor.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-odroid-n2-plus-spinor.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12b-odroid-n2-plus-spinor.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12b-odroid-n2-plus-spinor.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12b-odroid-n2-spinor.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-odroid-n2-spinor.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12b-odroid-n2-spinor.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12b-odroid-n2-spinor.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12b-radxa-zero2-spidev.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-radxa-zero2-spidev.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12b-radxa-zero2-spidev.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12b-radxa-zero2-spidev.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-g12b-waveshare-cm4-io-base-b.dts b/patch/kernel/archive/meson64-6.15/dt/meson-g12b-waveshare-cm4-io-base-b.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-g12b-waveshare-cm4-io-base-b.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-g12b-waveshare-cm4-io-base-b.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-gxm-c400-plus.dts b/patch/kernel/archive/meson64-6.15/dt/meson-gxm-c400-plus.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-gxm-c400-plus.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-gxm-c400-plus.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-gxm-mini-m8s-pro.dts b/patch/kernel/archive/meson64-6.15/dt/meson-gxm-mini-m8s-pro.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-gxm-mini-m8s-pro.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-gxm-mini-m8s-pro.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-gxm-t95z-plus.dts b/patch/kernel/archive/meson64-6.15/dt/meson-gxm-t95z-plus.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-gxm-t95z-plus.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-gxm-t95z-plus.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-sm1-jethome-jethub-j200-spinor.dts b/patch/kernel/archive/meson64-6.15/dt/meson-sm1-jethome-jethub-j200-spinor.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-sm1-jethome-jethub-j200-spinor.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-sm1-jethome-jethub-j200-spinor.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-sm1-jethome-jethub-j200.dts b/patch/kernel/archive/meson64-6.15/dt/meson-sm1-jethome-jethub-j200.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-sm1-jethome-jethub-j200.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-sm1-jethome-jethub-j200.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-sm1-khadas-vim3l-spidev.dts b/patch/kernel/archive/meson64-6.15/dt/meson-sm1-khadas-vim3l-spidev.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-sm1-khadas-vim3l-spidev.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-sm1-khadas-vim3l-spidev.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-sm1-khadas-vim3l-spinor.dts b/patch/kernel/archive/meson64-6.15/dt/meson-sm1-khadas-vim3l-spinor.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-sm1-khadas-vim3l-spinor.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-sm1-khadas-vim3l-spinor.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-sm1-odroid-c4-spidev.dts b/patch/kernel/archive/meson64-6.15/dt/meson-sm1-odroid-c4-spidev.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-sm1-odroid-c4-spidev.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-sm1-odroid-c4-spidev.dts diff --git a/patch/kernel/archive/meson64-6.14/dt/meson-sm1-ugoos-x3.dts b/patch/kernel/archive/meson64-6.15/dt/meson-sm1-ugoos-x3.dts similarity index 100% rename from patch/kernel/archive/meson64-6.14/dt/meson-sm1-ugoos-x3.dts rename to patch/kernel/archive/meson64-6.15/dt/meson-sm1-ugoos-x3.dts diff --git a/patch/kernel/archive/meson64-6.14/general-add-Amlogic-Meson-GX-PM-Suspend.patch b/patch/kernel/archive/meson64-6.15/general-add-Amlogic-Meson-GX-PM-Suspend.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-add-Amlogic-Meson-GX-PM-Suspend.patch rename to patch/kernel/archive/meson64-6.15/general-add-Amlogic-Meson-GX-PM-Suspend.patch diff --git a/patch/kernel/archive/meson64-6.14/general-add-overlay-compilation-support.patch b/patch/kernel/archive/meson64-6.15/general-add-overlay-compilation-support.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-add-overlay-compilation-support.patch rename to patch/kernel/archive/meson64-6.15/general-add-overlay-compilation-support.patch diff --git a/patch/kernel/archive/meson64-6.14/general-driver-tm1628-auxdisplay-add-support-for-Titanmec-TM16.patch b/patch/kernel/archive/meson64-6.15/general-driver-tm1628-auxdisplay-add-support-for-Titanmec-TM16.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-driver-tm1628-auxdisplay-add-support-for-Titanmec-TM16.patch rename to patch/kernel/archive/meson64-6.15/general-driver-tm1628-auxdisplay-add-support-for-Titanmec-TM16.patch diff --git a/patch/kernel/archive/meson64-6.14/general-drm-dw-hdmi-call-hdmi_set_cts_n-after-clock.patch b/patch/kernel/archive/meson64-6.15/general-drm-dw-hdmi-call-hdmi_set_cts_n-after-clock.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-drm-dw-hdmi-call-hdmi_set_cts_n-after-clock.patch rename to patch/kernel/archive/meson64-6.15/general-drm-dw-hdmi-call-hdmi_set_cts_n-after-clock.patch diff --git a/patch/kernel/archive/meson64-6.14/general-drm-panfrost-fix-reference-leak.patch b/patch/kernel/archive/meson64-6.15/general-drm-panfrost-fix-reference-leak.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-drm-panfrost-fix-reference-leak.patch rename to patch/kernel/archive/meson64-6.15/general-drm-panfrost-fix-reference-leak.patch diff --git a/patch/kernel/archive/meson64-6.14/general-fix-Kodi-sysinfo-CPU-information.patch b/patch/kernel/archive/meson64-6.15/general-fix-Kodi-sysinfo-CPU-information.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-fix-Kodi-sysinfo-CPU-information.patch rename to patch/kernel/archive/meson64-6.15/general-fix-Kodi-sysinfo-CPU-information.patch diff --git a/patch/kernel/archive/meson64-6.14/general-gpu-drm-add-new-display-resolution-2560x1440.patch b/patch/kernel/archive/meson64-6.15/general-gpu-drm-add-new-display-resolution-2560x1440.patch similarity index 92% rename from patch/kernel/archive/meson64-6.14/general-gpu-drm-add-new-display-resolution-2560x1440.patch rename to patch/kernel/archive/meson64-6.15/general-gpu-drm-add-new-display-resolution-2560x1440.patch index 58d2d168894a..3db849138ffc 100644 --- a/patch/kernel/archive/meson64-6.14/general-gpu-drm-add-new-display-resolution-2560x1440.patch +++ b/patch/kernel/archive/meson64-6.15/general-gpu-drm-add-new-display-resolution-2560x1440.patch @@ -15,7 +15,7 @@ diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vc index 111111111111..222222222222 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c -@@ -357,6 +357,8 @@ enum { +@@ -360,6 +360,8 @@ enum { MESON_VCLK_HDMI_594000, /* 2970 /1 /1 /1 /5 /1 => /1 /2 */ MESON_VCLK_HDMI_594000_YUV420, @@ -24,7 +24,7 @@ index 111111111111..222222222222 100644 }; struct meson_vclk_params { -@@ -467,6 +469,18 @@ struct meson_vclk_params { +@@ -470,6 +472,18 @@ struct meson_vclk_params { .vid_pll_div = VID_PLL_DIV_5, .vclk_div = 1, }, @@ -43,7 +43,7 @@ index 111111111111..222222222222 100644 { /* sentinel */ }, }; -@@ -873,6 +887,10 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, +@@ -879,6 +893,10 @@ static void meson_vclk_set(struct meson_drm *priv, m = 0xf7; frac = vic_alternate_clock ? 0x8148 : 0x10000; break; diff --git a/patch/kernel/archive/meson64-6.14/general-input-touchscreen-Add-D-WAV-Multitouch.patch b/patch/kernel/archive/meson64-6.15/general-input-touchscreen-Add-D-WAV-Multitouch.patch similarity index 98% rename from patch/kernel/archive/meson64-6.14/general-input-touchscreen-Add-D-WAV-Multitouch.patch rename to patch/kernel/archive/meson64-6.15/general-input-touchscreen-Add-D-WAV-Multitouch.patch index d24db3cbb419..e34b5ea7e9eb 100644 --- a/patch/kernel/archive/meson64-6.14/general-input-touchscreen-Add-D-WAV-Multitouch.patch +++ b/patch/kernel/archive/meson64-6.15/general-input-touchscreen-Add-D-WAV-Multitouch.patch @@ -16,7 +16,7 @@ diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 111111111111..222222222222 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h -@@ -1483,4 +1483,10 @@ +@@ -1524,4 +1524,10 @@ #define USB_VENDOR_ID_SIGNOTEC 0x2133 #define USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011 0x0018 @@ -31,7 +31,7 @@ diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 111111111111..222222222222 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c -@@ -892,6 +892,9 @@ static const struct hid_device_id hid_ignore_list[] = { +@@ -904,6 +904,9 @@ static const struct hid_device_id hid_ignore_list[] = { #endif { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_HP_5MP_CAMERA_5473) }, @@ -45,7 +45,7 @@ diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconf index 111111111111..222222222222 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig -@@ -1390,4 +1390,14 @@ config TOUCHSCREEN_HIMAX_HX83112B +@@ -1403,4 +1403,14 @@ config TOUCHSCREEN_HIMAX_HX83112B To compile this driver as a module, choose M here: the module will be called himax_hx83112b. @@ -64,7 +64,7 @@ diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Make index 111111111111..222222222222 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile -@@ -116,4 +116,5 @@ obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o +@@ -117,4 +117,5 @@ obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o obj-$(CONFIG_TOUCHSCREEN_IQS7211) += iqs7211.o obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o diff --git a/patch/kernel/archive/meson64-6.14/general-media-cec-silence-CEC-timeout-message-HACK.patch b/patch/kernel/archive/meson64-6.15/general-media-cec-silence-CEC-timeout-message-HACK.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-media-cec-silence-CEC-timeout-message-HACK.patch rename to patch/kernel/archive/meson64-6.15/general-media-cec-silence-CEC-timeout-message-HACK.patch diff --git a/patch/kernel/archive/meson64-6.14/general-memory-marked-nomap.patch b/patch/kernel/archive/meson64-6.15/general-memory-marked-nomap.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-memory-marked-nomap.patch rename to patch/kernel/archive/meson64-6.15/general-memory-marked-nomap.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson-aiu-Fix-HDMI-codec-control-selection.patch b/patch/kernel/archive/meson64-6.15/general-meson-aiu-Fix-HDMI-codec-control-selection.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-meson-aiu-Fix-HDMI-codec-control-selection.patch rename to patch/kernel/archive/meson64-6.15/general-meson-aiu-Fix-HDMI-codec-control-selection.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson-mmc-1-arm64-amlogic-mmc-meson-gx-Add-core-tx-rx-eMMC-SD-SD.patch b/patch/kernel/archive/meson64-6.15/general-meson-mmc-1-arm64-amlogic-mmc-meson-gx-Add-core-tx-rx-eMMC-SD-SD.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-meson-mmc-1-arm64-amlogic-mmc-meson-gx-Add-core-tx-rx-eMMC-SD-SD.patch rename to patch/kernel/archive/meson64-6.15/general-meson-mmc-1-arm64-amlogic-mmc-meson-gx-Add-core-tx-rx-eMMC-SD-SD.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson-mmc-2-arm64-amlogic-dts-meson-update-meson-axg-device-tree.patch b/patch/kernel/archive/meson64-6.15/general-meson-mmc-2-arm64-amlogic-dts-meson-update-meson-axg-device-tree.patch similarity index 94% rename from patch/kernel/archive/meson64-6.14/general-meson-mmc-2-arm64-amlogic-dts-meson-update-meson-axg-device-tree.patch rename to patch/kernel/archive/meson64-6.15/general-meson-mmc-2-arm64-amlogic-dts-meson-update-meson-axg-device-tree.patch index da5343474d41..80a613dbff49 100644 --- a/patch/kernel/archive/meson64-6.14/general-meson-mmc-2-arm64-amlogic-dts-meson-update-meson-axg-device-tree.patch +++ b/patch/kernel/archive/meson64-6.15/general-meson-mmc-2-arm64-amlogic-dts-meson-update-meson-axg-device-tree.patch @@ -23,7 +23,7 @@ index 111111111111..222222222222 100644 / { compatible = "amlogic,meson-axg"; -@@ -1922,6 +1923,7 @@ sd_emmc_b: mmc@5000 { +@@ -1938,6 +1939,7 @@ sd_emmc_b: mmc@5000 { <&clkc CLKID_SD_EMMC_B_CLK0>, <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; @@ -31,7 +31,7 @@ index 111111111111..222222222222 100644 resets = <&reset RESET_SD_EMMC_B>; }; -@@ -1935,6 +1937,7 @@ sd_emmc_c: mmc@7000 { +@@ -1951,6 +1953,7 @@ sd_emmc_c: mmc@7000 { <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; resets = <&reset RESET_SD_EMMC_C>; diff --git a/patch/kernel/archive/meson64-6.14/general-meson-mmc-3-arm64-dts-docs-Update-mmc-meson-gx-documentation-for.patch b/patch/kernel/archive/meson64-6.15/general-meson-mmc-3-arm64-dts-docs-Update-mmc-meson-gx-documentation-for.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-meson-mmc-3-arm64-dts-docs-Update-mmc-meson-gx-documentation-for.patch rename to patch/kernel/archive/meson64-6.15/general-meson-mmc-3-arm64-dts-docs-Update-mmc-meson-gx-documentation-for.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson-vdec-add-HEVC-decode-codec.patch b/patch/kernel/archive/meson64-6.15/general-meson-vdec-add-HEVC-decode-codec.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-meson-vdec-add-HEVC-decode-codec.patch rename to patch/kernel/archive/meson64-6.15/general-meson-vdec-add-HEVC-decode-codec.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson-vdec-add-handling-to-HEVC-decoder-.patch b/patch/kernel/archive/meson64-6.15/general-meson-vdec-add-handling-to-HEVC-decoder-.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-meson-vdec-add-handling-to-HEVC-decoder-.patch rename to patch/kernel/archive/meson64-6.15/general-meson-vdec-add-handling-to-HEVC-decoder-.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson-vdec-check-if-parser-has-really-parser.patch b/patch/kernel/archive/meson64-6.15/general-meson-vdec-check-if-parser-has-really-parser.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-meson-vdec-check-if-parser-has-really-parser.patch rename to patch/kernel/archive/meson64-6.15/general-meson-vdec-check-if-parser-has-really-parser.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson-vdec-improve-mmu-and-fbc-handling-.patch b/patch/kernel/archive/meson64-6.15/general-meson-vdec-improve-mmu-and-fbc-handling-.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-meson-vdec-improve-mmu-and-fbc-handling-.patch rename to patch/kernel/archive/meson64-6.15/general-meson-vdec-improve-mmu-and-fbc-handling-.patch diff --git a/patch/kernel/archive/meson64-6.14/general-meson64-overlays.patch b/patch/kernel/archive/meson64-6.15/general-meson64-overlays.patch similarity index 92% rename from patch/kernel/archive/meson64-6.14/general-meson64-overlays.patch rename to patch/kernel/archive/meson64-6.15/general-meson64-overlays.patch index 43c434b227fb..9f388172ee64 100644 --- a/patch/kernel/archive/meson64-6.14/general-meson64-overlays.patch +++ b/patch/kernel/archive/meson64-6.15/general-meson64-overlays.patch @@ -12,7 +12,7 @@ diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 111111111111..222222222222 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib -@@ -75,6 +75,9 @@ always-y += $(hostprogs-always-y) $(hostprogs-always-m) +@@ -70,6 +70,9 @@ always-y += $(hostprogs-always-y) $(hostprogs-always-m) userprogs += $(userprogs-always-y) $(userprogs-always-m) always-y += $(userprogs-always-y) $(userprogs-always-m) diff --git a/patch/kernel/archive/meson64-6.14/general-si2168-fix-cmd-timeout.patch b/patch/kernel/archive/meson64-6.15/general-si2168-fix-cmd-timeout.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-si2168-fix-cmd-timeout.patch rename to patch/kernel/archive/meson64-6.15/general-si2168-fix-cmd-timeout.patch diff --git a/patch/kernel/archive/meson64-6.14/general-soc-0001-soc-amlogic-meson-gx-socinfo-move-common-code-to-hea.patch b/patch/kernel/archive/meson64-6.15/general-soc-0001-soc-amlogic-meson-gx-socinfo-move-common-code-to-hea.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-soc-0001-soc-amlogic-meson-gx-socinfo-move-common-code-to-hea.patch rename to patch/kernel/archive/meson64-6.15/general-soc-0001-soc-amlogic-meson-gx-socinfo-move-common-code-to-hea.patch diff --git a/patch/kernel/archive/meson64-6.14/general-soc-0002-soc-amlogic-meson-gx-socinfo-sm-Add-Amlogic-secure-m.patch b/patch/kernel/archive/meson64-6.15/general-soc-0002-soc-amlogic-meson-gx-socinfo-sm-Add-Amlogic-secure-m.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-soc-0002-soc-amlogic-meson-gx-socinfo-sm-Add-Amlogic-secure-m.patch rename to patch/kernel/archive/meson64-6.15/general-soc-0002-soc-amlogic-meson-gx-socinfo-sm-Add-Amlogic-secure-m.patch diff --git a/patch/kernel/archive/meson64-6.14/general-soc-0003-dt-bindings-arm-amlogic-amlogic-meson-gx-ao-secure-a.patch b/patch/kernel/archive/meson64-6.15/general-soc-0003-dt-bindings-arm-amlogic-amlogic-meson-gx-ao-secure-a.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-soc-0003-dt-bindings-arm-amlogic-amlogic-meson-gx-ao-secure-a.patch rename to patch/kernel/archive/meson64-6.15/general-soc-0003-dt-bindings-arm-amlogic-amlogic-meson-gx-ao-secure-a.patch diff --git a/patch/kernel/archive/meson64-6.14/general-soc-0004-arm64-dts-meson-add-dts-links-to-secure-monitor-for-.patch b/patch/kernel/archive/meson64-6.15/general-soc-0004-arm64-dts-meson-add-dts-links-to-secure-monitor-for-.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-soc-0004-arm64-dts-meson-add-dts-links-to-secure-monitor-for-.patch rename to patch/kernel/archive/meson64-6.15/general-soc-0004-arm64-dts-meson-add-dts-links-to-secure-monitor-for-.patch diff --git a/patch/kernel/archive/meson64-6.14/general-sound-soc-remove-mono-channel-as-it-curren.patch b/patch/kernel/archive/meson64-6.15/general-sound-soc-remove-mono-channel-as-it-curren.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-sound-soc-remove-mono-channel-as-it-curren.patch rename to patch/kernel/archive/meson64-6.15/general-sound-soc-remove-mono-channel-as-it-curren.patch diff --git a/patch/kernel/archive/meson64-6.14/general-spi-nor-add-support-for-XT25F128B.patch b/patch/kernel/archive/meson64-6.15/general-spi-nor-add-support-for-XT25F128B.patch similarity index 98% rename from patch/kernel/archive/meson64-6.14/general-spi-nor-add-support-for-XT25F128B.patch rename to patch/kernel/archive/meson64-6.15/general-spi-nor-add-support-for-XT25F128B.patch index b4c4e24ce642..f7f370f3d11b 100644 --- a/patch/kernel/archive/meson64-6.14/general-spi-nor-add-support-for-XT25F128B.patch +++ b/patch/kernel/archive/meson64-6.15/general-spi-nor-add-support-for-XT25F128B.patch @@ -46,7 +46,7 @@ diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 111111111111..222222222222 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c -@@ -1981,6 +1981,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = { +@@ -1954,6 +1954,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_sst, &spi_nor_winbond, &spi_nor_xmc, diff --git a/patch/kernel/archive/meson64-6.14/general-usb-core-improve-handling-of-hubs-with-no-ports.patch b/patch/kernel/archive/meson64-6.15/general-usb-core-improve-handling-of-hubs-with-no-ports.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/general-usb-core-improve-handling-of-hubs-with-no-ports.patch rename to patch/kernel/archive/meson64-6.15/general-usb-core-improve-handling-of-hubs-with-no-ports.patch diff --git a/patch/kernel/archive/meson64-6.14/hwmon-emc2305-fixups-for-driver.patch b/patch/kernel/archive/meson64-6.15/hwmon-emc2305-fixups-for-driver.patch similarity index 62% rename from patch/kernel/archive/meson64-6.14/hwmon-emc2305-fixups-for-driver.patch rename to patch/kernel/archive/meson64-6.15/hwmon-emc2305-fixups-for-driver.patch index 14cbdd500365..ec101a49ca7c 100644 --- a/patch/kernel/archive/meson64-6.14/hwmon-emc2305-fixups-for-driver.patch +++ b/patch/kernel/archive/meson64-6.15/hwmon-emc2305-fixups-for-driver.patch @@ -1,24 +1,40 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Patrick Yavitz -Date: Tue, 10 Oct 2023 18:54:22 -0400 +From: Patrick Yavitz +Date: Wed, 9 Apr 2025 04:34:27 -0400 Subject: hwmon: emc2305: fixups for driver -BPI-CM4 fan control - -hwmon: emc2305: fixups for driver The driver had a number of issues, checkpatch warnings/errors, and other limitations, so fix these up to make it usable. -hwmon: emc2305: Change OF properties pwm-min & pwm-max to u8 -hwmon: emc2305: Add calls to initialize cooling maps -https://github.com/raspberrypi/linux/commits/233096b8a9023f7e02960543c85447d46af81e81/drivers/hwmon/emc2305.c -Tested-on: CM4-IO-BASE-B: https://www.waveshare.com/wiki/CM4-IO-BASE-B Signed-off-by: Phil Elwell Signed-off-by: Dave Stevenson -Signed-off-by: Patrick Yavitz + +hwmon: emc2305: Add calls to initialise of cooling maps + +Commit 46ef9d4 ("hwmon: emc2305: fixups for driver submitted to +mailing lists") missed adding the call to thermal_of_cooling_device_register +required to configure any cooling maps for the device, hence stopping it +from actually ever changing speed. + +Signed-off-by: Dave Stevenson + +hwmon: emc2305: Change OF properties pwm-min & pwm-max to u8 + +There is no DT binding for emc2305 as mainline are still +discussing how to do a generic fan binding. +The 5.15 driver was reading the "emc2305," properties +"cooling-levels", "pwm-max", "pwm-min", and "pwm-channel" as u8. +The overlay was writing them as u16 (;) so it was working. + +The 6.1 driver was reading as u32, which failed as there is +insufficient data. + +As this is all downstream only, revert to u8 to match 5.15. + +Signed-off-by: Dave Stevenson --- - drivers/hwmon/emc2305.c | 96 +++++++++- - 1 file changed, 88 insertions(+), 8 deletions(-) + drivers/hwmon/emc2305.c | 110 +++++++++- + 1 file changed, 104 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 111111111111..222222222222 100644 @@ -47,24 +63,7 @@ index 111111111111..222222222222 100644 #define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n)) #define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n)) -@@ -55,6 +57,16 @@ static const struct i2c_device_id emc2305_ids[] = { - }; - MODULE_DEVICE_TABLE(i2c, emc2305_ids); - -+static const struct of_device_id emc2305_dt_ids[] = { -+ { .compatible = "smsc,emc2305" }, -+ { .compatible = "microchip,emc2305" }, -+ { .compatible = "microchip,emc2303" }, -+ { .compatible = "microchip,emc2302" }, -+ { .compatible = "microchip,emc2301" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, emc2305_dt_ids); -+ - /** - * struct emc2305_cdev_data - device-specific cooling device state - * @cdev: cooling device -@@ -100,6 +112,7 @@ struct emc2305_data { +@@ -100,6 +102,7 @@ struct emc2305_data { u8 pwm_num; bool pwm_separate; u8 pwm_min[EMC2305_PWM_MAX]; @@ -72,7 +71,16 @@ index 111111111111..222222222222 100644 struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX]; }; -@@ -272,7 +285,7 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel) +@@ -112,6 +115,8 @@ static char *emc2305_fan_name[] = { + "emc2305_fan5", + }; + ++static void emc2305_unset_tz(struct device *dev); ++ + static int emc2305_get_max_channel(const struct emc2305_data *data) + { + return data->pwm_num; +@@ -270,7 +275,7 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel) struct i2c_client *client = data->client; int ret; @@ -81,7 +89,7 @@ index 111111111111..222222222222 100644 return -EINVAL; ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(channel), val); -@@ -283,6 +296,49 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel) +@@ -281,6 +286,49 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel) return 0; } @@ -131,13 +139,13 @@ index 111111111111..222222222222 100644 static int emc2305_set_single_tz(struct device *dev, int idx) { struct emc2305_data *data = dev_get_drvdata(dev); -@@ -292,9 +348,17 @@ static int emc2305_set_single_tz(struct device *dev, int idx) +@@ -290,9 +338,16 @@ static int emc2305_set_single_tz(struct device *dev, int idx) cdev_idx = (idx) ? idx - 1 : 0; pwm = data->pwm_min[cdev_idx]; - data->cdev_data[cdev_idx].cdev = -- thermal_cooling_device_register(emc2305_fan_name[idx], data, -- &emc2305_cooling_ops); +- devm_thermal_of_cooling_device_register(dev, dev->of_node, +- emc2305_fan_name[idx], data, + if (dev->of_node) + data->cdev_data[cdev_idx].cdev = + devm_thermal_of_cooling_device_register(dev, dev->of_node, @@ -148,17 +156,29 @@ index 111111111111..222222222222 100644 + data->cdev_data[cdev_idx].cdev = + thermal_cooling_device_register(emc2305_fan_name[idx], + data, -+ &emc2305_cooling_ops); + &emc2305_cooling_ops); if (IS_ERR(data->cdev_data[cdev_idx].cdev)) { - dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]); -@@ -347,9 +411,11 @@ static void emc2305_unset_tz(struct device *dev) - int i; - - /* Unregister cooling device. */ -- for (i = 0; i < EMC2305_PWM_MAX; i++) -- if (data->cdev_data[i].cdev) -- thermal_cooling_device_unregister(data->cdev_data[i].cdev); +@@ -331,9 +386,26 @@ static int emc2305_set_tz(struct device *dev) + for (i = 0; i < data->pwm_num; i++) { + ret = emc2305_set_single_tz(dev, i + 1); + if (ret) +- return ret; ++ goto thermal_cooling_device_register_fail; + } + return 0; ++ ++thermal_cooling_device_register_fail: ++ emc2305_unset_tz(dev); ++ return ret; ++} ++ ++static void emc2305_unset_tz(struct device *dev) ++{ ++ struct emc2305_data *data = dev_get_drvdata(dev); ++ int i; ++ ++ /* Unregister cooling device. */ + if (!dev->of_node) { + for (i = 0; i < EMC2305_PWM_MAX; i++) + if (data->cdev_data[i].cdev) @@ -167,7 +187,7 @@ index 111111111111..222222222222 100644 } static umode_t -@@ -571,11 +637,18 @@ static int emc2305_probe(struct i2c_client *client) +@@ -555,11 +627,18 @@ static int emc2305_probe(struct i2c_client *client) data->pwm_separate = pdata->pwm_separate; for (i = 0; i < EMC2305_PWM_MAX; i++) data->pwm_min[i] = pdata->pwm_min[i]; @@ -186,7 +206,7 @@ index 111111111111..222222222222 100644 } data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data, -@@ -596,6 +669,12 @@ static int emc2305_probe(struct i2c_client *client) +@@ -580,21 +659,40 @@ static int emc2305_probe(struct i2c_client *client) return ret; } @@ -199,14 +219,34 @@ index 111111111111..222222222222 100644 return 0; } -@@ -610,6 +689,7 @@ static void emc2305_remove(struct i2c_client *client) + static const struct of_device_id of_emc2305_match_table[] = { ++ { .compatible = "smsc,emc2305" }, + { .compatible = "microchip,emc2305", }, ++ { .compatible = "microchip,emc2303", }, ++ { .compatible = "microchip,emc2302", }, ++ { .compatible = "microchip,emc2301", }, + {}, + }; + MODULE_DEVICE_TABLE(of, of_emc2305_match_table); + ++static void emc2305_remove(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ ++ if (IS_REACHABLE(CONFIG_THERMAL)) ++ emc2305_unset_tz(dev); ++} ++ static struct i2c_driver emc2305_driver = { .driver = { .name = "emc2305", -+ .of_match_table = emc2305_dt_ids, + .of_match_table = of_emc2305_match_table, }, .probe = emc2305_probe, - .remove = emc2305_remove, ++ .remove = emc2305_remove, + .id_table = emc2305_ids, + }; + -- Armbian diff --git a/patch/kernel/archive/meson64-6.14/jethome-0001-Fix-meson64-add-gpio-irq-patch-from-https-lkml.org-l.patch b/patch/kernel/archive/meson64-6.15/jethome-0001-Fix-meson64-add-gpio-irq-patch-from-https-lkml.org-l.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/jethome-0001-Fix-meson64-add-gpio-irq-patch-from-https-lkml.org-l.patch rename to patch/kernel/archive/meson64-6.15/jethome-0001-Fix-meson64-add-gpio-irq-patch-from-https-lkml.org-l.patch diff --git a/patch/kernel/archive/meson64-6.14/jethome-0002-arm64-dts-jethub-j1xx-add-eeprom-node.patch b/patch/kernel/archive/meson64-6.15/jethome-0002-arm64-dts-jethub-j1xx-add-eeprom-node.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/jethome-0002-arm64-dts-jethub-j1xx-add-eeprom-node.patch rename to patch/kernel/archive/meson64-6.15/jethome-0002-arm64-dts-jethub-j1xx-add-eeprom-node.patch diff --git a/patch/kernel/archive/meson64-6.14/jethome-0003-arm64-dts-meson-add-dts-links-to-secure-monitor-for-jethub.patch.disabled b/patch/kernel/archive/meson64-6.15/jethome-0003-arm64-dts-meson-add-dts-links-to-secure-monitor-for-jethub.patch.disabled similarity index 100% rename from patch/kernel/archive/meson64-6.14/jethome-0003-arm64-dts-meson-add-dts-links-to-secure-monitor-for-jethub.patch.disabled rename to patch/kernel/archive/meson64-6.15/jethome-0003-arm64-dts-meson-add-dts-links-to-secure-monitor-for-jethub.patch.disabled diff --git a/patch/kernel/archive/meson64-6.14/kernel-6.8-tools-cgroup-makefile.patch b/patch/kernel/archive/meson64-6.15/kernel-6.8-tools-cgroup-makefile.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/kernel-6.8-tools-cgroup-makefile.patch rename to patch/kernel/archive/meson64-6.15/kernel-6.8-tools-cgroup-makefile.patch diff --git a/patch/kernel/archive/meson64-6.14/meson-g12a-pinctrl-add-missing-ir-options.patch b/patch/kernel/archive/meson64-6.15/meson-g12a-pinctrl-add-missing-ir-options.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/meson-g12a-pinctrl-add-missing-ir-options.patch rename to patch/kernel/archive/meson64-6.15/meson-g12a-pinctrl-add-missing-ir-options.patch diff --git a/patch/kernel/archive/meson64-6.14/meson-g12a-radxa-zero-gpio-pin-names.patch b/patch/kernel/archive/meson64-6.15/meson-g12a-radxa-zero-gpio-pin-names.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/meson-g12a-radxa-zero-gpio-pin-names.patch rename to patch/kernel/archive/meson64-6.15/meson-g12a-radxa-zero-gpio-pin-names.patch diff --git a/patch/kernel/archive/meson64-6.14/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch b/patch/kernel/archive/meson64-6.15/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch similarity index 75% rename from patch/kernel/archive/meson64-6.14/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch rename to patch/kernel/archive/meson64-6.15/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch index b3de0ee701ef..9c88f042ccd9 100644 --- a/patch/kernel/archive/meson64-6.14/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch +++ b/patch/kernel/archive/meson64-6.15/meson-g12b-pinctrl-Add-missing-pinmux-for-pwm.patch @@ -1,7 +1,7 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From e1e66c32b7a9ce7cf52922fe073c4bff40054599 Mon Sep 17 00:00:00 2001 From: Yuntian Zhang Date: Thu, 13 Jan 2022 21:34:10 +0800 -Subject: pinctrl: meson: Add several missing pinmux for pwm functions +Subject: [PATCH] pinctrl: meson: Add several missing pinmux for pwm functions The following pin definitions are mentioned in A311D Quick Reference Manual and S922X Public Datasheet, but not in S905Y2 @@ -11,15 +11,15 @@ They are currently exposed in Radxa Zero 2's GPIO header. Signed-off-by: Yuntian Zhang --- - arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 34 ++++++++++ - drivers/pinctrl/meson/pinctrl-meson-g12a.c | 14 +++- - 2 files changed, 45 insertions(+), 3 deletions(-) + arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 42 +++++++++++++++++++++ + drivers/pinctrl/meson/pinctrl-meson-g12a.c | 16 ++++++-- + 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi -index 111111111111..222222222222 100644 +index 86e6ceb31..b2f9a09b2 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi -@@ -149,3 +149,37 @@ &pmu { +@@ -149,3 +149,45 @@ &pmu { &npu { power-domains = <&pwrc PWRC_G12A_NNA_ID>; }; @@ -56,12 +56,20 @@ index 111111111111..222222222222 100644 + bias-disable; + }; + }; ++ ++ pwm_d_a_pins: pwm-d-a { ++ mux { ++ groups = "pwm_d_a"; ++ function = "pwm_d"; ++ bias-disable; ++ }; ++ }; +}; diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c -index 111111111111..222222222222 100644 +index e2788bfc5..c94360afc 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c +++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c -@@ -271,17 +271,21 @@ static const unsigned int eth_act_led_pins[] = { GPIOZ_15 }; +@@ -268,17 +268,22 @@ static const unsigned int eth_act_led_pins[] = { GPIOZ_15 }; static const unsigned int pwm_a_pins[] = { GPIOX_6 }; /* pwm_b */ @@ -80,20 +88,22 @@ index 111111111111..222222222222 100644 static const unsigned int pwm_d_x3_pins[] = { GPIOX_3 }; static const unsigned int pwm_d_x6_pins[] = { GPIOX_6 }; +static const unsigned int pwm_d_z_pins[] = { GPIOZ_2 }; ++static const unsigned int pwm_d_a_pins[] = { GPIOA_4 }; /* pwm_e */ static const unsigned int pwm_e_pins[] = { GPIOX_16 }; -@@ -594,6 +598,9 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { +@@ -591,6 +596,10 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { GROUP(bt565_a_din5, 2), GROUP(bt565_a_din6, 2), GROUP(bt565_a_din7, 2), + GROUP(pwm_b_z, 5), + GROUP(pwm_c_z, 5), + GROUP(pwm_d_z, 2), ++ GROUP(pwm_d_a, 3), GROUP(tsin_b_valid_z, 3), GROUP(tsin_b_sop_z, 3), GROUP(tsin_b_din0_z, 3), -@@ -726,6 +733,7 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { +@@ -723,6 +732,7 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = { GROUP(uart_c_rts, 2), GROUP(iso7816_clk_h, 1), GROUP(iso7816_data_h, 1), @@ -101,7 +111,7 @@ index 111111111111..222222222222 100644 GROUP(pwm_f_h, 4), GROUP(cec_ao_a_h, 4), GROUP(cec_ao_b_h, 5), -@@ -1066,15 +1074,15 @@ static const char * const pwm_a_groups[] = { +@@ -1058,15 +1068,15 @@ static const char * const pwm_a_groups[] = { }; static const char * const pwm_b_groups[] = { @@ -116,10 +126,10 @@ index 111111111111..222222222222 100644 static const char * const pwm_d_groups[] = { - "pwm_d_x3", "pwm_d_x6", -+ "pwm_d_x3", "pwm_d_x6", "pwm_d_z", ++ "pwm_d_x3", "pwm_d_x6", "pwm_d_z", "pwm_d_a", }; static const char * const pwm_e_groups[] = { -- -Armbian +2.49.0 diff --git a/patch/kernel/archive/meson64-6.14/meson-gx-dts-add-support-for-GX-PM-and-VRTC.patch b/patch/kernel/archive/meson64-6.15/meson-gx-dts-add-support-for-GX-PM-and-VRTC.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/meson-gx-dts-add-support-for-GX-PM-and-VRTC.patch rename to patch/kernel/archive/meson64-6.15/meson-gx-dts-add-support-for-GX-PM-and-VRTC.patch diff --git a/patch/kernel/archive/meson64-6.14/meson-gxbb-dts-i2cX-missing-pins.patch b/patch/kernel/archive/meson64-6.15/meson-gxbb-dts-i2cX-missing-pins.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/meson-gxbb-dts-i2cX-missing-pins.patch rename to patch/kernel/archive/meson64-6.15/meson-gxbb-dts-i2cX-missing-pins.patch diff --git a/patch/kernel/archive/meson64-6.14/meson-gxbb-vdec-add-HEVC-support-to-GXBB.patch b/patch/kernel/archive/meson64-6.15/meson-gxbb-vdec-add-HEVC-support-to-GXBB.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/meson-gxbb-vdec-add-HEVC-support-to-GXBB.patch rename to patch/kernel/archive/meson64-6.15/meson-gxbb-vdec-add-HEVC-support-to-GXBB.patch diff --git a/patch/kernel/archive/meson64-6.14/meson-gxl-gxm-arm64-dts-meson-set-p212-p23x-q20x-SDIO-to-100MH.patch b/patch/kernel/archive/meson64-6.15/meson-gxl-gxm-arm64-dts-meson-set-p212-p23x-q20x-SDIO-to-100MH.patch similarity index 98% rename from patch/kernel/archive/meson64-6.14/meson-gxl-gxm-arm64-dts-meson-set-p212-p23x-q20x-SDIO-to-100MH.patch rename to patch/kernel/archive/meson64-6.15/meson-gxl-gxm-arm64-dts-meson-set-p212-p23x-q20x-SDIO-to-100MH.patch index 9d1c1ebdd3bb..31284ff1be0e 100644 --- a/patch/kernel/archive/meson64-6.14/meson-gxl-gxm-arm64-dts-meson-set-p212-p23x-q20x-SDIO-to-100MH.patch +++ b/patch/kernel/archive/meson64-6.15/meson-gxl-gxm-arm64-dts-meson-set-p212-p23x-q20x-SDIO-to-100MH.patch @@ -90,7 +90,7 @@ diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/bo index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi -@@ -260,7 +260,11 @@ &sd_emmc_a { +@@ -258,7 +258,11 @@ &sd_emmc_a { bus-width = <4>; cap-sd-highspeed; @@ -107,7 +107,7 @@ diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi b/arch/arm64/ index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi -@@ -121,7 +121,11 @@ &sd_emmc_a { +@@ -119,7 +119,11 @@ &sd_emmc_a { bus-width = <4>; cap-sd-highspeed; diff --git a/patch/kernel/archive/meson64-6.14/meson-gxm-vdec-add-VP9-support-to-GXM.patch b/patch/kernel/archive/meson64-6.15/meson-gxm-vdec-add-VP9-support-to-GXM.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/meson-gxm-vdec-add-VP9-support-to-GXM.patch rename to patch/kernel/archive/meson64-6.15/meson-gxm-vdec-add-VP9-support-to-GXM.patch diff --git a/patch/kernel/archive/meson64-6.14/meson-sm1-dts-add-higher-clocks.patch b/patch/kernel/archive/meson64-6.15/meson-sm1-dts-add-higher-clocks.patch similarity index 100% rename from patch/kernel/archive/meson64-6.14/meson-sm1-dts-add-higher-clocks.patch rename to patch/kernel/archive/meson64-6.15/meson-sm1-dts-add-higher-clocks.patch diff --git a/patch/kernel/archive/meson64-6.14/overlay/Makefile b/patch/kernel/archive/meson64-6.15/overlay/Makefile similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/Makefile rename to patch/kernel/archive/meson64-6.15/overlay/Makefile diff --git a/patch/kernel/archive/meson64-6.14/overlay/README.meson-overlays b/patch/kernel/archive/meson64-6.15/overlay/README.meson-overlays similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/README.meson-overlays rename to patch/kernel/archive/meson64-6.15/overlay/README.meson-overlays diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-fixup.scr-cmd b/patch/kernel/archive/meson64-6.15/overlay/meson-fixup.scr-cmd similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-fixup.scr-cmd rename to patch/kernel/archive/meson64-6.15/overlay/meson-fixup.scr-cmd diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12-gxl-cma-pool-896MB.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12-gxl-cma-pool-896MB.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12-gxl-cma-pool-896MB.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12-gxl-cma-pool-896MB.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12-pwm-gpiox-5-fan.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12-pwm-gpiox-5-fan.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12-pwm-gpiox-5-fan.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12-pwm-gpiox-5-fan.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-gpio-10-led.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-gpio-10-led.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-gpio-10-led.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-gpio-10-led.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-gpio-8-led.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-gpio-8-led.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-gpio-8-led.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-gpio-8-led.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ao-m0-gpioao-2-gpioao-3.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ao-m0-gpioao-2-gpioao-3.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ao-m0-gpioao-2-gpioao-3.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ao-m0-gpioao-2-gpioao-3.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpioh-6-gpioh-7.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpioh-6-gpioh-7.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpioh-6-gpioh-7.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpioh-6-gpioh-7.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpiox-10-gpiox-11.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpiox-10-gpiox-11.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpiox-10-gpiox-11.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ee-m1-gpiox-10-gpiox-11.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ee-m3-gpioa-14-gpioa-15.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ee-m3-gpioa-14-gpioa-15.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-i2c-ee-m3-gpioa-14-gpioa-15.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-i2c-ee-m3-gpioa-14-gpioa-15.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-pwm-c-on-gpiox-8.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-pwm-c-on-gpiox-8.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-pwm-c-on-gpiox-8.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-pwm-c-on-gpiox-8.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-pwmao-a-on-gpioao-11.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-pwmao-a-on-gpioao-11.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-pwmao-a-on-gpioao-11.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-pwmao-a-on-gpioao-11.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-spi-spidev.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-spi-spidev.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-spi-spidev.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-spi-spidev.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ao-a-on-gpioao-0-gpioao-1.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ao-a-on-gpioao-0-gpioao-1.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ao-a-on-gpioao-0-gpioao-1.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ao-a-on-gpioao-0-gpioao-1.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-2-gpioao-3.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-2-gpioao-3.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-2-gpioao-3.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-2-gpioao-3.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-8-gpioao-9.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-8-gpioao-9.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-8-gpioao-9.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ao-b-on-gpioao-8-gpioao-9.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ee-c.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ee-c.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12a-radxa-zero-uart-ee-c.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12a-radxa-zero-uart-ee-c.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-cm4-i2c2.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-cm4-i2c2.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-cm4-i2c2.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-cm4-i2c2.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-cm4-pwm-gpioh-5-fan.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-cm4-pwm-gpioh-5-fan.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-cm4-pwm-gpioh-5-fan.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-cm4-pwm-gpioh-5-fan.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-cm4-wifi-freq-200mhz.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-cm4-wifi-freq-200mhz.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-cm4-wifi-freq-200mhz.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-cm4-wifi-freq-200mhz.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-m2s-rtl8822cs.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-m2s-rtl8822cs.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12b-bananapi-m2s-rtl8822cs.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12b-bananapi-m2s-rtl8822cs.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12b-odroid-n2-spi.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12b-odroid-n2-spi.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12b-odroid-n2-spi.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12b-odroid-n2-spi.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-g12b-waveshare-cm4-io-base-usb.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-g12b-waveshare-cm4-io-base-usb.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-g12b-waveshare-cm4-io-base-usb.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-g12b-waveshare-cm4-io-base-usb.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-i2cA.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-i2cA.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-i2cA.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-i2cA.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-i2cB.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-i2cB.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-i2cB.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-i2cB.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-m5-rtl8822cs.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-m5-rtl8822cs.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-m5-rtl8822cs.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-m5-rtl8822cs.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-uartA.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-uartA.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-uartA.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-uartA.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-uartAO_B.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-uartAO_B.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-uartAO_B.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-uartAO_B.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-uartA_cts_rts.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-uartA_cts_rts.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-sm1-bananapi-uartA_cts_rts.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-sm1-bananapi-uartA_cts_rts.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-sm1-jethome-jethub-j200-spi.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-sm1-jethome-jethub-j200-spi.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-sm1-jethome-jethub-j200-spi.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-sm1-jethome-jethub-j200-spi.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-sm1-odroid-c4-i2c0.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-sm1-odroid-c4-i2c0.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-sm1-odroid-c4-i2c0.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-sm1-odroid-c4-i2c0.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-sm1-odroid-c4-i2c1.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-sm1-odroid-c4-i2c1.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-sm1-odroid-c4-i2c1.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-sm1-odroid-c4-i2c1.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-uartA.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-uartA.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-uartA.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-uartA.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-uartC.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-uartC.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-uartC.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-uartC.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-w1-gpio.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-w1-gpio.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-w1-gpio.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-w1-gpio.dtso diff --git a/patch/kernel/archive/meson64-6.14/overlay/meson-w1AB-gpio.dtso b/patch/kernel/archive/meson64-6.15/overlay/meson-w1AB-gpio.dtso similarity index 100% rename from patch/kernel/archive/meson64-6.14/overlay/meson-w1AB-gpio.dtso rename to patch/kernel/archive/meson64-6.15/overlay/meson-w1AB-gpio.dtso diff --git a/patch/kernel/archive/odroidxu4-6.6/patch-6.6.88-89.patch b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.88-89.patch new file mode 100644 index 000000000000..56b336c43150 --- /dev/null +++ b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.88-89.patch @@ -0,0 +1,6884 @@ +diff --git a/Documentation/scheduler/sched-capacity.rst b/Documentation/scheduler/sched-capacity.rst +index e2c1cf7431588e..de414b33dd2abd 100644 +--- a/Documentation/scheduler/sched-capacity.rst ++++ b/Documentation/scheduler/sched-capacity.rst +@@ -39,14 +39,15 @@ per Hz, leading to:: + ------------------- + + Two different capacity values are used within the scheduler. A CPU's +-``capacity_orig`` is its maximum attainable capacity, i.e. its maximum +-attainable performance level. A CPU's ``capacity`` is its ``capacity_orig`` to +-which some loss of available performance (e.g. time spent handling IRQs) is +-subtracted. ++``original capacity`` is its maximum attainable capacity, i.e. its maximum ++attainable performance level. This original capacity is returned by ++the function arch_scale_cpu_capacity(). A CPU's ``capacity`` is its ``original ++capacity`` to which some loss of available performance (e.g. time spent ++handling IRQs) is subtracted. + + Note that a CPU's ``capacity`` is solely intended to be used by the CFS class, +-while ``capacity_orig`` is class-agnostic. The rest of this document will use +-the term ``capacity`` interchangeably with ``capacity_orig`` for the sake of ++while ``original capacity`` is class-agnostic. The rest of this document will use ++the term ``capacity`` interchangeably with ``original capacity`` for the sake of + brevity. + + 1.3 Platform examples +diff --git a/Makefile b/Makefile +index b1dfe3df7dfc9d..23e90df5785c84 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 88 ++SUBLEVEL = 89 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi +index 39110c1232e0da..db10b4b46cca9d 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi +@@ -196,13 +196,6 @@ key-power { + wakeup-event-action = ; + wakeup-source; + }; +- +- key-suspend { +- label = "Suspend"; +- gpios = <&gpio TEGRA234_MAIN_GPIO(G, 2) GPIO_ACTIVE_LOW>; +- linux,input-type = ; +- linux,code = ; +- }; + }; + + fan: pwm-fan { +diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig +index 623cf80639decc..25aa993abebcea 100644 +--- a/arch/loongarch/Kconfig ++++ b/arch/loongarch/Kconfig +@@ -59,6 +59,7 @@ config LOONGARCH + select ARCH_SUPPORTS_NUMA_BALANCING + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_CMPXCHG_LOCKREF ++ select ARCH_USE_MEMTEST + select ARCH_USE_QUEUED_RWLOCKS + select ARCH_USE_QUEUED_SPINLOCKS + select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT +diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h +index f3ddaed9ef7f08..a5b63c84f8541a 100644 +--- a/arch/loongarch/include/asm/ptrace.h ++++ b/arch/loongarch/include/asm/ptrace.h +@@ -33,9 +33,9 @@ struct pt_regs { + unsigned long __last[]; + } __aligned(8); + +-static inline int regs_irqs_disabled(struct pt_regs *regs) ++static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) + { +- return arch_irqs_disabled_flags(regs->csr_prmd); ++ return !(regs->csr_prmd & CSR_PRMD_PIE); + } + + static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c +index d59052c03d9b7e..2b4b99b4e6c94e 100644 +--- a/arch/loongarch/kernel/traps.c ++++ b/arch/loongarch/kernel/traps.c +@@ -527,9 +527,10 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs) + die_if_kernel("Kernel ale access", regs); + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr); + #else ++ bool pie = regs_irqs_disabled(regs); + unsigned int *pc; + +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr); +@@ -556,7 +557,7 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs) + die_if_kernel("Kernel ale access", regs); + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr); + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + #endif + irqentry_exit(regs, state); +@@ -588,12 +589,13 @@ static void bug_handler(struct pt_regs *regs) + asmlinkage void noinstr do_bce(struct pt_regs *regs) + { + bool user = user_mode(regs); ++ bool pie = regs_irqs_disabled(regs); + unsigned long era = exception_era(regs); + u64 badv = 0, lower = 0, upper = ULONG_MAX; + union loongarch_instruction insn; + irqentry_state_t state = irqentry_enter(regs); + +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + current->thread.trap_nr = read_csr_excode(); +@@ -659,7 +661,7 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs) + force_sig_bnderr((void __user *)badv, (void __user *)lower, (void __user *)upper); + + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + + irqentry_exit(regs, state); +@@ -677,11 +679,12 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs) + asmlinkage void noinstr do_bp(struct pt_regs *regs) + { + bool user = user_mode(regs); ++ bool pie = regs_irqs_disabled(regs); + unsigned int opcode, bcode; + unsigned long era = exception_era(regs); + irqentry_state_t state = irqentry_enter(regs); + +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + if (__get_inst(&opcode, (u32 *)era, user)) +@@ -747,7 +750,7 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs) + } + + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + + irqentry_exit(regs, state); +@@ -982,6 +985,7 @@ static void init_restore_lbt(void) + + asmlinkage void noinstr do_lbt(struct pt_regs *regs) + { ++ bool pie = regs_irqs_disabled(regs); + irqentry_state_t state = irqentry_enter(regs); + + /* +@@ -991,7 +995,7 @@ asmlinkage void noinstr do_lbt(struct pt_regs *regs) + * (including the user using 'MOVGR2GCSR' to turn on TM, which + * will not trigger the BTE), we need to check PRMD first. + */ +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + if (!cpu_has_lbt) { +@@ -1005,7 +1009,7 @@ asmlinkage void noinstr do_lbt(struct pt_regs *regs) + preempt_enable(); + + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + + irqentry_exit(regs, state); +diff --git a/arch/loongarch/mm/hugetlbpage.c b/arch/loongarch/mm/hugetlbpage.c +index 1e76fcb83093dd..41308429f44612 100644 +--- a/arch/loongarch/mm/hugetlbpage.c ++++ b/arch/loongarch/mm/hugetlbpage.c +@@ -47,7 +47,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr, + pmd = pmd_offset(pud, addr); + } + } +- return (pte_t *) pmd; ++ return pmd_none(pmdp_get(pmd)) ? NULL : (pte_t *) pmd; + } + + int pmd_huge(pmd_t pmd) +diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c +index 4dd53427f65785..a5bf96993bb1a6 100644 +--- a/arch/loongarch/mm/init.c ++++ b/arch/loongarch/mm/init.c +@@ -64,9 +64,6 @@ void __init paging_init(void) + { + unsigned long max_zone_pfns[MAX_NR_ZONES]; + +-#ifdef CONFIG_ZONE_DMA +- max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; +-#endif + #ifdef CONFIG_ZONE_DMA32 + max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; + #endif +diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h +index 696b40beb774f5..8494466740ccad 100644 +--- a/arch/mips/include/asm/mips-cm.h ++++ b/arch/mips/include/asm/mips-cm.h +@@ -47,6 +47,16 @@ extern phys_addr_t __mips_cm_phys_base(void); + */ + extern int mips_cm_is64; + ++/* ++ * mips_cm_is_l2_hci_broken - determine if HCI is broken ++ * ++ * Some CM reports show that Hardware Cache Initialization is ++ * complete, but in reality it's not the case. They also incorrectly ++ * indicate that Hardware Cache Initialization is supported. This ++ * flags allows warning about this broken feature. ++ */ ++extern bool mips_cm_is_l2_hci_broken; ++ + /** + * mips_cm_error_report - Report CM cache errors + */ +@@ -85,6 +95,18 @@ static inline bool mips_cm_present(void) + #endif + } + ++/** ++ * mips_cm_update_property - update property from the device tree ++ * ++ * Retrieve the properties from the device tree if a CM node exist and ++ * update the internal variable based on this. ++ */ ++#ifdef CONFIG_MIPS_CM ++extern void mips_cm_update_property(void); ++#else ++static inline void mips_cm_update_property(void) {} ++#endif ++ + /** + * mips_cm_has_l2sync - determine whether an L2-only sync region is present + * +diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c +index 3f00788b08718d..4f75160f08949f 100644 +--- a/arch/mips/kernel/mips-cm.c ++++ b/arch/mips/kernel/mips-cm.c +@@ -5,6 +5,7 @@ + */ + + #include ++#include + #include + #include + +@@ -14,6 +15,7 @@ + void __iomem *mips_gcr_base; + void __iomem *mips_cm_l2sync_base; + int mips_cm_is64; ++bool mips_cm_is_l2_hci_broken; + + static char *cm2_tr[8] = { + "mem", "gcr", "gic", "mmio", +@@ -243,6 +245,18 @@ static void mips_cm_probe_l2sync(void) + mips_cm_l2sync_base = ioremap(addr, MIPS_CM_L2SYNC_SIZE); + } + ++void mips_cm_update_property(void) ++{ ++ struct device_node *cm_node; ++ ++ cm_node = of_find_compatible_node(of_root, NULL, "mobileye,eyeq6-cm"); ++ if (!cm_node) ++ return; ++ pr_info("HCI (Hardware Cache Init for the L2 cache) in GCR_L2_RAM_CONFIG from the CM3 is broken"); ++ mips_cm_is_l2_hci_broken = true; ++ of_node_put(cm_node); ++} ++ + int mips_cm_probe(void) + { + phys_addr_t addr; +diff --git a/arch/parisc/kernel/pdt.c b/arch/parisc/kernel/pdt.c +index 0f9b3b5914cf69..b70b67adb855f6 100644 +--- a/arch/parisc/kernel/pdt.c ++++ b/arch/parisc/kernel/pdt.c +@@ -63,6 +63,7 @@ static unsigned long pdt_entry[MAX_PDT_ENTRIES] __page_aligned_bss; + #define PDT_ADDR_PERM_ERR (pdt_type != PDT_PDC ? 2UL : 0UL) + #define PDT_ADDR_SINGLE_ERR 1UL + ++#ifdef CONFIG_PROC_FS + /* report PDT entries via /proc/meminfo */ + void arch_report_meminfo(struct seq_file *m) + { +@@ -74,6 +75,7 @@ void arch_report_meminfo(struct seq_file *m) + seq_printf(m, "PDT_cur_entries: %7lu\n", + pdt_status.pdt_entries); + } ++#endif + + static int get_info_pat_new(void) + { +diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h +index 721ec275ce57e3..231d777d936c2d 100644 +--- a/arch/riscv/include/asm/alternative-macros.h ++++ b/arch/riscv/include/asm/alternative-macros.h +@@ -115,24 +115,19 @@ + \old_c + .endm + +-#define _ALTERNATIVE_CFG(old_c, ...) \ +- ALTERNATIVE_CFG old_c +- +-#define _ALTERNATIVE_CFG_2(old_c, ...) \ +- ALTERNATIVE_CFG old_c ++#define __ALTERNATIVE_CFG(old_c, ...) ALTERNATIVE_CFG old_c ++#define __ALTERNATIVE_CFG_2(old_c, ...) ALTERNATIVE_CFG old_c + + #else /* !__ASSEMBLY__ */ + +-#define __ALTERNATIVE_CFG(old_c) \ +- old_c "\n" ++#define __ALTERNATIVE_CFG(old_c, ...) old_c "\n" ++#define __ALTERNATIVE_CFG_2(old_c, ...) old_c "\n" + +-#define _ALTERNATIVE_CFG(old_c, ...) \ +- __ALTERNATIVE_CFG(old_c) ++#endif /* __ASSEMBLY__ */ + +-#define _ALTERNATIVE_CFG_2(old_c, ...) \ +- __ALTERNATIVE_CFG(old_c) ++#define _ALTERNATIVE_CFG(old_c, ...) __ALTERNATIVE_CFG(old_c) ++#define _ALTERNATIVE_CFG_2(old_c, ...) __ALTERNATIVE_CFG_2(old_c) + +-#endif /* __ASSEMBLY__ */ + #endif /* CONFIG_RISCV_ALTERNATIVE */ + + /* +diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c +index b16352083ff987..f0be263b334ced 100644 +--- a/arch/s390/kvm/intercept.c ++++ b/arch/s390/kvm/intercept.c +@@ -94,7 +94,7 @@ static int handle_validity(struct kvm_vcpu *vcpu) + + vcpu->stat.exit_validity++; + trace_kvm_s390_intercept_validity(vcpu, viwhy); +- KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy, ++ KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%p)", viwhy, + current->pid, vcpu->kvm); + + /* do not warn on invalid runtime instrumentation mode */ +diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c +index efaebba5ee19c7..fe4841104ed924 100644 +--- a/arch/s390/kvm/interrupt.c ++++ b/arch/s390/kvm/interrupt.c +@@ -3161,7 +3161,7 @@ void kvm_s390_gisa_clear(struct kvm *kvm) + if (!gi->origin) + return; + gisa_clear_ipm(gi->origin); +- VM_EVENT(kvm, 3, "gisa 0x%pK cleared", gi->origin); ++ VM_EVENT(kvm, 3, "gisa 0x%p cleared", gi->origin); + } + + void kvm_s390_gisa_init(struct kvm *kvm) +@@ -3178,7 +3178,7 @@ void kvm_s390_gisa_init(struct kvm *kvm) + gi->timer.function = gisa_vcpu_kicker; + memset(gi->origin, 0, sizeof(struct kvm_s390_gisa)); + gi->origin->next_alert = (u32)virt_to_phys(gi->origin); +- VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin); ++ VM_EVENT(kvm, 3, "gisa 0x%p initialized", gi->origin); + } + + void kvm_s390_gisa_enable(struct kvm *kvm) +@@ -3219,7 +3219,7 @@ void kvm_s390_gisa_destroy(struct kvm *kvm) + process_gib_alert_list(); + hrtimer_cancel(&gi->timer); + gi->origin = NULL; +- VM_EVENT(kvm, 3, "gisa 0x%pK destroyed", gisa); ++ VM_EVENT(kvm, 3, "gisa 0x%p destroyed", gisa); + } + + void kvm_s390_gisa_disable(struct kvm *kvm) +@@ -3468,7 +3468,7 @@ int __init kvm_s390_gib_init(u8 nisc) + } + } + +- KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc); ++ KVM_EVENT(3, "gib 0x%p (nisc=%d) initialized", gib, gib->nisc); + goto out; + + out_unreg_gal: +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index 348d030d2660ca..890d850f51f076 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -990,7 +990,7 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att + } + mutex_unlock(&kvm->lock); + VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit); +- VM_EVENT(kvm, 3, "New guest asce: 0x%pK", ++ VM_EVENT(kvm, 3, "New guest asce: 0x%p", + (void *) kvm->arch.gmap->asce); + break; + } +@@ -3418,7 +3418,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) + kvm_s390_gisa_init(kvm); + INIT_LIST_HEAD(&kvm->arch.pv.need_cleanup); + kvm->arch.pv.set_aside = NULL; +- KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid); ++ KVM_EVENT(3, "vm 0x%p created by pid %u", kvm, current->pid); + + return 0; + out_err: +@@ -3481,7 +3481,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) + kvm_s390_destroy_adapters(kvm); + kvm_s390_clear_float_irqs(kvm); + kvm_s390_vsie_destroy(kvm); +- KVM_EVENT(3, "vm 0x%pK destroyed", kvm); ++ KVM_EVENT(3, "vm 0x%p destroyed", kvm); + } + + /* Section: vcpu related */ +@@ -3602,7 +3602,7 @@ static int sca_switch_to_extended(struct kvm *kvm) + + free_page((unsigned long)old_sca); + +- VM_EVENT(kvm, 2, "Switched to ESCA (0x%pK -> 0x%pK)", ++ VM_EVENT(kvm, 2, "Switched to ESCA (0x%p -> 0x%p)", + old_sca, kvm->arch.sca); + return 0; + } +@@ -3974,7 +3974,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) + goto out_free_sie_block; + } + +- VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK", ++ VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%p, sie block at 0x%p", + vcpu->vcpu_id, vcpu, vcpu->arch.sie_block); + trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block); + +diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h +index 6f0209d45164f0..9c5f546a2e1a3c 100644 +--- a/arch/s390/kvm/trace-s390.h ++++ b/arch/s390/kvm/trace-s390.h +@@ -56,7 +56,7 @@ TRACE_EVENT(kvm_s390_create_vcpu, + __entry->sie_block = sie_block; + ), + +- TP_printk("create cpu %d at 0x%pK, sie block at 0x%pK", ++ TP_printk("create cpu %d at 0x%p, sie block at 0x%p", + __entry->id, __entry->vcpu, __entry->sie_block) + ); + +@@ -255,7 +255,7 @@ TRACE_EVENT(kvm_s390_enable_css, + __entry->kvm = kvm; + ), + +- TP_printk("enabling channel I/O support (kvm @ %pK)\n", ++ TP_printk("enabling channel I/O support (kvm @ %p)\n", + __entry->kvm) + ); + +diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S +index 2143358d0c4c74..78fd2442b49dcd 100644 +--- a/arch/x86/entry/entry.S ++++ b/arch/x86/entry/entry.S +@@ -16,7 +16,7 @@ + + SYM_FUNC_START(entry_ibpb) + movl $MSR_IA32_PRED_CMD, %ecx +- movl $PRED_CMD_IBPB, %eax ++ movl _ASM_RIP(x86_pred_cmd), %eax + xorl %edx, %edx + wrmsr + +diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c +index 1458ccaa6a0579..ad63bd408cd900 100644 +--- a/arch/x86/events/core.c ++++ b/arch/x86/events/core.c +@@ -623,7 +623,7 @@ int x86_pmu_hw_config(struct perf_event *event) + if (event->attr.type == event->pmu->type) + event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK; + +- if (!event->attr.freq && x86_pmu.limit_period) { ++ if (is_sampling_event(event) && !event->attr.freq && x86_pmu.limit_period) { + s64 left = event->attr.sample_period; + x86_pmu.limit_period(event, &left); + if (left > event->attr.sample_period) +diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h +index ca8eed1d496ab4..2bec0c89a95c27 100644 +--- a/arch/x86/include/asm/asm.h ++++ b/arch/x86/include/asm/asm.h +@@ -229,9 +229,6 @@ register unsigned long current_stack_pointer asm(_ASM_SP); + #define _ASM_EXTABLE_UA(from, to) \ + _ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS) + +-#define _ASM_EXTABLE_CPY(from, to) \ +- _ASM_EXTABLE_TYPE(from, to, EX_TYPE_COPY) +- + #define _ASM_EXTABLE_FAULT(from, to) \ + _ASM_EXTABLE_TYPE(from, to, EX_TYPE_FAULT) + +diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h +index 991e31cfde94cc..afad9c0b07e0c8 100644 +--- a/arch/x86/include/asm/extable_fixup_types.h ++++ b/arch/x86/include/asm/extable_fixup_types.h +@@ -36,7 +36,7 @@ + #define EX_TYPE_DEFAULT 1 + #define EX_TYPE_FAULT 2 + #define EX_TYPE_UACCESS 3 +-#define EX_TYPE_COPY 4 ++/* unused, was: #define EX_TYPE_COPY 4 */ + #define EX_TYPE_CLEAR_FS 5 + #define EX_TYPE_FPU_RESTORE 6 + #define EX_TYPE_BPF 7 +diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h +index f81a851c46dca5..652c0137e909f3 100644 +--- a/arch/x86/include/asm/intel-family.h ++++ b/arch/x86/include/asm/intel-family.h +@@ -159,6 +159,8 @@ + #define INTEL_FAM6_GRANITERAPIDS_D 0xAE + #define INTEL_GRANITERAPIDS_D IFM(6, 0xAE) + ++#define INTEL_BARTLETTLAKE IFM(6, 0xD7) /* Raptor Cove */ ++ + /* "Hybrid" Processors (P-Core/E-Core) */ + + #define INTEL_FAM6_LAKEFIELD 0x8A /* Sunny Cove / Tremont */ +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 7df458a6553eb2..78545f7e9cc6ca 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -1574,7 +1574,7 @@ static void __init spec_ctrl_disable_kernel_rrsba(void) + rrsba_disabled = true; + } + +-static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_mitigation mode) ++static void __init spectre_v2_select_rsb_mitigation(enum spectre_v2_mitigation mode) + { + /* + * Similar to context switches, there are two types of RSB attacks +@@ -1598,27 +1598,30 @@ static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_ + */ + switch (mode) { + case SPECTRE_V2_NONE: +- return; ++ break; + +- case SPECTRE_V2_EIBRS_LFENCE: + case SPECTRE_V2_EIBRS: ++ case SPECTRE_V2_EIBRS_LFENCE: ++ case SPECTRE_V2_EIBRS_RETPOLINE: + if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) { +- setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT_LITE); + pr_info("Spectre v2 / PBRSB-eIBRS: Retire a single CALL on VMEXIT\n"); ++ setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT_LITE); + } +- return; ++ break; + +- case SPECTRE_V2_EIBRS_RETPOLINE: + case SPECTRE_V2_RETPOLINE: + case SPECTRE_V2_LFENCE: + case SPECTRE_V2_IBRS: ++ pr_info("Spectre v2 / SpectreRSB: Filling RSB on context switch and VMEXIT\n"); ++ setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); + setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT); +- pr_info("Spectre v2 / SpectreRSB : Filling RSB on VMEXIT\n"); +- return; +- } ++ break; + +- pr_warn_once("Unknown Spectre v2 mode, disabling RSB mitigation at VM exit"); +- dump_stack(); ++ default: ++ pr_warn_once("Unknown Spectre v2 mode, disabling RSB mitigation\n"); ++ dump_stack(); ++ break; ++ } + } + + /* +@@ -1844,10 +1847,7 @@ static void __init spectre_v2_select_mitigation(void) + * + * FIXME: Is this pointless for retbleed-affected AMD? + */ +- setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); +- pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n"); +- +- spectre_v2_determine_rsb_fill_type_at_vmexit(mode); ++ spectre_v2_select_rsb_mitigation(mode); + + /* + * Retpoline protects the kernel, but doesn't protect firmware. IBRS +diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c +index c4477162c07d13..9c5754229d6ed3 100644 +--- a/arch/x86/kernel/cpu/mce/severity.c ++++ b/arch/x86/kernel/cpu/mce/severity.c +@@ -288,14 +288,12 @@ static noinstr int error_context(struct mce *m, struct pt_regs *regs) + copy_user = is_copy_from_user(regs); + instrumentation_end(); + +- switch (fixup_type) { +- case EX_TYPE_UACCESS: +- case EX_TYPE_COPY: +- if (!copy_user) +- return IN_KERNEL; +- m->kflags |= MCE_IN_KERNEL_COPYIN; +- fallthrough; ++ if (copy_user) { ++ m->kflags |= MCE_IN_KERNEL_COPYIN | MCE_IN_KERNEL_RECOV; ++ return IN_KERNEL_RECOV; ++ } + ++ switch (fixup_type) { + case EX_TYPE_FAULT_MCE_SAFE: + case EX_TYPE_DEFAULT_MCE_SAFE: + m->kflags |= MCE_IN_KERNEL_RECOV; +diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c +index 80e262bb627fe1..cb9852ad609893 100644 +--- a/arch/x86/kernel/i8253.c ++++ b/arch/x86/kernel/i8253.c +@@ -46,7 +46,8 @@ bool __init pit_timer_init(void) + * VMMs otherwise steal CPU time just to pointlessly waggle + * the (masked) IRQ. + */ +- clockevent_i8253_disable(); ++ scoped_guard(irq) ++ clockevent_i8253_disable(); + return false; + } + clockevent_i8253_init(true); +diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c +index 4b74ea91f4e6bb..6970b11a6b4c62 100644 +--- a/arch/x86/kvm/svm/avic.c ++++ b/arch/x86/kvm/svm/avic.c +@@ -820,7 +820,7 @@ static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi) + * Allocating new amd_iommu_pi_data, which will get + * add to the per-vcpu ir_list. + */ +- ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_KERNEL_ACCOUNT); ++ ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_ATOMIC | __GFP_ACCOUNT); + if (!ir) { + ret = -ENOMEM; + goto out; +@@ -896,6 +896,7 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + { + struct kvm_kernel_irq_routing_entry *e; + struct kvm_irq_routing_table *irq_rt; ++ bool enable_remapped_mode = true; + int idx, ret = 0; + + if (!kvm_arch_has_assigned_device(kvm) || +@@ -933,6 +934,8 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + kvm_vcpu_apicv_active(&svm->vcpu)) { + struct amd_iommu_pi_data pi; + ++ enable_remapped_mode = false; ++ + /* Try to enable guest_mode in IRTE */ + pi.base = __sme_set(page_to_phys(svm->avic_backing_page) & + AVIC_HPA_MASK); +@@ -951,33 +954,6 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + */ + if (!ret && pi.is_guest_mode) + svm_ir_list_add(svm, &pi); +- } else { +- /* Use legacy mode in IRTE */ +- struct amd_iommu_pi_data pi; +- +- /** +- * Here, pi is used to: +- * - Tell IOMMU to use legacy mode for this interrupt. +- * - Retrieve ga_tag of prior interrupt remapping data. +- */ +- pi.prev_ga_tag = 0; +- pi.is_guest_mode = false; +- ret = irq_set_vcpu_affinity(host_irq, &pi); +- +- /** +- * Check if the posted interrupt was previously +- * setup with the guest_mode by checking if the ga_tag +- * was cached. If so, we need to clean up the per-vcpu +- * ir_list. +- */ +- if (!ret && pi.prev_ga_tag) { +- int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag); +- struct kvm_vcpu *vcpu; +- +- vcpu = kvm_get_vcpu_by_id(kvm, id); +- if (vcpu) +- svm_ir_list_del(to_svm(vcpu), &pi); +- } + } + + if (!ret && svm) { +@@ -993,6 +969,34 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + } + + ret = 0; ++ if (enable_remapped_mode) { ++ /* Use legacy mode in IRTE */ ++ struct amd_iommu_pi_data pi; ++ ++ /** ++ * Here, pi is used to: ++ * - Tell IOMMU to use legacy mode for this interrupt. ++ * - Retrieve ga_tag of prior interrupt remapping data. ++ */ ++ pi.prev_ga_tag = 0; ++ pi.is_guest_mode = false; ++ ret = irq_set_vcpu_affinity(host_irq, &pi); ++ ++ /** ++ * Check if the posted interrupt was previously ++ * setup with the guest_mode by checking if the ga_tag ++ * was cached. If so, we need to clean up the per-vcpu ++ * ir_list. ++ */ ++ if (!ret && pi.prev_ga_tag) { ++ int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag); ++ struct kvm_vcpu *vcpu; ++ ++ vcpu = kvm_get_vcpu_by_id(kvm, id); ++ if (vcpu) ++ svm_ir_list_del(to_svm(vcpu), &pi); ++ } ++ } + out: + srcu_read_unlock(&kvm->irq_srcu, idx); + return ret; +diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c +index af662312fd0778..b54e0cb86e5d61 100644 +--- a/arch/x86/kvm/vmx/posted_intr.c ++++ b/arch/x86/kvm/vmx/posted_intr.c +@@ -274,6 +274,7 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + { + struct kvm_kernel_irq_routing_entry *e; + struct kvm_irq_routing_table *irq_rt; ++ bool enable_remapped_mode = true; + struct kvm_lapic_irq irq; + struct kvm_vcpu *vcpu; + struct vcpu_data vcpu_info; +@@ -312,21 +313,8 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + + kvm_set_msi_irq(kvm, e, &irq); + if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) || +- !kvm_irq_is_postable(&irq)) { +- /* +- * Make sure the IRTE is in remapped mode if +- * we don't handle it in posted mode. +- */ +- ret = irq_set_vcpu_affinity(host_irq, NULL); +- if (ret < 0) { +- printk(KERN_INFO +- "failed to back to remapped mode, irq: %u\n", +- host_irq); +- goto out; +- } +- ++ !kvm_irq_is_postable(&irq)) + continue; +- } + + vcpu_info.pi_desc_addr = __pa(vcpu_to_pi_desc(vcpu)); + vcpu_info.vector = irq.vector; +@@ -334,11 +322,12 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + trace_kvm_pi_irte_update(host_irq, vcpu->vcpu_id, e->gsi, + vcpu_info.vector, vcpu_info.pi_desc_addr, set); + +- if (set) +- ret = irq_set_vcpu_affinity(host_irq, &vcpu_info); +- else +- ret = irq_set_vcpu_affinity(host_irq, NULL); ++ if (!set) ++ continue; + ++ enable_remapped_mode = false; ++ ++ ret = irq_set_vcpu_affinity(host_irq, &vcpu_info); + if (ret < 0) { + printk(KERN_INFO "%s: failed to update PI IRTE\n", + __func__); +@@ -346,6 +335,9 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + } + } + ++ if (enable_remapped_mode) ++ ret = irq_set_vcpu_affinity(host_irq, NULL); ++ + ret = 0; + out: + srcu_read_unlock(&kvm->irq_srcu, idx); +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 2a2dbeb56897d8..f67fe8a65820c8 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -13297,7 +13297,8 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq, + bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old, + struct kvm_kernel_irq_routing_entry *new) + { +- if (new->type != KVM_IRQ_ROUTING_MSI) ++ if (old->type != KVM_IRQ_ROUTING_MSI || ++ new->type != KVM_IRQ_ROUTING_MSI) + return true; + + return !!memcmp(&old->msi, &new->msi, sizeof(new->msi)); +diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c +index 271dcb2deabc31..2354c0156e51c9 100644 +--- a/arch/x86/mm/extable.c ++++ b/arch/x86/mm/extable.c +@@ -163,13 +163,6 @@ static bool ex_handler_uaccess(const struct exception_table_entry *fixup, + return ex_handler_default(fixup, regs); + } + +-static bool ex_handler_copy(const struct exception_table_entry *fixup, +- struct pt_regs *regs, int trapnr) +-{ +- WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?"); +- return ex_handler_fault(fixup, regs, trapnr); +-} +- + static bool ex_handler_msr(const struct exception_table_entry *fixup, + struct pt_regs *regs, bool wrmsr, bool safe, int reg) + { +@@ -267,8 +260,6 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, + return ex_handler_fault(e, regs, trapnr); + case EX_TYPE_UACCESS: + return ex_handler_uaccess(e, regs, trapnr, fault_addr); +- case EX_TYPE_COPY: +- return ex_handler_copy(e, regs, trapnr); + case EX_TYPE_CLEAR_FS: + return ex_handler_clear_fs(e, regs); + case EX_TYPE_FPU_RESTORE: +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index df1794a5e38a57..4872bb082b1935 100644 +--- a/arch/x86/mm/tlb.c ++++ b/arch/x86/mm/tlb.c +@@ -392,9 +392,9 @@ static void cond_mitigation(struct task_struct *next) + prev_mm = this_cpu_read(cpu_tlbstate.last_user_mm_spec); + + /* +- * Avoid user/user BTB poisoning by flushing the branch predictor +- * when switching between processes. This stops one process from +- * doing Spectre-v2 attacks on another. ++ * Avoid user->user BTB/RSB poisoning by flushing them when switching ++ * between processes. This stops one process from doing Spectre-v2 ++ * attacks on another. + * + * Both, the conditional and the always IBPB mode use the mm + * pointer to avoid the IBPB when switching between tasks of the +diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S +index c4365a05ab83b3..fc46b4dfbd7475 100644 +--- a/arch/x86/platform/pvh/head.S ++++ b/arch/x86/platform/pvh/head.S +@@ -100,7 +100,12 @@ SYM_CODE_START_LOCAL(pvh_start_xen) + xor %edx, %edx + wrmsr + +- call xen_prepare_pvh ++ /* Call xen_prepare_pvh() via the kernel virtual mapping */ ++ leaq xen_prepare_pvh(%rip), %rax ++ subq phys_base(%rip), %rax ++ addq $__START_KERNEL_map, %rax ++ ANNOTATE_RETPOLINE_SAFE ++ call *%rax + + /* startup_64 expects boot_params in %rsi. */ + mov $_pa(pvh_bootparams), %rsi +diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c +index 5b84b0f7cc178f..3378670286535a 100644 +--- a/crypto/crypto_null.c ++++ b/crypto/crypto_null.c +@@ -17,10 +17,10 @@ + #include + #include + #include +-#include ++#include + #include + +-static DEFINE_MUTEX(crypto_default_null_skcipher_lock); ++static DEFINE_SPINLOCK(crypto_default_null_skcipher_lock); + static struct crypto_sync_skcipher *crypto_default_null_skcipher; + static int crypto_default_null_skcipher_refcnt; + +@@ -152,23 +152,32 @@ MODULE_ALIAS_CRYPTO("cipher_null"); + + struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void) + { ++ struct crypto_sync_skcipher *ntfm = NULL; + struct crypto_sync_skcipher *tfm; + +- mutex_lock(&crypto_default_null_skcipher_lock); ++ spin_lock_bh(&crypto_default_null_skcipher_lock); + tfm = crypto_default_null_skcipher; + + if (!tfm) { +- tfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0); +- if (IS_ERR(tfm)) +- goto unlock; +- +- crypto_default_null_skcipher = tfm; ++ spin_unlock_bh(&crypto_default_null_skcipher_lock); ++ ++ ntfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0); ++ if (IS_ERR(ntfm)) ++ return ntfm; ++ ++ spin_lock_bh(&crypto_default_null_skcipher_lock); ++ tfm = crypto_default_null_skcipher; ++ if (!tfm) { ++ tfm = ntfm; ++ ntfm = NULL; ++ crypto_default_null_skcipher = tfm; ++ } + } + + crypto_default_null_skcipher_refcnt++; ++ spin_unlock_bh(&crypto_default_null_skcipher_lock); + +-unlock: +- mutex_unlock(&crypto_default_null_skcipher_lock); ++ crypto_free_sync_skcipher(ntfm); + + return tfm; + } +@@ -176,12 +185,16 @@ EXPORT_SYMBOL_GPL(crypto_get_default_null_skcipher); + + void crypto_put_default_null_skcipher(void) + { +- mutex_lock(&crypto_default_null_skcipher_lock); ++ struct crypto_sync_skcipher *tfm = NULL; ++ ++ spin_lock_bh(&crypto_default_null_skcipher_lock); + if (!--crypto_default_null_skcipher_refcnt) { +- crypto_free_sync_skcipher(crypto_default_null_skcipher); ++ tfm = crypto_default_null_skcipher; + crypto_default_null_skcipher = NULL; + } +- mutex_unlock(&crypto_default_null_skcipher_lock); ++ spin_unlock_bh(&crypto_default_null_skcipher_lock); ++ ++ crypto_free_sync_skcipher(tfm); + } + EXPORT_SYMBOL_GPL(crypto_put_default_null_skcipher); + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index 115994dfefec1e..77d6af61158936 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -2301,6 +2301,34 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "103C_5336AN HP ZHAN 66 Pro"), + }, + }, ++ /* ++ * Lenovo Legion Go S; touchscreen blocks HW sleep when woken up from EC ++ * https://gitlab.freedesktop.org/drm/amd/-/issues/3929 ++ */ ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83L3"), ++ } ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83N6"), ++ } ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83Q2"), ++ } ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83Q3"), ++ } ++ }, + { }, + }; + +diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c +index a35dd0e41c2704..f73ce6e13065dd 100644 +--- a/drivers/acpi/pptt.c ++++ b/drivers/acpi/pptt.c +@@ -229,7 +229,7 @@ static int acpi_pptt_leaf_node(struct acpi_table_header *table_hdr, + node_entry = ACPI_PTR_DIFF(node, table_hdr); + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, + sizeof(struct acpi_table_pptt)); +- proc_sz = sizeof(struct acpi_pptt_processor *); ++ proc_sz = sizeof(struct acpi_pptt_processor); + + while ((unsigned long)entry + proc_sz < table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; +@@ -270,7 +270,7 @@ static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_he + table_end = (unsigned long)table_hdr + table_hdr->length; + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, + sizeof(struct acpi_table_pptt)); +- proc_sz = sizeof(struct acpi_pptt_processor *); ++ proc_sz = sizeof(struct acpi_pptt_processor); + + /* find the processor structure associated with this cpuid */ + while ((unsigned long)entry + proc_sz < table_end) { +diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c +index 5377d094bf7548..6a1460d35447cc 100644 +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -2354,8 +2354,8 @@ static unsigned int ata_msense_control_ata_feature(struct ata_device *dev, + */ + put_unaligned_be16(ATA_FEATURE_SUB_MPAGE_LEN - 4, &buf[2]); + +- if (dev->flags & ATA_DFLAG_CDL) +- buf[4] = 0x02; /* Support T2A and T2B pages */ ++ if (dev->flags & ATA_DFLAG_CDL_ENABLED) ++ buf[4] = 0x02; /* T2A and T2B pages enabled */ + else + buf[4] = 0; + +@@ -3764,12 +3764,11 @@ static int ata_mselect_control_spg0(struct ata_queued_cmd *qc, + } + + /* +- * Translate MODE SELECT control mode page, sub-pages f2h (ATA feature mode ++ * Translate MODE SELECT control mode page, sub-page f2h (ATA feature mode + * page) into a SET FEATURES command. + */ +-static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, +- const u8 *buf, int len, +- u16 *fp) ++static int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, ++ const u8 *buf, int len, u16 *fp) + { + struct ata_device *dev = qc->dev; + struct ata_taskfile *tf = &qc->tf; +@@ -3787,17 +3786,27 @@ static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, + /* Check cdl_ctrl */ + switch (buf[0] & 0x03) { + case 0: +- /* Disable CDL */ ++ /* Disable CDL if it is enabled */ ++ if (!(dev->flags & ATA_DFLAG_CDL_ENABLED)) ++ return 0; ++ ata_dev_dbg(dev, "Disabling CDL\n"); + cdl_action = 0; + dev->flags &= ~ATA_DFLAG_CDL_ENABLED; + break; + case 0x02: +- /* Enable CDL T2A/T2B: NCQ priority must be disabled */ ++ /* ++ * Enable CDL if not already enabled. Since this is mutually ++ * exclusive with NCQ priority, allow this only if NCQ priority ++ * is disabled. ++ */ ++ if (dev->flags & ATA_DFLAG_CDL_ENABLED) ++ return 0; + if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) { + ata_dev_err(dev, + "NCQ priority must be disabled to enable CDL\n"); + return -EINVAL; + } ++ ata_dev_dbg(dev, "Enabling CDL\n"); + cdl_action = 1; + dev->flags |= ATA_DFLAG_CDL_ENABLED; + break; +diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c +index d56a5d508ccd7b..8b690f59df27d6 100644 +--- a/drivers/auxdisplay/hd44780.c ++++ b/drivers/auxdisplay/hd44780.c +@@ -313,13 +313,13 @@ static int hd44780_probe(struct platform_device *pdev) + fail3: + kfree(hd); + fail2: +- kfree(lcd); ++ charlcd_free(lcd); + fail1: + kfree(hdc); + return ret; + } + +-static int hd44780_remove(struct platform_device *pdev) ++static void hd44780_remove(struct platform_device *pdev) + { + struct charlcd *lcd = platform_get_drvdata(pdev); + struct hd44780_common *hdc = lcd->drvdata; +@@ -328,8 +328,7 @@ static int hd44780_remove(struct platform_device *pdev) + kfree(hdc->hd44780); + kfree(lcd->drvdata); + +- kfree(lcd); +- return 0; ++ charlcd_free(lcd); + } + + static const struct of_device_id hd44780_of_match[] = { +@@ -340,7 +339,7 @@ MODULE_DEVICE_TABLE(of, hd44780_of_match); + + static struct platform_driver hd44780_driver = { + .probe = hd44780_probe, +- .remove = hd44780_remove, ++ .remove_new = hd44780_remove, + .driver = { + .name = "hd44780", + .of_match_table = hd44780_of_match, +diff --git a/drivers/base/base.h b/drivers/base/base.h +index a8e3d8165232fd..0b491449b022a1 100644 +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -73,6 +73,7 @@ static inline void subsys_put(struct subsys_private *sp) + kset_put(&sp->subsys); + } + ++struct subsys_private *bus_to_subsys(const struct bus_type *bus); + struct subsys_private *class_to_subsys(const struct class *class); + + struct driver_private { +@@ -179,6 +180,22 @@ int driver_add_groups(struct device_driver *drv, const struct attribute_group ** + void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups); + void device_driver_detach(struct device *dev); + ++static inline void device_set_driver(struct device *dev, const struct device_driver *drv) ++{ ++ /* ++ * Majority (all?) read accesses to dev->driver happens either ++ * while holding device lock or in bus/driver code that is only ++ * invoked when the device is bound to a driver and there is no ++ * concern of the pointer being changed while it is being read. ++ * However when reading device's uevent file we read driver pointer ++ * without taking device lock (so we do not block there for ++ * arbitrary amount of time). We use WRITE_ONCE() here to prevent ++ * tearing so that READ_ONCE() can safely be used in uevent code. ++ */ ++ // FIXME - this cast should not be needed "soon" ++ WRITE_ONCE(dev->driver, (struct device_driver *)drv); ++} ++ + int devres_release_all(struct device *dev); + void device_block_probing(void); + void device_unblock_probing(void); +diff --git a/drivers/base/bus.c b/drivers/base/bus.c +index d4361ad3b433f5..b97e13a52c3308 100644 +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -57,7 +57,7 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, + * NULL. A call to subsys_put() must be done when finished with the pointer in + * order for it to be properly freed. + */ +-static struct subsys_private *bus_to_subsys(const struct bus_type *bus) ++struct subsys_private *bus_to_subsys(const struct bus_type *bus) + { + struct subsys_private *sp = NULL; + struct kobject *kobj; +diff --git a/drivers/base/core.c b/drivers/base/core.c +index 8e2caa9eb5cd41..a192ce5bb8f902 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -2570,6 +2570,35 @@ static const char *dev_uevent_name(const struct kobject *kobj) + return NULL; + } + ++/* ++ * Try filling "DRIVER=" uevent variable for a device. Because this ++ * function may race with binding and unbinding the device from a driver, ++ * we need to be careful. Binding is generally safe, at worst we miss the ++ * fact that the device is already bound to a driver (but the driver ++ * information that is delivered through uevents is best-effort, it may ++ * become obsolete as soon as it is generated anyways). Unbinding is more ++ * risky as driver pointer is transitioning to NULL, so READ_ONCE() should ++ * be used to make sure we are dealing with the same pointer, and to ++ * ensure that driver structure is not going to disappear from under us ++ * we take bus' drivers klist lock. The assumption that only registered ++ * driver can be bound to a device, and to unregister a driver bus code ++ * will take the same lock. ++ */ ++static void dev_driver_uevent(const struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct subsys_private *sp = bus_to_subsys(dev->bus); ++ ++ if (sp) { ++ scoped_guard(spinlock, &sp->klist_drivers.k_lock) { ++ struct device_driver *drv = READ_ONCE(dev->driver); ++ if (drv) ++ add_uevent_var(env, "DRIVER=%s", drv->name); ++ } ++ ++ subsys_put(sp); ++ } ++} ++ + static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) + { + const struct device *dev = kobj_to_dev(kobj); +@@ -2601,8 +2630,8 @@ static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) + if (dev->type && dev->type->name) + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); + +- if (dev->driver) +- add_uevent_var(env, "DRIVER=%s", dev->driver->name); ++ /* Add "DRIVER=%s" variable if the device is bound to a driver */ ++ dev_driver_uevent(dev, env); + + /* Add common DT information about the device */ + of_device_uevent(dev, env); +@@ -2672,11 +2701,8 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, + if (!env) + return -ENOMEM; + +- /* Synchronize with really_probe() */ +- device_lock(dev); + /* let the kset specific function add its keys */ + retval = kset->uevent_ops->uevent(&dev->kobj, env); +- device_unlock(dev); + if (retval) + goto out; + +@@ -3691,7 +3717,7 @@ int device_add(struct device *dev) + device_pm_remove(dev); + dpm_sysfs_remove(dev); + DPMError: +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + bus_remove_device(dev); + BusError: + device_remove_attrs(dev); +diff --git a/drivers/base/dd.c b/drivers/base/dd.c +index 0c3725c3eefa46..7e2fb159bb895b 100644 +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -550,7 +550,7 @@ static void device_unbind_cleanup(struct device *dev) + arch_teardown_dma_ops(dev); + kfree(dev->dma_range_map); + dev->dma_range_map = NULL; +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + dev_set_drvdata(dev, NULL); + if (dev->pm_domain && dev->pm_domain->dismiss) + dev->pm_domain->dismiss(dev); +@@ -629,7 +629,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) + } + + re_probe: +- dev->driver = drv; ++ device_set_driver(dev, drv); + + /* If using pinctrl, bind pins now before probing */ + ret = pinctrl_bind_pins(dev); +@@ -1014,7 +1014,7 @@ static int __device_attach(struct device *dev, bool allow_async) + if (ret == 0) + ret = 1; + else { +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + ret = 0; + } + } else { +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 8a6c1146df00fd..455e2a2b149f4b 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -441,7 +441,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, + cmd->iocb.ki_filp = file; + cmd->iocb.ki_complete = lo_rw_aio_complete; + cmd->iocb.ki_flags = IOCB_DIRECT; +- cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0); ++ cmd->iocb.ki_ioprio = req_get_ioprio(rq); + + if (rw == ITER_SOURCE) + ret = call_write_iter(file, &cmd->iocb, &iter); +diff --git a/drivers/char/misc.c b/drivers/char/misc.c +index f7dd455dd0dd3c..dda466f9181acf 100644 +--- a/drivers/char/misc.c ++++ b/drivers/char/misc.c +@@ -315,7 +315,7 @@ static int __init misc_init(void) + goto fail_remove; + + err = -EIO; +- if (register_chrdev(MISC_MAJOR, "misc", &misc_fops)) ++ if (__register_chrdev(MISC_MAJOR, 0, MINORMASK + 1, "misc", &misc_fops)) + goto fail_printk; + return 0; + +diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c +index 796ab9a4e48fa1..80e0f485170a8f 100644 +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -1612,8 +1612,8 @@ static void handle_control_message(struct virtio_device *vdev, + break; + case VIRTIO_CONSOLE_RESIZE: { + struct { +- __u16 rows; +- __u16 cols; ++ __virtio16 rows; ++ __virtio16 cols; + } size; + + if (!is_console_port(port)) +@@ -1621,7 +1621,8 @@ static void handle_control_message(struct virtio_device *vdev, + + memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), + sizeof(size)); +- set_console_size(port, size.rows, size.cols); ++ set_console_size(port, virtio16_to_cpu(vdev, size.rows), ++ virtio16_to_cpu(vdev, size.cols)); + + port->cons.hvc->irq_requested = 1; + resize_console(port); +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 5bbd036f5295f5..8474099e2cac19 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -5216,6 +5216,10 @@ of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec) + if (!clkspec) + return ERR_PTR(-EINVAL); + ++ /* Check if node in clkspec is in disabled/fail state */ ++ if (!of_device_is_available(clkspec->np)) ++ return ERR_PTR(-ENOENT); ++ + mutex_lock(&of_clk_mutex); + list_for_each_entry(provider, &of_clk_providers, link) { + if (provider->node == clkspec->np) { +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 6c6bc79b2e9cec..865d47800791bd 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -14,6 +14,17 @@ + + #include "rzg2l-cpg.h" + ++/* Specific registers. */ ++#define CPG_PL2SDHI_DSEL (0x218) ++ ++/* Clock select configuration. */ ++#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) ++#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) ++ ++/* Clock status configuration. */ ++#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) ++#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G043_CLK_P0_DIV2, +@@ -75,8 +86,12 @@ static const struct clk_div_table dtable_1_32[] = { + + /* Mux clock tables */ + static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; ++#ifdef CONFIG_ARM64 + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; +-static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++#endif ++static const char * const sel_sdhi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++ ++static const u32 mtable_sdhi[] = { 1, 2, 3 }; + + static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + /* External Clock Inputs */ +@@ -120,11 +135,18 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + DEF_DIV("P2", R9A07G043_CLK_P2, CLK_PLL3_DIV2_4_2, DIVPL3A, dtable_1_32), + DEF_FIXED("M0", R9A07G043_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), + DEF_FIXED("ZT", R9A07G043_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1), ++#ifdef CONFIG_ARM64 + DEF_MUX("HP", R9A07G043_CLK_HP, SEL_PLL6_2, sel_pll6_2), ++#endif ++#ifdef CONFIG_RISCV ++ DEF_FIXED("HP", R9A07G043_CLK_HP, CLK_PLL6_250, 1, 1), ++#endif + DEF_FIXED("SPI0", R9A07G043_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, sel_shdi), +- DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, sel_shdi), ++ DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), ++ DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), + }; +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index c597414a94d8a0..48404cafea3f51 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -15,6 +15,17 @@ + + #include "rzg2l-cpg.h" + ++/* Specific registers. */ ++#define CPG_PL2SDHI_DSEL (0x218) ++ ++/* Clock select configuration. */ ++#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) ++#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) ++ ++/* Clock status configuration. */ ++#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) ++#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A, +@@ -95,9 +106,11 @@ static const struct clk_div_table dtable_16_128[] = { + static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; + static const char * const sel_pll5_4[] = { ".pll5_foutpostdiv", ".pll5_fout1ph0" }; + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; +-static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++static const char * const sel_sdhi[] = { ".clk_533", ".clk_400", ".clk_266" }; + static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" }; + ++static const u32 mtable_sdhi[] = { 1, 2, 3 }; ++ + static const struct { + struct cpg_core_clk common[56]; + #ifdef CONFIG_CLK_R9A07G054 +@@ -163,8 +176,10 @@ static const struct { + DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, sel_pll6_2), + DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, sel_shdi), +- DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, sel_shdi), ++ DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), ++ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), + DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8), +diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c +index f8dbb092b9f1b2..77eefb6ee4538a 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.c ++++ b/drivers/clk/renesas/rzg2l-cpg.c +@@ -56,15 +56,37 @@ + #define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff) + #define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff) + ++#define CPG_WEN_BIT BIT(16) ++ + #define MAX_VCLK_FREQ (148500000) + +-struct sd_hw_data { ++/** ++ * struct clk_hw_data - clock hardware data ++ * @hw: clock hw ++ * @conf: clock configuration (register offset, shift, width) ++ * @sconf: clock status configuration (register offset, shift, width) ++ * @priv: CPG private data structure ++ */ ++struct clk_hw_data { + struct clk_hw hw; + u32 conf; ++ u32 sconf; + struct rzg2l_cpg_priv *priv; + }; + +-#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw) ++#define to_clk_hw_data(_hw) container_of(_hw, struct clk_hw_data, hw) ++ ++/** ++ * struct sd_mux_hw_data - SD MUX clock hardware data ++ * @hw_data: clock hw data ++ * @mtable: clock mux table ++ */ ++struct sd_mux_hw_data { ++ struct clk_hw_data hw_data; ++ const u32 *mtable; ++}; ++ ++#define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data) + + struct rzg2l_pll5_param { + u32 pl5_fracin; +@@ -121,6 +143,76 @@ static void rzg2l_cpg_del_clk_provider(void *data) + of_clk_del_provider(data); + } + ++/* Must be called in atomic context. */ ++static int rzg2l_cpg_wait_clk_update_done(void __iomem *base, u32 conf) ++{ ++ u32 bitmask = GENMASK(GET_WIDTH(conf) - 1, 0) << GET_SHIFT(conf); ++ u32 off = GET_REG_OFFSET(conf); ++ u32 val; ++ ++ return readl_poll_timeout_atomic(base + off, val, !(val & bitmask), 10, 200); ++} ++ ++int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, ++ void *data) ++{ ++ struct clk_notifier_data *cnd = data; ++ struct clk_hw *hw = __clk_get_hw(cnd->clk); ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 off = GET_REG_OFFSET(clk_hw_data->conf); ++ u32 shift = GET_SHIFT(clk_hw_data->conf); ++ const u32 clk_src_266 = 3; ++ unsigned long flags; ++ int ret; ++ ++ if (event != PRE_RATE_CHANGE || (cnd->new_rate / MEGA == 266)) ++ return NOTIFY_DONE; ++ ++ spin_lock_irqsave(&priv->rmw_lock, flags); ++ ++ /* ++ * As per the HW manual, we should not directly switch from 533 MHz to ++ * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) ++ * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, ++ * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 ++ * (400 MHz)). ++ * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock ++ * switching register is prohibited. ++ * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and ++ * the index to value mapping is done by adding 1 to the index. ++ */ ++ ++ writel((CPG_WEN_BIT | clk_src_266) << shift, priv->base + off); ++ ++ /* Wait for the update done. */ ++ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); ++ ++ spin_unlock_irqrestore(&priv->rmw_lock, flags); ++ ++ if (ret) ++ dev_err(priv->dev, "failed to switch to safe clk source\n"); ++ ++ return notifier_from_errno(ret); ++} ++ ++static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core, ++ struct rzg2l_cpg_priv *priv) ++{ ++ struct notifier_block *nb; ++ ++ if (!core->notifier) ++ return 0; ++ ++ nb = devm_kzalloc(priv->dev, sizeof(*nb), GFP_KERNEL); ++ if (!nb) ++ return -ENOMEM; ++ ++ nb->notifier_call = core->notifier; ++ ++ return clk_notifier_register(hw->clk, nb); ++} ++ + static struct clk * __init + rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, + struct clk **clks, +@@ -183,63 +275,44 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, + + static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + { +- struct sd_hw_data *hwdata = to_sd_hw_data(hw); +- struct rzg2l_cpg_priv *priv = hwdata->priv; +- u32 off = GET_REG_OFFSET(hwdata->conf); +- u32 shift = GET_SHIFT(hwdata->conf); +- const u32 clk_src_266 = 2; +- u32 msk, val, bitmask; ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 off = GET_REG_OFFSET(clk_hw_data->conf); ++ u32 shift = GET_SHIFT(clk_hw_data->conf); + unsigned long flags; ++ u32 val; + int ret; + +- /* +- * As per the HW manual, we should not directly switch from 533 MHz to +- * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) +- * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, +- * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 +- * (400 MHz)). +- * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock +- * switching register is prohibited. +- * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and +- * the index to value mapping is done by adding 1 to the index. +- */ +- bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; +- msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; ++ val = clk_mux_index_to_val(sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, index); ++ + spin_lock_irqsave(&priv->rmw_lock, flags); +- if (index != clk_src_266) { +- writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); +- +- ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, +- !(val & msk), 10, +- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +- if (ret) +- goto unlock; +- } + +- writel(bitmask | ((index + 1) << shift), priv->base + off); ++ writel((CPG_WEN_BIT | val) << shift, priv->base + off); ++ ++ /* Wait for the update done. */ ++ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); + +- ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, +- !(val & msk), 10, +- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +-unlock: + spin_unlock_irqrestore(&priv->rmw_lock, flags); + + if (ret) +- dev_err(priv->dev, "failed to switch clk source\n"); ++ dev_err(priv->dev, "Failed to switch parent\n"); + + return ret; + } + + static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) + { +- struct sd_hw_data *hwdata = to_sd_hw_data(hw); +- struct rzg2l_cpg_priv *priv = hwdata->priv; +- u32 val = readl(priv->base + GET_REG_OFFSET(hwdata->conf)); ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 val; + +- val >>= GET_SHIFT(hwdata->conf); +- val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0); ++ val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); ++ val >>= GET_SHIFT(clk_hw_data->conf); ++ val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); + +- return val ? val - 1 : 0; ++ return clk_mux_val_to_index(hw, sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, val); + } + + static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { +@@ -253,31 +326,40 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, + void __iomem *base, + struct rzg2l_cpg_priv *priv) + { +- struct sd_hw_data *clk_hw_data; ++ struct sd_mux_hw_data *sd_mux_hw_data; + struct clk_init_data init; + struct clk_hw *clk_hw; + int ret; + +- clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); +- if (!clk_hw_data) ++ sd_mux_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_mux_hw_data), GFP_KERNEL); ++ if (!sd_mux_hw_data) + return ERR_PTR(-ENOMEM); + +- clk_hw_data->priv = priv; +- clk_hw_data->conf = core->conf; ++ sd_mux_hw_data->hw_data.priv = priv; ++ sd_mux_hw_data->hw_data.conf = core->conf; ++ sd_mux_hw_data->hw_data.sconf = core->sconf; ++ sd_mux_hw_data->mtable = core->mtable; + + init.name = GET_SHIFT(core->conf) ? "sd1" : "sd0"; + init.ops = &rzg2l_cpg_sd_clk_mux_ops; +- init.flags = 0; ++ init.flags = core->flag; + init.num_parents = core->num_parents; + init.parent_names = core->parent_names; + +- clk_hw = &clk_hw_data->hw; ++ clk_hw = &sd_mux_hw_data->hw_data.hw; + clk_hw->init = &init; + + ret = devm_clk_hw_register(priv->dev, clk_hw); + if (ret) + return ERR_PTR(ret); + ++ ret = rzg2l_register_notifier(clk_hw, core, priv); ++ if (ret) { ++ dev_err(priv->dev, "Failed to register notifier for %s\n", ++ core->name); ++ return ERR_PTR(ret); ++ } ++ + return clk_hw->clk; + } + +diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h +index 91e9c2569f801b..e662459cc6d963 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.h ++++ b/drivers/clk/renesas/rzg2l-cpg.h +@@ -9,6 +9,8 @@ + #ifndef __RENESAS_RZG2L_CPG_H__ + #define __RENESAS_RZG2L_CPG_H__ + ++#include ++ + #define CPG_SIPLL5_STBY (0x140) + #define CPG_SIPLL5_CLK1 (0x144) + #define CPG_SIPLL5_CLK3 (0x14C) +@@ -19,7 +21,6 @@ + #define CPG_PL2_DDIV (0x204) + #define CPG_PL3A_DDIV (0x208) + #define CPG_PL6_DDIV (0x210) +-#define CPG_PL2SDHI_DSEL (0x218) + #define CPG_CLKSTATUS (0x280) + #define CPG_PL3_SSEL (0x408) + #define CPG_PL6_SSEL (0x414) +@@ -43,8 +44,6 @@ + #define CPG_CLKSTATUS_SELSDHI0_STS BIT(28) + #define CPG_CLKSTATUS_SELSDHI1_STS BIT(29) + +-#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 200 +- + /* n = 0/1/2 for PLL1/4/6 */ + #define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n)) + #define CPG_SAMPLL_CLK2(n) (0x08 + (16 * n)) +@@ -69,9 +68,6 @@ + #define SEL_PLL6_2 SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1) + #define SEL_GPU2 SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1) + +-#define SEL_SDHI0 DDIV_PACK(CPG_PL2SDHI_DSEL, 0, 2) +-#define SEL_SDHI1 DDIV_PACK(CPG_PL2SDHI_DSEL, 4, 2) +- + #define EXTAL_FREQ_IN_MEGA_HZ (24) + + /** +@@ -90,10 +86,13 @@ struct cpg_core_clk { + unsigned int mult; + unsigned int type; + unsigned int conf; ++ unsigned int sconf; + const struct clk_div_table *dtable; ++ const u32 *mtable; + const char * const *parent_names; +- int flag; +- int mux_flags; ++ notifier_fn_t notifier; ++ u32 flag; ++ u32 mux_flags; + int num_parents; + }; + +@@ -151,10 +150,11 @@ enum clk_types { + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .mux_flags = CLK_MUX_READ_ONLY) +-#define DEF_SD_MUX(_name, _id, _conf, _parent_names) \ +- DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, \ ++#define DEF_SD_MUX(_name, _id, _conf, _sconf, _parent_names, _mtable, _clk_flags, _notifier) \ ++ DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \ + .parent_names = _parent_names, \ +- .num_parents = ARRAY_SIZE(_parent_names)) ++ .num_parents = ARRAY_SIZE(_parent_names), \ ++ .mtable = _mtable, .flag = _clk_flags, .notifier = _notifier) + #define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \ + DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent) + #define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names) \ +@@ -273,4 +273,6 @@ extern const struct rzg2l_cpg_info r9a07g044_cpg_info; + extern const struct rzg2l_cpg_info r9a07g054_cpg_info; + extern const struct rzg2l_cpg_info r9a09g011_cpg_info; + ++int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, void *data); ++ + #endif +diff --git a/drivers/comedi/drivers/jr3_pci.c b/drivers/comedi/drivers/jr3_pci.c +index 951c23fa0369ea..75dce1ff24193b 100644 +--- a/drivers/comedi/drivers/jr3_pci.c ++++ b/drivers/comedi/drivers/jr3_pci.c +@@ -758,7 +758,7 @@ static void jr3_pci_detach(struct comedi_device *dev) + struct jr3_pci_dev_private *devpriv = dev->private; + + if (devpriv) +- del_timer_sync(&devpriv->timer); ++ timer_shutdown_sync(&devpriv->timer); + + comedi_pci_detach(dev); + } +diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c +index 021f423705e1b1..9ba6b09775f617 100644 +--- a/drivers/cpufreq/apple-soc-cpufreq.c ++++ b/drivers/cpufreq/apple-soc-cpufreq.c +@@ -103,11 +103,17 @@ static const struct of_device_id apple_soc_cpufreq_of_match[] = { + + static unsigned int apple_soc_cpufreq_get_rate(unsigned int cpu) + { +- struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); +- struct apple_cpu_priv *priv = policy->driver_data; ++ struct cpufreq_policy *policy; ++ struct apple_cpu_priv *priv; + struct cpufreq_frequency_table *p; + unsigned int pstate; + ++ policy = cpufreq_cpu_get_raw(cpu); ++ if (unlikely(!policy)) ++ return 0; ++ ++ priv = policy->driver_data; ++ + if (priv->info->cur_pstate_mask) { + u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS); + +diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c +index c8447ecad797e7..aa34af940cb53b 100644 +--- a/drivers/cpufreq/cppc_cpufreq.c ++++ b/drivers/cpufreq/cppc_cpufreq.c +@@ -773,7 +773,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) + int ret; + + if (!policy) +- return -ENODEV; ++ return 0; + + cpu_data = policy->driver_data; + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 079940c69ee0ba..e4989764efe2a8 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -33,11 +33,17 @@ static const struct scmi_perf_proto_ops *perf_ops; + + static unsigned int scmi_cpufreq_get_rate(unsigned int cpu) + { +- struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); +- struct scmi_data *priv = policy->driver_data; ++ struct cpufreq_policy *policy; ++ struct scmi_data *priv; + unsigned long rate; + int ret; + ++ policy = cpufreq_cpu_get_raw(cpu); ++ if (unlikely(!policy)) ++ return 0; ++ ++ priv = policy->driver_data; ++ + ret = perf_ops->freq_get(ph, priv->domain_id, &rate, false); + if (ret) + return 0; +diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c +index bfc2e65e1e5022..2aef39bff7d6f5 100644 +--- a/drivers/cpufreq/scpi-cpufreq.c ++++ b/drivers/cpufreq/scpi-cpufreq.c +@@ -29,9 +29,16 @@ static struct scpi_ops *scpi_ops; + + static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) + { +- struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); +- struct scpi_data *priv = policy->driver_data; +- unsigned long rate = clk_get_rate(priv->clk); ++ struct cpufreq_policy *policy; ++ struct scpi_data *priv; ++ unsigned long rate; ++ ++ policy = cpufreq_cpu_get_raw(cpu); ++ if (unlikely(!policy)) ++ return 0; ++ ++ priv = policy->driver_data; ++ rate = clk_get_rate(priv->clk); + + return rate / 1000; + } +diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c +index c77f482d2a97e9..5bc809146ffea0 100644 +--- a/drivers/crypto/atmel-sha204a.c ++++ b/drivers/crypto/atmel-sha204a.c +@@ -107,6 +107,12 @@ static int atmel_sha204a_probe(struct i2c_client *client) + i2c_priv->hwrng.name = dev_name(&client->dev); + i2c_priv->hwrng.read = atmel_sha204a_rng_read; + ++ /* ++ * According to review by Bill Cox [1], this HWRNG has very low entropy. ++ * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html ++ */ ++ i2c_priv->hwrng.quality = 1; ++ + ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng); + if (ret) + dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 0caa57dafc525a..b1e60542351a66 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -577,6 +577,7 @@ static const struct pci_device_id sp_pci_table[] = { + { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, + { PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] }, + { PCI_VDEVICE(AMD, 0x1649), (kernel_ulong_t)&dev_vdata[6] }, ++ { PCI_VDEVICE(AMD, 0x1134), (kernel_ulong_t)&dev_vdata[7] }, + { PCI_VDEVICE(AMD, 0x17E0), (kernel_ulong_t)&dev_vdata[7] }, + { PCI_VDEVICE(AMD, 0x156E), (kernel_ulong_t)&dev_vdata[8] }, + /* Last entry must be zero */ +diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c +index bab4592db647f7..92ef68849fbea8 100644 +--- a/drivers/cxl/core/regs.c ++++ b/drivers/cxl/core/regs.c +@@ -478,7 +478,6 @@ resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri + resource_size_t rcrb = ri->base; + void __iomem *addr; + u32 bar0, bar1; +- u16 cmd; + u32 id; + + if (which == CXL_RCRB_UPSTREAM) +@@ -500,7 +499,6 @@ resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri + } + + id = readl(addr + PCI_VENDOR_ID); +- cmd = readw(addr + PCI_COMMAND); + bar0 = readl(addr + PCI_BASE_ADDRESS_0); + bar1 = readl(addr + PCI_BASE_ADDRESS_1); + iounmap(addr); +@@ -515,8 +513,6 @@ resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri + dev_err(dev, "Failed to access Downstream Port RCRB\n"); + return CXL_RESOURCE_NONE; + } +- if (!(cmd & PCI_COMMAND_MEMORY)) +- return CXL_RESOURCE_NONE; + /* The RCRB is a Memory Window, and the MEM_TYPE_1M bit is obsolete */ + if (bar0 & (PCI_BASE_ADDRESS_MEM_TYPE_1M | PCI_BASE_ADDRESS_SPACE_IO)) + return CXL_RESOURCE_NONE; +diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c +index d1fcdd1f9aaed3..373282beeb6068 100644 +--- a/drivers/dma-buf/udmabuf.c ++++ b/drivers/dma-buf/udmabuf.c +@@ -214,7 +214,7 @@ static long udmabuf_create(struct miscdevice *device, + if (!ubuf) + return -ENOMEM; + +- pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; ++ pglimit = ((u64)size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; + for (i = 0; i < head->count; i++) { + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) + goto err; +diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c +index ffe621695e472b..78b8a97b236376 100644 +--- a/drivers/dma/dmatest.c ++++ b/drivers/dma/dmatest.c +@@ -827,9 +827,9 @@ static int dmatest_func(void *data) + } else { + dma_async_issue_pending(chan); + +- wait_event_freezable_timeout(thread->done_wait, +- done->done, +- msecs_to_jiffies(params->timeout)); ++ wait_event_timeout(thread->done_wait, ++ done->done, ++ msecs_to_jiffies(params->timeout)); + + status = dma_async_is_tx_complete(chan, cookie, NULL, + NULL); +diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c +index cec9e8f29bbdfe..a0a2a0f75bba46 100644 +--- a/drivers/gpio/gpiolib-of.c ++++ b/drivers/gpio/gpiolib-of.c +@@ -247,6 +247,9 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np, + { "fsl,imx8qm-fec", "phy-reset-gpios", "phy-reset-active-high" }, + { "fsl,s32v234-fec", "phy-reset-gpios", "phy-reset-active-high" }, + #endif ++#if IS_ENABLED(CONFIG_MMC_ATMELMCI) ++ { "atmel,hsmci", "cd-gpios", "cd-inverted" }, ++#endif + #if IS_ENABLED(CONFIG_PCI_IMX6) + { "fsl,imx6q-pcie", "reset-gpio", "reset-gpio-active-high" }, + { "fsl,imx6sx-pcie", "reset-gpio", "reset-gpio-active-high" }, +@@ -272,9 +275,6 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np, + #if IS_ENABLED(CONFIG_REGULATOR_GPIO) + { "regulator-gpio", "enable-gpio", "enable-active-high" }, + { "regulator-gpio", "enable-gpios", "enable-active-high" }, +-#endif +-#if IS_ENABLED(CONFIG_MMC_ATMELMCI) +- { "atmel,hsmci", "cd-gpios", "cd-inverted" }, + #endif + }; + unsigned int i; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 28f2b4022d34e3..e6bc590533194d 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -2789,16 +2789,16 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state, + for (k = 0; k < dc_state->stream_count; k++) { + bundle->stream_update.stream = dc_state->streams[k]; + +- for (m = 0; m < dc_state->stream_status->plane_count; m++) { ++ for (m = 0; m < dc_state->stream_status[k].plane_count; m++) { + bundle->surface_updates[m].surface = +- dc_state->stream_status->plane_states[m]; ++ dc_state->stream_status[k].plane_states[m]; + bundle->surface_updates[m].surface->force_full_update = + true; + } + + update_planes_and_stream_adapter(dm->dc, + UPDATE_TYPE_FULL, +- dc_state->stream_status->plane_count, ++ dc_state->stream_status[k].plane_count, + dc_state->streams[k], + &bundle->stream_update, + bundle->surface_updates); +@@ -9590,6 +9590,9 @@ static bool should_reset_plane(struct drm_atomic_state *state, + if (adev->ip_versions[DCE_HWIP][0] < IP_VERSION(3, 2, 0) && state->allow_modeset) + return true; + ++ if (amdgpu_in_reset(adev) && state->allow_modeset) ++ return true; ++ + /* Exit early if we know that we're adding or removing the plane. */ + if (old_plane_state->crtc != new_plane_state->crtc) + return true; +diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c +index 70a25949142c0d..74b0c85944bd61 100644 +--- a/drivers/iio/adc/ad7768-1.c ++++ b/drivers/iio/adc/ad7768-1.c +@@ -142,7 +142,7 @@ static const struct iio_chan_spec ad7768_channels[] = { + .channel = 0, + .scan_index = 0, + .scan_type = { +- .sign = 'u', ++ .sign = 's', + .realbits = 24, + .storagebits = 32, + .shift = 8, +@@ -370,12 +370,11 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, + return ret; + + ret = ad7768_scan_direct(indio_dev); +- if (ret >= 0) +- *val = ret; + + iio_device_release_direct_mode(indio_dev); + if (ret < 0) + return ret; ++ *val = sign_extend32(ret, chan->scan_type.realbits - 1); + + return IIO_VAL_INT; + +diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c +index 11155e0fb8395c..35d777976c2952 100644 +--- a/drivers/infiniband/hw/qib/qib_fs.c ++++ b/drivers/infiniband/hw/qib/qib_fs.c +@@ -55,6 +55,7 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry, + struct inode *inode = new_inode(dir->i_sb); + + if (!inode) { ++ dput(dentry); + error = -EPERM; + goto bail; + } +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 95bd7c25ba6f36..83c5d786686d07 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -3619,7 +3619,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) + * we should not modify the IRTE + */ + if (!dev_data || !dev_data->use_vapic) +- return 0; ++ return -EINVAL; + + ir_data->cfg = irqd_cfg(data); + pi_data->ir_data = ir_data; +diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c +index d83c2c85962c37..683e8721e3b498 100644 +--- a/drivers/irqchip/irq-gic-v2m.c ++++ b/drivers/irqchip/irq-gic-v2m.c +@@ -454,7 +454,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, + #ifdef CONFIG_ACPI + static int acpi_num_msi; + +-static __init struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) ++static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) + { + struct v2m_data *data; + +diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c +index 82102a4c5d6883..f8215a8f656a46 100644 +--- a/drivers/mailbox/pcc.c ++++ b/drivers/mailbox/pcc.c +@@ -313,6 +313,10 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + int ret; + + pchan = chan->con_priv; ++ ++ if (pcc_chan_reg_read_modify_write(&pchan->plat_irq_ack)) ++ return IRQ_NONE; ++ + if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE && + !pchan->chan_in_use) + return IRQ_NONE; +@@ -330,13 +334,16 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + return IRQ_NONE; + } + +- if (pcc_chan_reg_read_modify_write(&pchan->plat_irq_ack)) +- return IRQ_NONE; +- ++ /* ++ * Clear this flag after updating interrupt ack register and just ++ * before mbox_chan_received_data() which might call pcc_send_data() ++ * where the flag is set again to start new transfer. This is ++ * required to avoid any possible race in updatation of this flag. ++ */ ++ pchan->chan_in_use = false; + mbox_chan_received_data(chan, NULL); + + check_and_ack(pchan, chan); +- pchan->chan_in_use = false; + + return IRQ_HANDLED; + } +diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c +index 1ae37e693de045..d080e21df666d9 100644 +--- a/drivers/mcb/mcb-parse.c ++++ b/drivers/mcb/mcb-parse.c +@@ -101,7 +101,7 @@ static int chameleon_parse_gdd(struct mcb_bus *bus, + + ret = mcb_device_register(bus, mdev); + if (ret < 0) +- goto err; ++ return ret; + + return 0; + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 65309da1dca340..8b25287c89ed6d 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -2061,14 +2061,9 @@ static int fix_sync_read_error(struct r1bio *r1_bio) + if (!rdev_set_badblocks(rdev, sect, s, 0)) + abort = 1; + } +- if (abort) { +- conf->recovery_disabled = +- mddev->recovery_disabled; +- set_bit(MD_RECOVERY_INTR, &mddev->recovery); +- md_done_sync(mddev, r1_bio->sectors, 0); +- put_buf(r1_bio); ++ if (abort) + return 0; +- } ++ + /* Try next page */ + sectors -= s; + sect += s; +@@ -2207,10 +2202,21 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio) + int disks = conf->raid_disks * 2; + struct bio *wbio; + +- if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) +- /* ouch - failed to read all of that. */ +- if (!fix_sync_read_error(r1_bio)) ++ if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) { ++ /* ++ * ouch - failed to read all of that. ++ * No need to fix read error for check/repair ++ * because all member disks are read. ++ */ ++ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) || ++ !fix_sync_read_error(r1_bio)) { ++ conf->recovery_disabled = mddev->recovery_disabled; ++ set_bit(MD_RECOVERY_INTR, &mddev->recovery); ++ md_done_sync(mddev, r1_bio->sectors, 0); ++ put_buf(r1_bio); + return; ++ } ++ } + + if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) + process_checks(r1_bio); +diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c +index 807551a5143b78..15d863f97cbf96 100644 +--- a/drivers/media/test-drivers/vimc/vimc-streamer.c ++++ b/drivers/media/test-drivers/vimc/vimc-streamer.c +@@ -59,6 +59,12 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) + continue; + + sd = media_entity_to_v4l2_subdev(ved->ent); ++ /* ++ * Do not call .s_stream() to stop an already ++ * stopped/unstarted subdev. ++ */ ++ if (!v4l2_subdev_is_streaming(sd)) ++ continue; + v4l2_subdev_call(sd, video, s_stream, 0); + } + } +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index a32ef739eb4490..5f115438d07228 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -363,12 +363,8 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) + * The .s_stream() operation must never be called to start or stop an + * already started or stopped subdev. Catch offenders but don't return + * an error yet to avoid regressions. +- * +- * As .s_stream() is mutually exclusive with the .enable_streams() and +- * .disable_streams() operation, we can use the enabled_streams field +- * to store the subdev streaming state. + */ +- if (WARN_ON(!!sd->enabled_streams == !!enable)) ++ if (WARN_ON(sd->s_stream_enabled == !!enable)) + return 0; + + ret = sd->ops->video->s_stream(sd, enable); +@@ -379,7 +375,7 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) + } + + if (!ret) { +- sd->enabled_streams = enable ? BIT(0) : 0; ++ sd->s_stream_enabled = enable; + + #if IS_REACHABLE(CONFIG_LEDS_CLASS) + if (!IS_ERR_OR_NULL(sd->privacy_led)) { +@@ -1929,37 +1925,43 @@ static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) + { + struct device *dev = sd->entity.graph_obj.mdev->dev; +- unsigned int i; + int ret; + + /* + * The subdev doesn't implement pad-based stream enable, fall back +- * on the .s_stream() operation. This can only be done for subdevs that +- * have a single source pad, as sd->enabled_streams is global to the +- * subdev. ++ * to the .s_stream() operation. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + +- for (i = 0; i < sd->entity.num_pads; ++i) { +- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) +- return -EOPNOTSUPP; +- } ++ /* ++ * .s_stream() means there is no streams support, so the only allowed ++ * stream is the implicit stream 0. ++ */ ++ if (streams_mask != BIT_ULL(0)) ++ return -EOPNOTSUPP; ++ ++ /* ++ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices ++ * with 64 pads or less can be supported. ++ */ ++ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE) ++ return -EOPNOTSUPP; + +- if (sd->enabled_streams & streams_mask) { +- dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n", +- streams_mask, sd->entity.name, pad); ++ if (sd->enabled_pads & BIT_ULL(pad)) { ++ dev_dbg(dev, "pad %u already enabled on %s\n", ++ pad, sd->entity.name); + return -EALREADY; + } + +- /* Start streaming when the first streams are enabled. */ +- if (!sd->enabled_streams) { ++ /* Start streaming when the first pad is enabled. */ ++ if (!sd->enabled_pads) { + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret) + return ret; + } + +- sd->enabled_streams |= streams_mask; ++ sd->enabled_pads |= BIT_ULL(pad); + + return 0; + } +@@ -2046,37 +2048,43 @@ static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) + { + struct device *dev = sd->entity.graph_obj.mdev->dev; +- unsigned int i; + int ret; + + /* +- * If the subdev doesn't implement pad-based stream enable, fall back +- * on the .s_stream() operation. This can only be done for subdevs that +- * have a single source pad, as sd->enabled_streams is global to the +- * subdev. ++ * If the subdev doesn't implement pad-based stream enable, fall back ++ * to the .s_stream() operation. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + +- for (i = 0; i < sd->entity.num_pads; ++i) { +- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) +- return -EOPNOTSUPP; +- } ++ /* ++ * .s_stream() means there is no streams support, so the only allowed ++ * stream is the implicit stream 0. ++ */ ++ if (streams_mask != BIT_ULL(0)) ++ return -EOPNOTSUPP; ++ ++ /* ++ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices ++ * with 64 pads or less can be supported. ++ */ ++ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE) ++ return -EOPNOTSUPP; + +- if ((sd->enabled_streams & streams_mask) != streams_mask) { +- dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n", +- streams_mask, sd->entity.name, pad); ++ if (!(sd->enabled_pads & BIT_ULL(pad))) { ++ dev_dbg(dev, "pad %u already disabled on %s\n", ++ pad, sd->entity.name); + return -EALREADY; + } + + /* Stop streaming when the last streams are disabled. */ +- if (!(sd->enabled_streams & ~streams_mask)) { ++ if (!(sd->enabled_pads & ~BIT_ULL(pad))) { + ret = v4l2_subdev_call(sd, video, s_stream, 0); + if (ret) + return ret; + } + +- sd->enabled_streams &= ~streams_mask; ++ sd->enabled_pads &= ~BIT_ULL(pad); + + return 0; + } +@@ -2232,6 +2240,31 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + } + EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event); + ++bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd) ++{ ++ struct v4l2_subdev_state *state; ++ ++ if (!v4l2_subdev_has_op(sd, pad, enable_streams)) ++ return sd->s_stream_enabled; ++ ++ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) ++ return !!sd->enabled_pads; ++ ++ state = v4l2_subdev_get_locked_active_state(sd); ++ ++ for (unsigned int i = 0; i < state->stream_configs.num_configs; ++i) { ++ const struct v4l2_subdev_stream_config *cfg; ++ ++ cfg = &state->stream_configs.configs[i]; ++ ++ if (cfg->enabled) ++ return true; ++ } ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(v4l2_subdev_is_streaming); ++ + int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd) + { + #if IS_REACHABLE(CONFIG_LEDS_CLASS) +diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c +index 5b861dbff27e9a..6c24426104ba6f 100644 +--- a/drivers/misc/lkdtm/perms.c ++++ b/drivers/misc/lkdtm/perms.c +@@ -28,6 +28,13 @@ static const unsigned long rodata = 0xAA55AA55; + /* This is marked __ro_after_init, so it should ultimately be .rodata. */ + static unsigned long ro_after_init __ro_after_init = 0x55AA5500; + ++/* ++ * This is a pointer to do_nothing() which is initialized at runtime rather ++ * than build time to avoid objtool IBT validation warnings caused by an ++ * inlined unrolled memcpy() in execute_location(). ++ */ ++static void __ro_after_init *do_nothing_ptr; ++ + /* + * This just returns to the caller. It is designed to be copied into + * non-executable memory regions. +@@ -65,13 +72,12 @@ static noinline __nocfi void execute_location(void *dst, bool write) + { + void (*func)(void); + func_desc_t fdesc; +- void *do_nothing_text = dereference_function_descriptor(do_nothing); + +- pr_info("attempting ok execution at %px\n", do_nothing_text); ++ pr_info("attempting ok execution at %px\n", do_nothing_ptr); + do_nothing(); + + if (write == CODE_WRITE) { +- memcpy(dst, do_nothing_text, EXEC_SIZE); ++ memcpy(dst, do_nothing_ptr, EXEC_SIZE); + flush_icache_range((unsigned long)dst, + (unsigned long)dst + EXEC_SIZE); + } +@@ -267,6 +273,8 @@ static void lkdtm_ACCESS_NULL(void) + + void __init lkdtm_perms_init(void) + { ++ do_nothing_ptr = dereference_function_descriptor(do_nothing); ++ + /* Make sure we can write to __ro_after_init values during __init */ + ro_after_init |= 0xAA; + } +diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +index 3c1359d8d4e692..55b892f982e93e 100644 +--- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c ++++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +@@ -37,6 +37,7 @@ + struct pci1xxxx_gpio { + struct auxiliary_device *aux_dev; + void __iomem *reg_base; ++ raw_spinlock_t wa_lock; + struct gpio_chip gpio; + spinlock_t lock; + int irq_base; +@@ -164,7 +165,7 @@ static void pci1xxxx_gpio_irq_ack(struct irq_data *data) + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); +- pci1xxx_assign_bit(priv->reg_base, INTR_STAT_OFFSET(gpio), (gpio % 32), true); ++ writel(BIT(gpio % 32), priv->reg_base + INTR_STAT_OFFSET(gpio)); + spin_unlock_irqrestore(&priv->lock, flags); + } + +@@ -254,6 +255,7 @@ static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) + struct pci1xxxx_gpio *priv = dev_id; + struct gpio_chip *gc = &priv->gpio; + unsigned long int_status = 0; ++ unsigned long wa_flags; + unsigned long flags; + u8 pincount; + int bit; +@@ -277,7 +279,9 @@ static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) + writel(BIT(bit), priv->reg_base + INTR_STATUS_OFFSET(gpiobank)); + spin_unlock_irqrestore(&priv->lock, flags); + irq = irq_find_mapping(gc->irq.domain, (bit + (gpiobank * 32))); +- handle_nested_irq(irq); ++ raw_spin_lock_irqsave(&priv->wa_lock, wa_flags); ++ generic_handle_irq(irq); ++ raw_spin_unlock_irqrestore(&priv->wa_lock, wa_flags); + } + } + spin_lock_irqsave(&priv->lock, flags); +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index a4668ddd94551a..4adfa5af162f1d 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -117,6 +117,7 @@ + + #define MEI_DEV_ID_LNL_M 0xA870 /* Lunar Lake Point M */ + ++#define MEI_DEV_ID_PTL_H 0xE370 /* Panther Lake H */ + #define MEI_DEV_ID_PTL_P 0xE470 /* Panther Lake P */ + + /* +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6826cc50d29f36..93b98a7f4c7fd9 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -124,6 +124,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + + {MEI_PCI_DEVICE(MEI_DEV_ID_LNL_M, MEI_ME_PCH15_CFG)}, + ++ {MEI_PCI_DEVICE(MEI_DEV_ID_PTL_H, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_PTL_P, MEI_ME_PCH15_CFG)}, + + /* required last entry */ +diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c +index 945d08531de376..82808cc373f68b 100644 +--- a/drivers/mmc/host/sdhci-msm.c ++++ b/drivers/mmc/host/sdhci-msm.c +@@ -1866,7 +1866,7 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, + if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS)) + return 0; + +- ice = of_qcom_ice_get(dev); ++ ice = devm_of_qcom_ice_get(dev); + if (ice == ERR_PTR(-EOPNOTSUPP)) { + dev_warn(dev, "Disabling inline encryption support\n"); + ice = NULL; +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +index 90ab2f1058ce0e..2d18a03d927421 100644 +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2596,6 +2596,9 @@ mt7531_setup_common(struct dsa_switch *ds) + struct mt7530_priv *priv = ds->priv; + int ret, i; + ++ ds->assisted_learning_on_cpu_port = true; ++ ds->mtu_enforcement_ingress = true; ++ + mt753x_trap_frames(priv); + + /* Enable and reset MIB counters */ +@@ -2735,9 +2738,6 @@ mt7531_setup(struct dsa_switch *ds) + + mt7531_setup_common(ds); + +- ds->assisted_learning_on_cpu_port = true; +- ds->mtu_enforcement_ingress = true; +- + return 0; + } + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index da7260e505a2e4..ef52d1ae27d694 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -5047,6 +5047,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { + .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, + .port_tag_remap = mv88e6095_port_tag_remap, ++ .port_set_policy = mv88e6352_port_set_policy, + .port_set_frame_mode = mv88e6351_port_set_frame_mode, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, +@@ -5071,8 +5072,10 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, +- .vtu_getnext = mv88e6185_g1_vtu_getnext, +- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, ++ .vtu_getnext = mv88e6352_g1_vtu_getnext, ++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, ++ .stu_getnext = mv88e6352_g1_stu_getnext, ++ .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, +@@ -5097,6 +5100,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { + .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, + .port_tag_remap = mv88e6095_port_tag_remap, ++ .port_set_policy = mv88e6352_port_set_policy, + .port_set_frame_mode = mv88e6351_port_set_frame_mode, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, +@@ -5120,8 +5124,10 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, +- .vtu_getnext = mv88e6185_g1_vtu_getnext, +- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, ++ .vtu_getnext = mv88e6352_g1_vtu_getnext, ++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, ++ .stu_getnext = mv88e6352_g1_stu_getnext, ++ .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, +@@ -5713,7 +5719,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .global1_addr = 0x1b, + .global2_addr = 0x1c, + .age_time_coeff = 3750, +- .atu_move_port_mask = 0x1f, ++ .atu_move_port_mask = 0xf, + .g1_irqs = 9, + .g2_irqs = 10, + .pvt = true, +@@ -6114,9 +6120,11 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .num_databases = 4096, + .num_macs = 8192, + .num_ports = 7, +- .num_internal_phys = 5, ++ .num_internal_phys = 2, ++ .internal_phys_offset = 3, + .num_gpio = 15, + .max_vid = 4095, ++ .max_sid = 63, + .port_base_addr = 0x10, + .phy_base_addr = 0x0, + .global1_addr = 0x1b, +@@ -6139,9 +6147,11 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .num_databases = 4096, + .num_macs = 8192, + .num_ports = 7, +- .num_internal_phys = 5, ++ .num_internal_phys = 2, ++ .internal_phys_offset = 3, + .num_gpio = 15, + .max_vid = 4095, ++ .max_sid = 63, + .port_base_addr = 0x10, + .phy_base_addr = 0x0, + .global1_addr = 0x1b, +@@ -6150,6 +6160,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .g1_irqs = 8, + .g2_irqs = 10, + .atu_move_port_mask = 0xf, ++ .pvt = true, + .multi_chip = true, + .edsa_support = MV88E6XXX_EDSA_SUPPORTED, + .ptp_support = true, +@@ -6172,7 +6183,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .global1_addr = 0x1b, + .global2_addr = 0x1c, + .age_time_coeff = 3750, +- .atu_move_port_mask = 0x1f, ++ .atu_move_port_mask = 0xf, + .g1_irqs = 9, + .g2_irqs = 10, + .pvt = true, +diff --git a/drivers/net/ethernet/amd/pds_core/adminq.c b/drivers/net/ethernet/amd/pds_core/adminq.c +index ea773cfa0af67b..733f133d69e75f 100644 +--- a/drivers/net/ethernet/amd/pds_core/adminq.c ++++ b/drivers/net/ethernet/amd/pds_core/adminq.c +@@ -5,11 +5,6 @@ + + #include "core.h" + +-struct pdsc_wait_context { +- struct pdsc_qcq *qcq; +- struct completion wait_completion; +-}; +- + static int pdsc_process_notifyq(struct pdsc_qcq *qcq) + { + union pds_core_notifyq_comp *comp; +@@ -110,10 +105,10 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq) + q_info = &q->info[q->tail_idx]; + q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); + +- /* Copy out the completion data */ +- memcpy(q_info->dest, comp, sizeof(*comp)); +- +- complete_all(&q_info->wc->wait_completion); ++ if (!completion_done(&q_info->completion)) { ++ memcpy(q_info->dest, comp, sizeof(*comp)); ++ complete(&q_info->completion); ++ } + + if (cq->tail_idx == cq->num_descs - 1) + cq->done_color = !cq->done_color; +@@ -166,8 +161,7 @@ irqreturn_t pdsc_adminq_isr(int irq, void *data) + static int __pdsc_adminq_post(struct pdsc *pdsc, + struct pdsc_qcq *qcq, + union pds_core_adminq_cmd *cmd, +- union pds_core_adminq_comp *comp, +- struct pdsc_wait_context *wc) ++ union pds_core_adminq_comp *comp) + { + struct pdsc_queue *q = &qcq->q; + struct pdsc_q_info *q_info; +@@ -209,9 +203,9 @@ static int __pdsc_adminq_post(struct pdsc *pdsc, + /* Post the request */ + index = q->head_idx; + q_info = &q->info[index]; +- q_info->wc = wc; + q_info->dest = comp; + memcpy(q_info->desc, cmd, sizeof(*cmd)); ++ reinit_completion(&q_info->completion); + + dev_dbg(pdsc->dev, "head_idx %d tail_idx %d\n", + q->head_idx, q->tail_idx); +@@ -235,16 +229,13 @@ int pdsc_adminq_post(struct pdsc *pdsc, + union pds_core_adminq_comp *comp, + bool fast_poll) + { +- struct pdsc_wait_context wc = { +- .wait_completion = +- COMPLETION_INITIALIZER_ONSTACK(wc.wait_completion), +- }; + unsigned long poll_interval = 1; + unsigned long poll_jiffies; + unsigned long time_limit; + unsigned long time_start; + unsigned long time_done; + unsigned long remaining; ++ struct completion *wc; + int err = 0; + int index; + +@@ -254,20 +245,19 @@ int pdsc_adminq_post(struct pdsc *pdsc, + return -ENXIO; + } + +- wc.qcq = &pdsc->adminqcq; +- index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp, &wc); ++ index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp); + if (index < 0) { + err = index; + goto err_out; + } + ++ wc = &pdsc->adminqcq.q.info[index].completion; + time_start = jiffies; + time_limit = time_start + HZ * pdsc->devcmd_timeout; + do { + /* Timeslice the actual wait to catch IO errors etc early */ + poll_jiffies = msecs_to_jiffies(poll_interval); +- remaining = wait_for_completion_timeout(&wc.wait_completion, +- poll_jiffies); ++ remaining = wait_for_completion_timeout(wc, poll_jiffies); + if (remaining) + break; + +@@ -296,9 +286,11 @@ int pdsc_adminq_post(struct pdsc *pdsc, + dev_dbg(pdsc->dev, "%s: elapsed %d msecs\n", + __func__, jiffies_to_msecs(time_done - time_start)); + +- /* Check the results */ +- if (time_after_eq(time_done, time_limit)) ++ /* Check the results and clear an un-completed timeout */ ++ if (time_after_eq(time_done, time_limit) && !completion_done(wc)) { + err = -ETIMEDOUT; ++ complete(wc); ++ } + + dev_dbg(pdsc->dev, "read admin queue completion idx %d:\n", index); + dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1, +diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c +index fd1a5149c00319..fb7a5403e630db 100644 +--- a/drivers/net/ethernet/amd/pds_core/auxbus.c ++++ b/drivers/net/ethernet/amd/pds_core/auxbus.c +@@ -107,9 +107,6 @@ int pds_client_adminq_cmd(struct pds_auxiliary_dev *padev, + dev_dbg(pf->dev, "%s: %s opcode %d\n", + __func__, dev_name(&padev->aux_dev.dev), req->opcode); + +- if (pf->state) +- return -ENXIO; +- + /* Wrap the client's request */ + cmd.client_request.opcode = PDS_AQ_CMD_CLIENT_CMD; + cmd.client_request.client_id = cpu_to_le16(padev->client_id); +diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c +index eb73c921dc1ed9..b3fa867c8ccd91 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.c ++++ b/drivers/net/ethernet/amd/pds_core/core.c +@@ -169,8 +169,10 @@ static void pdsc_q_map(struct pdsc_queue *q, void *base, dma_addr_t base_pa) + q->base = base; + q->base_pa = base_pa; + +- for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) ++ for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) { + cur->desc = base + (i * q->desc_size); ++ init_completion(&cur->completion); ++ } + } + + static void pdsc_cq_map(struct pdsc_cq *cq, void *base, dma_addr_t base_pa) +diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h +index f410f7d132056b..858bebf7977624 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.h ++++ b/drivers/net/ethernet/amd/pds_core/core.h +@@ -96,7 +96,7 @@ struct pdsc_q_info { + unsigned int bytes; + unsigned int nbufs; + struct pdsc_buf_info bufs[PDS_CORE_MAX_FRAGS]; +- struct pdsc_wait_context *wc; ++ struct completion completion; + void *dest; + }; + +diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c +index 971d4278280d65..0032e8e3518117 100644 +--- a/drivers/net/ethernet/amd/pds_core/devlink.c ++++ b/drivers/net/ethernet/amd/pds_core/devlink.c +@@ -101,7 +101,7 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, + .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL, + .fw_control.oper = PDS_CORE_FW_GET_LIST, + }; +- struct pds_core_fw_list_info fw_list; ++ struct pds_core_fw_list_info fw_list = {}; + struct pdsc *pdsc = devlink_priv(dl); + union pds_core_dev_comp comp; + char buf[32]; +@@ -114,8 +114,6 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, + if (!err) + memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list)); + mutex_unlock(&pdsc->devcmd_lock); +- if (err && err != -EIO) +- return err; + + listlen = min(fw_list.num_fw_slots, ARRAY_SIZE(fw_list.fw_names)); + for (i = 0; i < listlen; i++) { +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c201ea20e40476..dc89dbc13b251f 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3949,11 +3949,27 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset) + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + + if (mtk_is_netsys_v3_or_greater(eth)) { +- /* PSE should not drop port1, port8 and port9 packets */ +- mtk_w32(eth, 0x00000302, PSE_DROP_CFG); ++ /* PSE dummy page mechanism */ ++ mtk_w32(eth, PSE_DUMMY_WORK_GDM(1) | PSE_DUMMY_WORK_GDM(2) | ++ PSE_DUMMY_WORK_GDM(3) | DUMMY_PAGE_THR, PSE_DUMY_REQ); ++ ++ /* PSE free buffer drop threshold */ ++ mtk_w32(eth, 0x00600009, PSE_IQ_REV(8)); ++ ++ /* PSE should not drop port8, port9 and port13 packets from ++ * WDMA Tx ++ */ ++ mtk_w32(eth, 0x00002300, PSE_DROP_CFG); ++ ++ /* PSE should drop packets to port8, port9 and port13 on WDMA Rx ++ * ring full ++ */ ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(0)); ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(1)); ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(2)); + + /* GDM and CDM Threshold */ +- mtk_w32(eth, 0x00000707, MTK_CDMW0_THRES); ++ mtk_w32(eth, 0x08000707, MTK_CDMW0_THRES); + mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES); + + /* Disable GDM1 RX CRC stripping */ +@@ -3970,7 +3986,7 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset) + mtk_w32(eth, 0x00000300, PSE_DROP_CFG); + + /* PSE should drop packets to port 8/9 on WDMA Rx ring full */ +- mtk_w32(eth, 0x00000300, PSE_PPE0_DROP); ++ mtk_w32(eth, 0x00000300, PSE_PPE_DROP(0)); + + /* PSE Free Queue Flow Control */ + mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 403219d987eff5..d1c7b5f1ee4a9c 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -149,7 +149,15 @@ + #define PSE_FQFC_CFG1 0x100 + #define PSE_FQFC_CFG2 0x104 + #define PSE_DROP_CFG 0x108 +-#define PSE_PPE0_DROP 0x110 ++#define PSE_PPE_DROP(x) (0x110 + ((x) * 0x4)) ++ ++/* PSE Last FreeQ Page Request Control */ ++#define PSE_DUMY_REQ 0x10C ++/* PSE_DUMY_REQ is not a typo but actually called like that also in ++ * MediaTek's datasheet ++ */ ++#define PSE_DUMMY_WORK_GDM(x) BIT(16 + (x)) ++#define DUMMY_PAGE_THR 0x1 + + /* PSE Input Queue Reservation Register*/ + #define PSE_IQ_REV(x) (0x140 + (((x) - 1) << 2)) +diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c +index 0b88635f4fbca9..623607fd2cefd3 100644 +--- a/drivers/net/phy/microchip.c ++++ b/drivers/net/phy/microchip.c +@@ -31,47 +31,6 @@ static int lan88xx_write_page(struct phy_device *phydev, int page) + return __phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, page); + } + +-static int lan88xx_phy_config_intr(struct phy_device *phydev) +-{ +- int rc; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- /* unmask all source and clear them before enable */ +- rc = phy_write(phydev, LAN88XX_INT_MASK, 0x7FFF); +- rc = phy_read(phydev, LAN88XX_INT_STS); +- rc = phy_write(phydev, LAN88XX_INT_MASK, +- LAN88XX_INT_MASK_MDINTPIN_EN_ | +- LAN88XX_INT_MASK_LINK_CHANGE_); +- } else { +- rc = phy_write(phydev, LAN88XX_INT_MASK, 0); +- if (rc) +- return rc; +- +- /* Ack interrupts after they have been disabled */ +- rc = phy_read(phydev, LAN88XX_INT_STS); +- } +- +- return rc < 0 ? rc : 0; +-} +- +-static irqreturn_t lan88xx_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read(phydev, LAN88XX_INT_STS); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & LAN88XX_INT_STS_LINK_CHANGE_)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- + static int lan88xx_suspend(struct phy_device *phydev) + { + struct lan88xx_priv *priv = phydev->priv; +@@ -392,8 +351,9 @@ static struct phy_driver microchip_phy_driver[] = { + .config_aneg = lan88xx_config_aneg, + .link_change_notify = lan88xx_link_change_notify, + +- .config_intr = lan88xx_phy_config_intr, +- .handle_interrupt = lan88xx_handle_interrupt, ++ /* Interrupt handling is broken, do not define related ++ * functions to force polling. ++ */ + + .suspend = lan88xx_suspend, + .resume = genphy_resume, +diff --git a/drivers/net/phy/phy_led_triggers.c b/drivers/net/phy/phy_led_triggers.c +index f550576eb9dae7..6f9d8da76c4dfb 100644 +--- a/drivers/net/phy/phy_led_triggers.c ++++ b/drivers/net/phy/phy_led_triggers.c +@@ -91,9 +91,8 @@ int phy_led_triggers_register(struct phy_device *phy) + if (!phy->phy_num_led_triggers) + return 0; + +- phy->led_link_trigger = devm_kzalloc(&phy->mdio.dev, +- sizeof(*phy->led_link_trigger), +- GFP_KERNEL); ++ phy->led_link_trigger = kzalloc(sizeof(*phy->led_link_trigger), ++ GFP_KERNEL); + if (!phy->led_link_trigger) { + err = -ENOMEM; + goto out_clear; +@@ -103,10 +102,9 @@ int phy_led_triggers_register(struct phy_device *phy) + if (err) + goto out_free_link; + +- phy->phy_led_triggers = devm_kcalloc(&phy->mdio.dev, +- phy->phy_num_led_triggers, +- sizeof(struct phy_led_trigger), +- GFP_KERNEL); ++ phy->phy_led_triggers = kcalloc(phy->phy_num_led_triggers, ++ sizeof(struct phy_led_trigger), ++ GFP_KERNEL); + if (!phy->phy_led_triggers) { + err = -ENOMEM; + goto out_unreg_link; +@@ -127,11 +125,11 @@ int phy_led_triggers_register(struct phy_device *phy) + out_unreg: + while (i--) + phy_led_trigger_unregister(&phy->phy_led_triggers[i]); +- devm_kfree(&phy->mdio.dev, phy->phy_led_triggers); ++ kfree(phy->phy_led_triggers); + out_unreg_link: + phy_led_trigger_unregister(phy->led_link_trigger); + out_free_link: +- devm_kfree(&phy->mdio.dev, phy->led_link_trigger); ++ kfree(phy->led_link_trigger); + phy->led_link_trigger = NULL; + out_clear: + phy->phy_num_led_triggers = 0; +@@ -145,8 +143,13 @@ void phy_led_triggers_unregister(struct phy_device *phy) + + for (i = 0; i < phy->phy_num_led_triggers; i++) + phy_led_trigger_unregister(&phy->phy_led_triggers[i]); ++ kfree(phy->phy_led_triggers); ++ phy->phy_led_triggers = NULL; + +- if (phy->led_link_trigger) ++ if (phy->led_link_trigger) { + phy_led_trigger_unregister(phy->led_link_trigger); ++ kfree(phy->led_link_trigger); ++ phy->led_link_trigger = NULL; ++ } + } + EXPORT_SYMBOL_GPL(phy_led_triggers_unregister); +diff --git a/drivers/net/vmxnet3/vmxnet3_xdp.c b/drivers/net/vmxnet3/vmxnet3_xdp.c +index 616ecc38d1726c..5f470499e60024 100644 +--- a/drivers/net/vmxnet3/vmxnet3_xdp.c ++++ b/drivers/net/vmxnet3/vmxnet3_xdp.c +@@ -397,7 +397,7 @@ vmxnet3_process_xdp(struct vmxnet3_adapter *adapter, + + xdp_init_buff(&xdp, PAGE_SIZE, &rq->xdp_rxq); + xdp_prepare_buff(&xdp, page_address(page), rq->page_pool->p.offset, +- rbi->len, false); ++ rcd->len, false); + xdp_buff_clear_frags_flag(&xdp); + + xdp_prog = rcu_dereference(rq->adapter->xdp_bpf_prog); +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index bcb5651f18e0f5..0115f8f5b7245f 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -985,20 +985,27 @@ static u32 xennet_run_xdp(struct netfront_queue *queue, struct page *pdata, + act = bpf_prog_run_xdp(prog, xdp); + switch (act) { + case XDP_TX: +- get_page(pdata); + xdpf = xdp_convert_buff_to_frame(xdp); ++ if (unlikely(!xdpf)) { ++ trace_xdp_exception(queue->info->netdev, prog, act); ++ break; ++ } ++ get_page(pdata); + err = xennet_xdp_xmit(queue->info->netdev, 1, &xdpf, 0); +- if (unlikely(!err)) ++ if (unlikely(err <= 0)) { ++ if (err < 0) ++ trace_xdp_exception(queue->info->netdev, prog, act); + xdp_return_frame_rx_napi(xdpf); +- else if (unlikely(err < 0)) +- trace_xdp_exception(queue->info->netdev, prog, act); ++ } + break; + case XDP_REDIRECT: + get_page(pdata); + err = xdp_do_redirect(queue->info->netdev, xdp, prog); + *need_xdp_flush = true; +- if (unlikely(err)) ++ if (unlikely(err)) { + trace_xdp_exception(queue->info->netdev, prog, act); ++ xdp_return_buff(xdp); ++ } + break; + case XDP_PASS: + case XDP_DROP: +diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c +index d687e8c2cc78dc..63ceed89b62ef9 100644 +--- a/drivers/ntb/hw/amd/ntb_hw_amd.c ++++ b/drivers/ntb/hw/amd/ntb_hw_amd.c +@@ -1318,6 +1318,7 @@ static const struct pci_device_id amd_ntb_pci_tbl[] = { + { PCI_VDEVICE(AMD, 0x148b), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(AMD, 0x14c0), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(AMD, 0x14c3), (kernel_ulong_t)&dev_data[1] }, ++ { PCI_VDEVICE(AMD, 0x155a), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(HYGON, 0x145b), (kernel_ulong_t)&dev_data[0] }, + { 0, } + }; +diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c +index 48823b53ede3e9..22aaa60d2d3846 100644 +--- a/drivers/ntb/hw/idt/ntb_hw_idt.c ++++ b/drivers/ntb/hw/idt/ntb_hw_idt.c +@@ -1041,7 +1041,7 @@ static inline char *idt_get_mw_name(enum idt_mw_type mw_type) + static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, + unsigned char *mw_cnt) + { +- struct idt_mw_cfg mws[IDT_MAX_NR_MWS], *ret_mws; ++ struct idt_mw_cfg *mws; + const struct idt_ntb_bar *bars; + enum idt_mw_type mw_type; + unsigned char widx, bidx, en_cnt; +@@ -1049,6 +1049,11 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, + int aprt_size; + u32 data; + ++ mws = devm_kcalloc(&ndev->ntb.pdev->dev, IDT_MAX_NR_MWS, ++ sizeof(*mws), GFP_KERNEL); ++ if (!mws) ++ return ERR_PTR(-ENOMEM); ++ + /* Retrieve the array of the BARs registers */ + bars = portdata_tbl[port].bars; + +@@ -1103,16 +1108,7 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, + } + } + +- /* Allocate memory for memory window descriptors */ +- ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws), +- GFP_KERNEL); +- if (!ret_mws) +- return ERR_PTR(-ENOMEM); +- +- /* Copy the info of detected memory windows */ +- memcpy(ret_mws, mws, (*mw_cnt)*sizeof(*ret_mws)); +- +- return ret_mws; ++ return mws; + } + + /* +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index f00665ad0c11a3..c6b0637e61debd 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -3972,6 +3972,15 @@ static void nvme_scan_work(struct work_struct *work) + nvme_scan_ns_sequential(ctrl); + } + mutex_unlock(&ctrl->scan_lock); ++ ++ /* Requeue if we have missed AENs */ ++ if (test_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events)) ++ nvme_queue_scan(ctrl); ++#ifdef CONFIG_NVME_MULTIPATH ++ else if (ctrl->ana_log_buf) ++ /* Re-read the ANA log page to not miss updates */ ++ queue_work(nvme_wq, &ctrl->ana_work); ++#endif + } + + /* +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index 32283301199f01..119afdfe4b91e9 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -426,7 +426,7 @@ static bool nvme_available_path(struct nvme_ns_head *head) + struct nvme_ns *ns; + + if (!test_bit(NVME_NSHEAD_DISK_LIVE, &head->flags)) +- return NULL; ++ return false; + + list_for_each_entry_srcu(ns, &head->list, siblings, + srcu_read_lock_held(&head->srcu)) { +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index d40d5a4ea932e0..570c58d2b5a585 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -1030,33 +1030,24 @@ nvmet_fc_alloc_hostport(struct nvmet_fc_tgtport *tgtport, void *hosthandle) + struct nvmet_fc_hostport *newhost, *match = NULL; + unsigned long flags; + ++ /* ++ * Caller holds a reference on tgtport. ++ */ ++ + /* if LLDD not implemented, leave as NULL */ + if (!hosthandle) + return NULL; + +- /* +- * take reference for what will be the newly allocated hostport if +- * we end up using a new allocation +- */ +- if (!nvmet_fc_tgtport_get(tgtport)) +- return ERR_PTR(-EINVAL); +- + spin_lock_irqsave(&tgtport->lock, flags); + match = nvmet_fc_match_hostport(tgtport, hosthandle); + spin_unlock_irqrestore(&tgtport->lock, flags); + +- if (match) { +- /* no new allocation - release reference */ +- nvmet_fc_tgtport_put(tgtport); ++ if (match) + return match; +- } + + newhost = kzalloc(sizeof(*newhost), GFP_KERNEL); +- if (!newhost) { +- /* no new allocation - release reference */ +- nvmet_fc_tgtport_put(tgtport); ++ if (!newhost) + return ERR_PTR(-ENOMEM); +- } + + spin_lock_irqsave(&tgtport->lock, flags); + match = nvmet_fc_match_hostport(tgtport, hosthandle); +@@ -1065,6 +1056,7 @@ nvmet_fc_alloc_hostport(struct nvmet_fc_tgtport *tgtport, void *hosthandle) + kfree(newhost); + newhost = match; + } else { ++ nvmet_fc_tgtport_get(tgtport); + newhost->tgtport = tgtport; + newhost->hosthandle = hosthandle; + INIT_LIST_HEAD(&newhost->host_list); +@@ -1099,7 +1091,8 @@ static void + nvmet_fc_schedule_delete_assoc(struct nvmet_fc_tgt_assoc *assoc) + { + nvmet_fc_tgtport_get(assoc->tgtport); +- queue_work(nvmet_wq, &assoc->del_work); ++ if (!queue_work(nvmet_wq, &assoc->del_work)) ++ nvmet_fc_tgtport_put(assoc->tgtport); + } + + static struct nvmet_fc_tgt_assoc * +diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c +index b278ab4338ceb5..d5c1b2a126a560 100644 +--- a/drivers/of/resolver.c ++++ b/drivers/of/resolver.c +@@ -262,25 +262,22 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, + */ + int of_resolve_phandles(struct device_node *overlay) + { +- struct device_node *child, *local_fixups, *refnode; +- struct device_node *tree_symbols, *overlay_fixups; ++ struct device_node *child, *refnode; ++ struct device_node *overlay_fixups; ++ struct device_node __free(device_node) *local_fixups = NULL; + struct property *prop; + const char *refpath; + phandle phandle, phandle_delta; + int err; + +- tree_symbols = NULL; +- + if (!overlay) { + pr_err("null overlay\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + if (!of_node_check_flag(overlay, OF_DETACHED)) { + pr_err("overlay not detached\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + phandle_delta = live_tree_max_phandle() + 1; +@@ -292,7 +289,7 @@ int of_resolve_phandles(struct device_node *overlay) + + err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); + if (err) +- goto out; ++ return err; + + overlay_fixups = NULL; + +@@ -301,16 +298,13 @@ int of_resolve_phandles(struct device_node *overlay) + overlay_fixups = child; + } + +- if (!overlay_fixups) { +- err = 0; +- goto out; +- } ++ if (!overlay_fixups) ++ return 0; + +- tree_symbols = of_find_node_by_path("/__symbols__"); ++ struct device_node __free(device_node) *tree_symbols = of_find_node_by_path("/__symbols__"); + if (!tree_symbols) { + pr_err("no symbols in root of device tree.\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + for_each_property_of_node(overlay_fixups, prop) { +@@ -324,14 +318,12 @@ int of_resolve_phandles(struct device_node *overlay) + if (err) { + pr_err("node label '%s' not found in live devicetree symbols table\n", + prop->name); +- goto out; ++ return err; + } + + refnode = of_find_node_by_path(refpath); +- if (!refnode) { +- err = -ENOENT; +- goto out; +- } ++ if (!refnode) ++ return -ENOENT; + + phandle = refnode->phandle; + of_node_put(refnode); +@@ -341,11 +333,8 @@ int of_resolve_phandles(struct device_node *overlay) + break; + } + +-out: + if (err) + pr_err("overlay phandle fixup failed: %d\n", err); +- of_node_put(tree_symbols); +- + return err; + } + EXPORT_SYMBOL_GPL(of_resolve_phandles); +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 8e5d818c29a983..b7cec139d816ba 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -885,6 +885,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + resource_size_t offset, next_offset; + LIST_HEAD(resources); + struct resource *res, *next_res; ++ bool bus_registered = false; + char addr[64], *fmt; + const char *name; + int err; +@@ -948,6 +949,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + name = dev_name(&bus->dev); + + err = device_register(&bus->dev); ++ bus_registered = true; + if (err) + goto unregister; + +@@ -1031,12 +1033,15 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + unregister: + put_device(&bridge->dev); + device_del(&bridge->dev); +- + free: + #ifdef CONFIG_PCI_DOMAINS_GENERIC + pci_bus_release_domain_nr(bus, parent); + #endif +- kfree(bus); ++ if (bus_registered) ++ put_device(&bus->dev); ++ else ++ kfree(bus); ++ + return err; + } + +diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c +index c5d733216508e8..df660b7e1300ca 100644 +--- a/drivers/pinctrl/renesas/pinctrl-rza2.c ++++ b/drivers/pinctrl/renesas/pinctrl-rza2.c +@@ -243,6 +243,9 @@ static int rza2_gpio_register(struct rza2_pinctrl_priv *priv) + int ret; + + chip.label = devm_kasprintf(priv->dev, GFP_KERNEL, "%pOFn", np); ++ if (!chip.label) ++ return -ENOMEM; ++ + chip.parent = priv->dev; + chip.ngpio = priv->npins; + +diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c +index 374d80dc6d17ab..bec22a001a5dd5 100644 +--- a/drivers/regulator/rk808-regulator.c ++++ b/drivers/regulator/rk808-regulator.c +@@ -267,8 +267,8 @@ static const unsigned int rk817_buck1_4_ramp_table[] = { + + static int rk806_set_mode_dcdc(struct regulator_dev *rdev, unsigned int mode) + { +- int rid = rdev_get_id(rdev); +- int ctr_bit, reg; ++ unsigned int rid = rdev_get_id(rdev); ++ unsigned int ctr_bit, reg; + + reg = RK806_POWER_FPWM_EN0 + rid / 8; + ctr_bit = rid % 8; +diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c +index 905986c616559b..73848f764559b4 100644 +--- a/drivers/rtc/rtc-pcf85063.c ++++ b/drivers/rtc/rtc-pcf85063.c +@@ -35,6 +35,7 @@ + #define PCF85063_REG_CTRL1_CAP_SEL BIT(0) + #define PCF85063_REG_CTRL1_STOP BIT(5) + #define PCF85063_REG_CTRL1_EXT_TEST BIT(7) ++#define PCF85063_REG_CTRL1_SWR 0x58 + + #define PCF85063_REG_CTRL2 0x01 + #define PCF85063_CTRL2_AF BIT(6) +@@ -589,7 +590,7 @@ static int pcf85063_probe(struct i2c_client *client) + + i2c_set_clientdata(client, pcf85063); + +- err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp); ++ err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp); + if (err) { + dev_err(&client->dev, "RTC chip is not present\n"); + return err; +@@ -599,6 +600,22 @@ static int pcf85063_probe(struct i2c_client *client) + if (IS_ERR(pcf85063->rtc)) + return PTR_ERR(pcf85063->rtc); + ++ /* ++ * If a Power loss is detected, SW reset the device. ++ * From PCF85063A datasheet: ++ * There is a low probability that some devices will have corruption ++ * of the registers after the automatic power-on reset... ++ */ ++ if (tmp & PCF85063_REG_SC_OS) { ++ dev_warn(&client->dev, ++ "POR issue detected, sending a SW reset\n"); ++ err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1, ++ PCF85063_REG_CTRL1_SWR); ++ if (err < 0) ++ dev_warn(&client->dev, ++ "SW reset failed, trying to continue\n"); ++ } ++ + err = pcf85063_load_capacitance(pcf85063, client->dev.of_node, + config->force_cap_7000 ? 7000 : 0); + if (err < 0) +diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c +index e5d947c763ea5d..6a030ba38bf360 100644 +--- a/drivers/s390/char/sclp_con.c ++++ b/drivers/s390/char/sclp_con.c +@@ -263,6 +263,19 @@ static struct console sclp_console = + .index = 0 /* ttyS0 */ + }; + ++/* ++ * Release allocated pages. ++ */ ++static void __init __sclp_console_free_pages(void) ++{ ++ struct list_head *page, *p; ++ ++ list_for_each_safe(page, p, &sclp_con_pages) { ++ list_del(page); ++ free_page((unsigned long)page); ++ } ++} ++ + /* + * called by console_init() in drivers/char/tty_io.c at boot-time. + */ +@@ -282,6 +295,10 @@ sclp_console_init(void) + /* Allocate pages for output buffering */ + for (i = 0; i < sclp_console_pages; i++) { + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); ++ if (!page) { ++ __sclp_console_free_pages(); ++ return -ENOMEM; ++ } + list_add_tail(page, &sclp_con_pages); + } + sclp_conbuf = NULL; +diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c +index 892c18d2f87e90..d3edacb6ee148b 100644 +--- a/drivers/s390/char/sclp_tty.c ++++ b/drivers/s390/char/sclp_tty.c +@@ -490,6 +490,17 @@ static const struct tty_operations sclp_ops = { + .flush_buffer = sclp_tty_flush_buffer, + }; + ++/* Release allocated pages. */ ++static void __init __sclp_tty_free_pages(void) ++{ ++ struct list_head *page, *p; ++ ++ list_for_each_safe(page, p, &sclp_tty_pages) { ++ list_del(page); ++ free_page((unsigned long)page); ++ } ++} ++ + static int __init + sclp_tty_init(void) + { +@@ -516,6 +527,7 @@ sclp_tty_init(void) + for (i = 0; i < MAX_KMEM_PAGES; i++) { + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (page == NULL) { ++ __sclp_tty_free_pages(); + tty_driver_kref_put(driver); + return -ENOMEM; + } +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index f78c5f8a49ffac..7e64661d215bd2 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -911,8 +911,28 @@ static void hisi_sas_phyup_work_common(struct work_struct *work, + container_of(work, typeof(*phy), works[event]); + struct hisi_hba *hisi_hba = phy->hisi_hba; + struct asd_sas_phy *sas_phy = &phy->sas_phy; ++ struct asd_sas_port *sas_port = sas_phy->port; ++ struct hisi_sas_port *port = phy->port; ++ struct device *dev = hisi_hba->dev; ++ struct domain_device *port_dev; + int phy_no = sas_phy->id; + ++ if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) && ++ sas_port && port && (port->id != phy->port_id)) { ++ dev_info(dev, "phy%d's hw port id changed from %d to %llu\n", ++ phy_no, port->id, phy->port_id); ++ port_dev = sas_port->port_dev; ++ if (port_dev && !dev_is_expander(port_dev->dev_type)) { ++ /* ++ * Set the device state to gone to block ++ * sending IO to the device. ++ */ ++ set_bit(SAS_DEV_GONE, &port_dev->state); ++ hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); ++ return; ++ } ++ } ++ + phy->wait_phyup_cnt = 0; + if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP) + hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no); +diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c +index ee2da8e49d4cfb..a9d6dac4133466 100644 +--- a/drivers/scsi/pm8001/pm8001_sas.c ++++ b/drivers/scsi/pm8001/pm8001_sas.c +@@ -719,6 +719,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) + spin_lock_irqsave(&pm8001_ha->lock, flags); + } + PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id); ++ pm8001_ha->phy[pm8001_dev->attached_phy].phy_attached = 0; + pm8001_free_dev(pm8001_dev); + } else { + pm8001_dbg(pm8001_ha, DISC, "Found dev has gone.\n"); +diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c +index 22bdce0bc32792..9c0142a010bac1 100644 +--- a/drivers/scsi/scsi.c ++++ b/drivers/scsi/scsi.c +@@ -693,26 +693,23 @@ void scsi_cdl_check(struct scsi_device *sdev) + */ + int scsi_cdl_enable(struct scsi_device *sdev, bool enable) + { +- struct scsi_mode_data data; +- struct scsi_sense_hdr sshdr; +- struct scsi_vpd *vpd; +- bool is_ata = false; + char buf[64]; ++ bool is_ata; + int ret; + + if (!sdev->cdl_supported) + return -EOPNOTSUPP; + + rcu_read_lock(); +- vpd = rcu_dereference(sdev->vpd_pg89); +- if (vpd) +- is_ata = true; ++ is_ata = rcu_dereference(sdev->vpd_pg89); + rcu_read_unlock(); + + /* + * For ATA devices, CDL needs to be enabled with a SET FEATURES command. + */ + if (is_ata) { ++ struct scsi_mode_data data; ++ struct scsi_sense_hdr sshdr; + char *buf_data; + int len; + +@@ -721,16 +718,30 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) + if (ret) + return -EINVAL; + +- /* Enable CDL using the ATA feature page */ ++ /* Enable or disable CDL using the ATA feature page */ + len = min_t(size_t, sizeof(buf), + data.length - data.header_length - + data.block_descriptor_length); + buf_data = buf + data.header_length + + data.block_descriptor_length; +- if (enable) +- buf_data[4] = 0x02; +- else +- buf_data[4] = 0; ++ ++ /* ++ * If we want to enable CDL and CDL is already enabled on the ++ * device, do nothing. This avoids needlessly resetting the CDL ++ * statistics on the device as that is implied by the CDL enable ++ * action. Similar to this, there is no need to do anything if ++ * we want to disable CDL and CDL is already disabled. ++ */ ++ if (enable) { ++ if ((buf_data[4] & 0x03) == 0x02) ++ goto out; ++ buf_data[4] &= ~0x03; ++ buf_data[4] |= 0x02; ++ } else { ++ if ((buf_data[4] & 0x03) == 0x00) ++ goto out; ++ buf_data[4] &= ~0x03; ++ } + + ret = scsi_mode_select(sdev, 1, 0, buf_data, len, 5 * HZ, 3, + &data, &sshdr); +@@ -742,6 +753,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) + } + } + ++out: + sdev->cdl_enable = enable; + + return 0; +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index e6dc2c556fde9e..bd75e3ebc14da3 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1152,8 +1152,12 @@ EXPORT_SYMBOL_GPL(scsi_alloc_request); + */ + static void scsi_cleanup_rq(struct request *rq) + { ++ struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); ++ ++ cmd->flags = 0; ++ + if (rq->rq_flags & RQF_DONTPREP) { +- scsi_mq_uninit_cmd(blk_mq_rq_to_pdu(rq)); ++ scsi_mq_uninit_cmd(cmd); + rq->rq_flags &= ~RQF_DONTPREP; + } + } +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index fbab7fe5c652b9..d6e205e3812a96 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -328,6 +329,53 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) + } + EXPORT_SYMBOL_GPL(of_qcom_ice_get); + ++static void qcom_ice_put(const struct qcom_ice *ice) ++{ ++ struct platform_device *pdev = to_platform_device(ice->dev); ++ ++ if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice")) ++ platform_device_put(pdev); ++} ++ ++static void devm_of_qcom_ice_put(struct device *dev, void *res) ++{ ++ qcom_ice_put(*(struct qcom_ice **)res); ++} ++ ++/** ++ * devm_of_qcom_ice_get() - Devres managed helper to get an ICE instance from ++ * a DT node. ++ * @dev: device pointer for the consumer device. ++ * ++ * This function will provide an ICE instance either by creating one for the ++ * consumer device if its DT node provides the 'ice' reg range and the 'ice' ++ * clock (for legacy DT style). On the other hand, if consumer provides a ++ * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already ++ * be created and so this function will return that instead. ++ * ++ * Return: ICE pointer on success, NULL if there is no ICE data provided by the ++ * consumer or ERR_PTR() on error. ++ */ ++struct qcom_ice *devm_of_qcom_ice_get(struct device *dev) ++{ ++ struct qcom_ice *ice, **dr; ++ ++ dr = devres_alloc(devm_of_qcom_ice_put, sizeof(*dr), GFP_KERNEL); ++ if (!dr) ++ return ERR_PTR(-ENOMEM); ++ ++ ice = of_qcom_ice_get(dev); ++ if (!IS_ERR_OR_NULL(ice)) { ++ *dr = ice; ++ devres_add(dev, dr); ++ } else { ++ devres_free(dr); ++ } ++ ++ return ice; ++} ++EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get); ++ + static int qcom_ice_probe(struct platform_device *pdev) + { + struct qcom_ice *engine; +diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c +index daa32bde615561..da4442954375b1 100644 +--- a/drivers/spi/spi-imx.c ++++ b/drivers/spi/spi-imx.c +@@ -1614,10 +1614,13 @@ static int spi_imx_transfer_one(struct spi_controller *controller, + struct spi_device *spi, + struct spi_transfer *transfer) + { ++ int ret; + struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); + unsigned long hz_per_byte, byte_limit; + +- spi_imx_setupxfer(spi, transfer); ++ ret = spi_imx_setupxfer(spi, transfer); ++ if (ret < 0) ++ return ret; + transfer->effective_speed_hz = spi_imx->spi_bus_clk; + + /* flush rxfifo before transfer */ +diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c +index d1afa4140e8a26..e3c236025a7b3b 100644 +--- a/drivers/spi/spi-tegra210-quad.c ++++ b/drivers/spi/spi-tegra210-quad.c +@@ -1117,9 +1117,9 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, + (&tqspi->xfer_completion, + QSPI_DMA_TIMEOUT); + +- if (WARN_ON(ret == 0)) { +- dev_err(tqspi->dev, "QSPI Transfer failed with timeout: %d\n", +- ret); ++ if (WARN_ON_ONCE(ret == 0)) { ++ dev_err_ratelimited(tqspi->dev, ++ "QSPI Transfer failed with timeout\n"); + if (tqspi->is_curr_dma_xfer && + (tqspi->cur_direction & DATA_DIR_TX)) + dmaengine_terminate_all +diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c +index 7c3310a2b28a41..b92a8a5b2e8c97 100644 +--- a/drivers/thunderbolt/tb.c ++++ b/drivers/thunderbolt/tb.c +@@ -1370,11 +1370,15 @@ static void tb_scan_port(struct tb_port *port) + goto out_rpm_put; + } + +- tb_retimer_scan(port, true); +- + sw = tb_switch_alloc(port->sw->tb, &port->sw->dev, + tb_downstream_route(port)); + if (IS_ERR(sw)) { ++ /* ++ * Make the downstream retimers available even if there ++ * is no router connected. ++ */ ++ tb_retimer_scan(port, true); ++ + /* + * If there is an error accessing the connected switch + * it may be connected to another domain. Also we allow +@@ -1424,6 +1428,14 @@ static void tb_scan_port(struct tb_port *port) + upstream_port = tb_upstream_port(sw); + tb_configure_link(port, upstream_port, sw); + ++ /* ++ * Scan for downstream retimers. We only scan them after the ++ * router has been enumerated to avoid issues with certain ++ * Pluggable devices that expect the host to enumerate them ++ * within certain timeout. ++ */ ++ tb_retimer_scan(port, true); ++ + /* + * CL0s and CL1 are enabled and supported together. + * Silently ignore CLx enabling in case CLx is not supported. +diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c +index 90953e679e386a..76b6429fb9e92e 100644 +--- a/drivers/tty/serial/msm_serial.c ++++ b/drivers/tty/serial/msm_serial.c +@@ -1741,6 +1741,12 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device, + if (!device->port.membase) + return -ENODEV; + ++ /* Disable DM / single-character modes */ ++ msm_write(&device->port, 0, UARTDM_DMEN); ++ msm_write(&device->port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); ++ msm_write(&device->port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); ++ msm_write(&device->port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR); ++ + device->con->write = msm_serial_early_write_dm; + return 0; + } +diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c +index d195c5de52e78f..e86b00873d0ea6 100644 +--- a/drivers/tty/serial/sifive.c ++++ b/drivers/tty/serial/sifive.c +@@ -562,8 +562,11 @@ static void sifive_serial_break_ctl(struct uart_port *port, int break_state) + static int sifive_serial_startup(struct uart_port *port) + { + struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); ++ unsigned long flags; + ++ uart_port_lock_irqsave(&ssp->port, &flags); + __ssp_enable_rxwm(ssp); ++ uart_port_unlock_irqrestore(&ssp->port, flags); + + return 0; + } +@@ -571,9 +574,12 @@ static int sifive_serial_startup(struct uart_port *port) + static void sifive_serial_shutdown(struct uart_port *port) + { + struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); ++ unsigned long flags; + ++ uart_port_lock_irqsave(&ssp->port, &flags); + __ssp_disable_rxwm(ssp); + __ssp_disable_txwm(ssp); ++ uart_port_unlock_irqrestore(&ssp->port, flags); + } + + /** +diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c +index da8c1734d33358..411109a5ebbffd 100644 +--- a/drivers/ufs/core/ufs-mcq.c ++++ b/drivers/ufs/core/ufs-mcq.c +@@ -632,13 +632,6 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) + unsigned long flags; + int err; + +- if (!ufshcd_cmd_inflight(lrbp->cmd)) { +- dev_err(hba->dev, +- "%s: skip abort. cmd at tag %d already completed.\n", +- __func__, tag); +- return FAILED; +- } +- + /* Skip task abort in case previous aborts failed and report failure */ + if (lrbp->req_abort_skip) { + dev_err(hba->dev, "%s: skip abort. tag %d failed earlier\n", +@@ -647,6 +640,11 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) + } + + hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd)); ++ if (!hwq) { ++ dev_err(hba->dev, "%s: skip abort. cmd at tag %d already completed.\n", ++ __func__, tag); ++ return FAILED; ++ } + + if (ufshcd_mcq_sqe_search(hba, hwq, tag)) { + /* +diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c +index d138b66d5e350b..f61126189876e9 100644 +--- a/drivers/ufs/host/ufs-exynos.c ++++ b/drivers/ufs/host/ufs-exynos.c +@@ -990,9 +990,14 @@ static int exynos_ufs_pre_link(struct ufs_hba *hba) + exynos_ufs_config_intr(ufs, DFES_DEF_L4_ERRS, UNIPRO_L4); + exynos_ufs_set_unipro_pclk_div(ufs); + ++ exynos_ufs_setup_clocks(hba, true, PRE_CHANGE); ++ + /* unipro */ + exynos_ufs_config_unipro(ufs); + ++ if (ufs->drv_data->pre_link) ++ ufs->drv_data->pre_link(ufs); ++ + /* m-phy */ + exynos_ufs_phy_init(ufs); + if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR)) { +@@ -1000,11 +1005,6 @@ static int exynos_ufs_pre_link(struct ufs_hba *hba) + exynos_ufs_config_phy_cap_attr(ufs); + } + +- exynos_ufs_setup_clocks(hba, true, PRE_CHANGE); +- +- if (ufs->drv_data->pre_link) +- ufs->drv_data->pre_link(ufs); +- + return 0; + } + +diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c +index 51ed40529f9a7b..c6417ef074a478 100644 +--- a/drivers/ufs/host/ufs-qcom.c ++++ b/drivers/ufs/host/ufs-qcom.c +@@ -121,7 +121,7 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) + struct device *dev = hba->dev; + struct qcom_ice *ice; + +- ice = of_qcom_ice_get(dev); ++ ice = devm_of_qcom_ice_get(dev); + if (ice == ERR_PTR(-EOPNOTSUPP)) { + dev_warn(dev, "Disabling inline encryption support\n"); + ice = NULL; +diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c +index b1b46c7c63f8b3..05e8414c31df4c 100644 +--- a/drivers/usb/cdns3/cdns3-gadget.c ++++ b/drivers/usb/cdns3/cdns3-gadget.c +@@ -1962,6 +1962,7 @@ static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) + unsigned int bit; + unsigned long reg; + ++ local_bh_disable(); + spin_lock_irqsave(&priv_dev->lock, flags); + + reg = readl(&priv_dev->regs->usb_ists); +@@ -2003,6 +2004,7 @@ static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) + irqend: + writel(~0, &priv_dev->regs->ep_ien); + spin_unlock_irqrestore(&priv_dev->lock, flags); ++ local_bh_enable(); + + return ret; + } +diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c +index b3cbca361a9696..73d5b9466676c4 100644 +--- a/drivers/usb/chipidea/ci_hdrc_imx.c ++++ b/drivers/usb/chipidea/ci_hdrc_imx.c +@@ -328,6 +328,13 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) + return ret; + } + ++static void ci_hdrc_imx_disable_regulator(void *arg) ++{ ++ struct ci_hdrc_imx_data *data = arg; ++ ++ regulator_disable(data->hsic_pad_regulator); ++} ++ + static int ci_hdrc_imx_probe(struct platform_device *pdev) + { + struct ci_hdrc_imx_data *data; +@@ -386,6 +393,13 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + "Failed to enable HSIC pad regulator\n"); + goto err_put; + } ++ ret = devm_add_action_or_reset(dev, ++ ci_hdrc_imx_disable_regulator, data); ++ if (ret) { ++ dev_err(dev, ++ "Failed to add regulator devm action\n"); ++ goto err_put; ++ } + } + } + +@@ -424,11 +438,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + + ret = imx_get_clks(dev); + if (ret) +- goto disable_hsic_regulator; ++ goto qos_remove_request; + + ret = imx_prepare_enable_clks(dev); + if (ret) +- goto disable_hsic_regulator; ++ goto qos_remove_request; + + data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0); + if (IS_ERR(data->phy)) { +@@ -458,7 +472,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) { + pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL; + data->override_phy_control = true; +- usb_phy_init(pdata.usb_phy); ++ ret = usb_phy_init(pdata.usb_phy); ++ if (ret) { ++ dev_err(dev, "Failed to init phy\n"); ++ goto err_clk; ++ } + } + + if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) +@@ -467,7 +485,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + ret = imx_usbmisc_init(data->usbmisc_data); + if (ret) { + dev_err(dev, "usbmisc init failed, ret=%d\n", ret); +- goto err_clk; ++ goto phy_shutdown; + } + + data->ci_pdev = ci_hdrc_add_device(dev, +@@ -476,7 +494,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + if (IS_ERR(data->ci_pdev)) { + ret = PTR_ERR(data->ci_pdev); + dev_err_probe(dev, ret, "ci_hdrc_add_device failed\n"); +- goto err_clk; ++ goto phy_shutdown; + } + + if (data->usbmisc_data) { +@@ -510,17 +528,18 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + + disable_device: + ci_hdrc_remove_device(data->ci_pdev); ++phy_shutdown: ++ if (data->override_phy_control) ++ usb_phy_shutdown(data->phy); + err_clk: + imx_disable_unprepare_clks(dev); +-disable_hsic_regulator: +- if (data->hsic_pad_regulator) +- /* don't overwrite original ret (cf. EPROBE_DEFER) */ +- regulator_disable(data->hsic_pad_regulator); ++qos_remove_request: + if (pdata.flags & CI_HDRC_PMQOS) + cpu_latency_qos_remove_request(&data->pm_qos_req); + data->ci_pdev = NULL; + err_put: +- put_device(data->usbmisc_data->dev); ++ if (data->usbmisc_data) ++ put_device(data->usbmisc_data->dev); + return ret; + } + +@@ -541,10 +560,9 @@ static void ci_hdrc_imx_remove(struct platform_device *pdev) + imx_disable_unprepare_clks(&pdev->dev); + if (data->plat_data->flags & CI_HDRC_PMQOS) + cpu_latency_qos_remove_request(&data->pm_qos_req); +- if (data->hsic_pad_regulator) +- regulator_disable(data->hsic_pad_regulator); + } +- put_device(data->usbmisc_data->dev); ++ if (data->usbmisc_data) ++ put_device(data->usbmisc_data->dev); + } + + static void ci_hdrc_imx_shutdown(struct platform_device *pdev) +diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c +index 6830be4419e20a..559c121f092300 100644 +--- a/drivers/usb/class/cdc-wdm.c ++++ b/drivers/usb/class/cdc-wdm.c +@@ -726,7 +726,7 @@ static int wdm_open(struct inode *inode, struct file *file) + rv = -EBUSY; + goto out; + } +- ++ smp_rmb(); /* ordered against wdm_wwan_port_stop() */ + rv = usb_autopm_get_interface(desc->intf); + if (rv < 0) { + dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); +@@ -829,6 +829,7 @@ static struct usb_class_driver wdm_class = { + static int wdm_wwan_port_start(struct wwan_port *port) + { + struct wdm_device *desc = wwan_port_get_drvdata(port); ++ int rv; + + /* The interface is both exposed via the WWAN framework and as a + * legacy usbmisc chardev. If chardev is already open, just fail +@@ -848,7 +849,15 @@ static int wdm_wwan_port_start(struct wwan_port *port) + wwan_port_txon(port); + + /* Start getting events */ +- return usb_submit_urb(desc->validity, GFP_KERNEL); ++ rv = usb_submit_urb(desc->validity, GFP_KERNEL); ++ if (rv < 0) { ++ wwan_port_txoff(port); ++ desc->manage_power(desc->intf, 0); ++ /* this must be last lest we race with chardev open */ ++ clear_bit(WDM_WWAN_IN_USE, &desc->flags); ++ } ++ ++ return rv; + } + + static void wdm_wwan_port_stop(struct wwan_port *port) +@@ -859,8 +868,10 @@ static void wdm_wwan_port_stop(struct wwan_port *port) + poison_urbs(desc); + desc->manage_power(desc->intf, 0); + clear_bit(WDM_READ, &desc->flags); +- clear_bit(WDM_WWAN_IN_USE, &desc->flags); + unpoison_urbs(desc); ++ smp_wmb(); /* ordered against wdm_open() */ ++ /* this must be last lest we open a poisoned device */ ++ clear_bit(WDM_WWAN_IN_USE, &desc->flags); + } + + static void wdm_wwan_port_tx_complete(struct urb *urb) +@@ -868,7 +879,7 @@ static void wdm_wwan_port_tx_complete(struct urb *urb) + struct sk_buff *skb = urb->context; + struct wdm_device *desc = skb_shinfo(skb)->destructor_arg; + +- usb_autopm_put_interface(desc->intf); ++ usb_autopm_put_interface_async(desc->intf); + wwan_port_txon(desc->wwanp); + kfree_skb(skb); + } +@@ -898,7 +909,7 @@ static int wdm_wwan_port_tx(struct wwan_port *port, struct sk_buff *skb) + req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); + req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; + req->wValue = 0; +- req->wIndex = desc->inum; ++ req->wIndex = desc->inum; /* already converted */ + req->wLength = cpu_to_le16(skb->len); + + skb_shinfo(skb)->destructor_arg = desc; +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 6926bd639ec6ff..4903c733d37ae7 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -369,6 +369,9 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM }, + { USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* SanDisk Corp. SanDisk 3.2Gen1 */ ++ { USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Realforce 87U Keyboard */ + { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM }, + +@@ -383,6 +386,9 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x0904, 0x6103), .driver_info = + USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL }, + ++ /* Silicon Motion Flash Drive */ ++ { USB_DEVICE(0x090c, 0x1000), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Sound Devices USBPre2 */ + { USB_DEVICE(0x0926, 0x0202), .driver_info = + USB_QUIRK_ENDPOINT_IGNORE }, +@@ -536,6 +542,9 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x2040, 0x7200), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + ++ /* VLI disk */ ++ { USB_DEVICE(0x2109, 0x0711), .driver_info = USB_QUIRK_NO_LPM }, ++ + /* Raydium Touchscreen */ + { USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM }, + +diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c +index 052852f8014676..54a4ee2b90b7f4 100644 +--- a/drivers/usb/dwc3/dwc3-pci.c ++++ b/drivers/usb/dwc3/dwc3-pci.c +@@ -148,11 +148,21 @@ static const struct property_entry dwc3_pci_intel_byt_properties[] = { + {} + }; + ++/* ++ * Intel Merrifield SoC uses these endpoints for tracing and they cannot ++ * be re-allocated if being used because the side band flow control signals ++ * are hard wired to certain endpoints: ++ * - 1 High BW Bulk IN (IN#1) (RTIT) ++ * - 1 1KB BW Bulk IN (IN#8) + 1 1KB BW Bulk OUT (Run Control) (OUT#8) ++ */ ++static const u8 dwc3_pci_mrfld_reserved_endpoints[] = { 3, 16, 17 }; ++ + static const struct property_entry dwc3_pci_mrfld_properties[] = { + PROPERTY_ENTRY_STRING("dr_mode", "otg"), + PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"), + PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"), + PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"), ++ PROPERTY_ENTRY_U8_ARRAY("snps,reserved-endpoints", dwc3_pci_mrfld_reserved_endpoints), + PROPERTY_ENTRY_BOOL("snps,usb2-gadget-lpm-disable"), + PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), + {} +diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c +index d19a5d2d65adb9..ae30aa50a58257 100644 +--- a/drivers/usb/dwc3/dwc3-xilinx.c ++++ b/drivers/usb/dwc3/dwc3-xilinx.c +@@ -207,15 +207,13 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) + + skip_usb3_phy: + /* ulpi reset via gpio-modepin or gpio-framework driver */ +- reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); ++ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) { + return dev_err_probe(dev, PTR_ERR(reset_gpio), + "Failed to request reset GPIO\n"); + } + + if (reset_gpio) { +- /* Toggle ulpi to reset the phy. */ +- gpiod_set_value_cansleep(reset_gpio, 1); + usleep_range(5000, 10000); + gpiod_set_value_cansleep(reset_gpio, 0); + usleep_range(5000, 10000); +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index fdaace1564f96f..f51d743bb3ecc6 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -548,6 +548,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep) + int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index) + { + struct dwc3_gadget_ep_cmd_params params; ++ struct dwc3_ep *dep; + u32 cmd; + int i; + int ret; +@@ -564,8 +565,13 @@ int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index) + return ret; + + /* Reset resource allocation flags */ +- for (i = resource_index; i < dwc->num_eps && dwc->eps[i]; i++) +- dwc->eps[i]->flags &= ~DWC3_EP_RESOURCE_ALLOCATED; ++ for (i = resource_index; i < dwc->num_eps; i++) { ++ dep = dwc->eps[i]; ++ if (!dep) ++ continue; ++ ++ dep->flags &= ~DWC3_EP_RESOURCE_ALLOCATED; ++ } + + return 0; + } +@@ -752,9 +758,11 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) + + dwc->last_fifo_depth = fifo_depth; + /* Clear existing TXFIFO for all IN eps except ep0 */ +- for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); +- num += 2) { ++ for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); num += 2) { + dep = dwc->eps[num]; ++ if (!dep) ++ continue; ++ + /* Don't change TXFRAMNUM on usb31 version */ + size = DWC3_IP_IS(DWC3) ? 0 : + dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & +@@ -3670,6 +3678,8 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep, + + for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { + dep = dwc->eps[i]; ++ if (!dep) ++ continue; + + if (!(dep->flags & DWC3_EP_ENABLED)) + continue; +@@ -3858,6 +3868,10 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, + u8 epnum = event->endpoint_number; + + dep = dwc->eps[epnum]; ++ if (!dep) { ++ dev_warn(dwc->dev, "spurious event, endpoint %u is not allocated\n", epnum); ++ return; ++ } + + if (!(dep->flags & DWC3_EP_ENABLED)) { + if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED)) +@@ -4570,6 +4584,12 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) + if (!count) + return IRQ_NONE; + ++ if (count > evt->length) { ++ dev_err_ratelimited(dwc->dev, "invalid count(%u) > evt->length(%u)\n", ++ count, evt->length); ++ return IRQ_NONE; ++ } ++ + evt->count = count; + evt->flags |= DWC3_EVENT_PENDING; + +diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c +index 573109ca5b7990..a09f72772e6e95 100644 +--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c ++++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c +@@ -548,6 +548,9 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) + d->vhub = vhub; + d->index = idx; + d->name = devm_kasprintf(parent, GFP_KERNEL, "port%d", idx+1); ++ if (!d->name) ++ return -ENOMEM; ++ + d->regs = vhub->regs + 0x100 + 0x10 * idx; + + ast_vhub_init_ep0(vhub, &d->ep0, d); +diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c +index a219260ad3e6c2..cc1f579f02de1c 100644 +--- a/drivers/usb/host/max3421-hcd.c ++++ b/drivers/usb/host/max3421-hcd.c +@@ -1946,6 +1946,12 @@ max3421_remove(struct spi_device *spi) + usb_put_hcd(hcd); + } + ++static const struct spi_device_id max3421_spi_ids[] = { ++ { "max3421" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(spi, max3421_spi_ids); ++ + static const struct of_device_id max3421_of_match_table[] = { + { .compatible = "maxim,max3421", }, + {}, +@@ -1955,6 +1961,7 @@ MODULE_DEVICE_TABLE(of, max3421_of_match_table); + static struct spi_driver max3421_driver = { + .probe = max3421_probe, + .remove = max3421_remove, ++ .id_table = max3421_spi_ids, + .driver = { + .name = "max3421-hcd", + .of_match_table = max3421_of_match_table, +diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c +index 900ea0d368e034..9f0a6b27e47cb6 100644 +--- a/drivers/usb/host/ohci-pci.c ++++ b/drivers/usb/host/ohci-pci.c +@@ -165,6 +165,25 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) + return 0; + } + ++static int ohci_quirk_loongson(struct usb_hcd *hcd) ++{ ++ struct pci_dev *pdev = to_pci_dev(hcd->self.controller); ++ ++ /* ++ * Loongson's LS7A OHCI controller (rev 0x02) has a ++ * flaw. MMIO register with offset 0x60/64 is treated ++ * as legacy PS2-compatible keyboard/mouse interface. ++ * Since OHCI only use 4KB BAR resource, LS7A OHCI's ++ * 32KB BAR is wrapped around (the 2nd 4KB BAR space ++ * is the same as the 1st 4KB internally). So add 4KB ++ * offset (0x1000) to the OHCI registers as a quirk. ++ */ ++ if (pdev->revision == 0x2) ++ hcd->regs += SZ_4K; /* SZ_4K = 0x1000 */ ++ ++ return 0; ++} ++ + static int ohci_quirk_qemu(struct usb_hcd *hcd) + { + struct ohci_hcd *ohci = hcd_to_ohci(hcd); +@@ -224,6 +243,10 @@ static const struct pci_device_id ohci_pci_quirks[] = { + PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), + .driver_data = (unsigned long)ohci_quirk_amd700, + }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a24), ++ .driver_data = (unsigned long)ohci_quirk_loongson, ++ }, + { + .vendor = PCI_VENDOR_ID_APPLE, + .device = 0x003f, +diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c +index 87f1597a0e5ab7..257e4d79971fda 100644 +--- a/drivers/usb/host/xhci-mvebu.c ++++ b/drivers/usb/host/xhci-mvebu.c +@@ -73,13 +73,3 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) + + return 0; + } +- +-int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +-{ +- struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- +- /* Without reset on resume, the HC won't work at all */ +- xhci->quirks |= XHCI_RESET_ON_RESUME; +- +- return 0; +-} +diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h +index 3be021793cc8b0..9d26e22c48422f 100644 +--- a/drivers/usb/host/xhci-mvebu.h ++++ b/drivers/usb/host/xhci-mvebu.h +@@ -12,16 +12,10 @@ struct usb_hcd; + + #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) + int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); +-int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd); + #else + static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) + { + return 0; + } +- +-static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +-{ +- return 0; +-} + #endif + #endif /* __LINUX_XHCI_MVEBU_H */ +diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c +index d68e9abcdc69a6..8832e0cedadaff 100644 +--- a/drivers/usb/host/xhci-plat.c ++++ b/drivers/usb/host/xhci-plat.c +@@ -106,7 +106,7 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = { + }; + + static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { +- .init_quirk = xhci_mvebu_a3700_init_quirk, ++ .quirks = XHCI_RESET_ON_RESUME, + }; + + static const struct xhci_plat_priv xhci_plat_brcm = { +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 4a081685a1953e..cb944396294516 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1214,16 +1214,19 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, + * Stopped state, but it will soon change to Running. + * + * Assume this bug on unexpected Stop Endpoint failures. +- * Keep retrying until the EP starts and stops again, on +- * chips where this is known to help. Wait for 100ms. ++ * Keep retrying until the EP starts and stops again. + */ +- if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) +- break; + fallthrough; + case EP_STATE_RUNNING: + /* Race, HW handled stop ep cmd before ep was running */ + xhci_dbg(xhci, "Stop ep completion ctx error, ctx_state %d\n", + GET_EP_CTX_STATE(ep_ctx)); ++ /* ++ * Don't retry forever if we guessed wrong or a defective HC never starts ++ * the EP or says 'Running' but fails the command. We must give back TDs. ++ */ ++ if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) ++ break; + + command = xhci_alloc_command(xhci, false, GFP_ATOMIC); + if (!command) { +@@ -3876,7 +3879,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + * enqueue a No Op TRB, this can prevent the Setup and Data Stage + * TRB to be breaked by the Link TRB. + */ +- if (trb_is_link(ep_ring->enqueue + 1)) { ++ if (last_trb_on_seg(ep_ring->enq_seg, ep_ring->enqueue + 1)) { + field = TRB_TYPE(TRB_TR_NOOP) | ep_ring->cycle_state; + queue_trb(xhci, ep_ring, false, 0, 0, + TRB_INTR_TARGET(0), field); +diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c +index b8e2bfd4282809..b583b31ea5e72e 100644 +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -1093,6 +1093,8 @@ static const struct usb_device_id id_table_combined[] = { + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) }, ++ /* Abacus Electrics */ ++ { USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) }, + { } /* Terminating entry */ + }; + +diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h +index 52be47d684ea66..9acb6f83732763 100644 +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -442,6 +442,11 @@ + #define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ + #define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ + ++/* ++ * Abacus Electrics ++ */ ++#define ABACUS_OPTICAL_PROBE_PID 0xf458 /* ABACUS ELECTRICS Optical Probe */ ++ + /* + * Oceanic product ids + */ +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index a9f95bb35bb0f5..5d669511609892 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -611,6 +611,7 @@ static void option_instat_callback(struct urb *urb); + /* Sierra Wireless products */ + #define SIERRA_VENDOR_ID 0x1199 + #define SIERRA_PRODUCT_EM9191 0x90d3 ++#define SIERRA_PRODUCT_EM9291 0x90e3 + + /* UNISOC (Spreadtrum) products */ + #define UNISOC_VENDOR_ID 0x1782 +@@ -2432,6 +2433,8 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x30) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, + { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0530, 0xff), /* TCL IK512 MBIM */ +diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c +index 24b8772a345e2f..bac5ab6377ae4b 100644 +--- a/drivers/usb/serial/usb-serial-simple.c ++++ b/drivers/usb/serial/usb-serial-simple.c +@@ -101,6 +101,11 @@ DEVICE(nokia, NOKIA_IDS); + { USB_DEVICE(0x09d7, 0x0100) } /* NovAtel FlexPack GPS */ + DEVICE_N(novatel_gps, NOVATEL_IDS, 3); + ++/* OWON electronic test and measurement equipment driver */ ++#define OWON_IDS() \ ++ { USB_DEVICE(0x5345, 0x1234) } /* HDS200 oscilloscopes and others */ ++DEVICE(owon, OWON_IDS); ++ + /* Siemens USB/MPI adapter */ + #define SIEMENS_IDS() \ + { USB_DEVICE(0x908, 0x0004) } +@@ -135,6 +140,7 @@ static struct usb_serial_driver * const serial_drivers[] = { + &motorola_tetra_device, + &nokia_device, + &novatel_gps_device, ++ &owon_device, + &siemens_mpi_device, + &suunto_device, + &vivopay_device, +@@ -154,6 +160,7 @@ static const struct usb_device_id id_table[] = { + MOTOROLA_TETRA_IDS(), + NOKIA_IDS(), + NOVATEL_IDS(), ++ OWON_IDS(), + SIEMENS_IDS(), + SUUNTO_IDS(), + VIVOPAY_IDS(), +diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h +index 1f8c9b16a0fb85..d460d71b425783 100644 +--- a/drivers/usb/storage/unusual_uas.h ++++ b/drivers/usb/storage/unusual_uas.h +@@ -83,6 +83,13 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_REPORT_LUNS), + ++/* Reported-by: Oliver Neukum */ ++UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, ++ "ADATA", ++ "Portable HDD CH94", ++ USB_SC_DEVICE, USB_PR_DEVICE, NULL, ++ US_FL_NO_ATA_1X), ++ + /* Reported-by: Benjamin Tissoires */ + UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, + "Initio Corporation", +diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig +index d43153fec18ea8..af5c214b220699 100644 +--- a/drivers/xen/Kconfig ++++ b/drivers/xen/Kconfig +@@ -278,7 +278,7 @@ config XEN_PRIVCMD_IRQFD + + config XEN_ACPI_PROCESSOR + tristate "Xen ACPI processor" +- depends on XEN && XEN_PV_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ ++ depends on XEN && XEN_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ + default m + help + This ACPI processor uploads Power Management information to the Xen +diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c +index 68092b64e29eac..e794606e7c780b 100644 +--- a/fs/btrfs/file.c ++++ b/fs/btrfs/file.c +@@ -2225,15 +2225,20 @@ static void btrfs_punch_hole_lock_range(struct inode *inode, + * will always return true. + * So here we need to do extra page alignment for + * filemap_range_has_page(). ++ * ++ * And do not decrease page_lockend right now, as it can be 0. + */ + const u64 page_lockstart = round_up(lockstart, PAGE_SIZE); +- const u64 page_lockend = round_down(lockend + 1, PAGE_SIZE) - 1; ++ const u64 page_lockend = round_down(lockend + 1, PAGE_SIZE); + + while (1) { + truncate_pagecache_range(inode, lockstart, lockend); + + lock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend, + cached_state); ++ /* The same page or adjacent pages. */ ++ if (page_lockend <= page_lockstart) ++ break; + /* + * We can't have ordered extents in the range, nor dirty/writeback + * pages, because we have locked the inode's VFS lock in exclusive +@@ -2245,7 +2250,7 @@ static void btrfs_punch_hole_lock_range(struct inode *inode, + * we do, unlock the range and retry. + */ + if (!filemap_range_has_page(inode->i_mapping, page_lockstart, +- page_lockend)) ++ page_lockend - 1)) + break; + + unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend, +diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c +index db6977c15c2828..f0befbeb6cb833 100644 +--- a/fs/ceph/inode.c ++++ b/fs/ceph/inode.c +@@ -2319,7 +2319,7 @@ static int fill_fscrypt_truncate(struct inode *inode, + + /* Try to writeback the dirty pagecaches */ + if (issued & (CEPH_CAP_FILE_BUFFER)) { +- loff_t lend = orig_pos + CEPH_FSCRYPT_BLOCK_SHIFT - 1; ++ loff_t lend = orig_pos + CEPH_FSCRYPT_BLOCK_SIZE - 1; + + ret = filemap_write_and_wait_range(inode->i_mapping, + orig_pos, lend); +diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c +index 6fe3c941b56514..4d6ba140276b5f 100644 +--- a/fs/ext4/block_validity.c ++++ b/fs/ext4/block_validity.c +@@ -351,10 +351,9 @@ int ext4_check_blockref(const char *function, unsigned int line, + { + __le32 *bref = p; + unsigned int blk; ++ journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; + +- if (ext4_has_feature_journal(inode->i_sb) && +- (inode->i_ino == +- le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) ++ if (journal && inode == journal->j_inode) + return 0; + + while (bref < p+max) { +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index ddfeaf19bff1ba..d3d28e65872027 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -378,10 +378,11 @@ static int __check_block_validity(struct inode *inode, const char *func, + unsigned int line, + struct ext4_map_blocks *map) + { +- if (ext4_has_feature_journal(inode->i_sb) && +- (inode->i_ino == +- le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) ++ journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; ++ ++ if (journal && inode == journal->j_inode) + return 0; ++ + if (!ext4_inode_block_valid(inode, map->m_pblk, map->m_len)) { + ext4_error_inode(inode, func, line, map->m_pblk, + "lblock %lu mapped to illegal pblock %llu " +@@ -5478,7 +5479,7 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + oldsize & (inode->i_sb->s_blocksize - 1)) { + error = ext4_inode_attach_jinode(inode); + if (error) +- goto err_out; ++ goto out_mmap_sem; + } + + handle = ext4_journal_start(inode, EXT4_HT_INODE, 3); +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index e7e6701806ad26..7ffdf0d037fae0 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -224,7 +224,7 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio, + } + + /* truncate len if we find any trailing uptodate block(s) */ +- for ( ; i <= last; i++) { ++ while (++i <= last) { + if (ifs_block_is_uptodate(ifs, i)) { + plen -= (last - i + 1) * block_size; + last = i - 1; +diff --git a/fs/namespace.c b/fs/namespace.c +index 671e266b8fc5d2..5a885d35efe937 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -2439,56 +2439,62 @@ static struct mountpoint *do_lock_mount(struct path *path, bool beneath) + struct vfsmount *mnt = path->mnt; + struct dentry *dentry; + struct mountpoint *mp = ERR_PTR(-ENOENT); ++ struct path under = {}; + + for (;;) { +- struct mount *m; ++ struct mount *m = real_mount(mnt); + + if (beneath) { +- m = real_mount(mnt); ++ path_put(&under); + read_seqlock_excl(&mount_lock); +- dentry = dget(m->mnt_mountpoint); ++ under.mnt = mntget(&m->mnt_parent->mnt); ++ under.dentry = dget(m->mnt_mountpoint); + read_sequnlock_excl(&mount_lock); ++ dentry = under.dentry; + } else { + dentry = path->dentry; + } + + inode_lock(dentry->d_inode); +- if (unlikely(cant_mount(dentry))) { +- inode_unlock(dentry->d_inode); +- goto out; +- } +- + namespace_lock(); + +- if (beneath && (!is_mounted(mnt) || m->mnt_mountpoint != dentry)) { ++ if (unlikely(cant_mount(dentry) || !is_mounted(mnt))) ++ break; // not to be mounted on ++ ++ if (beneath && unlikely(m->mnt_mountpoint != dentry || ++ &m->mnt_parent->mnt != under.mnt)) { + namespace_unlock(); + inode_unlock(dentry->d_inode); +- goto out; ++ continue; // got moved + } + + mnt = lookup_mnt(path); +- if (likely(!mnt)) ++ if (unlikely(mnt)) { ++ namespace_unlock(); ++ inode_unlock(dentry->d_inode); ++ path_put(path); ++ path->mnt = mnt; ++ path->dentry = dget(mnt->mnt_root); ++ continue; // got overmounted ++ } ++ mp = get_mountpoint(dentry); ++ if (IS_ERR(mp)) + break; +- +- namespace_unlock(); +- inode_unlock(dentry->d_inode); +- if (beneath) +- dput(dentry); +- path_put(path); +- path->mnt = mnt; +- path->dentry = dget(mnt->mnt_root); +- } +- +- mp = get_mountpoint(dentry); +- if (IS_ERR(mp)) { +- namespace_unlock(); +- inode_unlock(dentry->d_inode); ++ if (beneath) { ++ /* ++ * @under duplicates the references that will stay ++ * at least until namespace_unlock(), so the path_put() ++ * below is safe (and OK to do under namespace_lock - ++ * we are not dropping the final references here). ++ */ ++ path_put(&under); ++ } ++ return mp; + } +- +-out: ++ namespace_unlock(); ++ inode_unlock(dentry->d_inode); + if (beneath) +- dput(dentry); +- ++ path_put(&under); + return mp; + } + +@@ -2499,14 +2505,11 @@ static inline struct mountpoint *lock_mount(struct path *path) + + static void unlock_mount(struct mountpoint *where) + { +- struct dentry *dentry = where->m_dentry; +- ++ inode_unlock(where->m_dentry->d_inode); + read_seqlock_excl(&mount_lock); + put_mountpoint(where); + read_sequnlock_excl(&mount_lock); +- + namespace_unlock(); +- inode_unlock(dentry->d_inode); + } + + static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp) +diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c +index 2ecd0303f9421b..4aea458216117f 100644 +--- a/fs/ntfs3/file.c ++++ b/fs/ntfs3/file.c +@@ -335,6 +335,7 @@ static int ntfs_extend(struct inode *inode, loff_t pos, size_t count, + } + + if (extend_init && !is_compressed(ni)) { ++ WARN_ON(ni->i_valid >= pos); + err = ntfs_extend_initialized_size(file, ni, ni->i_valid, pos); + if (err) + goto out; +diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c +index c2a98b2736645d..f04922eb45d4c9 100644 +--- a/fs/smb/client/sess.c ++++ b/fs/smb/client/sess.c +@@ -732,6 +732,22 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) + *pbcc_area = bcc_ptr; + } + ++static void ++ascii_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) ++{ ++ char *bcc_ptr = *pbcc_area; ++ ++ strcpy(bcc_ptr, "Linux version "); ++ bcc_ptr += strlen("Linux version "); ++ strcpy(bcc_ptr, init_utsname()->release); ++ bcc_ptr += strlen(init_utsname()->release) + 1; ++ ++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); ++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ ++ *pbcc_area = bcc_ptr; ++} ++ + static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, + const struct nls_table *nls_cp) + { +@@ -756,6 +772,25 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, + *pbcc_area = bcc_ptr; + } + ++static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses, ++ const struct nls_table *nls_cp) ++{ ++ char *bcc_ptr = *pbcc_area; ++ int len; ++ ++ /* copy domain */ ++ if (ses->domainName != NULL) { ++ len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN); ++ if (WARN_ON_ONCE(len < 0)) ++ len = CIFS_MAX_DOMAINNAME_LEN - 1; ++ bcc_ptr += len; ++ } /* else we send a null domain name so server will default to its own domain */ ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ ++ *pbcc_area = bcc_ptr; ++} ++ + static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, + const struct nls_table *nls_cp) + { +@@ -801,25 +836,10 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, + *bcc_ptr = 0; + bcc_ptr++; /* account for null termination */ + +- /* copy domain */ +- if (ses->domainName != NULL) { +- len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN); +- if (WARN_ON_ONCE(len < 0)) +- len = CIFS_MAX_DOMAINNAME_LEN - 1; +- bcc_ptr += len; +- } /* else we send a null domain name so server will default to its own domain */ +- *bcc_ptr = 0; +- bcc_ptr++; +- + /* BB check for overflow here */ + +- strcpy(bcc_ptr, "Linux version "); +- bcc_ptr += strlen("Linux version "); +- strcpy(bcc_ptr, init_utsname()->release); +- bcc_ptr += strlen(init_utsname()->release) + 1; +- +- strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); +- bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ ascii_domain_string(&bcc_ptr, ses, nls_cp); ++ ascii_oslm_strings(&bcc_ptr, nls_cp); + + *pbcc_area = bcc_ptr; + } +@@ -1622,7 +1642,7 @@ sess_auth_kerberos(struct sess_data *sess_data) + sess_data->iov[1].iov_len = msg->secblob_len; + pSMB->req.SecurityBlobLength = cpu_to_le16(sess_data->iov[1].iov_len); + +- if (ses->capabilities & CAP_UNICODE) { ++ if (pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) { + /* unicode strings must be word aligned */ + if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) { + *bcc_ptr = 0; +@@ -1631,8 +1651,8 @@ sess_auth_kerberos(struct sess_data *sess_data) + unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); + unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + } else { +- /* BB: is this right? */ +- ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); ++ ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp); ++ ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + } + + sess_data->iov[2].iov_len = (long) bcc_ptr - +diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c +index bc1bac36c1b291..caa1d852ece49c 100644 +--- a/fs/smb/client/smb1ops.c ++++ b/fs/smb/client/smb1ops.c +@@ -597,6 +597,42 @@ static int cifs_query_path_info(const unsigned int xid, + CIFSSMBClose(xid, tcon, fid.netfid); + } + ++#ifdef CONFIG_CIFS_XATTR ++ /* ++ * For WSL CHR and BLK reparse points it is required to fetch ++ * EA $LXDEV which contains major and minor device numbers. ++ */ ++ if (!rc && data->reparse_point) { ++ struct smb2_file_full_ea_info *ea; ++ ++ ea = (struct smb2_file_full_ea_info *)data->wsl.eas; ++ rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_DEV, ++ &ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1], ++ SMB2_WSL_XATTR_DEV_SIZE, cifs_sb); ++ if (rc == SMB2_WSL_XATTR_DEV_SIZE) { ++ ea->next_entry_offset = cpu_to_le32(0); ++ ea->flags = 0; ++ ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN; ++ ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE); ++ memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1); ++ data->wsl.eas_len = sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 + ++ SMB2_WSL_XATTR_DEV_SIZE; ++ rc = 0; ++ } else if (rc >= 0) { ++ /* It is an error if EA $LXDEV has wrong size. */ ++ rc = -EINVAL; ++ } else { ++ /* ++ * In all other cases ignore error if fetching ++ * of EA $LXDEV failed. It is needed only for ++ * WSL CHR and BLK reparse points and wsl_to_fattr() ++ * handle the case when EA is missing. ++ */ ++ rc = 0; ++ } ++ } ++#endif ++ + return rc; + } + +diff --git a/fs/splice.c b/fs/splice.c +index d983d375ff1130..6f9b06bbb860ac 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -45,7 +45,7 @@ + * here if set to avoid blocking other users of this pipe if splice is + * being done on it. + */ +-static noinline void noinline pipe_clear_nowait(struct file *file) ++static noinline void pipe_clear_nowait(struct file *file) + { + fmode_t fmode = READ_ONCE(file->f_mode); + +diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h +index b9caa01dfac485..adec808b371a11 100644 +--- a/include/linux/energy_model.h ++++ b/include/linux/energy_model.h +@@ -243,7 +243,6 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd, + scale_cpu = arch_scale_cpu_capacity(cpu); + ps = &pd->table[pd->nr_perf_states - 1]; + +- max_util = map_util_perf(max_util); + max_util = min(max_util, allowed_cpu_cap); + freq = map_util_freq(max_util, ps->frequency, scale_cpu); + +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index ab2a7ef61d420f..b4fcd0164048ed 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -1038,10 +1038,11 @@ struct v4l2_subdev_platform_data { + * @active_state: Active state for the subdev (NULL for subdevs tracking the + * state internally). Initialized by calling + * v4l2_subdev_init_finalize(). +- * @enabled_streams: Bitmask of enabled streams used by +- * v4l2_subdev_enable_streams() and +- * v4l2_subdev_disable_streams() helper functions for fallback +- * cases. ++ * @enabled_pads: Bitmask of enabled pads used by v4l2_subdev_enable_streams() ++ * and v4l2_subdev_disable_streams() helper functions for ++ * fallback cases. ++ * @s_stream_enabled: Tracks whether streaming has been enabled with s_stream. ++ * This is only for call_s_stream() internal use. + * + * Each instance of a subdev driver should create this struct, either + * stand-alone or embedded in a larger struct. +@@ -1089,7 +1090,8 @@ struct v4l2_subdev { + * doesn't support it. + */ + struct v4l2_subdev_state *active_state; +- u64 enabled_streams; ++ u64 enabled_pads; ++ bool s_stream_enabled; + }; + + +@@ -1916,4 +1918,17 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers; + void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + const struct v4l2_event *ev); + ++/** ++ * v4l2_subdev_is_streaming() - Returns if the subdevice is streaming ++ * @sd: The subdevice ++ * ++ * v4l2_subdev_is_streaming() tells if the subdevice is currently streaming. ++ * "Streaming" here means whether .s_stream() or .enable_streams() has been ++ * successfully called, and the streaming has not yet been disabled. ++ * ++ * If the subdevice implements .enable_streams() this function must be called ++ * while holding the active state lock. ++ */ ++bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd); ++ + #endif /* _V4L2_SUBDEV_H */ +diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h +index 5870a94599a258..d5f6a228df6594 100644 +--- a/include/soc/qcom/ice.h ++++ b/include/soc/qcom/ice.h +@@ -34,4 +34,6 @@ int qcom_ice_program_key(struct qcom_ice *ice, + int slot); + int qcom_ice_evict_key(struct qcom_ice *ice, int slot); + struct qcom_ice *of_qcom_ice_get(struct device *dev); ++struct qcom_ice *devm_of_qcom_ice_get(struct device *dev); ++ + #endif /* __QCOM_ICE_H__ */ +diff --git a/include/trace/stages/stage3_trace_output.h b/include/trace/stages/stage3_trace_output.h +index c1fb1355d3094b..1e7b0bef95f525 100644 +--- a/include/trace/stages/stage3_trace_output.h ++++ b/include/trace/stages/stage3_trace_output.h +@@ -119,6 +119,14 @@ + trace_print_array_seq(p, array, count, el_size); \ + }) + ++#undef __print_dynamic_array ++#define __print_dynamic_array(array, el_size) \ ++ ({ \ ++ __print_array(__get_dynamic_array(array), \ ++ __get_dynamic_array_len(array) / (el_size), \ ++ (el_size)); \ ++ }) ++ + #undef __print_hex_dump + #define __print_hex_dump(prefix_str, prefix_type, \ + rowsize, groupsize, buf, len, ascii) \ +diff --git a/include/trace/stages/stage7_class_define.h b/include/trace/stages/stage7_class_define.h +index bcb960d16fc0ed..fcd564a590f434 100644 +--- a/include/trace/stages/stage7_class_define.h ++++ b/include/trace/stages/stage7_class_define.h +@@ -22,6 +22,7 @@ + #undef __get_rel_cpumask + #undef __get_rel_sockaddr + #undef __print_array ++#undef __print_dynamic_array + #undef __print_hex_dump + #undef __get_buf + +diff --git a/init/Kconfig b/init/Kconfig +index 1105cb53f391ab..8b630143c720f6 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -689,7 +689,7 @@ endmenu # "CPU/Task time and stats accounting" + + config CPU_ISOLATION + bool "CPU isolation" +- depends on SMP || COMPILE_TEST ++ depends on SMP + default y + help + Make sure that CPUs running critical tasks are not disturbed by +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index efa7849b82c184..3ce93418e0151d 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -1247,21 +1247,22 @@ static __cold void io_fallback_tw(struct io_uring_task *tctx, bool sync) + while (node) { + req = container_of(node, struct io_kiocb, io_task_work.node); + node = node->next; +- if (sync && last_ctx != req->ctx) { ++ if (last_ctx != req->ctx) { + if (last_ctx) { +- flush_delayed_work(&last_ctx->fallback_work); ++ if (sync) ++ flush_delayed_work(&last_ctx->fallback_work); + percpu_ref_put(&last_ctx->refs); + } + last_ctx = req->ctx; + percpu_ref_get(&last_ctx->refs); + } +- if (llist_add(&req->io_task_work.node, +- &req->ctx->fallback_llist)) +- schedule_delayed_work(&req->ctx->fallback_work, 1); ++ if (llist_add(&req->io_task_work.node, &last_ctx->fallback_llist)) ++ schedule_delayed_work(&last_ctx->fallback_work, 1); + } + + if (last_ctx) { +- flush_delayed_work(&last_ctx->fallback_work); ++ if (sync) ++ flush_delayed_work(&last_ctx->fallback_work); + percpu_ref_put(&last_ctx->refs); + } + } +@@ -1916,7 +1917,7 @@ struct io_wq_work *io_wq_free_work(struct io_wq_work *work) + struct io_kiocb *req = container_of(work, struct io_kiocb, work); + struct io_kiocb *nxt = NULL; + +- if (req_ref_put_and_test(req)) { ++ if (req_ref_put_and_test_atomic(req)) { + if (req->flags & IO_REQ_LINK_FLAGS) + nxt = io_req_find_next(req); + io_free_req(req); +diff --git a/io_uring/refs.h b/io_uring/refs.h +index 1336de3f2a30aa..21a379b0f22d61 100644 +--- a/io_uring/refs.h ++++ b/io_uring/refs.h +@@ -17,6 +17,13 @@ static inline bool req_ref_inc_not_zero(struct io_kiocb *req) + return atomic_inc_not_zero(&req->refs); + } + ++static inline bool req_ref_put_and_test_atomic(struct io_kiocb *req) ++{ ++ WARN_ON_ONCE(!(data_race(req->flags) & REQ_F_REFCOUNT)); ++ WARN_ON_ONCE(req_ref_zero_or_close_to_overflow(req)); ++ return atomic_dec_and_test(&req->refs); ++} ++ + static inline bool req_ref_put_and_test(struct io_kiocb *req) + { + if (likely(!(req->flags & REQ_F_REFCOUNT))) +diff --git a/kernel/bpf/bpf_cgrp_storage.c b/kernel/bpf/bpf_cgrp_storage.c +index ee1c7b77096e7b..fbbf3b6b9f8353 100644 +--- a/kernel/bpf/bpf_cgrp_storage.c ++++ b/kernel/bpf/bpf_cgrp_storage.c +@@ -162,6 +162,7 @@ BPF_CALL_5(bpf_cgrp_storage_get, struct bpf_map *, map, struct cgroup *, cgroup, + void *, value, u64, flags, gfp_t, gfp_flags) + { + struct bpf_local_storage_data *sdata; ++ bool nobusy; + + WARN_ON_ONCE(!bpf_rcu_lock_held()); + if (flags & ~(BPF_LOCAL_STORAGE_GET_F_CREATE)) +@@ -170,21 +171,21 @@ BPF_CALL_5(bpf_cgrp_storage_get, struct bpf_map *, map, struct cgroup *, cgroup, + if (!cgroup) + return (unsigned long)NULL; + +- if (!bpf_cgrp_storage_trylock()) +- return (unsigned long)NULL; ++ nobusy = bpf_cgrp_storage_trylock(); + +- sdata = cgroup_storage_lookup(cgroup, map, true); ++ sdata = cgroup_storage_lookup(cgroup, map, nobusy); + if (sdata) + goto unlock; + + /* only allocate new storage, when the cgroup is refcounted */ + if (!percpu_ref_is_dying(&cgroup->self.refcnt) && +- (flags & BPF_LOCAL_STORAGE_GET_F_CREATE)) ++ (flags & BPF_LOCAL_STORAGE_GET_F_CREATE) && nobusy) + sdata = bpf_local_storage_update(cgroup, (struct bpf_local_storage_map *)map, + value, BPF_NOEXIST, gfp_flags); + + unlock: +- bpf_cgrp_storage_unlock(); ++ if (nobusy) ++ bpf_cgrp_storage_unlock(); + return IS_ERR_OR_NULL(sdata) ? (unsigned long)NULL : (unsigned long)sdata->data; + } + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index d6a4102312fadd..e443506b0a65a1 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -20106,6 +20106,33 @@ BTF_ID(func, __rcu_read_unlock) + #endif + BTF_SET_END(btf_id_deny) + ++/* fexit and fmod_ret can't be used to attach to __noreturn functions. ++ * Currently, we must manually list all __noreturn functions here. Once a more ++ * robust solution is implemented, this workaround can be removed. ++ */ ++BTF_SET_START(noreturn_deny) ++#ifdef CONFIG_IA32_EMULATION ++BTF_ID(func, __ia32_sys_exit) ++BTF_ID(func, __ia32_sys_exit_group) ++#endif ++#ifdef CONFIG_KUNIT ++BTF_ID(func, __kunit_abort) ++BTF_ID(func, kunit_try_catch_throw) ++#endif ++#ifdef CONFIG_MODULES ++BTF_ID(func, __module_put_and_kthread_exit) ++#endif ++#ifdef CONFIG_X86_64 ++BTF_ID(func, __x64_sys_exit) ++BTF_ID(func, __x64_sys_exit_group) ++#endif ++BTF_ID(func, do_exit) ++BTF_ID(func, do_group_exit) ++BTF_ID(func, kthread_complete_and_exit) ++BTF_ID(func, kthread_exit) ++BTF_ID(func, make_task_dead) ++BTF_SET_END(noreturn_deny) ++ + static bool can_be_sleepable(struct bpf_prog *prog) + { + if (prog->type == BPF_PROG_TYPE_TRACING) { +@@ -20194,6 +20221,11 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) + } else if (prog->type == BPF_PROG_TYPE_TRACING && + btf_id_set_contains(&btf_id_deny, btf_id)) { + return -EINVAL; ++ } else if ((prog->expected_attach_type == BPF_TRACE_FEXIT || ++ prog->expected_attach_type == BPF_MODIFY_RETURN) && ++ btf_id_set_contains(&noreturn_deny, btf_id)) { ++ verbose(env, "Attaching fexit/fmod_ret to __noreturn functions is rejected.\n"); ++ return -EINVAL; + } + + key = bpf_trampoline_compute_key(tgt_prog, prog->aux->attach_btf, btf_id); +diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c +index f005c66f378c32..a600819799637b 100644 +--- a/kernel/dma/contiguous.c ++++ b/kernel/dma/contiguous.c +@@ -70,8 +70,7 @@ struct cma *dma_contiguous_default_area; + * Users, who want to set the size of global CMA area for their system + * should use cma= kernel parameter. + */ +-static const phys_addr_t size_bytes __initconst = +- (phys_addr_t)CMA_SIZE_MBYTES * SZ_1M; ++#define size_bytes ((phys_addr_t)CMA_SIZE_MBYTES * SZ_1M) + static phys_addr_t size_cmdline __initdata = -1; + static phys_addr_t base_cmdline __initdata; + static phys_addr_t limit_cmdline __initdata; +diff --git a/kernel/events/core.c b/kernel/events/core.c +index b710976fb01b17..987807b1040ae0 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -13419,6 +13419,9 @@ inherit_event(struct perf_event *parent_event, + if (IS_ERR(child_event)) + return child_event; + ++ get_ctx(child_ctx); ++ child_event->ctx = child_ctx; ++ + pmu_ctx = find_get_pmu_context(child_event->pmu, child_ctx, child_event); + if (IS_ERR(pmu_ctx)) { + free_event(child_event); +@@ -13441,8 +13444,6 @@ inherit_event(struct perf_event *parent_event, + return NULL; + } + +- get_ctx(child_ctx); +- + /* + * Make the child state follow the state of the parent event, + * not its attr.disabled bit. We hold the parent's mutex, +@@ -13463,7 +13464,6 @@ inherit_event(struct perf_event *parent_event, + local64_set(&hwc->period_left, sample_period); + } + +- child_event->ctx = child_ctx; + child_event->overflow_handler = parent_event->overflow_handler; + child_event->overflow_handler_context + = parent_event->overflow_handler_context; +diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig +index 33a2e991f60814..b411315ecd3c4b 100644 +--- a/kernel/module/Kconfig ++++ b/kernel/module/Kconfig +@@ -229,6 +229,7 @@ comment "Do not forget to sign required modules with scripts/sign-file" + choice + prompt "Which hash algorithm should modules be signed with?" + depends on MODULE_SIG || IMA_APPRAISE_MODSIG ++ default MODULE_SIG_SHA512 + help + This determines which sort of hashing algorithm will be used during + signature generation. This algorithm _must_ be built into the kernel +diff --git a/kernel/panic.c b/kernel/panic.c +index ef9f9a4e928de6..d7973e97547482 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -763,9 +763,15 @@ device_initcall(register_warn_debugfs); + */ + __visible noinstr void __stack_chk_fail(void) + { ++ unsigned long flags; ++ + instrumentation_begin(); ++ flags = user_access_save(); ++ + panic("stack-protector: Kernel stack is corrupted in: %pB", + __builtin_return_address(0)); ++ ++ user_access_restore(flags); + instrumentation_end(); + } + EXPORT_SYMBOL(__stack_chk_fail); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 8c5f75af07db0e..760a6c3781cbfc 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -7406,18 +7406,13 @@ int sched_core_idle_cpu(int cpu) + * required to meet deadlines. + */ + unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, +- enum cpu_util_type type, +- struct task_struct *p) ++ unsigned long *min, ++ unsigned long *max) + { +- unsigned long dl_util, util, irq, max; ++ unsigned long util, irq, scale; + struct rq *rq = cpu_rq(cpu); + +- max = arch_scale_cpu_capacity(cpu); +- +- if (!uclamp_is_used() && +- type == FREQUENCY_UTIL && rt_rq_is_runnable(&rq->rt)) { +- return max; +- } ++ scale = arch_scale_cpu_capacity(cpu); + + /* + * Early check to see if IRQ/steal time saturates the CPU, can be +@@ -7425,45 +7420,49 @@ unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, + * update_irq_load_avg(). + */ + irq = cpu_util_irq(rq); +- if (unlikely(irq >= max)) +- return max; ++ if (unlikely(irq >= scale)) { ++ if (min) ++ *min = scale; ++ if (max) ++ *max = scale; ++ return scale; ++ } ++ ++ if (min) { ++ /* ++ * The minimum utilization returns the highest level between: ++ * - the computed DL bandwidth needed with the IRQ pressure which ++ * steals time to the deadline task. ++ * - The minimum performance requirement for CFS and/or RT. ++ */ ++ *min = max(irq + cpu_bw_dl(rq), uclamp_rq_get(rq, UCLAMP_MIN)); ++ ++ /* ++ * When an RT task is runnable and uclamp is not used, we must ++ * ensure that the task will run at maximum compute capacity. ++ */ ++ if (!uclamp_is_used() && rt_rq_is_runnable(&rq->rt)) ++ *min = max(*min, scale); ++ } + + /* + * Because the time spend on RT/DL tasks is visible as 'lost' time to + * CFS tasks and we use the same metric to track the effective + * utilization (PELT windows are synchronized) we can directly add them + * to obtain the CPU's actual utilization. +- * +- * CFS and RT utilization can be boosted or capped, depending on +- * utilization clamp constraints requested by currently RUNNABLE +- * tasks. +- * When there are no CFS RUNNABLE tasks, clamps are released and +- * frequency will be gracefully reduced with the utilization decay. + */ + util = util_cfs + cpu_util_rt(rq); +- if (type == FREQUENCY_UTIL) +- util = uclamp_rq_util_with(rq, util, p); +- +- dl_util = cpu_util_dl(rq); ++ util += cpu_util_dl(rq); + + /* +- * For frequency selection we do not make cpu_util_dl() a permanent part +- * of this sum because we want to use cpu_bw_dl() later on, but we need +- * to check if the CFS+RT+DL sum is saturated (ie. no idle time) such +- * that we select f_max when there is no idle time. +- * +- * NOTE: numerical errors or stop class might cause us to not quite hit +- * saturation when we should -- something for later. ++ * The maximum hint is a soft bandwidth requirement, which can be lower ++ * than the actual utilization because of uclamp_max requirements. + */ +- if (util + dl_util >= max) +- return max; ++ if (max) ++ *max = min(scale, uclamp_rq_get(rq, UCLAMP_MAX)); + +- /* +- * OTOH, for energy computation we need the estimated running time, so +- * include util_dl and ignore dl_bw. +- */ +- if (type == ENERGY_UTIL) +- util += dl_util; ++ if (util >= scale) ++ return scale; + + /* + * There is still idle time; further improve the number by using the +@@ -7474,28 +7473,15 @@ unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, + * U' = irq + --------- * U + * max + */ +- util = scale_irq_capacity(util, irq, max); ++ util = scale_irq_capacity(util, irq, scale); + util += irq; + +- /* +- * Bandwidth required by DEADLINE must always be granted while, for +- * FAIR and RT, we use blocked utilization of IDLE CPUs as a mechanism +- * to gracefully reduce the frequency when no tasks show up for longer +- * periods of time. +- * +- * Ideally we would like to set bw_dl as min/guaranteed freq and util + +- * bw_dl as requested freq. However, cpufreq is not yet ready for such +- * an interface. So, we only do the latter for now. +- */ +- if (type == FREQUENCY_UTIL) +- util += cpu_bw_dl(rq); +- +- return min(max, util); ++ return min(scale, util); + } + + unsigned long sched_cpu_util(int cpu) + { +- return effective_cpu_util(cpu, cpu_util_cfs(cpu), ENERGY_UTIL, NULL); ++ return effective_cpu_util(cpu, cpu_util_cfs(cpu), NULL, NULL); + } + #endif /* CONFIG_SMP */ + +@@ -10048,7 +10034,7 @@ void __init sched_init(void) + #ifdef CONFIG_SMP + rq->sd = NULL; + rq->rd = NULL; +- rq->cpu_capacity = rq->cpu_capacity_orig = SCHED_CAPACITY_SCALE; ++ rq->cpu_capacity = SCHED_CAPACITY_SCALE; + rq->balance_callback = &balance_push_callback; + rq->active_balance = 0; + rq->next_balance = jiffies; +diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c +index 57c92d751bcd73..95baa12a10293e 100644 +--- a/kernel/sched/cpudeadline.c ++++ b/kernel/sched/cpudeadline.c +@@ -131,7 +131,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p, + if (!dl_task_fits_capacity(p, cpu)) { + cpumask_clear_cpu(cpu, later_mask); + +- cap = capacity_orig_of(cpu); ++ cap = arch_scale_cpu_capacity(cpu); + + if (cap > max_cap || + (cpu == task_cpu(p) && cap == max_cap)) { +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index 259521b179aa11..776be0549162c9 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -47,7 +47,7 @@ struct sugov_cpu { + u64 last_update; + + unsigned long util; +- unsigned long bw_dl; ++ unsigned long bw_min; + + /* The field below is for single-CPU policies only: */ + #ifdef CONFIG_NO_HZ_COMMON +@@ -81,9 +81,20 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) + if (!cpufreq_this_cpu_can_update(sg_policy->policy)) + return false; + +- if (unlikely(sg_policy->limits_changed)) { +- sg_policy->limits_changed = false; ++ if (unlikely(READ_ONCE(sg_policy->limits_changed))) { ++ WRITE_ONCE(sg_policy->limits_changed, false); + sg_policy->need_freq_update = true; ++ ++ /* ++ * The above limits_changed update must occur before the reads ++ * of policy limits in cpufreq_driver_resolve_freq() or a policy ++ * limits update might be missed, so use a memory barrier to ++ * ensure it. ++ * ++ * This pairs with the write memory barrier in sugov_limits(). ++ */ ++ smp_mb(); ++ + return true; + } + +@@ -155,7 +166,6 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, + unsigned int freq = arch_scale_freq_invariant() ? + policy->cpuinfo.max_freq : policy->cur; + +- util = map_util_perf(util); + freq = map_util_freq(util, freq, max); + + if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update) +@@ -165,14 +175,30 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, + return cpufreq_driver_resolve_freq(policy, freq); + } + ++unsigned long sugov_effective_cpu_perf(int cpu, unsigned long actual, ++ unsigned long min, ++ unsigned long max) ++{ ++ /* Add dvfs headroom to actual utilization */ ++ actual = map_util_perf(actual); ++ /* Actually we don't need to target the max performance */ ++ if (actual < max) ++ max = actual; ++ ++ /* ++ * Ensure at least minimum performance while providing more compute ++ * capacity when possible. ++ */ ++ return max(min, max); ++} ++ + static void sugov_get_util(struct sugov_cpu *sg_cpu) + { +- unsigned long util = cpu_util_cfs_boost(sg_cpu->cpu); +- struct rq *rq = cpu_rq(sg_cpu->cpu); ++ unsigned long min, max, util = cpu_util_cfs_boost(sg_cpu->cpu); + +- sg_cpu->bw_dl = cpu_bw_dl(rq); +- sg_cpu->util = effective_cpu_util(sg_cpu->cpu, util, +- FREQUENCY_UTIL, NULL); ++ util = effective_cpu_util(sg_cpu->cpu, util, &min, &max); ++ sg_cpu->bw_min = min; ++ sg_cpu->util = sugov_effective_cpu_perf(sg_cpu->cpu, util, min, max); + } + + /** +@@ -318,8 +344,8 @@ static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; } + */ + static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu) + { +- if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl) +- sg_cpu->sg_policy->limits_changed = true; ++ if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_min) ++ WRITE_ONCE(sg_cpu->sg_policy->limits_changed, true); + } + + static inline bool sugov_update_single_common(struct sugov_cpu *sg_cpu, +@@ -419,8 +445,8 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, + sugov_cpu_is_busy(sg_cpu) && sg_cpu->util < prev_util) + sg_cpu->util = prev_util; + +- cpufreq_driver_adjust_perf(sg_cpu->cpu, map_util_perf(sg_cpu->bw_dl), +- map_util_perf(sg_cpu->util), max_cap); ++ cpufreq_driver_adjust_perf(sg_cpu->cpu, sg_cpu->bw_min, ++ sg_cpu->util, max_cap); + + sg_cpu->sg_policy->last_freq_update_time = time; + } +@@ -829,7 +855,16 @@ static void sugov_limits(struct cpufreq_policy *policy) + mutex_unlock(&sg_policy->work_lock); + } + +- sg_policy->limits_changed = true; ++ /* ++ * The limits_changed update below must take place before the updates ++ * of policy limits in cpufreq_set_policy() or a policy limits update ++ * might be missed, so use a memory barrier to ensure it. ++ * ++ * This pairs with the memory barrier in sugov_should_update_freq(). ++ */ ++ smp_wmb(); ++ ++ WRITE_ONCE(sg_policy->limits_changed, true); + } + + struct cpufreq_governor schedutil_gov = { +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 6c639e48e49a97..a15cf7969953a5 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -132,7 +132,7 @@ static inline unsigned long __dl_bw_capacity(const struct cpumask *mask) + int i; + + for_each_cpu_and(i, mask, cpu_active_mask) +- cap += capacity_orig_of(i); ++ cap += arch_scale_cpu_capacity(i); + + return cap; + } +@@ -144,7 +144,7 @@ static inline unsigned long __dl_bw_capacity(const struct cpumask *mask) + static inline unsigned long dl_bw_capacity(int i) + { + if (!sched_asym_cpucap_active() && +- capacity_orig_of(i) == SCHED_CAPACITY_SCALE) { ++ arch_scale_cpu_capacity(i) == SCHED_CAPACITY_SCALE) { + return dl_bw_cpus(i) << SCHED_CAPACITY_SHIFT; + } else { + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 2808dbdd03847e..268e2a49b964e0 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -4951,7 +4951,7 @@ static inline void util_est_update(struct cfs_rq *cfs_rq, + * To avoid overestimation of actual task utilization, skip updates if + * we cannot grant there is idle time in this CPU. + */ +- if (task_util(p) > capacity_orig_of(cpu_of(rq_of(cfs_rq)))) ++ if (task_util(p) > arch_scale_cpu_capacity(cpu_of(rq_of(cfs_rq)))) + return; + + /* +@@ -4999,14 +4999,14 @@ static inline int util_fits_cpu(unsigned long util, + return fits; + + /* +- * We must use capacity_orig_of() for comparing against uclamp_min and ++ * We must use arch_scale_cpu_capacity() for comparing against uclamp_min and + * uclamp_max. We only care about capacity pressure (by using + * capacity_of()) for comparing against the real util. + * + * If a task is boosted to 1024 for example, we don't want a tiny + * pressure to skew the check whether it fits a CPU or not. + * +- * Similarly if a task is capped to capacity_orig_of(little_cpu), it ++ * Similarly if a task is capped to arch_scale_cpu_capacity(little_cpu), it + * should fit a little cpu even if there's some pressure. + * + * Only exception is for thermal pressure since it has a direct impact +@@ -5018,7 +5018,7 @@ static inline int util_fits_cpu(unsigned long util, + * For uclamp_max, we can tolerate a drop in performance level as the + * goal is to cap the task. So it's okay if it's getting less. + */ +- capacity_orig = capacity_orig_of(cpu); ++ capacity_orig = arch_scale_cpu_capacity(cpu); + capacity_orig_thermal = capacity_orig - arch_scale_thermal_pressure(cpu); + + /* +@@ -7515,7 +7515,7 @@ select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target) + * Look for the CPU with best capacity. + */ + else if (fits < 0) +- cpu_cap = capacity_orig_of(cpu) - thermal_load_avg(cpu_rq(cpu)); ++ cpu_cap = arch_scale_cpu_capacity(cpu) - thermal_load_avg(cpu_rq(cpu)); + + /* + * First, select CPU which fits better (-1 being better than 0). +@@ -7757,7 +7757,7 @@ cpu_util(int cpu, struct task_struct *p, int dst_cpu, int boost) + util = max(util, util_est); + } + +- return min(util, capacity_orig_of(cpu)); ++ return min(util, arch_scale_cpu_capacity(cpu)); + } + + unsigned long cpu_util_cfs(int cpu) +@@ -7859,7 +7859,7 @@ static inline void eenv_pd_busy_time(struct energy_env *eenv, + for_each_cpu(cpu, pd_cpus) { + unsigned long util = cpu_util(cpu, p, -1, 0); + +- busy_time += effective_cpu_util(cpu, util, ENERGY_UTIL, NULL); ++ busy_time += effective_cpu_util(cpu, util, NULL, NULL); + } + + eenv->pd_busy_time = min(eenv->pd_cap, busy_time); +@@ -7882,7 +7882,7 @@ eenv_pd_max_util(struct energy_env *eenv, struct cpumask *pd_cpus, + for_each_cpu(cpu, pd_cpus) { + struct task_struct *tsk = (cpu == dst_cpu) ? p : NULL; + unsigned long util = cpu_util(cpu, p, dst_cpu, 1); +- unsigned long eff_util; ++ unsigned long eff_util, min, max; + + /* + * Performance domain frequency: utilization clamping +@@ -7891,7 +7891,23 @@ eenv_pd_max_util(struct energy_env *eenv, struct cpumask *pd_cpus, + * NOTE: in case RT tasks are running, by default the + * FREQUENCY_UTIL's utilization can be max OPP. + */ +- eff_util = effective_cpu_util(cpu, util, FREQUENCY_UTIL, tsk); ++ eff_util = effective_cpu_util(cpu, util, &min, &max); ++ ++ /* Task's uclamp can modify min and max value */ ++ if (tsk && uclamp_is_used()) { ++ min = max(min, uclamp_eff_value(p, UCLAMP_MIN)); ++ ++ /* ++ * If there is no active max uclamp constraint, ++ * directly use task's one, otherwise keep max. ++ */ ++ if (uclamp_rq_is_idle(cpu_rq(cpu))) ++ max = uclamp_eff_value(p, UCLAMP_MAX); ++ else ++ max = max(max, uclamp_eff_value(p, UCLAMP_MAX)); ++ } ++ ++ eff_util = sugov_effective_cpu_perf(cpu, eff_util, min, max); + max_util = max(max_util, eff_util); + } + +@@ -9544,8 +9560,6 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) + unsigned long capacity = scale_rt_capacity(cpu); + struct sched_group *sdg = sd->groups; + +- cpu_rq(cpu)->cpu_capacity_orig = arch_scale_cpu_capacity(cpu); +- + if (!capacity) + capacity = 1; + +@@ -9621,7 +9635,7 @@ static inline int + check_cpu_capacity(struct rq *rq, struct sched_domain *sd) + { + return ((rq->cpu_capacity * sd->imbalance_pct) < +- (rq->cpu_capacity_orig * 100)); ++ (arch_scale_cpu_capacity(cpu_of(rq)) * 100)); + } + + /* +@@ -9632,7 +9646,7 @@ check_cpu_capacity(struct rq *rq, struct sched_domain *sd) + static inline int check_misfit_status(struct rq *rq, struct sched_domain *sd) + { + return rq->misfit_task_load && +- (rq->cpu_capacity_orig < rq->rd->max_cpu_capacity || ++ (arch_scale_cpu_capacity(rq->cpu) < rq->rd->max_cpu_capacity || + check_cpu_capacity(rq, sd)); + } + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index b89223a973168f..91b1ee0d81fce4 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -519,7 +519,7 @@ static inline bool rt_task_fits_capacity(struct task_struct *p, int cpu) + min_cap = uclamp_eff_value(p, UCLAMP_MIN); + max_cap = uclamp_eff_value(p, UCLAMP_MAX); + +- cpu_cap = capacity_orig_of(cpu); ++ cpu_cap = arch_scale_cpu_capacity(cpu); + + return cpu_cap >= min(min_cap, max_cap); + } +diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h +index d48c6a292a83db..60dc51f43dd91f 100644 +--- a/kernel/sched/sched.h ++++ b/kernel/sched/sched.h +@@ -1048,7 +1048,6 @@ struct rq { + struct sched_domain __rcu *sd; + + unsigned long cpu_capacity; +- unsigned long cpu_capacity_orig; + + struct balance_callback *balance_callback; + +@@ -2985,29 +2984,14 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} + #endif + + #ifdef CONFIG_SMP +-static inline unsigned long capacity_orig_of(int cpu) +-{ +- return cpu_rq(cpu)->cpu_capacity_orig; +-} ++unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, ++ unsigned long *min, ++ unsigned long *max); + +-/** +- * enum cpu_util_type - CPU utilization type +- * @FREQUENCY_UTIL: Utilization used to select frequency +- * @ENERGY_UTIL: Utilization used during energy calculation +- * +- * The utilization signals of all scheduling classes (CFS/RT/DL) and IRQ time +- * need to be aggregated differently depending on the usage made of them. This +- * enum is used within effective_cpu_util() to differentiate the types of +- * utilization expected by the callers, and adjust the aggregation accordingly. +- */ +-enum cpu_util_type { +- FREQUENCY_UTIL, +- ENERGY_UTIL, +-}; ++unsigned long sugov_effective_cpu_perf(int cpu, unsigned long actual, ++ unsigned long min, ++ unsigned long max); + +-unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, +- enum cpu_util_type type, +- struct task_struct *p); + + /* + * Verify the fitness of task @p to run on @cpu taking into account the +diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c +index 2ed884bb362137..c61698cff0f3a8 100644 +--- a/kernel/sched/topology.c ++++ b/kernel/sched/topology.c +@@ -2486,12 +2486,15 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att + /* Attach the domains */ + rcu_read_lock(); + for_each_cpu(i, cpu_map) { ++ unsigned long capacity; ++ + rq = cpu_rq(i); + sd = *per_cpu_ptr(d.sd, i); + ++ capacity = arch_scale_cpu_capacity(i); + /* Use READ_ONCE()/WRITE_ONCE() to avoid load/store tearing: */ +- if (rq->cpu_capacity_orig > READ_ONCE(d.rd->max_cpu_capacity)) +- WRITE_ONCE(d.rd->max_cpu_capacity, rq->cpu_capacity_orig); ++ if (capacity > READ_ONCE(d.rd->max_cpu_capacity)) ++ WRITE_ONCE(d.rd->max_cpu_capacity, capacity); + + cpu_attach_domain(sd, d.rd, i); + } +diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c +index 7f2b17fc8ce403..ecdb8c2b2cab21 100644 +--- a/kernel/time/tick-common.c ++++ b/kernel/time/tick-common.c +@@ -495,6 +495,7 @@ void tick_resume(void) + + #ifdef CONFIG_SUSPEND + static DEFINE_RAW_SPINLOCK(tick_freeze_lock); ++static DEFINE_WAIT_OVERRIDE_MAP(tick_freeze_map, LD_WAIT_SLEEP); + static unsigned int tick_freeze_depth; + + /** +@@ -514,9 +515,22 @@ void tick_freeze(void) + if (tick_freeze_depth == num_online_cpus()) { + trace_suspend_resume(TPS("timekeeping_freeze"), + smp_processor_id(), true); ++ /* ++ * All other CPUs have their interrupts disabled and are ++ * suspended to idle. Other tasks have been frozen so there ++ * is no scheduling happening. This means that there is no ++ * concurrency in the system at this point. Therefore it is ++ * okay to acquire a sleeping lock on PREEMPT_RT, such as a ++ * spinlock, because the lock cannot be held by other CPUs ++ * or threads and acquiring it cannot block. ++ * ++ * Inform lockdep about the situation. ++ */ ++ lock_map_acquire_try(&tick_freeze_map); + system_state = SYSTEM_SUSPEND; + sched_clock_suspend(); + timekeeping_suspend(); ++ lock_map_release(&tick_freeze_map); + } else { + tick_suspend_local(); + } +@@ -538,8 +552,16 @@ void tick_unfreeze(void) + raw_spin_lock(&tick_freeze_lock); + + if (tick_freeze_depth == num_online_cpus()) { ++ /* ++ * Similar to tick_freeze(). On resumption the first CPU may ++ * acquire uncontended sleeping locks while other CPUs block on ++ * tick_freeze_lock. ++ */ ++ lock_map_acquire_try(&tick_freeze_map); + timekeeping_resume(); + sched_clock_resume(); ++ lock_map_release(&tick_freeze_map); ++ + system_state = SYSTEM_RUNNING; + trace_suspend_resume(TPS("timekeeping_freeze"), + smp_processor_id(), false); +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 545393601be8ce..97f660a8ddc73d 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -400,7 +400,7 @@ static const struct bpf_func_proto bpf_trace_printk_proto = { + .arg2_type = ARG_CONST_SIZE, + }; + +-static void __set_printk_clr_event(void) ++static void __set_printk_clr_event(struct work_struct *work) + { + /* + * This program might be calling bpf_trace_printk, +@@ -413,10 +413,11 @@ static void __set_printk_clr_event(void) + if (trace_set_clr_event("bpf_trace", "bpf_trace_printk", 1)) + pr_warn_ratelimited("could not enable bpf_trace_printk events"); + } ++static DECLARE_WORK(set_printk_work, __set_printk_clr_event); + + const struct bpf_func_proto *bpf_get_trace_printk_proto(void) + { +- __set_printk_clr_event(); ++ schedule_work(&set_printk_work); + return &bpf_trace_printk_proto; + } + +@@ -459,7 +460,7 @@ static const struct bpf_func_proto bpf_trace_vprintk_proto = { + + const struct bpf_func_proto *bpf_get_trace_vprintk_proto(void) + { +- __set_printk_clr_event(); ++ schedule_work(&set_printk_work); + return &bpf_trace_vprintk_proto; + } + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 1a936978c2b1a6..5f74e9f9c8a734 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -470,6 +470,7 @@ static void test_event_printk(struct trace_event_call *call) + case '%': + continue; + case 'p': ++ do_pointer: + /* Find dereferencing fields */ + switch (fmt[i + 1]) { + case 'B': case 'R': case 'r': +@@ -498,6 +499,12 @@ static void test_event_printk(struct trace_event_call *call) + continue; + if (fmt[i + j] == '*') { + star = true; ++ /* Handle %*pbl case */ ++ if (!j && fmt[i + 1] == 'p') { ++ arg++; ++ i++; ++ goto do_pointer; ++ } + continue; + } + if ((fmt[i + j] == 's')) { +diff --git a/lib/test_ubsan.c b/lib/test_ubsan.c +index 2062be1f2e80f6..f90f2b9842ec4f 100644 +--- a/lib/test_ubsan.c ++++ b/lib/test_ubsan.c +@@ -35,18 +35,22 @@ static void test_ubsan_shift_out_of_bounds(void) + + static void test_ubsan_out_of_bounds(void) + { +- volatile int i = 4, j = 5, k = -1; +- volatile char above[4] = { }; /* Protect surrounding memory. */ +- volatile int arr[4]; +- volatile char below[4] = { }; /* Protect surrounding memory. */ ++ int i = 4, j = 4, k = -1; ++ volatile struct { ++ char above[4]; /* Protect surrounding memory. */ ++ int arr[4]; ++ char below[4]; /* Protect surrounding memory. */ ++ } data; + +- above[0] = below[0]; ++ OPTIMIZER_HIDE_VAR(i); ++ OPTIMIZER_HIDE_VAR(j); ++ OPTIMIZER_HIDE_VAR(k); + + UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above"); +- arr[j] = i; ++ data.arr[j] = i; + + UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below"); +- arr[k] = i; ++ data.arr[k] = i; + } + + enum ubsan_test_enum { +diff --git a/net/9p/client.c b/net/9p/client.c +index d841d82e908fe3..cf73fe306219a9 100644 +--- a/net/9p/client.c ++++ b/net/9p/client.c +@@ -1547,7 +1547,8 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + struct p9_client *clnt = fid->clnt; + struct p9_req_t *req; + int count = iov_iter_count(to); +- int rsize, received, non_zc = 0; ++ u32 rsize, received; ++ bool non_zc = false; + char *dataptr; + + *err = 0; +@@ -1570,7 +1571,7 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + 0, 11, "dqd", fid->fid, + offset, rsize); + } else { +- non_zc = 1; ++ non_zc = true; + req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, + rsize); + } +@@ -1591,11 +1592,11 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + return 0; + } + if (rsize < received) { +- pr_err("bogus RREAD count (%d > %d)\n", received, rsize); ++ pr_err("bogus RREAD count (%u > %u)\n", received, rsize); + received = rsize; + } + +- p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", received); ++ p9_debug(P9_DEBUG_9P, "<<< RREAD count %u\n", received); + + if (non_zc) { + int n = copy_to_iter(dataptr, received, to); +@@ -1622,9 +1623,9 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) + *err = 0; + + while (iov_iter_count(from)) { +- int count = iov_iter_count(from); +- int rsize = fid->iounit; +- int written; ++ size_t count = iov_iter_count(from); ++ u32 rsize = fid->iounit; ++ u32 written; + + if (!rsize || rsize > clnt->msize - P9_IOHDRSZ) + rsize = clnt->msize - P9_IOHDRSZ; +@@ -1632,7 +1633,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) + if (count < rsize) + rsize = count; + +- p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d (/%d)\n", ++ p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %u (/%zu)\n", + fid->fid, offset, rsize, count); + + /* Don't bother zerocopy for small IO (< 1024) */ +@@ -1658,11 +1659,11 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) + break; + } + if (rsize < written) { +- pr_err("bogus RWRITE count (%d > %d)\n", written, rsize); ++ pr_err("bogus RWRITE count (%u > %u)\n", written, rsize); + written = rsize; + } + +- p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", written); ++ p9_debug(P9_DEBUG_9P, "<<< RWRITE count %u\n", written); + + p9_req_put(clnt, req); + iov_iter_revert(from, count - written - iov_iter_count(from)); +@@ -2049,7 +2050,8 @@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate); + + int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) + { +- int err, rsize, non_zc = 0; ++ int err, non_zc = 0; ++ u32 rsize; + struct p9_client *clnt; + struct p9_req_t *req; + char *dataptr; +@@ -2058,7 +2060,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) + + iov_iter_kvec(&to, ITER_DEST, &kv, 1, count); + +- p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", ++ p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %u\n", + fid->fid, offset, count); + + clnt = fid->clnt; +@@ -2093,11 +2095,11 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) + goto free_and_error; + } + if (rsize < count) { +- pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize); ++ pr_err("bogus RREADDIR count (%u > %u)\n", count, rsize); + count = rsize; + } + +- p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); ++ p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %u\n", count); + + if (non_zc) + memmove(data, dataptr, count); +diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c +index 4417a18b3e951a..f63586c9ce0216 100644 +--- a/net/core/lwtunnel.c ++++ b/net/core/lwtunnel.c +@@ -332,6 +332,8 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) + struct dst_entry *dst; + int ret; + ++ local_bh_disable(); ++ + if (dev_xmit_recursion()) { + net_crit_ratelimited("%s(): recursion limit reached on datapath\n", + __func__); +@@ -347,8 +349,10 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) + lwtstate = dst->lwtstate; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || +- lwtstate->type > LWTUNNEL_ENCAP_MAX) +- return 0; ++ lwtstate->type > LWTUNNEL_ENCAP_MAX) { ++ ret = 0; ++ goto out; ++ } + + ret = -EOPNOTSUPP; + rcu_read_lock(); +@@ -363,11 +367,13 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) + if (ret == -EOPNOTSUPP) + goto drop; + +- return ret; ++ goto out; + + drop: + kfree_skb(skb); + ++out: ++ local_bh_enable(); + return ret; + } + EXPORT_SYMBOL_GPL(lwtunnel_output); +@@ -379,6 +385,8 @@ int lwtunnel_xmit(struct sk_buff *skb) + struct dst_entry *dst; + int ret; + ++ local_bh_disable(); ++ + if (dev_xmit_recursion()) { + net_crit_ratelimited("%s(): recursion limit reached on datapath\n", + __func__); +@@ -395,8 +403,10 @@ int lwtunnel_xmit(struct sk_buff *skb) + lwtstate = dst->lwtstate; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || +- lwtstate->type > LWTUNNEL_ENCAP_MAX) +- return 0; ++ lwtstate->type > LWTUNNEL_ENCAP_MAX) { ++ ret = 0; ++ goto out; ++ } + + ret = -EOPNOTSUPP; + rcu_read_lock(); +@@ -411,11 +421,13 @@ int lwtunnel_xmit(struct sk_buff *skb) + if (ret == -EOPNOTSUPP) + goto drop; + +- return ret; ++ goto out; + + drop: + kfree_skb(skb); + ++out: ++ local_bh_enable(); + return ret; + } + EXPORT_SYMBOL_GPL(lwtunnel_xmit); +@@ -427,6 +439,8 @@ int lwtunnel_input(struct sk_buff *skb) + struct dst_entry *dst; + int ret; + ++ DEBUG_NET_WARN_ON_ONCE(!in_softirq()); ++ + if (dev_xmit_recursion()) { + net_crit_ratelimited("%s(): recursion limit reached on datapath\n", + __func__); +diff --git a/net/core/selftests.c b/net/core/selftests.c +index acb1ee97bbd324..7af99d07762ea0 100644 +--- a/net/core/selftests.c ++++ b/net/core/selftests.c +@@ -100,10 +100,10 @@ static struct sk_buff *net_test_get_skb(struct net_device *ndev, + ehdr->h_proto = htons(ETH_P_IP); + + if (attr->tcp) { ++ memset(thdr, 0, sizeof(*thdr)); + thdr->source = htons(attr->sport); + thdr->dest = htons(attr->dport); + thdr->doff = sizeof(struct tcphdr) / 4; +- thdr->check = 0; + } else { + uhdr->source = htons(attr->sport); + uhdr->dest = htons(attr->dport); +@@ -144,10 +144,18 @@ static struct sk_buff *net_test_get_skb(struct net_device *ndev, + attr->id = net_test_next_id; + shdr->id = net_test_next_id++; + +- if (attr->size) +- skb_put(skb, attr->size); +- if (attr->max_size && attr->max_size > skb->len) +- skb_put(skb, attr->max_size - skb->len); ++ if (attr->size) { ++ void *payload = skb_put(skb, attr->size); ++ ++ memset(payload, 0, attr->size); ++ } ++ ++ if (attr->max_size && attr->max_size > skb->len) { ++ size_t pad_len = attr->max_size - skb->len; ++ void *pad = skb_put(skb, pad_len); ++ ++ memset(pad, 0, pad_len); ++ } + + skb->csum = 0; + skb->ip_summed = CHECKSUM_PARTIAL; +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index 880c5f16b29ccf..371255e624332f 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -958,6 +958,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + + if (cl != NULL) { + int old_flags; ++ int len = 0; + + if (parentid) { + if (cl->cl_parent && +@@ -988,9 +989,13 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (usc != NULL) + hfsc_change_usc(cl, usc, cur_time); + ++ if (cl->qdisc->q.qlen != 0) ++ len = qdisc_peek_len(cl->qdisc); ++ /* Check queue length again since some qdisc implementations ++ * (e.g., netem/codel) might empty the queue during the peek ++ * operation. ++ */ + if (cl->qdisc->q.qlen != 0) { +- int len = qdisc_peek_len(cl->qdisc); +- + if (cl->cl_flags & HFSC_RSC) { + if (old_flags & HFSC_RSC) + update_ed(cl, len); +@@ -1633,10 +1638,16 @@ hfsc_dequeue(struct Qdisc *sch) + if (cl->qdisc->q.qlen != 0) { + /* update ed */ + next_len = qdisc_peek_len(cl->qdisc); +- if (realtime) +- update_ed(cl, next_len); +- else +- update_d(cl, next_len); ++ /* Check queue length again since some qdisc implementations ++ * (e.g., netem/codel) might empty the queue during the peek ++ * operation. ++ */ ++ if (cl->qdisc->q.qlen != 0) { ++ if (realtime) ++ update_ed(cl, next_len); ++ else ++ update_d(cl, next_len); ++ } + } else { + /* the class becomes passive */ + eltree_remove(cl); +diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c +index 77a3d016cadec1..ddc3e4e5e18d78 100644 +--- a/net/tipc/monitor.c ++++ b/net/tipc/monitor.c +@@ -716,7 +716,8 @@ void tipc_mon_reinit_self(struct net *net) + if (!mon) + continue; + write_lock_bh(&mon->lock); +- mon->self->addr = tipc_own_addr(net); ++ if (mon->self) ++ mon->self->addr = tipc_own_addr(net); + write_unlock_bh(&mon->lock); + } + } +diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h +index 1c6b843b8c4eeb..06be777b3b14b7 100644 +--- a/samples/trace_events/trace-events-sample.h ++++ b/samples/trace_events/trace-events-sample.h +@@ -302,6 +302,7 @@ TRACE_EVENT(foo_bar, + __bitmask( cpus, num_possible_cpus() ) + __cpumask( cpum ) + __vstring( vstr, fmt, va ) ++ __string_len( lstr, foo, bar / 2 < strlen(foo) ? bar / 2 : strlen(foo) ) + ), + + TP_fast_assign( +@@ -310,12 +311,14 @@ TRACE_EVENT(foo_bar, + memcpy(__get_dynamic_array(list), lst, + __length_of(lst) * sizeof(int)); + __assign_str(str, string); ++ __assign_str(lstr, foo); + __assign_vstr(vstr, fmt, va); + __assign_bitmask(cpus, cpumask_bits(mask), num_possible_cpus()); + __assign_cpumask(cpum, cpumask_bits(mask)); + ), + +- TP_printk("foo %s %d %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, ++ TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s [%d] %*pbl", ++ __entry->foo, __entry->bar, + + /* + * Notice here the use of some helper functions. This includes: +@@ -359,8 +362,17 @@ TRACE_EVENT(foo_bar, + __print_array(__get_dynamic_array(list), + __get_dynamic_array_len(list) / sizeof(int), + sizeof(int)), +- __get_str(str), __get_bitmask(cpus), __get_cpumask(cpum), +- __get_str(vstr)) ++ ++/* A shortcut is to use __print_dynamic_array for dynamic arrays */ ++ ++ __print_dynamic_array(list, sizeof(int)), ++ ++ __get_str(str), __get_str(lstr), ++ __get_bitmask(cpus), __get_cpumask(cpum), ++ __get_str(vstr), ++ __get_dynamic_array_len(cpus), ++ __get_dynamic_array_len(cpus), ++ __get_dynamic_array(cpus)) + ); + + /* +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index 44f20b1b853a50..4aecfb0a0ef6ae 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -268,7 +268,7 @@ objtool-args-$(CONFIG_SLS) += --sls + objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval + objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call + objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess +-objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable ++objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV)) += --no-unreachable + objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES) + + objtool-args = $(objtool-args-y) \ +diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c +index 1b6e376f3833cb..fe222c4b74c006 100644 +--- a/sound/soc/codecs/wcd934x.c ++++ b/sound/soc/codecs/wcd934x.c +@@ -2281,7 +2281,7 @@ static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data) + { + struct wcd934x_codec *wcd = data; + unsigned long status = 0; +- int i, j, port_id; ++ unsigned int i, j, port_id; + unsigned int val, int_val = 0; + irqreturn_t ret = IRQ_NONE; + bool tx; +diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c +index ff9f6a1c95df19..40b6a837f66bbc 100644 +--- a/sound/soc/qcom/apq8016_sbc.c ++++ b/sound/soc/qcom/apq8016_sbc.c +@@ -343,4 +343,4 @@ module_platform_driver(apq8016_sbc_platform_driver); + + MODULE_AUTHOR("Srinivas Kandagatla variant->exit) + drvdata->variant->exit(pdev); +- +- +- return 0; + } + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); + +@@ -1307,4 +1304,4 @@ void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev) + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown); + + MODULE_DESCRIPTION("QTi LPASS CPU Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c +index 24b1a7523adb90..ce753ebc08945a 100644 +--- a/sound/soc/qcom/lpass-hdmi.c ++++ b/sound/soc/qcom/lpass-hdmi.c +@@ -251,4 +251,4 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = { + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops); + + MODULE_DESCRIPTION("QTi LPASS HDMI Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c +index 2c97f295e39400..2a82684c04de45 100644 +--- a/sound/soc/qcom/lpass-ipq806x.c ++++ b/sound/soc/qcom/lpass-ipq806x.c +@@ -172,9 +172,9 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = { + .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id), + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + }; + module_platform_driver(ipq806x_lpass_cpu_platform_driver); + + MODULE_DESCRIPTION("QTi LPASS CPU Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c +index 73e3d39bd24c30..f918d9e16dc041 100644 +--- a/sound/soc/qcom/lpass-platform.c ++++ b/sound/soc/qcom/lpass-platform.c +@@ -1383,4 +1383,4 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register); + + MODULE_DESCRIPTION("QTi LPASS Platform Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c +index d16c0d83aaad92..98faf82c22568e 100644 +--- a/sound/soc/qcom/lpass-sc7180.c ++++ b/sound/soc/qcom/lpass-sc7180.c +@@ -315,11 +315,11 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = { + .pm = &sc7180_lpass_pm_ops, + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, + }; + + module_platform_driver(sc7180_lpass_cpu_platform_driver); + + MODULE_DESCRIPTION("SC7180 LPASS CPU DRIVER"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c +index 6b2eb25ed9390c..97b9053ed3b027 100644 +--- a/sound/soc/qcom/lpass-sc7280.c ++++ b/sound/soc/qcom/lpass-sc7280.c +@@ -445,7 +445,7 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = { + .pm = &sc7280_lpass_pm_ops, + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, + }; + +diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h +index ea12f02eca55f6..5caec24555ea2e 100644 +--- a/sound/soc/qcom/lpass.h ++++ b/sound/soc/qcom/lpass.h +@@ -399,8 +399,8 @@ struct lpass_pcm_data { + }; + + /* register the platform driver from the CPU DAI driver */ +-int asoc_qcom_lpass_platform_register(struct platform_device *); +-int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); ++int asoc_qcom_lpass_platform_register(struct platform_device *pdev); ++void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); + void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); + int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); + extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; +diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c +index 919e326b9462b3..fcef53b97ff98a 100644 +--- a/sound/soc/qcom/qdsp6/q6afe.c ++++ b/sound/soc/qcom/qdsp6/q6afe.c +@@ -552,13 +552,13 @@ struct q6afe_port { + }; + + struct afe_cmd_remote_lpass_core_hw_vote_request { +- uint32_t hw_block_id; +- char client_name[8]; ++ uint32_t hw_block_id; ++ char client_name[8]; + } __packed; + + struct afe_cmd_remote_lpass_core_hw_devote_request { +- uint32_t hw_block_id; +- uint32_t client_handle; ++ uint32_t hw_block_id; ++ uint32_t client_handle; + } __packed; + + +diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c +index def05ce58d176e..179f4f7386dd00 100644 +--- a/sound/soc/qcom/qdsp6/q6apm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6apm-dai.c +@@ -64,20 +64,16 @@ struct q6apm_dai_rtd { + phys_addr_t phys; + unsigned int pcm_size; + unsigned int pcm_count; +- unsigned int pos; /* Buffer position */ + unsigned int periods; + unsigned int bytes_sent; + unsigned int bytes_received; + unsigned int copied_total; + uint16_t bits_per_sample; +- uint16_t source; /* Encoding source bit mask */ +- uint16_t session_id; ++ snd_pcm_uframes_t queue_ptr; + bool next_track; + enum stream_state state; + struct q6apm_graph *graph; + spinlock_t lock; +- uint32_t initial_samples_drop; +- uint32_t trailing_samples_drop; + bool notify_on_drain; + }; + +@@ -127,25 +123,16 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo + { + struct q6apm_dai_rtd *prtd = priv; + struct snd_pcm_substream *substream = prtd->substream; +- unsigned long flags; + + switch (opcode) { + case APM_CLIENT_EVENT_CMD_EOS_DONE: + prtd->state = Q6APM_STREAM_STOPPED; + break; + case APM_CLIENT_EVENT_DATA_WRITE_DONE: +- spin_lock_irqsave(&prtd->lock, flags); +- prtd->pos += prtd->pcm_count; +- spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); +- if (prtd->state == Q6APM_STREAM_RUNNING) +- q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); + + break; + case APM_CLIENT_EVENT_DATA_READ_DONE: +- spin_lock_irqsave(&prtd->lock, flags); +- prtd->pos += prtd->pcm_count; +- spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); + if (prtd->state == Q6APM_STREAM_RUNNING) + q6apm_read(prtd->graph); +@@ -251,7 +238,6 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, + } + + prtd->pcm_count = snd_pcm_lib_period_bytes(substream); +- prtd->pos = 0; + /* rate and channels are sent to audio driver */ + ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); + if (ret < 0) { +@@ -297,6 +283,27 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, + return 0; + } + ++static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct q6apm_dai_rtd *prtd = runtime->private_data; ++ int i, ret = 0, avail_periods; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size; ++ for (i = 0; i < avail_periods; i++) { ++ ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP); ++ if (ret < 0) { ++ dev_err(component->dev, "Error queuing playback buffer %d\n", ret); ++ return ret; ++ } ++ prtd->queue_ptr += runtime->period_size; ++ } ++ } ++ ++ return ret; ++} ++ + static int q6apm_dai_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) + { +@@ -308,9 +315,6 @@ static int q6apm_dai_trigger(struct snd_soc_component *component, + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +- /* start writing buffers for playback only as we already queued capture buffers */ +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +- ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); + break; + case SNDRV_PCM_TRIGGER_STOP: + /* TODO support be handled via SoftPause Module */ +@@ -432,16 +436,12 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component, + struct snd_pcm_runtime *runtime = substream->runtime; + struct q6apm_dai_rtd *prtd = runtime->private_data; + snd_pcm_uframes_t ptr; +- unsigned long flags; + +- spin_lock_irqsave(&prtd->lock, flags); +- if (prtd->pos == prtd->pcm_size) +- prtd->pos = 0; +- +- ptr = bytes_to_frames(runtime, prtd->pos); +- spin_unlock_irqrestore(&prtd->lock, flags); ++ ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size; ++ if (ptr) ++ return ptr - 1; + +- return ptr; ++ return 0; + } + + static int q6apm_dai_hw_params(struct snd_soc_component *component, +@@ -656,8 +656,6 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component, + prtd->pcm_size = runtime->fragments * runtime->fragment_size; + prtd->bits_per_sample = 16; + +- prtd->pos = 0; +- + if (prtd->next_track != true) { + memcpy(&prtd->codec, codec, sizeof(*codec)); + +@@ -721,14 +719,12 @@ static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component, + + switch (metadata->key) { + case SNDRV_COMPRESS_ENCODER_PADDING: +- prtd->trailing_samples_drop = metadata->value[0]; + q6apm_remove_trailing_silence(component->dev, prtd->graph, +- prtd->trailing_samples_drop); ++ metadata->value[0]); + break; + case SNDRV_COMPRESS_ENCODER_DELAY: +- prtd->initial_samples_drop = metadata->value[0]; + q6apm_remove_initial_silence(component->dev, prtd->graph, +- prtd->initial_samples_drop); ++ metadata->value[0]); + break; + default: + ret = -EINVAL; +@@ -840,6 +836,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = { + .hw_params = q6apm_dai_hw_params, + .pointer = q6apm_dai_pointer, + .trigger = q6apm_dai_trigger, ++ .ack = q6apm_dai_ack, + .compress_ops = &q6apm_dai_compress_ops, + .use_dai_pcm_id = true, + }; +diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h +index 394604c349432f..a33d92c7bd6bff 100644 +--- a/sound/soc/qcom/qdsp6/q6asm.h ++++ b/sound/soc/qcom/qdsp6/q6asm.h +@@ -36,16 +36,16 @@ enum { + #define ASM_LAST_BUFFER_FLAG BIT(30) + + struct q6asm_flac_cfg { +- u32 sample_rate; +- u32 ext_sample_rate; +- u32 min_frame_size; +- u32 max_frame_size; +- u16 stream_info_present; +- u16 min_blk_size; +- u16 max_blk_size; +- u16 ch_cfg; +- u16 sample_size; +- u16 md5_sum; ++ u32 sample_rate; ++ u32 ext_sample_rate; ++ u32 min_frame_size; ++ u32 max_frame_size; ++ u16 stream_info_present; ++ u16 min_blk_size; ++ u16 max_blk_size; ++ u16 ch_cfg; ++ u16 sample_size; ++ u16 md5_sum; + }; + + struct q6asm_wma_cfg { +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index 130b22a34fb3b5..70572c83e1017d 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -545,6 +545,7 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap + + if (mod) { + int pn, id = 0; ++ + mod->module_id = module_id; + mod->max_ip_port = max_ip_port; + mod->max_op_port = max_op_port; +@@ -1271,7 +1272,7 @@ int audioreach_tplg_init(struct snd_soc_component *component) + + ret = request_firmware(&fw, tplg_fw_name, dev); + if (ret < 0) { +- dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); ++ dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret); + goto err; + } + +diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c +index d1fd40e3f7a9d8..1367752f2b63a6 100644 +--- a/sound/soc/qcom/sc7180.c ++++ b/sound/soc/qcom/sc7180.c +@@ -428,4 +428,4 @@ static struct platform_driver sc7180_snd_driver = { + module_platform_driver(sc7180_snd_driver); + + MODULE_DESCRIPTION("sc7180 ASoC Machine Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c +index 6e5f194bc34b06..d5cc967992d161 100644 +--- a/sound/soc/qcom/sc8280xp.c ++++ b/sound/soc/qcom/sc8280xp.c +@@ -174,4 +174,4 @@ static struct platform_driver snd_sc8280xp_driver = { + module_platform_driver(snd_sc8280xp_driver); + MODULE_AUTHOR("Srinivas Kandagatla substreams) + return -ENOMEM; + ++ /* ++ * Initialize critical substream fields early in case we hit an ++ * error path and end up trying to clean up uninitialized structures ++ * elsewhere. ++ */ ++ for (i = 0; i < snd->nsubstreams; ++i) { ++ struct virtio_pcm_substream *vss = &snd->substreams[i]; ++ ++ vss->snd = snd; ++ vss->sid = i; ++ INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); ++ init_waitqueue_head(&vss->msg_empty); ++ spin_lock_init(&vss->lock); ++ } ++ + info = kcalloc(snd->nsubstreams, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; +@@ -350,12 +365,6 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd) + struct virtio_pcm_substream *vss = &snd->substreams[i]; + struct virtio_pcm *vpcm; + +- vss->snd = snd; +- vss->sid = i; +- INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); +- init_waitqueue_head(&vss->msg_empty); +- spin_lock_init(&vss->lock); +- + rc = virtsnd_pcm_build_hw(vss, &info[i]); + if (rc) + goto on_exit; +diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c +index 90ae2ea61324cc..174e076e56af2a 100644 +--- a/tools/bpf/bpftool/prog.c ++++ b/tools/bpf/bpftool/prog.c +@@ -1924,6 +1924,7 @@ static int do_loader(int argc, char **argv) + + obj = bpf_object__open_file(file, &open_opts); + if (!obj) { ++ err = -1; + p_err("failed to open object file"); + goto err_close_obj; + } +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 8ba5bcfd5cd572..a1b14378bab045 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1225,12 +1225,15 @@ static const char *uaccess_safe_builtin[] = { + "__ubsan_handle_load_invalid_value", + /* STACKLEAK */ + "stackleak_track_stack", ++ /* TRACE_BRANCH_PROFILING */ ++ "ftrace_likely_update", ++ /* STACKPROTECTOR */ ++ "__stack_chk_fail", + /* misc */ + "csum_partial_copy_generic", + "copy_mc_fragile", + "copy_mc_fragile_handle_tail", + "copy_mc_enhanced_fast_string", +- "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */ + "rep_stos_alternative", + "rep_movs_alternative", + "__copy_user_nocache", +@@ -1549,6 +1552,8 @@ static int add_jump_destinations(struct objtool_file *file) + unsigned long dest_off; + + for_each_insn(file, insn) { ++ struct symbol *func = insn_func(insn); ++ + if (insn->jump_dest) { + /* + * handle_group_alt() may have previously set +@@ -1572,7 +1577,7 @@ static int add_jump_destinations(struct objtool_file *file) + } else if (reloc->sym->return_thunk) { + add_return_call(file, insn, true); + continue; +- } else if (insn_func(insn)) { ++ } else if (func) { + /* + * External sibling call or internal sibling call with + * STT_FUNC reloc. +@@ -1605,6 +1610,15 @@ static int add_jump_destinations(struct objtool_file *file) + continue; + } + ++ /* ++ * GCOV/KCOV dead code can jump to the end of the ++ * function/section. ++ */ ++ if (file->ignore_unreachables && func && ++ dest_sec == insn->sec && ++ dest_off == func->offset + func->len) ++ continue; ++ + WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", + dest_sec->name, dest_off); + return -1; +@@ -1613,8 +1627,7 @@ static int add_jump_destinations(struct objtool_file *file) + /* + * Cross-function jump. + */ +- if (insn_func(insn) && insn_func(jump_dest) && +- insn_func(insn) != insn_func(jump_dest)) { ++ if (func && insn_func(jump_dest) && func != insn_func(jump_dest)) { + + /* + * For GCC 8+, create parent/child links for any cold +@@ -1631,10 +1644,10 @@ static int add_jump_destinations(struct objtool_file *file) + * case where the parent function's only reference to a + * subfunction is through a jump table. + */ +- if (!strstr(insn_func(insn)->name, ".cold") && ++ if (!strstr(func->name, ".cold") && + strstr(insn_func(jump_dest)->name, ".cold")) { +- insn_func(insn)->cfunc = insn_func(jump_dest); +- insn_func(jump_dest)->pfunc = insn_func(insn); ++ func->cfunc = insn_func(jump_dest); ++ insn_func(jump_dest)->pfunc = func; + } + } + +@@ -3569,6 +3582,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + !strncmp(func->name, "__pfx_", 6)) + return 0; + ++ if (file->ignore_unreachables) ++ return 0; ++ + WARN("%s() falls through to next function %s()", + func->name, insn_func(insn)->name); + return 1; +@@ -3788,6 +3804,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + if (!next_insn) { + if (state.cfi.cfa.base == CFI_UNDEFINED) + return 0; ++ if (file->ignore_unreachables) ++ return 0; ++ + WARN("%s: unexpected end of section", sec->name); + return 1; + } +@@ -3940,6 +3959,9 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) + break; + } + ++ if (insn->dead_end) ++ return 0; ++ + if (!next) { + WARN_INSN(insn, "teh end!"); + return -1; +diff --git a/tools/testing/selftests/mincore/mincore_selftest.c b/tools/testing/selftests/mincore/mincore_selftest.c +index e949a43a614508..efabfcbe0b498c 100644 +--- a/tools/testing/selftests/mincore/mincore_selftest.c ++++ b/tools/testing/selftests/mincore/mincore_selftest.c +@@ -261,9 +261,6 @@ TEST(check_file_mmap) + TH_LOG("No read-ahead pages found in memory"); + } + +- EXPECT_LT(i, vec_size) { +- TH_LOG("Read-ahead pages reached the end of the file"); +- } + /* + * End of the readahead window. The rest of the pages shouldn't + * be in memory. +diff --git a/tools/testing/selftests/ublk/test_stripe_04.sh b/tools/testing/selftests/ublk/test_stripe_04.sh +new file mode 100755 +index 00000000000000..1f2b642381d179 +--- /dev/null ++++ b/tools/testing/selftests/ublk/test_stripe_04.sh +@@ -0,0 +1,24 @@ ++#!/bin/bash ++# SPDX-License-Identifier: GPL-2.0 ++ ++. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh ++ ++TID="stripe_04" ++ERR_CODE=0 ++ ++_prep_test "stripe" "mkfs & mount & umount on zero copy" ++ ++backfile_0=$(_create_backfile 256M) ++backfile_1=$(_create_backfile 256M) ++dev_id=$(_add_ublk_dev -t stripe -z -q 2 "$backfile_0" "$backfile_1") ++_check_add_dev $TID $? "$backfile_0" "$backfile_1" ++ ++_mkfs_mount_test /dev/ublkb"${dev_id}" ++ERR_CODE=$? ++ ++_cleanup_test "stripe" ++ ++_remove_backfile "$backfile_0" ++_remove_backfile "$backfile_1" ++ ++_show_result $TID $ERR_CODE diff --git a/patch/kernel/archive/odroidxu4-6.6/patch-6.6.89-90.patch b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.89-90.patch new file mode 100644 index 000000000000..ef784cc2c4ca --- /dev/null +++ b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.89-90.patch @@ -0,0 +1,5797 @@ +diff --git a/Makefile b/Makefile +index 23e90df5785c84..587a1586e76db8 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 89 ++SUBLEVEL = 90 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi +index f2386dcb9ff2c0..dda4fa91b2f2cc 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi +@@ -40,6 +40,9 @@ ethphy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&gpio4>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; ++ micrel,led-mode = <1>; ++ clocks = <&clks IMX6UL_CLK_ENET_REF>; ++ clock-names = "rmii-ref"; + status = "okay"; + }; + }; +diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi +index 5268a43218415f..ce5409acae1ce0 100644 +--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi ++++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi +@@ -73,14 +73,13 @@ scmi_reset: protocol@16 { + }; + + intc: interrupt-controller@4ac00000 { +- compatible = "arm,cortex-a7-gic"; ++ compatible = "arm,gic-400"; + #interrupt-cells = <3>; +- #address-cells = <1>; + interrupt-controller; + reg = <0x0 0x4ac10000 0x0 0x1000>, +- <0x0 0x4ac20000 0x0 0x2000>, +- <0x0 0x4ac40000 0x0 0x2000>, +- <0x0 0x4ac60000 0x0 0x2000>; ++ <0x0 0x4ac20000 0x0 0x20000>, ++ <0x0 0x4ac40000 0x0 0x20000>, ++ <0x0 0x4ac60000 0x0 0x20000>; + }; + + psci { +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index ecfbff6991bb5d..edc4c727783d82 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -879,10 +879,12 @@ static u8 spectre_bhb_loop_affected(void) + static const struct midr_range spectre_bhb_k132_list[] = { + MIDR_ALL_VERSIONS(MIDR_CORTEX_X3), + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2), ++ {}, + }; + static const struct midr_range spectre_bhb_k38_list[] = { + MIDR_ALL_VERSIONS(MIDR_CORTEX_A715), + MIDR_ALL_VERSIONS(MIDR_CORTEX_A720), ++ {}, + }; + static const struct midr_range spectre_bhb_k32_list[] = { + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78), +diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c +index 6ce427b58836c5..ecd27b48d61f9d 100644 +--- a/arch/parisc/math-emu/driver.c ++++ b/arch/parisc/math-emu/driver.c +@@ -103,9 +103,19 @@ handle_fpe(struct pt_regs *regs) + + memcpy(regs->fr, frcopy, sizeof regs->fr); + if (signalcode != 0) { +- force_sig_fault(signalcode >> 24, signalcode & 0xffffff, +- (void __user *) regs->iaoq[0]); +- return -1; ++ int sig = signalcode >> 24; ++ ++ if (sig == SIGFPE) { ++ /* ++ * Clear floating point trap bit to avoid trapping ++ * again on the first floating-point instruction in ++ * the userspace signal handler. ++ */ ++ regs->fr[0] &= ~(1ULL << 38); ++ } ++ force_sig_fault(sig, signalcode & 0xffffff, ++ (void __user *) regs->iaoq[0]); ++ return -1; + } + + return signalcode ? -1 : 0; +diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper +index 352d7de24018fb..ddb02cf0caaf59 100755 +--- a/arch/powerpc/boot/wrapper ++++ b/arch/powerpc/boot/wrapper +@@ -234,10 +234,8 @@ fi + + # suppress some warnings in recent ld versions + nowarn="-z noexecstack" +-if ! ld_is_lld; then +- if [ "$LD_VERSION" -ge "$(echo 2.39 | ld_version)" ]; then +- nowarn="$nowarn --no-warn-rwx-segments" +- fi ++if "${CROSS}ld" -v --no-warn-rwx-segments >/dev/null 2>&1; then ++ nowarn="$nowarn --no-warn-rwx-segments" + fi + + platformo=$object/"$platform".o +diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c +index c6a4ac766b2bf9..28460e33408084 100644 +--- a/arch/powerpc/mm/book3s64/radix_pgtable.c ++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c +@@ -1056,6 +1056,19 @@ int __meminit radix__vmemmap_populate(unsigned long start, unsigned long end, in + pmd_t *pmd; + pte_t *pte; + ++ /* ++ * Make sure we align the start vmemmap addr so that we calculate ++ * the correct start_pfn in altmap boundary check to decided whether ++ * we should use altmap or RAM based backing memory allocation. Also ++ * the address need to be aligned for set_pte operation. ++ ++ * If the start addr is already PMD_SIZE aligned we will try to use ++ * a pmd mapping. We don't want to be too aggressive here beacause ++ * that will cause more allocations in RAM. So only if the namespace ++ * vmemmap start addr is PMD_SIZE aligned we will use PMD mapping. ++ */ ++ ++ start = ALIGN_DOWN(start, PAGE_SIZE); + for (addr = start; addr < end; addr = next) { + next = pmd_addr_end(addr, end); + +@@ -1081,8 +1094,8 @@ int __meminit radix__vmemmap_populate(unsigned long start, unsigned long end, in + * in altmap block allocation failures, in which case + * we fallback to RAM for vmemmap allocation. + */ +- if (altmap && (!IS_ALIGNED(addr, PMD_SIZE) || +- altmap_cross_boundary(altmap, addr, PMD_SIZE))) { ++ if (!IS_ALIGNED(addr, PMD_SIZE) || (altmap && ++ altmap_cross_boundary(altmap, addr, PMD_SIZE))) { + /* + * make sure we don't create altmap mappings + * covering things outside the device. +diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h +index 9f5d6e14c40553..7228e266b9a1ae 100644 +--- a/arch/riscv/include/asm/patch.h ++++ b/arch/riscv/include/asm/patch.h +@@ -9,7 +9,7 @@ + int patch_insn_write(void *addr, const void *insn, size_t len); + int patch_text_nosync(void *addr, const void *insns, size_t len); + int patch_text_set_nosync(void *addr, u8 c, size_t len); +-int patch_text(void *addr, u32 *insns, int ninsns); ++int patch_text(void *addr, u32 *insns, size_t len); + + extern int riscv_patch_in_stop_machine; + +diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c +index 78387d843aa56b..aeda87240dbc1e 100644 +--- a/arch/riscv/kernel/patch.c ++++ b/arch/riscv/kernel/patch.c +@@ -19,7 +19,7 @@ + struct patch_insn { + void *addr; + u32 *insns; +- int ninsns; ++ size_t len; + atomic_t cpu_count; + }; + +@@ -234,14 +234,10 @@ NOKPROBE_SYMBOL(patch_text_nosync); + static int patch_text_cb(void *data) + { + struct patch_insn *patch = data; +- unsigned long len; +- int i, ret = 0; ++ int ret = 0; + + if (atomic_inc_return(&patch->cpu_count) == num_online_cpus()) { +- for (i = 0; ret == 0 && i < patch->ninsns; i++) { +- len = GET_INSN_LENGTH(patch->insns[i]); +- ret = patch_insn_write(patch->addr + i * len, &patch->insns[i], len); +- } ++ ret = patch_insn_write(patch->addr, patch->insns, patch->len); + /* + * Make sure the patching store is effective *before* we + * increment the counter which releases all waiting CPUs +@@ -262,13 +258,13 @@ static int patch_text_cb(void *data) + } + NOKPROBE_SYMBOL(patch_text_cb); + +-int patch_text(void *addr, u32 *insns, int ninsns) ++int patch_text(void *addr, u32 *insns, size_t len) + { + int ret; + struct patch_insn patch = { + .addr = addr, + .insns = insns, +- .ninsns = ninsns, ++ .len = len, + .cpu_count = ATOMIC_INIT(0), + }; + +diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c +index 4fbc70e823f0fa..297427ffc4e043 100644 +--- a/arch/riscv/kernel/probes/kprobes.c ++++ b/arch/riscv/kernel/probes/kprobes.c +@@ -23,13 +23,13 @@ post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *); + + static void __kprobes arch_prepare_ss_slot(struct kprobe *p) + { ++ size_t len = GET_INSN_LENGTH(p->opcode); + u32 insn = __BUG_INSN_32; +- unsigned long offset = GET_INSN_LENGTH(p->opcode); + +- p->ainsn.api.restore = (unsigned long)p->addr + offset; ++ p->ainsn.api.restore = (unsigned long)p->addr + len; + +- patch_text_nosync(p->ainsn.api.insn, &p->opcode, 1); +- patch_text_nosync((void *)p->ainsn.api.insn + offset, &insn, 1); ++ patch_text_nosync(p->ainsn.api.insn, &p->opcode, len); ++ patch_text_nosync((void *)p->ainsn.api.insn + len, &insn, GET_INSN_LENGTH(insn)); + } + + static void __kprobes arch_prepare_simulate(struct kprobe *p) +@@ -116,16 +116,18 @@ void *alloc_insn_page(void) + /* install breakpoint in text */ + void __kprobes arch_arm_kprobe(struct kprobe *p) + { +- u32 insn = (p->opcode & __INSN_LENGTH_MASK) == __INSN_LENGTH_32 ? +- __BUG_INSN_32 : __BUG_INSN_16; ++ size_t len = GET_INSN_LENGTH(p->opcode); ++ u32 insn = len == 4 ? __BUG_INSN_32 : __BUG_INSN_16; + +- patch_text(p->addr, &insn, 1); ++ patch_text(p->addr, &insn, len); + } + + /* remove breakpoint from text */ + void __kprobes arch_disarm_kprobe(struct kprobe *p) + { +- patch_text(p->addr, &p->opcode, 1); ++ size_t len = GET_INSN_LENGTH(p->opcode); ++ ++ patch_text(p->addr, &p->opcode, len); + } + + void __kprobes arch_remove_kprobe(struct kprobe *p) +diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c +index 26eeb397363193..16eb4cd11cbd67 100644 +--- a/arch/riscv/net/bpf_jit_comp64.c ++++ b/arch/riscv/net/bpf_jit_comp64.c +@@ -14,6 +14,7 @@ + #include "bpf_jit.h" + + #define RV_FENTRY_NINSNS 2 ++#define RV_FENTRY_NBYTES (RV_FENTRY_NINSNS * 4) + + #define RV_REG_TCC RV_REG_A6 + #define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */ +@@ -681,7 +682,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + if (ret) + return ret; + +- if (memcmp(ip, old_insns, RV_FENTRY_NINSNS * 4)) ++ if (memcmp(ip, old_insns, RV_FENTRY_NBYTES)) + return -EFAULT; + + ret = gen_jump_or_nops(new_addr, ip, new_insns, is_call); +@@ -690,8 +691,8 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + + cpus_read_lock(); + mutex_lock(&text_mutex); +- if (memcmp(ip, new_insns, RV_FENTRY_NINSNS * 4)) +- ret = patch_text(ip, new_insns, RV_FENTRY_NINSNS); ++ if (memcmp(ip, new_insns, RV_FENTRY_NBYTES)) ++ ret = patch_text(ip, new_insns, RV_FENTRY_NBYTES); + mutex_unlock(&text_mutex); + cpus_read_unlock(); + +diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c +index 66d5782df18f8c..835c9febb6a854 100644 +--- a/arch/x86/events/intel/core.c ++++ b/arch/x86/events/intel/core.c +@@ -4206,7 +4206,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) + arr[pebs_enable] = (struct perf_guest_switch_msr){ + .msr = MSR_IA32_PEBS_ENABLE, + .host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask, +- .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask, ++ .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask & kvm_pmu->pebs_enable, + }; + + if (arr[pebs_enable].host) { +diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h +index 9b419f0de713cc..e59ded9761663e 100644 +--- a/arch/x86/include/asm/kvm-x86-ops.h ++++ b/arch/x86/include/asm/kvm-x86-ops.h +@@ -48,6 +48,7 @@ KVM_X86_OP(set_idt) + KVM_X86_OP(get_gdt) + KVM_X86_OP(set_gdt) + KVM_X86_OP(sync_dirty_debug_regs) ++KVM_X86_OP(set_dr6) + KVM_X86_OP(set_dr7) + KVM_X86_OP(cache_reg) + KVM_X86_OP(get_rflags) +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index 39672561c6be87..5dfb8cc9616e55 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -1595,6 +1595,7 @@ struct kvm_x86_ops { + void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); + void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); + void (*sync_dirty_debug_regs)(struct kvm_vcpu *vcpu); ++ void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value); + void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value); + void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); + unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index 1d06b8fc15a85c..29c1be65cb71a0 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -2014,11 +2014,11 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd) + svm->asid = sd->next_asid++; + } + +-static void svm_set_dr6(struct vcpu_svm *svm, unsigned long value) ++static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value) + { +- struct vmcb *vmcb = svm->vmcb; ++ struct vmcb *vmcb = to_svm(vcpu)->vmcb; + +- if (svm->vcpu.arch.guest_state_protected) ++ if (vcpu->arch.guest_state_protected) + return; + + if (unlikely(value != vmcb->save.dr6)) { +@@ -4220,10 +4220,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) + * Run with all-zero DR6 unless needed, so that we can get the exact cause + * of a #DB. + */ +- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) +- svm_set_dr6(svm, vcpu->arch.dr6); +- else +- svm_set_dr6(svm, DR6_ACTIVE_LOW); ++ if (likely(!(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))) ++ svm_set_dr6(vcpu, DR6_ACTIVE_LOW); + + clgi(); + kvm_load_guest_xsave_state(vcpu); +@@ -5002,6 +5000,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { + .set_idt = svm_set_idt, + .get_gdt = svm_get_gdt, + .set_gdt = svm_set_gdt, ++ .set_dr6 = svm_set_dr6, + .set_dr7 = svm_set_dr7, + .sync_dirty_debug_regs = svm_sync_dirty_debug_regs, + .cache_reg = svm_cache_reg, +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index 52098844290ad4..e5a2c230110ea4 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -5617,6 +5617,12 @@ static void vmx_sync_dirty_debug_regs(struct kvm_vcpu *vcpu) + set_debugreg(DR6_RESERVED, 6); + } + ++static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val) ++{ ++ lockdep_assert_irqs_disabled(); ++ set_debugreg(vcpu->arch.dr6, 6); ++} ++ + static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val) + { + vmcs_writel(GUEST_DR7, val); +@@ -7356,10 +7362,6 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu) + vmx->loaded_vmcs->host_state.cr4 = cr4; + } + +- /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */ +- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) +- set_debugreg(vcpu->arch.dr6, 6); +- + /* When single-stepping over STI and MOV SS, we must clear the + * corresponding interruptibility bits in the guest state. Otherwise + * vmentry fails as it then expects bit 14 (BS) in pending debug +@@ -8292,6 +8294,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { + .set_idt = vmx_set_idt, + .get_gdt = vmx_get_gdt, + .set_gdt = vmx_set_gdt, ++ .set_dr6 = vmx_set_dr6, + .set_dr7 = vmx_set_dr7, + .sync_dirty_debug_regs = vmx_sync_dirty_debug_regs, + .cache_reg = vmx_cache_reg, +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index f67fe8a65820c8..1eeb01afa40ba9 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -10772,6 +10772,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) + set_debugreg(vcpu->arch.eff_db[1], 1); + set_debugreg(vcpu->arch.eff_db[2], 2); + set_debugreg(vcpu->arch.eff_db[3], 3); ++ /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */ ++ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) ++ static_call(kvm_x86_set_dr6)(vcpu, vcpu->arch.dr6); + } else if (unlikely(hw_breakpoint_active())) { + set_debugreg(0, 7); + } +diff --git a/drivers/base/module.c b/drivers/base/module.c +index a33663d92256d8..955582b34e54af 100644 +--- a/drivers/base/module.c ++++ b/drivers/base/module.c +@@ -42,16 +42,13 @@ int module_add_driver(struct module *mod, struct device_driver *drv) + if (mod) + mk = &mod->mkobj; + else if (drv->mod_name) { +- struct kobject *mkobj; +- +- /* Lookup built-in module entry in /sys/modules */ +- mkobj = kset_find_obj(module_kset, drv->mod_name); +- if (mkobj) { +- mk = container_of(mkobj, struct module_kobject, kobj); ++ /* Lookup or create built-in module entry in /sys/modules */ ++ mk = lookup_or_create_module_kobject(drv->mod_name); ++ if (mk) { + /* remember our module structure */ + drv->p->mkobj = mk; +- /* kset_find_obj took a reference */ +- kobject_put(mkobj); ++ /* lookup_or_create_module_kobject took a reference */ ++ kobject_put(&mk->kobj); + } + } + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index bc3f63f1ccd863..d6195565ef7aeb 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -3521,22 +3521,16 @@ static void btusb_coredump_qca(struct hci_dev *hdev) + bt_dev_err(hdev, "%s: triggle crash failed (%d)", __func__, err); + } + +-/* +- * ==0: not a dump pkt. +- * < 0: fails to handle a dump pkt +- * > 0: otherwise. +- */ ++/* Return: 0 on success, negative errno on failure. */ + static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- int ret = 1; ++ int ret = 0; + u8 pkt_type; + u8 *sk_ptr; + unsigned int sk_len; + u16 seqno; + u32 dump_size; + +- struct hci_event_hdr *event_hdr; +- struct hci_acl_hdr *acl_hdr; + struct qca_dump_hdr *dump_hdr; + struct btusb_data *btdata = hci_get_drvdata(hdev); + struct usb_device *udev = btdata->udev; +@@ -3546,30 +3540,14 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + sk_len = skb->len; + + if (pkt_type == HCI_ACLDATA_PKT) { +- acl_hdr = hci_acl_hdr(skb); +- if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE) +- return 0; + sk_ptr += HCI_ACL_HDR_SIZE; + sk_len -= HCI_ACL_HDR_SIZE; +- event_hdr = (struct hci_event_hdr *)sk_ptr; +- } else { +- event_hdr = hci_event_hdr(skb); + } + +- if ((event_hdr->evt != HCI_VENDOR_PKT) +- || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) +- return 0; +- + sk_ptr += HCI_EVENT_HDR_SIZE; + sk_len -= HCI_EVENT_HDR_SIZE; + + dump_hdr = (struct qca_dump_hdr *)sk_ptr; +- if ((sk_len < offsetof(struct qca_dump_hdr, data)) +- || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) +- || (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) +- return 0; +- +- /*it is dump pkt now*/ + seqno = le16_to_cpu(dump_hdr->seqno); + if (seqno == 0) { + set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags); +@@ -3643,17 +3621,84 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + return ret; + } + ++/* Return: true if the ACL packet is a dump packet, false otherwise. */ ++static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ u8 *sk_ptr; ++ unsigned int sk_len; ++ ++ struct hci_event_hdr *event_hdr; ++ struct hci_acl_hdr *acl_hdr; ++ struct qca_dump_hdr *dump_hdr; ++ ++ sk_ptr = skb->data; ++ sk_len = skb->len; ++ ++ acl_hdr = hci_acl_hdr(skb); ++ if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE) ++ return false; ++ ++ sk_ptr += HCI_ACL_HDR_SIZE; ++ sk_len -= HCI_ACL_HDR_SIZE; ++ event_hdr = (struct hci_event_hdr *)sk_ptr; ++ ++ if ((event_hdr->evt != HCI_VENDOR_PKT) || ++ (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) ++ return false; ++ ++ sk_ptr += HCI_EVENT_HDR_SIZE; ++ sk_len -= HCI_EVENT_HDR_SIZE; ++ ++ dump_hdr = (struct qca_dump_hdr *)sk_ptr; ++ if ((sk_len < offsetof(struct qca_dump_hdr, data)) || ++ (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ return false; ++ ++ return true; ++} ++ ++/* Return: true if the event packet is a dump packet, false otherwise. */ ++static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ u8 *sk_ptr; ++ unsigned int sk_len; ++ ++ struct hci_event_hdr *event_hdr; ++ struct qca_dump_hdr *dump_hdr; ++ ++ sk_ptr = skb->data; ++ sk_len = skb->len; ++ ++ event_hdr = hci_event_hdr(skb); ++ ++ if ((event_hdr->evt != HCI_VENDOR_PKT) ++ || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) ++ return false; ++ ++ sk_ptr += HCI_EVENT_HDR_SIZE; ++ sk_len -= HCI_EVENT_HDR_SIZE; ++ ++ dump_hdr = (struct qca_dump_hdr *)sk_ptr; ++ if ((sk_len < offsetof(struct qca_dump_hdr, data)) || ++ (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ return false; ++ ++ return true; ++} ++ + static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- if (handle_dump_pkt_qca(hdev, skb)) +- return 0; ++ if (acl_pkt_is_dump_qca(hdev, skb)) ++ return handle_dump_pkt_qca(hdev, skb); + return hci_recv_frame(hdev, skb); + } + + static int btusb_recv_evt_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- if (handle_dump_pkt_qca(hdev, skb)) +- return 0; ++ if (evt_pkt_is_dump_qca(hdev, skb)) ++ return handle_dump_pkt_qca(hdev, skb); + return hci_recv_frame(hdev, skb); + } + +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 0ac0998152ce81..6682f422cadd90 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -534,16 +534,18 @@ void cpufreq_disable_fast_switch(struct cpufreq_policy *policy) + EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch); + + static unsigned int __resolve_freq(struct cpufreq_policy *policy, +- unsigned int target_freq, unsigned int relation) ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ unsigned int relation) + { + unsigned int idx; + +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (!policy->freq_table) + return target_freq; + +- idx = cpufreq_frequency_table_target(policy, target_freq, relation); ++ idx = cpufreq_frequency_table_target(policy, target_freq, min, max, relation); + policy->cached_resolved_idx = idx; + policy->cached_target_freq = target_freq; + return policy->freq_table[idx].frequency; +@@ -563,7 +565,21 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy, + unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy, + unsigned int target_freq) + { +- return __resolve_freq(policy, target_freq, CPUFREQ_RELATION_LE); ++ unsigned int min = READ_ONCE(policy->min); ++ unsigned int max = READ_ONCE(policy->max); ++ ++ /* ++ * If this function runs in parallel with cpufreq_set_policy(), it may ++ * read policy->min before the update and policy->max after the update ++ * or the other way around, so there is no ordering guarantee. ++ * ++ * Resolve this by always honoring the max (in case it comes from ++ * thermal throttling or similar). ++ */ ++ if (unlikely(min > max)) ++ min = max; ++ ++ return __resolve_freq(policy, target_freq, min, max, CPUFREQ_RELATION_LE); + } + EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq); + +@@ -2335,7 +2351,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, + if (cpufreq_disabled()) + return -ENODEV; + +- target_freq = __resolve_freq(policy, target_freq, relation); ++ target_freq = __resolve_freq(policy, target_freq, policy->min, ++ policy->max, relation); + + pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", + policy->cpu, target_freq, relation, old_target_freq); +@@ -2625,11 +2642,18 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, + * Resolve policy min/max to available frequencies. It ensures + * no frequency resolution will neither overshoot the requested maximum + * nor undershoot the requested minimum. ++ * ++ * Avoid storing intermediate values in policy->max or policy->min and ++ * compiler optimizations around them because they may be accessed ++ * concurrently by cpufreq_driver_resolve_freq() during the update. + */ +- policy->min = new_data.min; +- policy->max = new_data.max; +- policy->min = __resolve_freq(policy, policy->min, CPUFREQ_RELATION_L); +- policy->max = __resolve_freq(policy, policy->max, CPUFREQ_RELATION_H); ++ WRITE_ONCE(policy->max, __resolve_freq(policy, new_data.max, ++ new_data.min, new_data.max, ++ CPUFREQ_RELATION_H)); ++ new_data.min = __resolve_freq(policy, new_data.min, new_data.min, ++ new_data.max, CPUFREQ_RELATION_L); ++ WRITE_ONCE(policy->min, new_data.min > policy->max ? policy->max : new_data.min); ++ + trace_cpu_frequency_limits(policy); + + policy->cached_target_freq = UINT_MAX; +diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c +index c52d19d67557f5..65cbd5ecbaf83d 100644 +--- a/drivers/cpufreq/cpufreq_ondemand.c ++++ b/drivers/cpufreq/cpufreq_ondemand.c +@@ -77,7 +77,8 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy, + return freq_next; + } + +- index = cpufreq_frequency_table_target(policy, freq_next, relation); ++ index = cpufreq_frequency_table_target(policy, freq_next, policy->min, ++ policy->max, relation); + freq_req = freq_table[index].frequency; + freq_reduc = freq_req * od_tuners->powersave_bias / 1000; + freq_avg = freq_req - freq_reduc; +diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c +index c17dc51a5a022d..94de089b145394 100644 +--- a/drivers/cpufreq/freq_table.c ++++ b/drivers/cpufreq/freq_table.c +@@ -116,8 +116,8 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy) + EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); + + int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, +- unsigned int target_freq, +- unsigned int relation) ++ unsigned int target_freq, unsigned int min, ++ unsigned int max, unsigned int relation) + { + struct cpufreq_frequency_table optimal = { + .driver_data = ~0, +@@ -148,7 +148,7 @@ int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, + cpufreq_for_each_valid_entry_idx(pos, table, i) { + freq = pos->frequency; + +- if ((freq < policy->min) || (freq > policy->max)) ++ if (freq < min || freq > max) + continue; + if (freq == target_freq) { + optimal.driver_data = i; +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 8b31cd54bdb6de..e04fd1a7e9aaea 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -98,7 +98,7 @@ static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id) + if (status & priv->ecc_stat_ce_mask) { + regmap_read(drvdata->mc_vbase, priv->ecc_saddr_offset, + &err_addr); +- if (priv->ecc_uecnt_offset) ++ if (priv->ecc_cecnt_offset) + regmap_read(drvdata->mc_vbase, priv->ecc_cecnt_offset, + &err_count); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count, +@@ -1015,9 +1015,6 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, + } + } + +- /* Interrupt mode set to every SBERR */ +- regmap_write(ecc_mgr_map, ALTR_A10_ECC_INTMODE_OFST, +- ALTR_A10_ECC_INTMODE); + /* Enable ECC */ + ecc_set_bits(ecc_ctrl_en_mask, (ecc_block_base + + ALTR_A10_ECC_CTRL_OFST)); +@@ -2138,6 +2135,10 @@ static int altr_edac_a10_probe(struct platform_device *pdev) + return PTR_ERR(edac->ecc_mgr_map); + } + ++ /* Set irq mask for DDR SBE to avoid any pending irq before registration */ ++ regmap_write(edac->ecc_mgr_map, A10_SYSMGR_ECC_INTMASK_SET_OFST, ++ (A10_SYSMGR_ECC_INTMASK_SDMMCB | A10_SYSMGR_ECC_INTMASK_DDR0)); ++ + edac->irq_chip.name = pdev->dev.of_node->name; + edac->irq_chip.irq_mask = a10_eccmgr_irq_mask; + edac->irq_chip.irq_unmask = a10_eccmgr_irq_unmask; +diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h +index 3727e72c8c2e70..7248d24c4908d7 100644 +--- a/drivers/edac/altera_edac.h ++++ b/drivers/edac/altera_edac.h +@@ -249,6 +249,8 @@ struct altr_sdram_mc_data { + #define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94 + #define A10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98 + #define A10_SYSMGR_ECC_INTMASK_OCRAM BIT(1) ++#define A10_SYSMGR_ECC_INTMASK_SDMMCB BIT(16) ++#define A10_SYSMGR_ECC_INTMASK_DDR0 BIT(17) + + #define A10_SYSMGR_ECC_INTSTAT_SERR_OFST 0x9C + #define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0 +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 7cd6b1564e8018..7c2db3f017651b 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -225,7 +225,8 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, + memcpy(buffer + idx, drv_info->rx_buffer + idx * sz, + buf_sz); + +- ffa_rx_release(); ++ if (!(flags & PARTITION_INFO_GET_RETURN_COUNT_ONLY)) ++ ffa_rx_release(); + + mutex_unlock(&drv_info->rx_lock); + +diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c +index dcf774d3edfe4c..51eeaf14367dac 100644 +--- a/drivers/firmware/arm_scmi/bus.c ++++ b/drivers/firmware/arm_scmi/bus.c +@@ -240,6 +240,9 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent, + if (!dev) + return NULL; + ++ /* Drop the refcnt bumped implicitly by device_find_child */ ++ put_device(dev); ++ + return to_scmi_dev(dev); + } + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +index 2ad9f900a85749..a048022d9865a7 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +@@ -172,7 +172,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, + struct mod_hdcp_display_adjustment display_adjust; + unsigned int conn_index = aconnector->base.index; + +- mutex_lock(&hdcp_w->mutex); ++ guard(mutex)(&hdcp_w->mutex); ++ drm_connector_get(&aconnector->base); ++ if (hdcp_w->aconnector[conn_index]) ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); + hdcp_w->aconnector[conn_index] = aconnector; + + memset(&link_adjust, 0, sizeof(link_adjust)); +@@ -209,7 +212,6 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, + mod_hdcp_update_display(&hdcp_w->hdcp, conn_index, &link_adjust, &display_adjust, &hdcp_w->output); + + process_output(hdcp_w); +- mutex_unlock(&hdcp_w->mutex); + } + + static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, +@@ -220,8 +222,7 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, + struct drm_connector_state *conn_state = aconnector->base.state; + unsigned int conn_index = aconnector->base.index; + +- mutex_lock(&hdcp_w->mutex); +- hdcp_w->aconnector[conn_index] = aconnector; ++ guard(mutex)(&hdcp_w->mutex); + + /* the removal of display will invoke auth reset -> hdcp destroy and + * we'd expect the Content Protection (CP) property changed back to +@@ -237,9 +238,11 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, + } + + mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output); +- ++ if (hdcp_w->aconnector[conn_index]) { ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); ++ hdcp_w->aconnector[conn_index] = NULL; ++ } + process_output(hdcp_w); +- mutex_unlock(&hdcp_w->mutex); + } + + void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index) +@@ -247,7 +250,7 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde + struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; + unsigned int conn_index; + +- mutex_lock(&hdcp_w->mutex); ++ guard(mutex)(&hdcp_w->mutex); + + mod_hdcp_reset_connection(&hdcp_w->hdcp, &hdcp_w->output); + +@@ -256,11 +259,13 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde + for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) { + hdcp_w->encryption_status[conn_index] = + MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; ++ if (hdcp_w->aconnector[conn_index]) { ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); ++ hdcp_w->aconnector[conn_index] = NULL; ++ } + } + + process_output(hdcp_w); +- +- mutex_unlock(&hdcp_w->mutex); + } + + void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, unsigned int link_index) +@@ -277,7 +282,7 @@ static void event_callback(struct work_struct *work) + hdcp_work = container_of(to_delayed_work(work), struct hdcp_workqueue, + callback_dwork); + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + cancel_delayed_work(&hdcp_work->callback_dwork); + +@@ -285,8 +290,6 @@ static void event_callback(struct work_struct *work) + &hdcp_work->output); + + process_output(hdcp_work); +- +- mutex_unlock(&hdcp_work->mutex); + } + + static void event_property_update(struct work_struct *work) +@@ -323,7 +326,7 @@ static void event_property_update(struct work_struct *work) + continue; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + if (conn_state->commit) { + ret = wait_for_completion_interruptible_timeout(&conn_state->commit->hw_done, +@@ -355,7 +358,6 @@ static void event_property_update(struct work_struct *work) + drm_hdcp_update_content_protection(connector, + DRM_MODE_CONTENT_PROTECTION_DESIRED); + } +- mutex_unlock(&hdcp_work->mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); + } + } +@@ -368,7 +370,7 @@ static void event_property_validate(struct work_struct *work) + struct amdgpu_dm_connector *aconnector; + unsigned int conn_index; + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; + conn_index++) { +@@ -408,8 +410,6 @@ static void event_property_validate(struct work_struct *work) + schedule_work(&hdcp_work->property_update_work); + } + } +- +- mutex_unlock(&hdcp_work->mutex); + } + + static void event_watchdog_timer(struct work_struct *work) +@@ -420,7 +420,7 @@ static void event_watchdog_timer(struct work_struct *work) + struct hdcp_workqueue, + watchdog_timer_dwork); + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + cancel_delayed_work(&hdcp_work->watchdog_timer_dwork); + +@@ -429,8 +429,6 @@ static void event_watchdog_timer(struct work_struct *work) + &hdcp_work->output); + + process_output(hdcp_work); +- +- mutex_unlock(&hdcp_work->mutex); + } + + static void event_cpirq(struct work_struct *work) +@@ -439,13 +437,11 @@ static void event_cpirq(struct work_struct *work) + + hdcp_work = container_of(work, struct hdcp_workqueue, cpirq_work); + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + mod_hdcp_process_event(&hdcp_work->hdcp, MOD_HDCP_EVENT_CPIRQ, &hdcp_work->output); + + process_output(hdcp_work); +- +- mutex_unlock(&hdcp_work->mutex); + } + + void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work) +@@ -479,7 +475,7 @@ static bool enable_assr(void *handle, struct dc_link *link) + + dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.context.mem_context.shared_buf; + +- mutex_lock(&psp->dtm_context.mutex); ++ guard(mutex)(&psp->dtm_context.mutex); + memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory)); + + dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE; +@@ -494,8 +490,6 @@ static bool enable_assr(void *handle, struct dc_link *link) + res = false; + } + +- mutex_unlock(&psp->dtm_context.mutex); +- + return res; + } + +@@ -504,6 +498,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) + struct hdcp_workqueue *hdcp_work = handle; + struct amdgpu_dm_connector *aconnector = config->dm_stream_ctx; + int link_index = aconnector->dc_link->link_index; ++ unsigned int conn_index = aconnector->base.index; + struct mod_hdcp_display *display = &hdcp_work[link_index].display; + struct mod_hdcp_link *link = &hdcp_work[link_index].link; + struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; +@@ -557,13 +552,14 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) + (!!aconnector->base.state) ? + aconnector->base.state->hdcp_content_type : -1); + +- mutex_lock(&hdcp_w->mutex); ++ guard(mutex)(&hdcp_w->mutex); + + mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output); +- ++ drm_connector_get(&aconnector->base); ++ if (hdcp_w->aconnector[conn_index]) ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); ++ hdcp_w->aconnector[conn_index] = aconnector; + process_output(hdcp_w); +- mutex_unlock(&hdcp_w->mutex); +- + } + + /** +diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c +index 1d22dba69b2753..b943221b238f87 100644 +--- a/drivers/gpu/drm/drm_file.c ++++ b/drivers/gpu/drm/drm_file.c +@@ -1015,6 +1015,10 @@ void drm_show_fdinfo(struct seq_file *m, struct file *f) + struct drm_file *file = f->private_data; + struct drm_device *dev = file->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); ++ int idx; ++ ++ if (!drm_dev_enter(dev, &idx)) ++ return; + + drm_printf(&p, "drm-driver:\t%s\n", dev->driver->name); + drm_printf(&p, "drm-client-id:\t%llu\n", file->client_id); +@@ -1029,6 +1033,8 @@ void drm_show_fdinfo(struct seq_file *m, struct file *f) + + if (dev->driver->show_fdinfo) + dev->driver->show_fdinfo(&p, file); ++ ++ drm_dev_exit(idx); + } + EXPORT_SYMBOL(drm_show_fdinfo); + +diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h +index 298ad38e6c7df6..c36d956b9b824f 100644 +--- a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h ++++ b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h +@@ -25,6 +25,7 @@ int intel_pxp_gsccs_init(struct intel_pxp *pxp); + + int intel_pxp_gsccs_create_session(struct intel_pxp *pxp, int arb_session_id); + void intel_pxp_gsccs_end_arb_fw_session(struct intel_pxp *pxp, u32 arb_session_id); ++bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp); + + #else + static inline void intel_pxp_gsccs_fini(struct intel_pxp *pxp) +@@ -36,8 +37,11 @@ static inline int intel_pxp_gsccs_init(struct intel_pxp *pxp) + return 0; + } + +-#endif ++static inline bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp) ++{ ++ return false; ++} + +-bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp); ++#endif + + #endif /*__INTEL_PXP_GSCCS_H__ */ +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index 2a942dc6a6dc23..2a82119eb58ed8 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -790,13 +790,13 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, + FREQ_1000_1001(params[i].pixel_freq)); + DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", + i, params[i].phy_freq, +- FREQ_1000_1001(params[i].phy_freq/1000)*1000); ++ FREQ_1000_1001(params[i].phy_freq/10)*10); + /* Match strict frequency */ + if (phy_freq == params[i].phy_freq && + vclk_freq == params[i].vclk_freq) + return MODE_OK; + /* Match 1000/1001 variant */ +- if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/1000)*1000) && ++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && + vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) + return MODE_OK; + } +@@ -1070,7 +1070,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + + for (freq = 0 ; params[freq].pixel_freq ; ++freq) { + if ((phy_freq == params[freq].phy_freq || +- phy_freq == FREQ_1000_1001(params[freq].phy_freq/1000)*1000) && ++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && + (vclk_freq == params[freq].vclk_freq || + vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { + if (vclk_freq != params[freq].vclk_freq) +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c +index 03eacb22648ef7..1bfa312d6fb857 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.c ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.c +@@ -90,7 +90,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) + while (!list_empty(&fctx->pending)) { + fence = list_entry(fctx->pending.next, typeof(*fence), head); + +- if (error) ++ if (error && !dma_fence_is_signaled_locked(&fence->base)) + dma_fence_set_error(&fence->base, error); + + if (nouveau_fence_signal(fence)) +diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c +index 5d4f04a3c6d322..b44b36bd565ea4 100644 +--- a/drivers/i2c/busses/i2c-imx-lpi2c.c ++++ b/drivers/i2c/busses/i2c-imx-lpi2c.c +@@ -616,9 +616,9 @@ static int lpi2c_imx_probe(struct platform_device *pdev) + return 0; + + rpm_disable: +- pm_runtime_put(&pdev->dev); +- pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); + + return ret; + } +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index ef3fae113dd643..2e7a12f306510c 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -3682,6 +3682,14 @@ static int __init parse_ivrs_acpihid(char *str) + while (*uid == '0' && *(uid + 1)) + uid++; + ++ if (strlen(hid) >= ACPIHID_HID_LEN) { ++ pr_err("Invalid command line: hid is too long\n"); ++ return 1; ++ } else if (strlen(uid) >= ACPIHID_UID_LEN) { ++ pr_err("Invalid command line: uid is too long\n"); ++ return 1; ++ } ++ + i = early_acpihid_map_size++; + memcpy(early_acpihid_map[i].hid, hid, strlen(hid)); + memcpy(early_acpihid_map[i].uid, uid, strlen(uid)); +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +index 6cecbac0e6babf..f2260f45728e79 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +@@ -1443,26 +1443,37 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid) + return 0; + } + ++static int arm_smmu_streams_cmp_key(const void *lhs, const struct rb_node *rhs) ++{ ++ struct arm_smmu_stream *stream_rhs = ++ rb_entry(rhs, struct arm_smmu_stream, node); ++ const u32 *sid_lhs = lhs; ++ ++ if (*sid_lhs < stream_rhs->id) ++ return -1; ++ if (*sid_lhs > stream_rhs->id) ++ return 1; ++ return 0; ++} ++ ++static int arm_smmu_streams_cmp_node(struct rb_node *lhs, ++ const struct rb_node *rhs) ++{ ++ return arm_smmu_streams_cmp_key( ++ &rb_entry(lhs, struct arm_smmu_stream, node)->id, rhs); ++} ++ + static struct arm_smmu_master * + arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid) + { + struct rb_node *node; +- struct arm_smmu_stream *stream; + + lockdep_assert_held(&smmu->streams_mutex); + +- node = smmu->streams.rb_node; +- while (node) { +- stream = rb_entry(node, struct arm_smmu_stream, node); +- if (stream->id < sid) +- node = node->rb_right; +- else if (stream->id > sid) +- node = node->rb_left; +- else +- return stream->master; +- } +- +- return NULL; ++ node = rb_find(&sid, &smmu->streams, arm_smmu_streams_cmp_key); ++ if (!node) ++ return NULL; ++ return rb_entry(node, struct arm_smmu_stream, node)->master; + } + + /* IRQ and event handlers */ +@@ -2575,8 +2586,6 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + { + int i; + int ret = 0; +- struct arm_smmu_stream *new_stream, *cur_stream; +- struct rb_node **new_node, *parent_node = NULL; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev); + + master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams), +@@ -2587,9 +2596,10 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + + mutex_lock(&smmu->streams_mutex); + for (i = 0; i < fwspec->num_ids; i++) { ++ struct arm_smmu_stream *new_stream = &master->streams[i]; ++ struct rb_node *existing; + u32 sid = fwspec->ids[i]; + +- new_stream = &master->streams[i]; + new_stream->id = sid; + new_stream->master = master; + +@@ -2598,28 +2608,23 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + break; + + /* Insert into SID tree */ +- new_node = &(smmu->streams.rb_node); +- while (*new_node) { +- cur_stream = rb_entry(*new_node, struct arm_smmu_stream, +- node); +- parent_node = *new_node; +- if (cur_stream->id > new_stream->id) { +- new_node = &((*new_node)->rb_left); +- } else if (cur_stream->id < new_stream->id) { +- new_node = &((*new_node)->rb_right); +- } else { +- dev_warn(master->dev, +- "stream %u already in tree\n", +- cur_stream->id); +- ret = -EINVAL; +- break; +- } +- } +- if (ret) +- break; ++ existing = rb_find_add(&new_stream->node, &smmu->streams, ++ arm_smmu_streams_cmp_node); ++ if (existing) { ++ struct arm_smmu_master *existing_master = ++ rb_entry(existing, struct arm_smmu_stream, node) ++ ->master; ++ ++ /* Bridged PCI devices may end up with duplicated IDs */ ++ if (existing_master == master) ++ continue; + +- rb_link_node(&new_stream->node, parent_node, new_node); +- rb_insert_color(&new_stream->node, &smmu->streams); ++ dev_warn(master->dev, ++ "stream %u already in tree from dev %s\n", sid, ++ dev_name(existing_master->dev)); ++ ret = -EINVAL; ++ break; ++ } + } + + if (ret) { +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index d6381c00bb8ddc..6a745616d85a4b 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -4855,6 +4855,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_igfx); + ++/* QM57/QS57 integrated gfx malfunctions with dmar */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_iommu_igfx); ++ + /* Broadwell igfx malfunctions with dmar */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1606, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160B, quirk_iommu_igfx); +@@ -4932,7 +4935,6 @@ static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev) + } + } + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt); +-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt); + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 3f1029c0825e95..f2b3a4e2e54fc8 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -566,6 +566,18 @@ int iommu_probe_device(struct device *dev) + mutex_lock(&iommu_probe_device_lock); + ret = __iommu_probe_device(dev, NULL); + mutex_unlock(&iommu_probe_device_lock); ++ ++ /* ++ * The dma_configure replay paths need bus_iommu_probe() to ++ * finish before they can call arch_setup_dma_ops() ++ */ ++ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !ret && dev->iommu_group) { ++ mutex_lock(&dev->iommu_group->mutex); ++ if (!dev->iommu_group->default_domain && ++ !dev_iommu_ops(dev)->set_platform_dma_ops) ++ ret = -EPROBE_DEFER; ++ mutex_unlock(&dev->iommu_group->mutex); ++ } + if (ret) + return ret; + +@@ -3149,6 +3161,12 @@ int iommu_device_use_default_domain(struct device *dev) + return 0; + + mutex_lock(&group->mutex); ++ /* We may race against bus_iommu_probe() finalising groups here */ ++ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !group->default_domain && ++ !dev_iommu_ops(dev)->set_platform_dma_ops) { ++ ret = -EPROBE_DEFER; ++ goto unlock_out; ++ } + if (group->owner_cnt) { + if (group->owner || !iommu_is_default_domain(group) || + !xa_empty(&group->pasid_array)) { +diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c +index 7124565234a586..0807e4aca933fb 100644 +--- a/drivers/irqchip/irq-qcom-mpm.c ++++ b/drivers/irqchip/irq-qcom-mpm.c +@@ -226,6 +226,9 @@ static int qcom_mpm_alloc(struct irq_domain *domain, unsigned int virq, + if (ret) + return ret; + ++ if (pin == GPIO_NO_WAKE_IRQ) ++ return irq_domain_disconnect_hierarchy(domain, virq); ++ + ret = irq_domain_set_hwirq_and_chip(domain, virq, pin, + &qcom_mpm_chip, priv); + if (ret) +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 30ddfb21f65818..2d3afeaf886877 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -68,6 +68,8 @@ + #define LIST_DIRTY 1 + #define LIST_SIZE 2 + ++#define SCAN_RESCHED_CYCLE 16 ++ + /*--------------------------------------------------------------*/ + + /* +@@ -2387,7 +2389,12 @@ static void __scan(struct dm_bufio_client *c) + + atomic_long_dec(&c->need_shrink); + freed++; +- cond_resched(); ++ ++ if (unlikely(freed % SCAN_RESCHED_CYCLE == 0)) { ++ dm_bufio_unlock(c); ++ cond_resched(); ++ dm_bufio_lock(c); ++ } + } + } + } +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index eb2b44f4a61f08..1e27a5bce2d942 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -4687,7 +4687,7 @@ static void dm_integrity_dtr(struct dm_target *ti) + BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress)); + BUG_ON(!list_empty(&ic->wait_list)); + +- if (ic->mode == 'B') ++ if (ic->mode == 'B' && ic->bitmap_flush_work.work.func) + cancel_delayed_work_sync(&ic->bitmap_flush_work); + if (ic->metadata_wq) + destroy_workqueue(ic->metadata_wq); +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index fd84e06670e8d7..319bd10548e9ad 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -500,8 +500,9 @@ static char **realloc_argv(unsigned int *size, char **old_argv) + gfp = GFP_NOIO; + } + argv = kmalloc_array(new_size, sizeof(*argv), gfp); +- if (argv && old_argv) { +- memcpy(argv, old_argv, *size * sizeof(*argv)); ++ if (argv) { ++ if (old_argv) ++ memcpy(argv, old_argv, *size * sizeof(*argv)); + *size = new_size; + } + +diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c +index c675dec587efb2..597b00e8c9539d 100644 +--- a/drivers/mmc/host/renesas_sdhi_core.c ++++ b/drivers/mmc/host/renesas_sdhi_core.c +@@ -1107,26 +1107,26 @@ int renesas_sdhi_probe(struct platform_device *pdev, + num_irqs = platform_irq_count(pdev); + if (num_irqs < 0) { + ret = num_irqs; +- goto eirq; ++ goto edisclk; + } + + /* There must be at least one IRQ source */ + if (!num_irqs) { + ret = -ENXIO; +- goto eirq; ++ goto edisclk; + } + + for (i = 0; i < num_irqs; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) { + ret = irq; +- goto eirq; ++ goto edisclk; + } + + ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, + dev_name(&pdev->dev), host); + if (ret) +- goto eirq; ++ goto edisclk; + } + + ret = tmio_mmc_host_probe(host); +@@ -1138,8 +1138,6 @@ int renesas_sdhi_probe(struct platform_device *pdev, + + return ret; + +-eirq: +- tmio_mmc_host_remove(host); + edisclk: + renesas_sdhi_clk_disable(host); + efree: +diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c +index 8d27933c3733b1..f91f25578f075b 100644 +--- a/drivers/net/dsa/ocelot/felix_vsc9959.c ++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c +@@ -1543,7 +1543,7 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) + struct tc_taprio_qopt_offload *taprio; + struct ocelot_port *ocelot_port; + struct timespec64 base_ts; +- int port; ++ int i, port; + u32 val; + + mutex_lock(&ocelot->fwd_domain_lock); +@@ -1575,6 +1575,9 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) + QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M, + QSYS_PARAM_CFG_REG_3); + ++ for (i = 0; i < taprio->num_entries; i++) ++ vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]); ++ + ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, + QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, + QSYS_TAS_PARAM_CFG_CTRL); +diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c +index fb7a5403e630db..889a18962270aa 100644 +--- a/drivers/net/ethernet/amd/pds_core/auxbus.c ++++ b/drivers/net/ethernet/amd/pds_core/auxbus.c +@@ -172,48 +172,57 @@ static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf, + return padev; + } + +-int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf) ++void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf, ++ struct pds_auxiliary_dev **pd_ptr) + { + struct pds_auxiliary_dev *padev; +- int err = 0; ++ ++ if (!*pd_ptr) ++ return; + + mutex_lock(&pf->config_lock); + +- padev = pf->vfs[cf->vf_id].padev; +- if (padev) { +- pds_client_unregister(pf, padev->client_id); +- auxiliary_device_delete(&padev->aux_dev); +- auxiliary_device_uninit(&padev->aux_dev); +- padev->client_id = 0; +- } +- pf->vfs[cf->vf_id].padev = NULL; ++ padev = *pd_ptr; ++ pds_client_unregister(pf, padev->client_id); ++ auxiliary_device_delete(&padev->aux_dev); ++ auxiliary_device_uninit(&padev->aux_dev); ++ *pd_ptr = NULL; + + mutex_unlock(&pf->config_lock); +- return err; + } + +-int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf) ++int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf, ++ enum pds_core_vif_types vt, ++ struct pds_auxiliary_dev **pd_ptr) + { + struct pds_auxiliary_dev *padev; +- enum pds_core_vif_types vt; + char devname[PDS_DEVNAME_LEN]; ++ unsigned long mask; + u16 vt_support; + int client_id; + int err = 0; + ++ if (!cf) ++ return -ENODEV; ++ ++ if (vt >= PDS_DEV_TYPE_MAX) ++ return -EINVAL; ++ + mutex_lock(&pf->config_lock); + +- /* We only support vDPA so far, so it is the only one to +- * be verified that it is available in the Core device and +- * enabled in the devlink param. In the future this might +- * become a loop for several VIF types. +- */ ++ mask = BIT_ULL(PDSC_S_FW_DEAD) | ++ BIT_ULL(PDSC_S_STOPPING_DRIVER); ++ if (cf->state & mask) { ++ dev_err(pf->dev, "%s: can't add dev, VF client in bad state %#lx\n", ++ __func__, cf->state); ++ err = -ENXIO; ++ goto out_unlock; ++ } + + /* Verify that the type is supported and enabled. It is not + * an error if there is no auxbus device support for this + * VF, it just means something else needs to happen with it. + */ +- vt = PDS_DEV_TYPE_VDPA; + vt_support = !!le16_to_cpu(pf->dev_ident.vif_types[vt]); + if (!(vt_support && + pf->viftype_status[vt].supported && +@@ -239,7 +248,7 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf) + err = PTR_ERR(padev); + goto out_unlock; + } +- pf->vfs[cf->vf_id].padev = padev; ++ *pd_ptr = padev; + + out_unlock: + mutex_unlock(&pf->config_lock); +diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h +index 858bebf7977624..61ee607ee48ace 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.h ++++ b/drivers/net/ethernet/amd/pds_core/core.h +@@ -300,8 +300,11 @@ void pdsc_health_thread(struct work_struct *work); + int pdsc_register_notify(struct notifier_block *nb); + void pdsc_unregister_notify(struct notifier_block *nb); + void pdsc_notify(unsigned long event, void *data); +-int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf); +-int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf); ++int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf, ++ enum pds_core_vif_types vt, ++ struct pds_auxiliary_dev **pd_ptr); ++void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf, ++ struct pds_auxiliary_dev **pd_ptr); + + void pdsc_process_adminq(struct pdsc_qcq *qcq); + void pdsc_work_thread(struct work_struct *work); +diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c +index f0e39ab4004503..e65a1632df505d 100644 +--- a/drivers/net/ethernet/amd/pds_core/dev.c ++++ b/drivers/net/ethernet/amd/pds_core/dev.c +@@ -42,6 +42,8 @@ int pdsc_err_to_errno(enum pds_core_status_code code) + return -ERANGE; + case PDS_RC_BAD_ADDR: + return -EFAULT; ++ case PDS_RC_BAD_PCI: ++ return -ENXIO; + case PDS_RC_EOPCODE: + case PDS_RC_EINTR: + case PDS_RC_DEV_CMD: +@@ -65,7 +67,7 @@ bool pdsc_is_fw_running(struct pdsc *pdsc) + /* Firmware is useful only if the running bit is set and + * fw_status != 0xff (bad PCI read) + */ +- return (pdsc->fw_status != 0xff) && ++ return (pdsc->fw_status != PDS_RC_BAD_PCI) && + (pdsc->fw_status & PDS_CORE_FW_STS_F_RUNNING); + } + +@@ -131,6 +133,7 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds) + unsigned long max_wait; + unsigned long duration; + int timeout = 0; ++ bool running; + int done = 0; + int err = 0; + int status; +@@ -139,6 +142,10 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds) + max_wait = start_time + (max_seconds * HZ); + + while (!done && !timeout) { ++ running = pdsc_is_fw_running(pdsc); ++ if (!running) ++ break; ++ + done = pdsc_devcmd_done(pdsc); + if (done) + break; +@@ -155,7 +162,7 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds) + dev_dbg(dev, "DEVCMD %d %s after %ld secs\n", + opcode, pdsc_devcmd_str(opcode), duration / HZ); + +- if (!done || timeout) { ++ if ((!done || timeout) && running) { + dev_err(dev, "DEVCMD %d %s timeout, done %d timeout %d max_seconds=%d\n", + opcode, pdsc_devcmd_str(opcode), done, timeout, + max_seconds); +diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c +index 0032e8e3518117..bee70e46e34c68 100644 +--- a/drivers/net/ethernet/amd/pds_core/devlink.c ++++ b/drivers/net/ethernet/amd/pds_core/devlink.c +@@ -55,8 +55,11 @@ int pdsc_dl_enable_set(struct devlink *dl, u32 id, + for (vf_id = 0; vf_id < pdsc->num_vfs; vf_id++) { + struct pdsc *vf = pdsc->vfs[vf_id].vf; + +- err = ctx->val.vbool ? pdsc_auxbus_dev_add(vf, pdsc) : +- pdsc_auxbus_dev_del(vf, pdsc); ++ if (ctx->val.vbool) ++ err = pdsc_auxbus_dev_add(vf, pdsc, vt_entry->vif_id, ++ &pdsc->vfs[vf_id].padev); ++ else ++ pdsc_auxbus_dev_del(vf, pdsc, &pdsc->vfs[vf_id].padev); + } + + return err; +diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c +index eddbf0acdde77f..76652e0e5b6d9c 100644 +--- a/drivers/net/ethernet/amd/pds_core/main.c ++++ b/drivers/net/ethernet/amd/pds_core/main.c +@@ -189,7 +189,8 @@ static int pdsc_init_vf(struct pdsc *vf) + devl_unlock(dl); + + pf->vfs[vf->vf_id].vf = vf; +- err = pdsc_auxbus_dev_add(vf, pf); ++ err = pdsc_auxbus_dev_add(vf, pf, PDS_DEV_TYPE_VDPA, ++ &pf->vfs[vf->vf_id].padev); + if (err) { + devl_lock(dl); + devl_unregister(dl); +@@ -415,7 +416,7 @@ static void pdsc_remove(struct pci_dev *pdev) + + pf = pdsc_get_pf_struct(pdsc->pdev); + if (!IS_ERR(pf)) { +- pdsc_auxbus_dev_del(pdsc, pf); ++ pdsc_auxbus_dev_del(pdsc, pf, &pf->vfs[pdsc->vf_id].padev); + pf->vfs[pdsc->vf_id].vf = NULL; + } + } else { +@@ -475,6 +476,15 @@ static void pdsc_reset_prepare(struct pci_dev *pdev) + pdsc_stop_health_thread(pdsc); + pdsc_fw_down(pdsc); + ++ if (pdev->is_virtfn) { ++ struct pdsc *pf; ++ ++ pf = pdsc_get_pf_struct(pdsc->pdev); ++ if (!IS_ERR(pf)) ++ pdsc_auxbus_dev_del(pdsc, pf, ++ &pf->vfs[pdsc->vf_id].padev); ++ } ++ + pdsc_unmap_bars(pdsc); + pci_release_regions(pdev); + pci_disable_device(pdev); +@@ -510,6 +520,15 @@ static void pdsc_reset_done(struct pci_dev *pdev) + + pdsc_fw_up(pdsc); + pdsc_restart_health_thread(pdsc); ++ ++ if (pdev->is_virtfn) { ++ struct pdsc *pf; ++ ++ pf = pdsc_get_pf_struct(pdsc->pdev); ++ if (!IS_ERR(pf)) ++ pdsc_auxbus_dev_add(pdsc, pf, PDS_DEV_TYPE_VDPA, ++ &pf->vfs[pdsc->vf_id].padev); ++ } + } + + static const struct pci_error_handlers pdsc_err_handler = { +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +index 230726d7b74f63..d41b58fad37bbf 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +@@ -373,8 +373,13 @@ static int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata, + } + + /* Set up the header page info */ +- xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa, +- XGBE_SKB_ALLOC_SIZE); ++ if (pdata->netdev->features & NETIF_F_RXCSUM) { ++ xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa, ++ XGBE_SKB_ALLOC_SIZE); ++ } else { ++ xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa, ++ pdata->rx_buf_size); ++ } + + /* Set up the buffer page info */ + xgbe_set_buffer_data(&rdata->rx.buf, &ring->rx_buf_pa, +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +index f393228d41c7be..f1b0fb02b3cd14 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +@@ -320,6 +320,18 @@ static void xgbe_config_sph_mode(struct xgbe_prv_data *pdata) + XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE); + } + ++static void xgbe_disable_sph_mode(struct xgbe_prv_data *pdata) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < pdata->channel_count; i++) { ++ if (!pdata->channel[i]->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 0); ++ } ++} ++ + static int xgbe_write_rss_reg(struct xgbe_prv_data *pdata, unsigned int type, + unsigned int index, unsigned int val) + { +@@ -3545,8 +3557,12 @@ static int xgbe_init(struct xgbe_prv_data *pdata) + xgbe_config_tx_coalesce(pdata); + xgbe_config_rx_buffer_size(pdata); + xgbe_config_tso_mode(pdata); +- xgbe_config_sph_mode(pdata); +- xgbe_config_rss(pdata); ++ ++ if (pdata->netdev->features & NETIF_F_RXCSUM) { ++ xgbe_config_sph_mode(pdata); ++ xgbe_config_rss(pdata); ++ } ++ + desc_if->wrapper_tx_desc_init(pdata); + desc_if->wrapper_rx_desc_init(pdata); + xgbe_enable_dma_interrupts(pdata); +@@ -3702,5 +3718,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) + hw_if->disable_vxlan = xgbe_disable_vxlan; + hw_if->set_vxlan_id = xgbe_set_vxlan_id; + ++ /* For Split Header*/ ++ hw_if->enable_sph = xgbe_config_sph_mode; ++ hw_if->disable_sph = xgbe_disable_sph_mode; ++ + DBGPR("<--xgbe_init_function_ptrs\n"); + } +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +index 6b73648b377936..34d45cebefb5d3 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +@@ -2257,10 +2257,17 @@ static int xgbe_set_features(struct net_device *netdev, + if (ret) + return ret; + +- if ((features & NETIF_F_RXCSUM) && !rxcsum) ++ if ((features & NETIF_F_RXCSUM) && !rxcsum) { ++ hw_if->enable_sph(pdata); ++ hw_if->enable_vxlan(pdata); + hw_if->enable_rx_csum(pdata); +- else if (!(features & NETIF_F_RXCSUM) && rxcsum) ++ schedule_work(&pdata->restart_work); ++ } else if (!(features & NETIF_F_RXCSUM) && rxcsum) { ++ hw_if->disable_sph(pdata); ++ hw_if->disable_vxlan(pdata); + hw_if->disable_rx_csum(pdata); ++ schedule_work(&pdata->restart_work); ++ } + + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan) + hw_if->enable_rx_vlan_stripping(pdata); +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h +index ad136ed493ed1f..173f4dad470f55 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h +@@ -865,6 +865,10 @@ struct xgbe_hw_if { + void (*enable_vxlan)(struct xgbe_prv_data *); + void (*disable_vxlan)(struct xgbe_prv_data *); + void (*set_vxlan_id)(struct xgbe_prv_data *); ++ ++ /* For Split Header */ ++ void (*enable_sph)(struct xgbe_prv_data *pdata); ++ void (*disable_sph)(struct xgbe_prv_data *pdata); + }; + + /* This structure represents implementation specific routines for an +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c +index c067898820360e..32813cdd5aa5cb 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c +@@ -66,20 +66,30 @@ static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, + } + } + ++ if (cmn_req->req_type == ++ cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) ++ info->dest_buf_size += len; ++ + if (info->dest_buf) { + if ((info->seg_start + off + len) <= + BNXT_COREDUMP_BUF_LEN(info->buf_len)) { +- memcpy(info->dest_buf + off, dma_buf, len); ++ u16 copylen = min_t(u16, len, ++ info->dest_buf_size - off); ++ ++ memcpy(info->dest_buf + off, dma_buf, copylen); ++ if (copylen < len) ++ break; + } else { + rc = -ENOBUFS; ++ if (cmn_req->req_type == ++ cpu_to_le16(HWRM_DBG_COREDUMP_LIST)) { ++ kfree(info->dest_buf); ++ info->dest_buf = NULL; ++ } + break; + } + } + +- if (cmn_req->req_type == +- cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) +- info->dest_buf_size += len; +- + if (!(cmn_resp->flags & HWRM_DBG_CMN_FLAGS_MORE)) + break; + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index 2e7ddbca9d53b1..dcedafa4d2e14f 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -1393,6 +1393,17 @@ static int bnxt_get_regs_len(struct net_device *dev) + return reg_len; + } + ++#define BNXT_PCIE_32B_ENTRY(start, end) \ ++ { offsetof(struct pcie_ctx_hw_stats, start), \ ++ offsetof(struct pcie_ctx_hw_stats, end) } ++ ++static const struct { ++ u16 start; ++ u16 end; ++} bnxt_pcie_32b_entries[] = { ++ BNXT_PCIE_32B_ENTRY(pcie_ltssm_histogram[0], pcie_ltssm_histogram[3]), ++}; ++ + static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *_p) + { +@@ -1424,12 +1435,27 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, + req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); + rc = hwrm_req_send(bp, req); + if (!rc) { +- __le64 *src = (__le64 *)hw_pcie_stats; +- u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); +- int i; +- +- for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) +- dst[i] = le64_to_cpu(src[i]); ++ u8 *dst = (u8 *)(_p + BNXT_PXP_REG_LEN); ++ u8 *src = (u8 *)hw_pcie_stats; ++ int i, j; ++ ++ for (i = 0, j = 0; i < sizeof(*hw_pcie_stats); ) { ++ if (i >= bnxt_pcie_32b_entries[j].start && ++ i <= bnxt_pcie_32b_entries[j].end) { ++ u32 *dst32 = (u32 *)(dst + i); ++ ++ *dst32 = le32_to_cpu(*(__le32 *)(src + i)); ++ i += 4; ++ if (i > bnxt_pcie_32b_entries[j].end && ++ j < ARRAY_SIZE(bnxt_pcie_32b_entries) - 1) ++ j++; ++ } else { ++ u64 *dst64 = (u64 *)(dst + i); ++ ++ *dst64 = le64_to_cpu(*(__le64 *)(src + i)); ++ i += 8; ++ } ++ } + } + hwrm_req_drop(bp, req); + } +diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c +index db6615aa921b19..ce46f3ac3b5a18 100644 +--- a/drivers/net/ethernet/dlink/dl2k.c ++++ b/drivers/net/ethernet/dlink/dl2k.c +@@ -352,7 +352,7 @@ parse_eeprom (struct net_device *dev) + eth_hw_addr_set(dev, psrom->mac_addr); + + if (np->chip_id == CHIP_IP1000A) { +- np->led_mode = psrom->led_mode; ++ np->led_mode = le16_to_cpu(psrom->led_mode); + return 0; + } + +diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h +index 195dc6cfd8955c..0e33e2eaae9606 100644 +--- a/drivers/net/ethernet/dlink/dl2k.h ++++ b/drivers/net/ethernet/dlink/dl2k.h +@@ -335,7 +335,7 @@ typedef struct t_SROM { + u16 sub_system_id; /* 0x06 */ + u16 pci_base_1; /* 0x08 (IP1000A only) */ + u16 pci_base_2; /* 0x0a (IP1000A only) */ +- u16 led_mode; /* 0x0c (IP1000A only) */ ++ __le16 led_mode; /* 0x0c (IP1000A only) */ + u16 reserved1[9]; /* 0x0e-0x1f */ + u8 mac_addr[6]; /* 0x20-0x25 */ + u8 reserved2[10]; /* 0x26-0x2f */ +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 2d6b50903c923d..7261838a09db63 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -695,7 +695,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; + } +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +index 4f385a18d288e4..36206273453f3a 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +@@ -60,7 +60,7 @@ static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = { + .name = "tm_qset", + .cmd = HNAE3_DBG_CMD_TM_QSET, + .dentry = HNS3_DBG_DENTRY_TM, +- .buf_len = HNS3_DBG_READ_LEN, ++ .buf_len = HNS3_DBG_READ_LEN_1MB, + .init = hns3_dbg_common_file_init, + }, + { +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 801801e8803e9f..0ed01f4d680618 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -473,20 +473,14 @@ static void hns3_mask_vector_irq(struct hns3_enet_tqp_vector *tqp_vector, + writel(mask_en, tqp_vector->mask_addr); + } + +-static void hns3_vector_enable(struct hns3_enet_tqp_vector *tqp_vector) ++static void hns3_irq_enable(struct hns3_enet_tqp_vector *tqp_vector) + { + napi_enable(&tqp_vector->napi); + enable_irq(tqp_vector->vector_irq); +- +- /* enable vector */ +- hns3_mask_vector_irq(tqp_vector, 1); + } + +-static void hns3_vector_disable(struct hns3_enet_tqp_vector *tqp_vector) ++static void hns3_irq_disable(struct hns3_enet_tqp_vector *tqp_vector) + { +- /* disable vector */ +- hns3_mask_vector_irq(tqp_vector, 0); +- + disable_irq(tqp_vector->vector_irq); + napi_disable(&tqp_vector->napi); + cancel_work_sync(&tqp_vector->rx_group.dim.work); +@@ -707,11 +701,42 @@ static int hns3_set_rx_cpu_rmap(struct net_device *netdev) + return 0; + } + ++static void hns3_enable_irqs_and_tqps(struct net_device *netdev) ++{ ++ struct hns3_nic_priv *priv = netdev_priv(netdev); ++ struct hnae3_handle *h = priv->ae_handle; ++ u16 i; ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_irq_enable(&priv->tqp_vector[i]); ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_mask_vector_irq(&priv->tqp_vector[i], 1); ++ ++ for (i = 0; i < h->kinfo.num_tqps; i++) ++ hns3_tqp_enable(h->kinfo.tqp[i]); ++} ++ ++static void hns3_disable_irqs_and_tqps(struct net_device *netdev) ++{ ++ struct hns3_nic_priv *priv = netdev_priv(netdev); ++ struct hnae3_handle *h = priv->ae_handle; ++ u16 i; ++ ++ for (i = 0; i < h->kinfo.num_tqps; i++) ++ hns3_tqp_disable(h->kinfo.tqp[i]); ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_mask_vector_irq(&priv->tqp_vector[i], 0); ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_irq_disable(&priv->tqp_vector[i]); ++} ++ + static int hns3_nic_net_up(struct net_device *netdev) + { + struct hns3_nic_priv *priv = netdev_priv(netdev); + struct hnae3_handle *h = priv->ae_handle; +- int i, j; + int ret; + + ret = hns3_nic_reset_all_ring(h); +@@ -720,23 +745,13 @@ static int hns3_nic_net_up(struct net_device *netdev) + + clear_bit(HNS3_NIC_STATE_DOWN, &priv->state); + +- /* enable the vectors */ +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_enable(&priv->tqp_vector[i]); +- +- /* enable rcb */ +- for (j = 0; j < h->kinfo.num_tqps; j++) +- hns3_tqp_enable(h->kinfo.tqp[j]); ++ hns3_enable_irqs_and_tqps(netdev); + + /* start the ae_dev */ + ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0; + if (ret) { + set_bit(HNS3_NIC_STATE_DOWN, &priv->state); +- while (j--) +- hns3_tqp_disable(h->kinfo.tqp[j]); +- +- for (j = i - 1; j >= 0; j--) +- hns3_vector_disable(&priv->tqp_vector[j]); ++ hns3_disable_irqs_and_tqps(netdev); + } + + return ret; +@@ -823,17 +838,9 @@ static void hns3_reset_tx_queue(struct hnae3_handle *h) + static void hns3_nic_net_down(struct net_device *netdev) + { + struct hns3_nic_priv *priv = netdev_priv(netdev); +- struct hnae3_handle *h = hns3_get_handle(netdev); + const struct hnae3_ae_ops *ops; +- int i; + +- /* disable vectors */ +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_disable(&priv->tqp_vector[i]); +- +- /* disable rcb */ +- for (i = 0; i < h->kinfo.num_tqps; i++) +- hns3_tqp_disable(h->kinfo.tqp[i]); ++ hns3_disable_irqs_and_tqps(netdev); + + /* stop ae_dev */ + ops = priv->ae_handle->ae_algo->ops; +@@ -5870,8 +5877,6 @@ int hns3_set_channels(struct net_device *netdev, + void hns3_external_lb_prepare(struct net_device *ndev, bool if_running) + { + struct hns3_nic_priv *priv = netdev_priv(ndev); +- struct hnae3_handle *h = priv->ae_handle; +- int i; + + if (!if_running) + return; +@@ -5882,11 +5887,7 @@ void hns3_external_lb_prepare(struct net_device *ndev, bool if_running) + netif_carrier_off(ndev); + netif_tx_disable(ndev); + +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_disable(&priv->tqp_vector[i]); +- +- for (i = 0; i < h->kinfo.num_tqps; i++) +- hns3_tqp_disable(h->kinfo.tqp[i]); ++ hns3_disable_irqs_and_tqps(ndev); + + /* delay ring buffer clearing to hns3_reset_notify_uninit_enet + * during reset process, because driver may not be able +@@ -5902,7 +5903,6 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running) + { + struct hns3_nic_priv *priv = netdev_priv(ndev); + struct hnae3_handle *h = priv->ae_handle; +- int i; + + if (!if_running) + return; +@@ -5918,11 +5918,7 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running) + + clear_bit(HNS3_NIC_STATE_DOWN, &priv->state); + +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_enable(&priv->tqp_vector[i]); +- +- for (i = 0; i < h->kinfo.num_tqps; i++) +- hns3_tqp_enable(h->kinfo.tqp[i]); ++ hns3_enable_irqs_and_tqps(ndev); + + netif_tx_wake_all_queues(ndev); + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c +index ddc691424c8163..9a806ac727cf5b 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c +@@ -440,6 +440,13 @@ static int hclge_ptp_create_clock(struct hclge_dev *hdev) + ptp->info.settime64 = hclge_ptp_settime; + + ptp->info.n_alarm = 0; ++ ++ spin_lock_init(&ptp->lock); ++ ptp->io_base = hdev->hw.hw.io_base + HCLGE_PTP_REG_OFFSET; ++ ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE; ++ ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF; ++ hdev->ptp = ptp; ++ + ptp->clock = ptp_clock_register(&ptp->info, &hdev->pdev->dev); + if (IS_ERR(ptp->clock)) { + dev_err(&hdev->pdev->dev, +@@ -451,12 +458,6 @@ static int hclge_ptp_create_clock(struct hclge_dev *hdev) + return -ENODEV; + } + +- spin_lock_init(&ptp->lock); +- ptp->io_base = hdev->hw.hw.io_base + HCLGE_PTP_REG_OFFSET; +- ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE; +- ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF; +- hdev->ptp = ptp; +- + return 0; + } + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +index 69bfcfb148def4..1ba0b57c7a72d7 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +@@ -1257,9 +1257,8 @@ static void hclgevf_sync_vlan_filter(struct hclgevf_dev *hdev) + rtnl_unlock(); + } + +-static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) ++static int hclgevf_en_hw_strip_rxvtag_cmd(struct hclgevf_dev *hdev, bool enable) + { +- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hclge_vf_to_pf_msg send_msg; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN, +@@ -1268,6 +1267,19 @@ static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) + return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + } + ++static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) ++{ ++ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); ++ int ret; ++ ++ ret = hclgevf_en_hw_strip_rxvtag_cmd(hdev, enable); ++ if (ret) ++ return ret; ++ ++ hdev->rxvtag_strip_en = enable; ++ return 0; ++} ++ + static int hclgevf_reset_tqp(struct hnae3_handle *handle) + { + #define HCLGEVF_RESET_ALL_QUEUE_DONE 1U +@@ -2143,12 +2155,13 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) + tc_valid, tc_size); + } + +-static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev) ++static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev, ++ bool rxvtag_strip_en) + { + struct hnae3_handle *nic = &hdev->nic; + int ret; + +- ret = hclgevf_en_hw_strip_rxvtag(nic, true); ++ ret = hclgevf_en_hw_strip_rxvtag(nic, rxvtag_strip_en); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to enable rx vlan offload, ret = %d\n", ret); +@@ -2815,7 +2828,7 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) + if (ret) + return ret; + +- ret = hclgevf_init_vlan_config(hdev); ++ ret = hclgevf_init_vlan_config(hdev, hdev->rxvtag_strip_en); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed(%d) to initialize VLAN config\n", ret); +@@ -2928,7 +2941,7 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) + goto err_config; + } + +- ret = hclgevf_init_vlan_config(hdev); ++ ret = hclgevf_init_vlan_config(hdev, true); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed(%d) to initialize VLAN config\n", ret); +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +index cccef32284616b..0208425ab594f5 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +@@ -253,6 +253,7 @@ struct hclgevf_dev { + int *vector_irq; + + bool gro_en; ++ bool rxvtag_strip_en; + + unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)]; + +diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +index 3ca5f44dea26eb..88c1acd5e8f05d 100644 +--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c ++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +@@ -1824,6 +1824,11 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg) + pf = vf->pf; + dev = ice_pf_to_dev(pf); + vf_vsi = ice_get_vf_vsi(vf); ++ if (!vf_vsi) { ++ dev_err(dev, "Can not get FDIR vf_vsi for VF %u\n", vf->vf_id); ++ v_ret = VIRTCHNL_STATUS_ERR_PARAM; ++ goto err_exit; ++ } + + #define ICE_VF_MAX_FDIR_FILTERS 128 + if (!ice_fdir_num_avail_fltr(&pf->hw, vf_vsi) || +diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c +index b6bb01a486d9d8..a82af96e6bd12f 100644 +--- a/drivers/net/ethernet/intel/igc/igc_ptp.c ++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c +@@ -1237,6 +1237,8 @@ void igc_ptp_reset(struct igc_adapter *adapter) + /* reset the tstamp_config */ + igc_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); + ++ mutex_lock(&adapter->ptm_lock); ++ + spin_lock_irqsave(&adapter->tmreg_lock, flags); + + switch (adapter->hw.mac.type) { +@@ -1255,7 +1257,6 @@ void igc_ptp_reset(struct igc_adapter *adapter) + if (!igc_is_crosststamp_supported(adapter)) + break; + +- mutex_lock(&adapter->ptm_lock); + wr32(IGC_PCIE_DIG_DELAY, IGC_PCIE_DIG_DELAY_DEFAULT); + wr32(IGC_PCIE_PHY_DELAY, IGC_PCIE_PHY_DELAY_DEFAULT); + +@@ -1279,7 +1280,6 @@ void igc_ptp_reset(struct igc_adapter *adapter) + netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n"); + + igc_ptm_reset(hw); +- mutex_unlock(&adapter->ptm_lock); + break; + default: + /* No work to do. */ +@@ -1296,5 +1296,7 @@ void igc_ptp_reset(struct igc_adapter *adapter) + out: + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + ++ mutex_unlock(&adapter->ptm_lock); ++ + wrfl(); + } +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +index 6f1fe7e283d4eb..7a30095b3486f3 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +@@ -917,7 +917,7 @@ static void octep_hb_timeout_task(struct work_struct *work) + miss_cnt); + rtnl_lock(); + if (netif_running(oct->netdev)) +- octep_stop(oct->netdev); ++ dev_close(oct->netdev); + rtnl_unlock(); + } + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index dc89dbc13b251f..d2ec8f642c2fa0 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2180,14 +2180,18 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, + ring->data[idx] = new_data; + rxd->rxd1 = (unsigned int)dma_addr; + release_desc: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) { ++ if (unlikely(dma_addr == DMA_MAPPING_ERROR)) ++ addr64 = FIELD_GET(RX_DMA_ADDR64_MASK, ++ rxd->rxd2); ++ else ++ addr64 = RX_DMA_PREP_ADDR64(dma_addr); ++ } ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; + else +- rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); +- +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA) && +- likely(dma_addr != DMA_MAPPING_ERROR)) +- rxd->rxd2 |= RX_DMA_PREP_ADDR64(dma_addr); ++ rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size) | addr64; + + ring->calc_idx = idx; + done++; +diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c +index 25989c79c92e61..c2ab87828d8589 100644 +--- a/drivers/net/ethernet/mediatek/mtk_star_emac.c ++++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c +@@ -1163,6 +1163,7 @@ static int mtk_star_tx_poll(struct napi_struct *napi, int budget) + struct net_device *ndev = priv->ndev; + unsigned int head = ring->head; + unsigned int entry = ring->tail; ++ unsigned long flags; + + while (entry != head && count < (MTK_STAR_RING_NUM_DESCS - 1)) { + ret = mtk_star_tx_complete_one(priv); +@@ -1182,9 +1183,9 @@ static int mtk_star_tx_poll(struct napi_struct *napi, int budget) + netif_wake_queue(ndev); + + if (napi_complete(napi)) { +- spin_lock(&priv->lock); ++ spin_lock_irqsave(&priv->lock, flags); + mtk_star_enable_dma_irq(priv, false, true); +- spin_unlock(&priv->lock); ++ spin_unlock_irqrestore(&priv->lock, flags); + } + + return 0; +@@ -1341,16 +1342,16 @@ static int mtk_star_rx(struct mtk_star_priv *priv, int budget) + static int mtk_star_rx_poll(struct napi_struct *napi, int budget) + { + struct mtk_star_priv *priv; ++ unsigned long flags; + int work_done = 0; + + priv = container_of(napi, struct mtk_star_priv, rx_napi); + + work_done = mtk_star_rx(priv, budget); +- if (work_done < budget) { +- napi_complete_done(napi, work_done); +- spin_lock(&priv->lock); ++ if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&priv->lock, flags); + mtk_star_enable_dma_irq(priv, true, false); +- spin_unlock(&priv->lock); ++ spin_unlock_irqrestore(&priv->lock, flags); + } + + return work_done; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +index 7eba3a5bb97cae..326c72b3df8671 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +@@ -3499,7 +3499,9 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) + int err; + + mutex_init(&esw->offloads.termtbl_mutex); +- mlx5_rdma_enable_roce(esw->dev); ++ err = mlx5_rdma_enable_roce(esw->dev); ++ if (err) ++ goto err_roce; + + err = mlx5_esw_host_number_init(esw); + if (err) +@@ -3560,6 +3562,7 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) + esw_offloads_metadata_uninit(esw); + err_metadata: + mlx5_rdma_disable_roce(esw->dev); ++err_roce: + mutex_destroy(&esw->offloads.termtbl_mutex); + return err; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c +index a42f6cd99b7448..5c552b71e371c5 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c +@@ -118,8 +118,8 @@ static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid * + + static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev) + { ++ u8 mac[ETH_ALEN] = {}; + union ib_gid gid; +- u8 mac[ETH_ALEN]; + + mlx5_rdma_make_default_gid(dev, &gid); + return mlx5_core_roce_gid_set(dev, 0, +@@ -140,17 +140,17 @@ void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev) + mlx5_nic_vport_disable_roce(dev); + } + +-void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) ++int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) + { + int err; + + if (!MLX5_CAP_GEN(dev, roce)) +- return; ++ return 0; + + err = mlx5_nic_vport_enable_roce(dev); + if (err) { + mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err); +- return; ++ return err; + } + + err = mlx5_rdma_add_roce_addr(dev); +@@ -165,10 +165,11 @@ void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) + goto del_roce_addr; + } + +- return; ++ return err; + + del_roce_addr: + mlx5_rdma_del_roce_addr(dev); + disable_roce: + mlx5_nic_vport_disable_roce(dev); ++ return err; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.h b/drivers/net/ethernet/mellanox/mlx5/core/rdma.h +index 750cff2a71a4bb..3d9e76c3d42fb1 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.h +@@ -8,12 +8,12 @@ + + #ifdef CONFIG_MLX5_ESWITCH + +-void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev); ++int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev); + void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev); + + #else /* CONFIG_MLX5_ESWITCH */ + +-static inline void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) {} ++static inline int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) { return 0; } + static inline void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev) {} + + #endif /* CONFIG_MLX5_ESWITCH */ +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 92010bfe5e4133..5d2ceff72784f2 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1949,6 +1949,7 @@ static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx, + if (nr_frags <= 0) { + tx->frame_data0 |= TX_DESC_DATA0_LS_; + tx->frame_data0 |= TX_DESC_DATA0_IOC_; ++ tx->frame_last = tx->frame_first; + } + tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; + tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); +@@ -2018,6 +2019,7 @@ static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx, + tx->frame_first = 0; + tx->frame_data0 = 0; + tx->frame_tail = 0; ++ tx->frame_last = 0; + return -ENOMEM; + } + +@@ -2058,16 +2060,18 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx, + TX_DESC_DATA0_DTYPE_DATA_) { + tx->frame_data0 |= TX_DESC_DATA0_LS_; + tx->frame_data0 |= TX_DESC_DATA0_IOC_; ++ tx->frame_last = tx->frame_tail; + } + +- tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; +- buffer_info = &tx->buffer_info[tx->frame_tail]; ++ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_last]; ++ buffer_info = &tx->buffer_info[tx->frame_last]; + buffer_info->skb = skb; + if (time_stamp) + buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED; + if (ignore_sync) + buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC; + ++ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; + tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); + tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); + tx->last_tail = tx->frame_tail; +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 3b2c6046eb3ad5..b6c83c68241e63 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -974,6 +974,7 @@ struct lan743x_tx { + u32 frame_first; + u32 frame_data0; + u32 frame_tail; ++ u32 frame_last; + + struct lan743x_tx_buffer_info *buffer_info; + +diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c +index f6aa5d6b6597e0..252d8e6f18c3cc 100644 +--- a/drivers/net/ethernet/mscc/ocelot.c ++++ b/drivers/net/ethernet/mscc/ocelot.c +@@ -453,9 +453,158 @@ static u16 ocelot_vlan_unaware_pvid(struct ocelot *ocelot, + return VLAN_N_VID - bridge_num - 1; + } + ++/** ++ * ocelot_update_vlan_reclassify_rule() - Make switch aware only to bridge VLAN TPID ++ * ++ * @ocelot: Switch private data structure ++ * @port: Index of ingress port ++ * ++ * IEEE 802.1Q-2018 clauses "5.5 C-VLAN component conformance" and "5.6 S-VLAN ++ * component conformance" suggest that a C-VLAN component should only recognize ++ * and filter on C-Tags, and an S-VLAN component should only recognize and ++ * process based on C-Tags. ++ * ++ * In Linux, as per commit 1a0b20b25732 ("Merge branch 'bridge-next'"), C-VLAN ++ * components are largely represented by a bridge with vlan_protocol 802.1Q, ++ * and S-VLAN components by a bridge with vlan_protocol 802.1ad. ++ * ++ * Currently the driver only offloads vlan_protocol 802.1Q, but the hardware ++ * design is non-conformant, because the switch assigns each frame to a VLAN ++ * based on an entirely different question, as detailed in figure "Basic VLAN ++ * Classification Flow" from its manual and reproduced below. ++ * ++ * Set TAG_TYPE, PCP, DEI, VID to port-default values in VLAN_CFG register ++ * if VLAN_AWARE_ENA[port] and frame has outer tag then: ++ * if VLAN_INNER_TAG_ENA[port] and frame has inner tag then: ++ * TAG_TYPE = (Frame.InnerTPID <> 0x8100) ++ * Set PCP, DEI, VID to values from inner VLAN header ++ * else: ++ * TAG_TYPE = (Frame.OuterTPID <> 0x8100) ++ * Set PCP, DEI, VID to values from outer VLAN header ++ * if VID == 0 then: ++ * VID = VLAN_CFG.VLAN_VID ++ * ++ * Summarized, the switch will recognize both 802.1Q and 802.1ad TPIDs as VLAN ++ * "with equal rights", and just set the TAG_TYPE bit to 0 (if 802.1Q) or to 1 ++ * (if 802.1ad). It will classify based on whichever of the tags is "outer", no ++ * matter what TPID that may have (or "inner", if VLAN_INNER_TAG_ENA[port]). ++ * ++ * In the VLAN Table, the TAG_TYPE information is not accessible - just the ++ * classified VID is - so it is as if each VLAN Table entry is for 2 VLANs: ++ * C-VLAN X, and S-VLAN X. ++ * ++ * Whereas the Linux bridge behavior is to only filter on frames with a TPID ++ * equal to the vlan_protocol, and treat everything else as VLAN-untagged. ++ * ++ * Consider an ingress packet tagged with 802.1ad VID=3 and 802.1Q VID=5, ++ * received on a bridge vlan_filtering=1 vlan_protocol=802.1Q port. This frame ++ * should be treated as 802.1Q-untagged, and classified to the PVID of that ++ * bridge port. Not to VID=3, and not to VID=5. ++ * ++ * The VCAP IS1 TCAM has everything we need to overwrite the choices made in ++ * the basic VLAN classification pipeline: it can match on TAG_TYPE in the key, ++ * and it can modify the classified VID in the action. Thus, for each port ++ * under a vlan_filtering bridge, we can insert a rule in VCAP IS1 lookup 0 to ++ * match on 802.1ad tagged frames and modify their classified VID to the 802.1Q ++ * PVID of the port. This effectively makes it appear to the outside world as ++ * if those packets were processed as VLAN-untagged. ++ * ++ * The rule needs to be updated each time the bridge PVID changes, and needs ++ * to be deleted if the bridge PVID is deleted, or if the port becomes ++ * VLAN-unaware. ++ */ ++static int ocelot_update_vlan_reclassify_rule(struct ocelot *ocelot, int port) ++{ ++ unsigned long cookie = OCELOT_VCAP_IS1_VLAN_RECLASSIFY(ocelot, port); ++ struct ocelot_vcap_block *block_vcap_is1 = &ocelot->block[VCAP_IS1]; ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ const struct ocelot_bridge_vlan *pvid_vlan; ++ struct ocelot_vcap_filter *filter; ++ int err, val, pcp, dei; ++ bool vid_replace_ena; ++ u16 vid; ++ ++ pvid_vlan = ocelot_port->pvid_vlan; ++ vid_replace_ena = ocelot_port->vlan_aware && pvid_vlan; ++ ++ filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, cookie, ++ false); ++ if (!vid_replace_ena) { ++ /* If the reclassification filter doesn't need to exist, delete ++ * it if it was previously installed, and exit doing nothing ++ * otherwise. ++ */ ++ if (filter) ++ return ocelot_vcap_filter_del(ocelot, filter); ++ ++ return 0; ++ } ++ ++ /* The reclassification rule must apply. See if it already exists ++ * or if it must be created. ++ */ ++ ++ /* Treating as VLAN-untagged means using as classified VID equal to ++ * the bridge PVID, and PCP/DEI set to the port default QoS values. ++ */ ++ vid = pvid_vlan->vid; ++ val = ocelot_read_gix(ocelot, ANA_PORT_QOS_CFG, port); ++ pcp = ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_X(val); ++ dei = !!(val & ANA_PORT_QOS_CFG_DP_DEFAULT_VAL); ++ ++ if (filter) { ++ bool changed = false; ++ ++ /* Filter exists, just update it */ ++ if (filter->action.vid != vid) { ++ filter->action.vid = vid; ++ changed = true; ++ } ++ if (filter->action.pcp != pcp) { ++ filter->action.pcp = pcp; ++ changed = true; ++ } ++ if (filter->action.dei != dei) { ++ filter->action.dei = dei; ++ changed = true; ++ } ++ ++ if (!changed) ++ return 0; ++ ++ return ocelot_vcap_filter_replace(ocelot, filter); ++ } ++ ++ /* Filter doesn't exist, create it */ ++ filter = kzalloc(sizeof(*filter), GFP_KERNEL); ++ if (!filter) ++ return -ENOMEM; ++ ++ filter->key_type = OCELOT_VCAP_KEY_ANY; ++ filter->ingress_port_mask = BIT(port); ++ filter->vlan.tpid = OCELOT_VCAP_BIT_1; ++ filter->prio = 1; ++ filter->id.cookie = cookie; ++ filter->id.tc_offload = false; ++ filter->block_id = VCAP_IS1; ++ filter->type = OCELOT_VCAP_FILTER_OFFLOAD; ++ filter->lookup = 0; ++ filter->action.vid_replace_ena = true; ++ filter->action.pcp_dei_ena = true; ++ filter->action.vid = vid; ++ filter->action.pcp = pcp; ++ filter->action.dei = dei; ++ ++ err = ocelot_vcap_filter_add(ocelot, filter, NULL); ++ if (err) ++ kfree(filter); ++ ++ return err; ++} ++ + /* Default vlan to clasify for untagged frames (may be zero) */ +-static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, +- const struct ocelot_bridge_vlan *pvid_vlan) ++static int ocelot_port_set_pvid(struct ocelot *ocelot, int port, ++ const struct ocelot_bridge_vlan *pvid_vlan) + { + struct ocelot_port *ocelot_port = ocelot->ports[port]; + u16 pvid = ocelot_vlan_unaware_pvid(ocelot, ocelot_port->bridge); +@@ -475,15 +624,23 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, + * happens automatically), but also 802.1p traffic which gets + * classified to VLAN 0, but that is always in our RX filter, so it + * would get accepted were it not for this setting. ++ * ++ * Also, we only support the bridge 802.1Q VLAN protocol, so ++ * 802.1ad-tagged frames (carrying S-Tags) should be considered ++ * 802.1Q-untagged, and also dropped. + */ + if (!pvid_vlan && ocelot_port->vlan_aware) + val = ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | +- ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA; ++ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA | ++ ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA; + + ocelot_rmw_gix(ocelot, val, + ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | +- ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, ++ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA | ++ ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA, + ANA_PORT_DROP_CFG, port); ++ ++ return ocelot_update_vlan_reclassify_rule(ocelot, port); + } + + static struct ocelot_bridge_vlan *ocelot_bridge_vlan_find(struct ocelot *ocelot, +@@ -631,7 +788,10 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, + ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M, + ANA_PORT_VLAN_CFG, port); + +- ocelot_port_set_pvid(ocelot, port, ocelot_port->pvid_vlan); ++ err = ocelot_port_set_pvid(ocelot, port, ocelot_port->pvid_vlan); ++ if (err) ++ return err; ++ + ocelot_port_manage_port_tag(ocelot, port); + + return 0; +@@ -670,6 +830,7 @@ EXPORT_SYMBOL(ocelot_vlan_prepare); + int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, + bool untagged) + { ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; + int err; + + /* Ignore VID 0 added to our RX filter by the 8021q module, since +@@ -684,9 +845,17 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, + return err; + + /* Default ingress vlan classification */ +- if (pvid) +- ocelot_port_set_pvid(ocelot, port, +- ocelot_bridge_vlan_find(ocelot, vid)); ++ if (pvid) { ++ err = ocelot_port_set_pvid(ocelot, port, ++ ocelot_bridge_vlan_find(ocelot, vid)); ++ if (err) ++ return err; ++ } else if (ocelot_port->pvid_vlan && ++ ocelot_bridge_vlan_find(ocelot, vid) == ocelot_port->pvid_vlan) { ++ err = ocelot_port_set_pvid(ocelot, port, NULL); ++ if (err) ++ return err; ++ } + + /* Untagged egress vlan clasification */ + ocelot_port_manage_port_tag(ocelot, port); +@@ -712,8 +881,11 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) + return err; + + /* Ingress */ +- if (del_pvid) +- ocelot_port_set_pvid(ocelot, port, NULL); ++ if (del_pvid) { ++ err = ocelot_port_set_pvid(ocelot, port, NULL); ++ if (err) ++ return err; ++ } + + /* Egress */ + ocelot_port_manage_port_tag(ocelot, port); +@@ -2607,7 +2779,7 @@ int ocelot_port_set_default_prio(struct ocelot *ocelot, int port, u8 prio) + ANA_PORT_QOS_CFG, + port); + +- return 0; ++ return ocelot_update_vlan_reclassify_rule(ocelot, port); + } + EXPORT_SYMBOL_GPL(ocelot_port_set_default_prio); + +diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c +index 73cdec5ca6a34d..5734b86aed5b53 100644 +--- a/drivers/net/ethernet/mscc/ocelot_vcap.c ++++ b/drivers/net/ethernet/mscc/ocelot_vcap.c +@@ -695,6 +695,7 @@ static void is1_entry_set(struct ocelot *ocelot, int ix, + vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_MC, filter->dmac_mc); + vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_BC, filter->dmac_bc); + vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_TAGGED, tag->tagged); ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TPID, tag->tpid); + vcap_key_set(vcap, &data, VCAP_IS1_HK_VID, + tag->vid.value, tag->vid.mask); + vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP, +diff --git a/drivers/net/ethernet/vertexcom/mse102x.c b/drivers/net/ethernet/vertexcom/mse102x.c +index 8f67c39f479eef..060a566bc6aae1 100644 +--- a/drivers/net/ethernet/vertexcom/mse102x.c ++++ b/drivers/net/ethernet/vertexcom/mse102x.c +@@ -6,6 +6,7 @@ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + ++#include + #include + #include + #include +@@ -33,7 +34,7 @@ + #define CMD_CTR (0x2 << CMD_SHIFT) + + #define CMD_MASK GENMASK(15, CMD_SHIFT) +-#define LEN_MASK GENMASK(CMD_SHIFT - 1, 0) ++#define LEN_MASK GENMASK(CMD_SHIFT - 2, 0) + + #define DET_CMD_LEN 4 + #define DET_SOF_LEN 2 +@@ -262,7 +263,7 @@ static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp, + } + + static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff, +- unsigned int frame_len) ++ unsigned int frame_len, bool drop) + { + struct mse102x_net_spi *mses = to_mse102x_spi(mse); + struct spi_transfer *xfer = &mses->spi_xfer; +@@ -280,6 +281,9 @@ static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff, + netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n", + __func__, ret); + mse->stats.xfer_err++; ++ } else if (drop) { ++ netdev_dbg(mse->ndev, "%s: Drop frame\n", __func__); ++ ret = -EINVAL; + } else if (*sof != cpu_to_be16(DET_SOF)) { + netdev_dbg(mse->ndev, "%s: SPI start of frame is invalid (0x%04x)\n", + __func__, *sof); +@@ -307,6 +311,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + struct sk_buff *skb; + unsigned int rxalign; + unsigned int rxlen; ++ bool drop = false; + __be16 rx = 0; + u16 cmd_resp; + u8 *rxpkt; +@@ -329,7 +334,8 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n", + __func__, cmd_resp); + mse->stats.invalid_rts++; +- return; ++ drop = true; ++ goto drop; + } + + net_dbg_ratelimited("%s: Unexpected response to first CMD\n", +@@ -337,12 +343,20 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + } + + rxlen = cmd_resp & LEN_MASK; +- if (!rxlen) { +- net_dbg_ratelimited("%s: No frame length defined\n", __func__); ++ if (rxlen < ETH_ZLEN || rxlen > VLAN_ETH_FRAME_LEN) { ++ net_dbg_ratelimited("%s: Invalid frame length: %d\n", __func__, ++ rxlen); + mse->stats.invalid_len++; +- return; ++ drop = true; + } + ++ /* In case of a invalid CMD_RTS, the frame must be consumed anyway. ++ * So assume the maximum possible frame length. ++ */ ++drop: ++ if (drop) ++ rxlen = VLAN_ETH_FRAME_LEN; ++ + rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4); + skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign); + if (!skb) +@@ -353,7 +367,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + * They are copied, but ignored. + */ + rxpkt = skb_put(skb, rxlen) - DET_SOF_LEN; +- if (mse102x_rx_frame_spi(mse, rxpkt, rxlen)) { ++ if (mse102x_rx_frame_spi(mse, rxpkt, rxlen, drop)) { + mse->ndev->stats.rx_errors++; + dev_kfree_skb(skb); + return; +@@ -509,6 +523,7 @@ static irqreturn_t mse102x_irq(int irq, void *_mse) + static int mse102x_net_open(struct net_device *ndev) + { + struct mse102x_net *mse = netdev_priv(ndev); ++ struct mse102x_net_spi *mses = to_mse102x_spi(mse); + int ret; + + ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT, +@@ -524,6 +539,13 @@ static int mse102x_net_open(struct net_device *ndev) + + netif_carrier_on(ndev); + ++ /* The SPI interrupt can stuck in case of pending packet(s). ++ * So poll for possible packet(s) to re-arm the interrupt. ++ */ ++ mutex_lock(&mses->lock); ++ mse102x_rx_pkt_spi(mse); ++ mutex_unlock(&mses->lock); ++ + netif_dbg(mse, ifup, ndev, "network device up\n"); + + return 0; +diff --git a/drivers/net/mdio/mdio-mux-meson-gxl.c b/drivers/net/mdio/mdio-mux-meson-gxl.c +index 76188575ca1fcf..19153d44800a94 100644 +--- a/drivers/net/mdio/mdio-mux-meson-gxl.c ++++ b/drivers/net/mdio/mdio-mux-meson-gxl.c +@@ -17,6 +17,7 @@ + #define REG2_LEDACT GENMASK(23, 22) + #define REG2_LEDLINK GENMASK(25, 24) + #define REG2_DIV4SEL BIT(27) ++#define REG2_REVERSED BIT(28) + #define REG2_ADCBYPASS BIT(30) + #define REG2_CLKINSEL BIT(31) + #define ETH_REG3 0x4 +@@ -65,7 +66,7 @@ static void gxl_enable_internal_mdio(struct gxl_mdio_mux *priv) + * The only constraint is that it must match the one in + * drivers/net/phy/meson-gxl.c to properly match the PHY. + */ +- writel(FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), ++ writel(REG2_REVERSED | FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), + priv->regs + ETH_REG2); + + /* Enable the internal phy */ +diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c +index bb0bf141587274..7b3739b29c8f72 100644 +--- a/drivers/net/usb/rndis_host.c ++++ b/drivers/net/usb/rndis_host.c +@@ -630,16 +630,6 @@ static const struct driver_info zte_rndis_info = { + .tx_fixup = rndis_tx_fixup, + }; + +-static const struct driver_info wwan_rndis_info = { +- .description = "Mobile Broadband RNDIS device", +- .flags = FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, +- .bind = rndis_bind, +- .unbind = rndis_unbind, +- .status = rndis_status, +- .rx_fixup = rndis_rx_fixup, +- .tx_fixup = rndis_tx_fixup, +-}; +- + /*-------------------------------------------------------------------------*/ + + static const struct usb_device_id products [] = { +@@ -676,11 +666,9 @@ static const struct usb_device_id products [] = { + USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &rndis_info, + }, { +- /* Mobile Broadband Modem, seen in Novatel Verizon USB730L and +- * Telit FN990A (RNDIS) +- */ ++ /* Novatel Verizon USB730L */ + USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1), +- .driver_info = (unsigned long)&wwan_rndis_info, ++ .driver_info = (unsigned long) &rndis_info, + }, + { }, // END + }; +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 6e6e9f05509ab0..06d19e90eadb59 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -627,7 +627,11 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan, + * default dst remote_ip previously added for this vni + */ + if (!vxlan_addr_any(&vninode->remote_ip) || +- !vxlan_addr_any(&dst->remote_ip)) ++ !vxlan_addr_any(&dst->remote_ip)) { ++ u32 hash_index = fdb_head_index(vxlan, all_zeros_mac, ++ vninode->vni); ++ ++ spin_lock_bh(&vxlan->hash_lock[hash_index]); + __vxlan_fdb_delete(vxlan, all_zeros_mac, + (vxlan_addr_any(&vninode->remote_ip) ? + dst->remote_ip : vninode->remote_ip), +@@ -635,6 +639,8 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan, + vninode->vni, vninode->vni, + dst->remote_ifindex, + true); ++ spin_unlock_bh(&vxlan->hash_lock[hash_index]); ++ } + + if (vxlan->dev->flags & IFF_UP) { + if (vxlan_addr_multicast(&vninode->remote_ip) && +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +index 2178675ae1a44d..6f64a05debd2cb 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -903,14 +903,16 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) + } + + /* 1) Prepare USB boot loader for runtime image */ +- brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state)); ++ err = brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state)); ++ if (err) ++ goto fail; + + rdlstate = le32_to_cpu(state.state); + rdlbytes = le32_to_cpu(state.bytes); + + /* 2) Check we are in the Waiting state */ + if (rdlstate != DL_WAITING) { +- brcmf_err("Failed to DL_START\n"); ++ brcmf_err("Invalid DL state: %u\n", rdlstate); + err = -EINVAL; + goto fail; + } +diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c +index 506d2f31efb5af..7ebc0df0944cb5 100644 +--- a/drivers/net/wireless/purelifi/plfxlc/mac.c ++++ b/drivers/net/wireless/purelifi/plfxlc/mac.c +@@ -103,7 +103,6 @@ int plfxlc_mac_init_hw(struct ieee80211_hw *hw) + void plfxlc_mac_release(struct plfxlc_mac *mac) + { + plfxlc_chip_release(&mac->chip); +- lockdep_assert_held(&mac->lock); + } + + int plfxlc_op_start(struct ieee80211_hw *hw) +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index a763df0200ab46..fdde38903ebcd5 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3377,7 +3377,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev) + + dev_info(dev->ctrl.device, "restart after slot reset\n"); + pci_restore_state(pdev); +- if (!nvme_try_sched_reset(&dev->ctrl)) ++ if (nvme_try_sched_reset(&dev->ctrl)) + nvme_unquiesce_io_queues(&dev->ctrl); + return PCI_ERS_RESULT_RECOVERED; + } +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 84db7f4f861cb1..5b76670f34be29 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1710,7 +1710,7 @@ static void __nvme_tcp_stop_queue(struct nvme_tcp_queue *queue) + cancel_work_sync(&queue->io_work); + } + +-static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid) ++static void nvme_tcp_stop_queue_nowait(struct nvme_ctrl *nctrl, int qid) + { + struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); + struct nvme_tcp_queue *queue = &ctrl->queues[qid]; +@@ -1724,6 +1724,31 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid) + mutex_unlock(&queue->queue_lock); + } + ++static void nvme_tcp_wait_queue(struct nvme_ctrl *nctrl, int qid) ++{ ++ struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); ++ struct nvme_tcp_queue *queue = &ctrl->queues[qid]; ++ int timeout = 100; ++ ++ while (timeout > 0) { ++ if (!test_bit(NVME_TCP_Q_ALLOCATED, &queue->flags) || ++ !sk_wmem_alloc_get(queue->sock->sk)) ++ return; ++ msleep(2); ++ timeout -= 2; ++ } ++ dev_warn(nctrl->device, ++ "qid %d: timeout draining sock wmem allocation expired\n", ++ qid); ++} ++ ++static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid) ++{ ++ nvme_tcp_stop_queue_nowait(nctrl, qid); ++ nvme_tcp_wait_queue(nctrl, qid); ++} ++ ++ + static void nvme_tcp_setup_sock_ops(struct nvme_tcp_queue *queue) + { + write_lock_bh(&queue->sock->sk->sk_callback_lock); +@@ -1790,7 +1815,9 @@ static void nvme_tcp_stop_io_queues(struct nvme_ctrl *ctrl) + int i; + + for (i = 1; i < ctrl->queue_count; i++) +- nvme_tcp_stop_queue(ctrl, i); ++ nvme_tcp_stop_queue_nowait(ctrl, i); ++ for (i = 1; i < ctrl->queue_count; i++) ++ nvme_tcp_wait_queue(ctrl, i); + } + + static int nvme_tcp_start_io_queues(struct nvme_ctrl *ctrl, +diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c +index 822a750b064b27..cedfbd4258631d 100644 +--- a/drivers/pci/controller/dwc/pci-imx6.c ++++ b/drivers/pci/controller/dwc/pci-imx6.c +@@ -1283,7 +1283,8 @@ static int imx6_pcie_probe(struct platform_device *pdev) + case IMX8MQ_EP: + if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR) + imx6_pcie->controller_id = 1; +- ++ fallthrough; ++ case IMX7D: + imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev, + "pciephy"); + if (IS_ERR(imx6_pcie->pciephy_reset)) { +diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c +index 70907e8f3ea96d..946a546cd9dd01 100644 +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -823,10 +823,9 @@ static void amd_pmc_s2idle_check(void) + struct smu_metrics table; + int rc; + +- /* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */ +- if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) && +- table.s0i3_last_entry_status) +- usleep_range(10000, 20000); ++ /* Avoid triggering OVP */ ++ if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status) ++ msleep(2500); + + /* Dump the IdleMask before we add to the STB */ + amd_pmc_idlemask_read(pdev, pdev->dev, NULL); +diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +index a3b25253b6fdeb..2c9c5cc7d854ed 100644 +--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c ++++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +@@ -121,15 +121,13 @@ static int uncore_event_cpu_online(unsigned int cpu) + { + struct uncore_data *data; + int target; ++ int ret; + + /* Check if there is an online cpu in the package for uncore MSR */ + target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu)); + if (target < nr_cpu_ids) + return 0; + +- /* Use this CPU on this die as a control CPU */ +- cpumask_set_cpu(cpu, &uncore_cpu_mask); +- + data = uncore_get_instance(cpu); + if (!data) + return 0; +@@ -138,7 +136,14 @@ static int uncore_event_cpu_online(unsigned int cpu) + data->die_id = topology_die_id(cpu); + data->domain_id = UNCORE_DOMAIN_ID_INVALID; + +- return uncore_freq_add_entry(data, cpu); ++ ret = uncore_freq_add_entry(data, cpu); ++ if (ret) ++ return ret; ++ ++ /* Use this CPU on this die as a control CPU */ ++ cpumask_set_cpu(cpu, &uncore_cpu_mask); ++ ++ return 0; + } + + static int uncore_event_cpu_offline(unsigned int cpu) +diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c +index 460f232dad508b..147d7052794f77 100644 +--- a/drivers/spi/spi-tegra114.c ++++ b/drivers/spi/spi-tegra114.c +@@ -728,9 +728,9 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi) + u32 inactive_cycles; + u8 cs_state; + +- if (setup->unit != SPI_DELAY_UNIT_SCK || +- hold->unit != SPI_DELAY_UNIT_SCK || +- inactive->unit != SPI_DELAY_UNIT_SCK) { ++ if ((setup->unit && setup->unit != SPI_DELAY_UNIT_SCK) || ++ (hold->unit && hold->unit != SPI_DELAY_UNIT_SCK) || ++ (inactive->unit && inactive->unit != SPI_DELAY_UNIT_SCK)) { + dev_err(&spi->dev, + "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n", + SPI_DELAY_UNIT_SCK); +diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c +index 99baa60ef50fe9..15a8402ee8a17a 100644 +--- a/drivers/usb/host/xhci-debugfs.c ++++ b/drivers/usb/host/xhci-debugfs.c +@@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci) + "command-ring", + xhci->debugfs_root); + +- xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring, ++ xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring, + "event-ring", + xhci->debugfs_root); + +diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c +index 0df5d807a77e8f..a2b6a922077ee3 100644 +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -1880,9 +1880,10 @@ int xhci_bus_resume(struct usb_hcd *hcd) + int slot_id; + int sret; + u32 next_state; +- u32 temp, portsc; ++ u32 portsc; + struct xhci_hub *rhub; + struct xhci_port **ports; ++ bool disabled_irq = false; + + rhub = xhci_get_rhub(hcd); + ports = rhub->ports; +@@ -1898,17 +1899,20 @@ int xhci_bus_resume(struct usb_hcd *hcd) + return -ESHUTDOWN; + } + +- /* delay the irqs */ +- temp = readl(&xhci->op_regs->command); +- temp &= ~CMD_EIE; +- writel(temp, &xhci->op_regs->command); +- + /* bus specific resume for ports we suspended at bus_suspend */ +- if (hcd->speed >= HCD_USB3) ++ if (hcd->speed >= HCD_USB3) { + next_state = XDEV_U0; +- else ++ } else { + next_state = XDEV_RESUME; +- ++ if (bus_state->bus_suspended) { ++ /* ++ * prevent port event interrupts from interfering ++ * with usb2 port resume process ++ */ ++ xhci_disable_interrupter(xhci->interrupters[0]); ++ disabled_irq = true; ++ } ++ } + port_index = max_ports; + while (port_index--) { + portsc = readl(ports[port_index]->addr); +@@ -1977,11 +1981,9 @@ int xhci_bus_resume(struct usb_hcd *hcd) + (void) readl(&xhci->op_regs->command); + + bus_state->next_statechange = jiffies + msecs_to_jiffies(5); +- /* re-enable irqs */ +- temp = readl(&xhci->op_regs->command); +- temp |= CMD_EIE; +- writel(temp, &xhci->op_regs->command); +- temp = readl(&xhci->op_regs->command); ++ /* re-enable interrupter */ ++ if (disabled_irq) ++ xhci_enable_interrupter(xhci->interrupters[0]); + + spin_unlock_irqrestore(&xhci->lock, flags); + return 0; +diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c +index fbc486546b8533..22cca89efbfd72 100644 +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -29,6 +29,7 @@ + static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, + unsigned int cycle_state, + unsigned int max_packet, ++ unsigned int num, + gfp_t flags) + { + struct xhci_segment *seg; +@@ -60,6 +61,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, + for (i = 0; i < TRBS_PER_SEGMENT; i++) + seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE); + } ++ seg->num = num; + seg->dma = dma; + seg->next = NULL; + +@@ -316,6 +318,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, + */ + ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; + } ++EXPORT_SYMBOL_GPL(xhci_initialize_ring_info); + + /* Allocate segments and link them for a ring */ + static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, +@@ -324,6 +327,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) + { + struct xhci_segment *prev; ++ unsigned int num = 0; + bool chain_links; + + /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */ +@@ -331,16 +335,17 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, + (type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST))); + +- prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); ++ prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags); + if (!prev) + return -ENOMEM; +- num_segs--; ++ num++; + + *first = prev; +- while (num_segs > 0) { ++ while (num < num_segs) { + struct xhci_segment *next; + +- next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); ++ next = xhci_segment_alloc(xhci, cycle_state, max_packet, num, ++ flags); + if (!next) { + prev = *first; + while (prev) { +@@ -353,7 +358,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, + xhci_link_segments(prev, next, type, chain_links); + + prev = next; +- num_segs--; ++ num++; + } + xhci_link_segments(prev, *first, type, chain_links); + *last = prev; +@@ -1799,23 +1804,13 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, + } + + static void +-xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) ++xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + { +- struct device *dev = xhci_to_hcd(xhci)->self.sysdev; +- size_t erst_size; +- u64 tmp64; + u32 tmp; + + if (!ir) + return; + +- erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; +- if (ir->erst.entries) +- dma_free_coherent(dev, erst_size, +- ir->erst.entries, +- ir->erst.erst_dma_addr); +- ir->erst.entries = NULL; +- + /* + * Clean out interrupter registers except ERSTBA. Clearing either the + * low or high 32 bits of ERSTBA immediately causes the controller to +@@ -1826,19 +1821,60 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + tmp &= ERST_SIZE_MASK; + writel(tmp, &ir->ir_set->erst_size); + +- tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); +- tmp64 &= (u64) ERST_PTR_MASK; +- xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue); ++ xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue); + } ++} + +- /* free interrrupter event ring */ ++static void ++xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) ++{ ++ struct device *dev = xhci_to_hcd(xhci)->self.sysdev; ++ size_t erst_size; ++ ++ if (!ir) ++ return; ++ ++ erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; ++ if (ir->erst.entries) ++ dma_free_coherent(dev, erst_size, ++ ir->erst.entries, ++ ir->erst.erst_dma_addr); ++ ir->erst.entries = NULL; ++ ++ /* free interrupter event ring */ + if (ir->event_ring) + xhci_ring_free(xhci, ir->event_ring); ++ + ir->event_ring = NULL; + + kfree(ir); + } + ++void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir) ++{ ++ struct xhci_hcd *xhci = hcd_to_xhci(hcd); ++ unsigned int intr_num; ++ ++ spin_lock_irq(&xhci->lock); ++ ++ /* interrupter 0 is primary interrupter, don't touch it */ ++ if (!ir || !ir->intr_num || ir->intr_num >= xhci->max_interrupters) { ++ xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n"); ++ spin_unlock_irq(&xhci->lock); ++ return; ++ } ++ ++ intr_num = ir->intr_num; ++ ++ xhci_remove_interrupter(xhci, ir); ++ xhci->interrupters[intr_num] = NULL; ++ ++ spin_unlock_irq(&xhci->lock); ++ ++ xhci_free_interrupter(xhci, ir); ++} ++EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter); ++ + void xhci_mem_cleanup(struct xhci_hcd *xhci) + { + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; +@@ -1846,9 +1882,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + + cancel_delayed_work_sync(&xhci->cmd_timer); + +- xhci_free_interrupter(xhci, xhci->interrupter); +- xhci->interrupter = NULL; +- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring"); ++ for (i = 0; xhci->interrupters && i < xhci->max_interrupters; i++) { ++ if (xhci->interrupters[i]) { ++ xhci_remove_interrupter(xhci, xhci->interrupters[i]); ++ xhci_free_interrupter(xhci, xhci->interrupters[i]); ++ xhci->interrupters[i] = NULL; ++ } ++ } ++ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters"); + + if (xhci->cmd_ring) + xhci_ring_free(xhci, xhci->cmd_ring); +@@ -1918,6 +1959,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + for (i = 0; i < xhci->num_port_caps; i++) + kfree(xhci->port_caps[i].psi); + kfree(xhci->port_caps); ++ kfree(xhci->interrupters); + xhci->num_port_caps = 0; + + xhci->usb2_rhub.ports = NULL; +@@ -1926,6 +1968,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + xhci->rh_bw = NULL; + xhci->ext_caps = NULL; + xhci->port_caps = NULL; ++ xhci->interrupters = NULL; + + xhci->page_size = 0; + xhci->page_shift = 0; +@@ -1935,7 +1978,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + + static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + { +- u64 temp; + dma_addr_t deq; + + deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, +@@ -1943,15 +1985,12 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter + if (!deq) + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n"); + /* Update HC event ring dequeue pointer */ +- temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); +- temp &= ERST_PTR_MASK; + /* Don't clear the EHB bit (which is RW1C) because + * there might be more events to service. + */ +- temp &= ~ERST_EHB; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Write event ring dequeue pointer, preserving EHB bit"); +- xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, ++ xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK), + &ir->ir_set->erst_dequeue); + } + +@@ -2236,18 +2275,24 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) + } + + static struct xhci_interrupter * +-xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags) ++xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags) + { + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + struct xhci_interrupter *ir; ++ unsigned int max_segs; + int ret; + ++ if (!segs) ++ segs = ERST_DEFAULT_SEGS; ++ ++ max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2)); ++ segs = min(segs, max_segs); ++ + ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); + if (!ir) + return NULL; + +- ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, +- 0, flags); ++ ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags); + if (!ir->event_ring) { + xhci_warn(xhci, "Failed to allocate interrupter event ring\n"); + kfree(ir); +@@ -2278,12 +2323,19 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, + return -EINVAL; + } + ++ if (xhci->interrupters[intr_num]) { ++ xhci_warn(xhci, "Interrupter %d\n already set up", intr_num); ++ return -EINVAL; ++ } ++ ++ xhci->interrupters[intr_num] = ir; ++ ir->intr_num = intr_num; + ir->ir_set = &xhci->run_regs->ir_set[intr_num]; + + /* set ERST count with the number of entries in the segment table */ + erst_size = readl(&ir->ir_set->erst_size); + erst_size &= ERST_SIZE_MASK; +- erst_size |= ERST_NUM_SEGS; ++ erst_size |= ir->event_ring->num_segs; + writel(erst_size, &ir->ir_set->erst_size); + + erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); +@@ -2300,10 +2352,58 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, + return 0; + } + ++struct xhci_interrupter * ++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, ++ u32 imod_interval) ++{ ++ struct xhci_hcd *xhci = hcd_to_xhci(hcd); ++ struct xhci_interrupter *ir; ++ unsigned int i; ++ int err = -ENOSPC; ++ ++ if (!xhci->interrupters || xhci->max_interrupters <= 1) ++ return NULL; ++ ++ ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL); ++ if (!ir) ++ return NULL; ++ ++ spin_lock_irq(&xhci->lock); ++ ++ /* Find available secondary interrupter, interrupter 0 is reserved for primary */ ++ for (i = 1; i < xhci->max_interrupters; i++) { ++ if (xhci->interrupters[i] == NULL) { ++ err = xhci_add_interrupter(xhci, ir, i); ++ break; ++ } ++ } ++ ++ spin_unlock_irq(&xhci->lock); ++ ++ if (err) { ++ xhci_warn(xhci, "Failed to add secondary interrupter, max interrupters %d\n", ++ xhci->max_interrupters); ++ xhci_free_interrupter(xhci, ir); ++ return NULL; ++ } ++ ++ err = xhci_set_interrupter_moderation(ir, imod_interval); ++ if (err) ++ xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n", ++ i, imod_interval); ++ ++ xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n", ++ i, xhci->max_interrupters); ++ ++ return ir; ++} ++EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter); ++ + int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) + { +- dma_addr_t dma; ++ struct xhci_interrupter *ir; + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; ++ dma_addr_t dma; + unsigned int val, val2; + u64 val_64; + u32 page_size, temp; +@@ -2428,11 +2528,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) + /* Allocate and set up primary interrupter 0 with an event ring. */ + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Allocating primary event ring"); +- xhci->interrupter = xhci_alloc_interrupter(xhci, flags); +- if (!xhci->interrupter) ++ xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters), ++ flags, dev_to_node(dev)); ++ ++ ir = xhci_alloc_interrupter(xhci, 0, flags); ++ if (!ir) + goto fail; + +- if (xhci_add_interrupter(xhci, xhci->interrupter, 0)) ++ if (xhci_add_interrupter(xhci, ir, 0)) + goto fail; + + xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index cb944396294516..5a53280fa2edfd 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -3167,7 +3167,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + return; + + /* Update HC event ring dequeue pointer */ +- temp_64 &= ERST_DESI_MASK; ++ temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK; + temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK); + } + +@@ -3225,7 +3225,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) + writel(status, &xhci->op_regs->status); + + /* This is the handler of the primary interrupter */ +- ir = xhci->interrupter; ++ ir = xhci->interrupters[0]; + if (!hcd->msi_enabled) { + u32 irq_pending; + irq_pending = readl(&ir->ir_set->irq_pending); +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 70e6c240a5409f..ce38cd2435c8c3 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -297,7 +297,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) + xhci_info(xhci, "Fault detected\n"); + } + +-static int xhci_enable_interrupter(struct xhci_interrupter *ir) ++int xhci_enable_interrupter(struct xhci_interrupter *ir) + { + u32 iman; + +@@ -310,7 +310,7 @@ static int xhci_enable_interrupter(struct xhci_interrupter *ir) + return 0; + } + +-static int xhci_disable_interrupter(struct xhci_interrupter *ir) ++int xhci_disable_interrupter(struct xhci_interrupter *ir) + { + u32 iman; + +@@ -323,6 +323,23 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) + return 0; + } + ++/* interrupt moderation interval imod_interval in nanoseconds */ ++int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, ++ u32 imod_interval) ++{ ++ u32 imod; ++ ++ if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250) ++ return -EINVAL; ++ ++ imod = readl(&ir->ir_set->irq_control); ++ imod &= ~ER_IRQ_INTERVAL_MASK; ++ imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK; ++ writel(imod, &ir->ir_set->irq_control); ++ ++ return 0; ++} ++ + static void compliance_mode_recovery(struct timer_list *t) + { + struct xhci_hcd *xhci; +@@ -457,7 +474,7 @@ static int xhci_init(struct usb_hcd *hcd) + + static int xhci_run_finished(struct xhci_hcd *xhci) + { +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir = xhci->interrupters[0]; + unsigned long flags; + u32 temp; + +@@ -505,11 +522,10 @@ static int xhci_run_finished(struct xhci_hcd *xhci) + */ + int xhci_run(struct usb_hcd *hcd) + { +- u32 temp; + u64 temp_64; + int ret; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir = xhci->interrupters[0]; + /* Start the xHCI host controller running only after the USB 2.0 roothub + * is setup. + */ +@@ -525,12 +541,7 @@ int xhci_run(struct usb_hcd *hcd) + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "ERST deq = 64'h%0lx", (long unsigned int) temp_64); + +- xhci_dbg_trace(xhci, trace_xhci_dbg_init, +- "// Set the interrupt modulation register"); +- temp = readl(&ir->ir_set->irq_control); +- temp &= ~ER_IRQ_INTERVAL_MASK; +- temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK; +- writel(temp, &ir->ir_set->irq_control); ++ xhci_set_interrupter_moderation(ir, xhci->imod_interval); + + if (xhci->quirks & XHCI_NEC_HOST) { + struct xhci_command *command; +@@ -573,7 +584,7 @@ void xhci_stop(struct usb_hcd *hcd) + { + u32 temp; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir = xhci->interrupters[0]; + + mutex_lock(&xhci->mutex); + +@@ -669,36 +680,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown); + #ifdef CONFIG_PM + static void xhci_save_registers(struct xhci_hcd *xhci) + { +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir; ++ unsigned int i; + + xhci->s3.command = readl(&xhci->op_regs->command); + xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification); + xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); + xhci->s3.config_reg = readl(&xhci->op_regs->config_reg); + +- if (!ir) +- return; ++ /* save both primary and all secondary interrupters */ ++ /* fixme, shold we lock to prevent race with remove secondary interrupter? */ ++ for (i = 0; i < xhci->max_interrupters; i++) { ++ ir = xhci->interrupters[i]; ++ if (!ir) ++ continue; + +- ir->s3_erst_size = readl(&ir->ir_set->erst_size); +- ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); +- ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); +- ir->s3_irq_pending = readl(&ir->ir_set->irq_pending); +- ir->s3_irq_control = readl(&ir->ir_set->irq_control); ++ ir->s3_erst_size = readl(&ir->ir_set->erst_size); ++ ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); ++ ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); ++ ir->s3_irq_pending = readl(&ir->ir_set->irq_pending); ++ ir->s3_irq_control = readl(&ir->ir_set->irq_control); ++ } + } + + static void xhci_restore_registers(struct xhci_hcd *xhci) + { +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir; ++ unsigned int i; + + writel(xhci->s3.command, &xhci->op_regs->command); + writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification); + xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); + writel(xhci->s3.config_reg, &xhci->op_regs->config_reg); +- writel(ir->s3_erst_size, &ir->ir_set->erst_size); +- xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base); +- xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue); +- writel(ir->s3_irq_pending, &ir->ir_set->irq_pending); +- writel(ir->s3_irq_control, &ir->ir_set->irq_control); ++ ++ /* FIXME should we lock to protect against freeing of interrupters */ ++ for (i = 0; i < xhci->max_interrupters; i++) { ++ ir = xhci->interrupters[i]; ++ if (!ir) ++ continue; ++ ++ writel(ir->s3_erst_size, &ir->ir_set->erst_size); ++ xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base); ++ xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue); ++ writel(ir->s3_irq_pending, &ir->ir_set->irq_pending); ++ writel(ir->s3_irq_control, &ir->ir_set->irq_control); ++ } + } + + static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) +@@ -1061,7 +1087,7 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg) + xhci_dbg(xhci, "// Disabling event ring interrupts\n"); + temp = readl(&xhci->op_regs->status); + writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status); +- xhci_disable_interrupter(xhci->interrupter); ++ xhci_disable_interrupter(xhci->interrupters[0]); + + xhci_dbg(xhci, "cleaning up memory\n"); + xhci_mem_cleanup(xhci); +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index df87e8bcb7d246..74bdd035d756a4 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1293,6 +1293,7 @@ struct xhci_segment { + union xhci_trb *trbs; + /* private to HCD */ + struct xhci_segment *next; ++ unsigned int num; + dma_addr_t dma; + /* Max packet sized bounce buffer for td-fragmant alignment */ + dma_addr_t bounce_dma; +@@ -1422,12 +1423,8 @@ struct urb_priv { + struct xhci_td td[]; + }; + +-/* +- * Each segment table entry is 4*32bits long. 1K seems like an ok size: +- * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, +- * meaning 64 ring segments. +- * Initial allocated size of the ERST, in number of entries */ +-#define ERST_NUM_SEGS 1 ++/* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */ ++#define ERST_DEFAULT_SEGS 2 + /* Poll every 60 seconds */ + #define POLL_TIMEOUT 60 + /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ +@@ -1552,7 +1549,7 @@ struct xhci_hcd { + struct reset_control *reset; + /* data structures */ + struct xhci_device_context_array *dcbaa; +- struct xhci_interrupter *interrupter; ++ struct xhci_interrupter **interrupters; + struct xhci_ring *cmd_ring; + unsigned int cmd_ring_state; + #define CMD_RING_STATE_RUNNING (1 << 0) +@@ -1869,6 +1866,11 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, + int type, gfp_t flags); + void xhci_free_container_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx); ++struct xhci_interrupter * ++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, ++ u32 imod_interval); ++void xhci_remove_secondary_interrupter(struct usb_hcd ++ *hcd, struct xhci_interrupter *ir); + + /* xHCI host controller glue */ + typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); +@@ -1904,6 +1906,10 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + struct usb_device *hdev, + struct usb_tt *tt, gfp_t mem_flags); ++int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, ++ u32 imod_interval); ++int xhci_enable_interrupter(struct xhci_interrupter *ir); ++int xhci_disable_interrupter(struct xhci_interrupter *ir); + + /* xHCI ring, segment, TRB, and TD functions */ + dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 11c4d69177f0ca..48d2579236729d 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -2058,12 +2058,13 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, + + /* + * If the found extent starts after requested offset, then +- * adjust extent_end to be right before this extent begins ++ * adjust cur_offset to be right before this extent begins. + */ + if (found_key.offset > cur_offset) { +- extent_end = found_key.offset; +- extent_type = 0; +- goto must_cow; ++ if (cow_start == (u64)-1) ++ cow_start = cur_offset; ++ cur_offset = found_key.offset; ++ goto next_slot; + } + + /* +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index 0af3535e08f308..4536b6fcfa0256 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -2932,6 +2932,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, + req->CreateContextsOffset = cpu_to_le32( + sizeof(struct smb2_create_req) + + iov[1].iov_len); ++ le32_add_cpu(&req->CreateContextsLength, iov[n_iov-1].iov_len); + pc_buf = iov[n_iov-1].iov_base; + } + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index 5345d2417c7fc9..f4b20b80af0620 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -546,7 +546,19 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, + retval = -ENOMEM; + goto out; + } +- sess->user = user; ++ ++ if (!sess->user) { ++ /* First successful authentication */ ++ sess->user = user; ++ } else { ++ if (!ksmbd_compare_user(sess->user, user)) { ++ ksmbd_debug(AUTH, "different user tried to reuse session\n"); ++ retval = -EPERM; ++ ksmbd_free_user(user); ++ goto out; ++ } ++ ksmbd_free_user(user); ++ } + + memcpy(sess->sess_key, resp->payload, resp->session_key_len); + memcpy(out_blob, resp->payload + resp->session_key_len, +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index d41d67ec5ee51a..13750a5e5ba02e 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -1599,11 +1599,6 @@ static int krb5_authenticate(struct ksmbd_work *work, + if (prev_sess_id && prev_sess_id != sess->id) + destroy_previous_session(conn, sess->user, prev_sess_id); + +- if (sess->state == SMB2_SESSION_VALID) { +- ksmbd_free_user(sess->user); +- sess->user = NULL; +- } +- + retval = ksmbd_krb5_authenticate(sess, in_blob, in_len, + out_blob, &out_len); + if (retval) { +diff --git a/include/linux/bpf.h b/include/linux/bpf.h +index 035e627f94f62d..17de12a98f858a 100644 +--- a/include/linux/bpf.h ++++ b/include/linux/bpf.h +@@ -1430,6 +1430,7 @@ struct bpf_prog_aux { + bool sleepable; + bool tail_call_reachable; + bool xdp_has_frags; ++ bool changes_pkt_data; + /* BTF_KIND_FUNC_PROTO for valid attach_btf_id */ + const struct btf_type *attach_func_proto; + /* function name for valid attach_btf_id */ +diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h +index 92919d52f7e1b2..32e89758176be8 100644 +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -573,6 +573,7 @@ struct bpf_subprog_info { + bool tail_call_reachable; + bool has_ld_abs; + bool is_async_cb; ++ bool changes_pkt_data; + }; + + struct bpf_verifier_env; +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index 9ca4211c063f39..184a84dd467ec7 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -787,8 +787,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy, + int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy); + + int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, +- unsigned int target_freq, +- unsigned int relation); ++ unsigned int target_freq, unsigned int min, ++ unsigned int max, unsigned int relation); + int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, + unsigned int freq); + +@@ -853,12 +853,12 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy, + return best; + } + +-/* Works only on sorted freq-tables */ +-static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy, +- unsigned int target_freq, +- bool efficiencies) ++static inline int find_index_l(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ bool efficiencies) + { +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_al(policy, target_freq, +@@ -868,6 +868,14 @@ static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy, + efficiencies); + } + ++/* Works only on sorted freq-tables */ ++static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ bool efficiencies) ++{ ++ return find_index_l(policy, target_freq, policy->min, policy->max, efficiencies); ++} ++ + /* Find highest freq at or below target in a table in ascending order */ + static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy, + unsigned int target_freq, +@@ -921,12 +929,12 @@ static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy, + return best; + } + +-/* Works only on sorted freq-tables */ +-static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy, +- unsigned int target_freq, +- bool efficiencies) ++static inline int find_index_h(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ bool efficiencies) + { +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_ah(policy, target_freq, +@@ -936,6 +944,14 @@ static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy, + efficiencies); + } + ++/* Works only on sorted freq-tables */ ++static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ bool efficiencies) ++{ ++ return find_index_h(policy, target_freq, policy->min, policy->max, efficiencies); ++} ++ + /* Find closest freq to target in a table in ascending order */ + static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, + unsigned int target_freq, +@@ -1006,12 +1022,12 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, + return best; + } + +-/* Works only on sorted freq-tables */ +-static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, +- unsigned int target_freq, +- bool efficiencies) ++static inline int find_index_c(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ bool efficiencies) + { +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_ac(policy, target_freq, +@@ -1021,7 +1037,17 @@ static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, + efficiencies); + } + +-static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, int idx) ++/* Works only on sorted freq-tables */ ++static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ bool efficiencies) ++{ ++ return find_index_c(policy, target_freq, policy->min, policy->max, efficiencies); ++} ++ ++static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, ++ unsigned int min, unsigned int max, ++ int idx) + { + unsigned int freq; + +@@ -1030,11 +1056,13 @@ static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, int idx) + + freq = policy->freq_table[idx].frequency; + +- return freq == clamp_val(freq, policy->min, policy->max); ++ return freq == clamp_val(freq, min, max); + } + + static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + unsigned int target_freq, ++ unsigned int min, ++ unsigned int max, + unsigned int relation) + { + bool efficiencies = policy->efficiencies_available && +@@ -1045,29 +1073,26 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + relation &= ~CPUFREQ_RELATION_E; + + if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED)) +- return cpufreq_table_index_unsorted(policy, target_freq, +- relation); ++ return cpufreq_table_index_unsorted(policy, target_freq, min, ++ max, relation); + retry: + switch (relation) { + case CPUFREQ_RELATION_L: +- idx = cpufreq_table_find_index_l(policy, target_freq, +- efficiencies); ++ idx = find_index_l(policy, target_freq, min, max, efficiencies); + break; + case CPUFREQ_RELATION_H: +- idx = cpufreq_table_find_index_h(policy, target_freq, +- efficiencies); ++ idx = find_index_h(policy, target_freq, min, max, efficiencies); + break; + case CPUFREQ_RELATION_C: +- idx = cpufreq_table_find_index_c(policy, target_freq, +- efficiencies); ++ idx = find_index_c(policy, target_freq, min, max, efficiencies); + break; + default: + WARN_ON_ONCE(1); + return 0; + } + +- /* Limit frequency index to honor policy->min/max */ +- if (!cpufreq_is_in_limits(policy, idx) && efficiencies) { ++ /* Limit frequency index to honor min and max */ ++ if (!cpufreq_is_in_limits(policy, min, max, idx) && efficiencies) { + efficiencies = false; + goto retry; + } +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 5090e940ba3e46..adf65eacade062 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -915,7 +915,7 @@ bool bpf_jit_needs_zext(void); + bool bpf_jit_supports_subprog_tailcalls(void); + bool bpf_jit_supports_kfunc_call(void); + bool bpf_jit_supports_far_kfunc_call(void); +-bool bpf_helper_changes_pkt_data(void *func); ++bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id); + + static inline bool bpf_dump_raw_ok(const struct cred *cred) + { +diff --git a/include/linux/module.h b/include/linux/module.h +index a98e188cf37b81..f2a8624eef1eca 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -162,6 +162,8 @@ extern void cleanup_module(void); + #define __INITRODATA_OR_MODULE __INITRODATA + #endif /*CONFIG_MODULES*/ + ++struct module_kobject *lookup_or_create_module_kobject(const char *name); ++ + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) + +diff --git a/include/linux/pds/pds_core_if.h b/include/linux/pds/pds_core_if.h +index e838a2b90440ca..17a87c1a55d7c7 100644 +--- a/include/linux/pds/pds_core_if.h ++++ b/include/linux/pds/pds_core_if.h +@@ -79,6 +79,7 @@ enum pds_core_status_code { + PDS_RC_EVFID = 31, /* VF ID does not exist */ + PDS_RC_BAD_FW = 32, /* FW file is invalid or corrupted */ + PDS_RC_ECLIENT = 33, /* No such client id */ ++ PDS_RC_BAD_PCI = 255, /* Broken PCI when reading status */ + }; + + /** +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 5f11f987334190..f7d392d849be56 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -685,6 +685,11 @@ typedef unsigned int sk_buff_data_t; + typedef unsigned char *sk_buff_data_t; + #endif + ++enum skb_tstamp_type { ++ SKB_CLOCK_REALTIME, ++ SKB_CLOCK_MONOTONIC, ++}; ++ + /** + * DOC: Basic sk_buff geometry + * +@@ -804,10 +809,8 @@ typedef unsigned char *sk_buff_data_t; + * @dst_pending_confirm: need to confirm neighbour + * @decrypted: Decrypted SKB + * @slow_gro: state present at GRO time, slower prepare step required +- * @mono_delivery_time: When set, skb->tstamp has the +- * delivery_time in mono clock base (i.e. EDT). Otherwise, the +- * skb->tstamp has the (rcv) timestamp at ingress and +- * delivery_time at egress. ++ * @tstamp_type: When set, skb->tstamp has the ++ * delivery_time clock base of skb->tstamp. + * @napi_id: id of the NAPI struct this skb came from + * @sender_cpu: (aka @napi_id) source CPU in XPS + * @alloc_cpu: CPU which did the skb allocation. +@@ -935,7 +938,7 @@ struct sk_buff { + /* private: */ + __u8 __mono_tc_offset[0]; + /* public: */ +- __u8 mono_delivery_time:1; /* See SKB_MONO_DELIVERY_TIME_MASK */ ++ __u8 tstamp_type:1; /* See skb_tstamp_type */ + #ifdef CONFIG_NET_XGRESS + __u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */ + __u8 tc_skip_classify:1; +@@ -4189,7 +4192,7 @@ static inline void skb_get_new_timestampns(const struct sk_buff *skb, + static inline void __net_timestamp(struct sk_buff *skb) + { + skb->tstamp = ktime_get_real(); +- skb->mono_delivery_time = 0; ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + } + + static inline ktime_t net_timedelta(ktime_t t) +@@ -4198,10 +4201,33 @@ static inline ktime_t net_timedelta(ktime_t t) + } + + static inline void skb_set_delivery_time(struct sk_buff *skb, ktime_t kt, +- bool mono) ++ u8 tstamp_type) + { + skb->tstamp = kt; +- skb->mono_delivery_time = kt && mono; ++ ++ if (kt) ++ skb->tstamp_type = tstamp_type; ++ else ++ skb->tstamp_type = SKB_CLOCK_REALTIME; ++} ++ ++static inline void skb_set_delivery_type_by_clockid(struct sk_buff *skb, ++ ktime_t kt, clockid_t clockid) ++{ ++ u8 tstamp_type = SKB_CLOCK_REALTIME; ++ ++ switch (clockid) { ++ case CLOCK_REALTIME: ++ break; ++ case CLOCK_MONOTONIC: ++ tstamp_type = SKB_CLOCK_MONOTONIC; ++ break; ++ default: ++ WARN_ON_ONCE(1); ++ kt = 0; ++ } ++ ++ skb_set_delivery_time(skb, kt, tstamp_type); + } + + DECLARE_STATIC_KEY_FALSE(netstamp_needed_key); +@@ -4211,8 +4237,8 @@ DECLARE_STATIC_KEY_FALSE(netstamp_needed_key); + */ + static inline void skb_clear_delivery_time(struct sk_buff *skb) + { +- if (skb->mono_delivery_time) { +- skb->mono_delivery_time = 0; ++ if (skb->tstamp_type) { ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + if (static_branch_unlikely(&netstamp_needed_key)) + skb->tstamp = ktime_get_real(); + else +@@ -4222,7 +4248,7 @@ static inline void skb_clear_delivery_time(struct sk_buff *skb) + + static inline void skb_clear_tstamp(struct sk_buff *skb) + { +- if (skb->mono_delivery_time) ++ if (skb->tstamp_type) + return; + + skb->tstamp = 0; +@@ -4230,7 +4256,7 @@ static inline void skb_clear_tstamp(struct sk_buff *skb) + + static inline ktime_t skb_tstamp(const struct sk_buff *skb) + { +- if (skb->mono_delivery_time) ++ if (skb->tstamp_type) + return 0; + + return skb->tstamp; +@@ -4238,7 +4264,7 @@ static inline ktime_t skb_tstamp(const struct sk_buff *skb) + + static inline ktime_t skb_tstamp_cond(const struct sk_buff *skb, bool cond) + { +- if (!skb->mono_delivery_time && skb->tstamp) ++ if (skb->tstamp_type != SKB_CLOCK_MONOTONIC && skb->tstamp) + return skb->tstamp; + + if (static_branch_unlikely(&netstamp_needed_key) || cond) +diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h +index 153960663ce4c2..5af6eb14c5db15 100644 +--- a/include/net/inet_frag.h ++++ b/include/net/inet_frag.h +@@ -76,7 +76,7 @@ struct frag_v6_compare_key { + * @stamp: timestamp of the last received fragment + * @len: total length of the original datagram + * @meat: length of received fragments so far +- * @mono_delivery_time: stamp has a mono delivery time (EDT) ++ * @tstamp_type: stamp has a mono delivery time (EDT) + * @flags: fragment queue flags + * @max_size: maximum received fragment size + * @fqdir: pointer to struct fqdir +@@ -97,7 +97,7 @@ struct inet_frag_queue { + ktime_t stamp; + int len; + int meat; +- u8 mono_delivery_time; ++ u8 tstamp_type; + __u8 flags; + u16 max_size; + struct fqdir *fqdir; +diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h +index c601a4598b0da8..eb19668a06db17 100644 +--- a/include/soc/mscc/ocelot_vcap.h ++++ b/include/soc/mscc/ocelot_vcap.h +@@ -13,6 +13,7 @@ + */ + #define OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream) ((upstream) << 16 | (port)) + #define OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port) (port) ++#define OCELOT_VCAP_IS1_VLAN_RECLASSIFY(ocelot, port) ((ocelot)->num_phys_ports + (port)) + #define OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port) (port) + #define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) ((ocelot)->num_phys_ports + (port)) + #define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2) +@@ -499,6 +500,7 @@ struct ocelot_vcap_key_vlan { + struct ocelot_vcap_u8 pcp; /* PCP (3 bit) */ + enum ocelot_vcap_bit dei; /* DEI */ + enum ocelot_vcap_bit tagged; /* Tagged/untagged frame */ ++ enum ocelot_vcap_bit tpid; + }; + + struct ocelot_vcap_key_etype { +diff --git a/include/sound/ump_convert.h b/include/sound/ump_convert.h +index d099ae27f8491a..682499b871eac4 100644 +--- a/include/sound/ump_convert.h ++++ b/include/sound/ump_convert.h +@@ -19,7 +19,7 @@ struct ump_cvt_to_ump_bank { + /* context for converting from MIDI1 byte stream to UMP packet */ + struct ump_cvt_to_ump { + /* MIDI1 intermediate buffer */ +- unsigned char buf[4]; ++ unsigned char buf[6]; /* up to 6 bytes for SysEx */ + int len; + int cmd_bytes; + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 02f327f05fd619..81fd1bb9941644 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -2893,7 +2893,7 @@ void __weak bpf_jit_compile(struct bpf_prog *prog) + { + } + +-bool __weak bpf_helper_changes_pkt_data(void *func) ++bool __weak bpf_helper_changes_pkt_data(enum bpf_func_id func_id) + { + return false; + } +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index e443506b0a65a1..756e179a1efe3e 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -2636,16 +2636,36 @@ static int cmp_subprogs(const void *a, const void *b) + ((struct bpf_subprog_info *)b)->start; + } + ++/* Find subprogram that contains instruction at 'off' */ ++static struct bpf_subprog_info *find_containing_subprog(struct bpf_verifier_env *env, int off) ++{ ++ struct bpf_subprog_info *vals = env->subprog_info; ++ int l, r, m; ++ ++ if (off >= env->prog->len || off < 0 || env->subprog_cnt == 0) ++ return NULL; ++ ++ l = 0; ++ r = env->subprog_cnt - 1; ++ while (l < r) { ++ m = l + (r - l + 1) / 2; ++ if (vals[m].start <= off) ++ l = m; ++ else ++ r = m - 1; ++ } ++ return &vals[l]; ++} ++ ++/* Find subprogram that starts exactly at 'off' */ + static int find_subprog(struct bpf_verifier_env *env, int off) + { + struct bpf_subprog_info *p; + +- p = bsearch(&off, env->subprog_info, env->subprog_cnt, +- sizeof(env->subprog_info[0]), cmp_subprogs); +- if (!p) ++ p = find_containing_subprog(env, off); ++ if (!p || p->start != off) + return -ENOENT; + return p - env->subprog_info; +- + } + + static int add_subprog(struct bpf_verifier_env *env, int off) +@@ -9344,6 +9364,8 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, + + if (env->log.level & BPF_LOG_LEVEL) + verbose(env, "Func#%d is global and valid. Skipping.\n", subprog); ++ if (env->subprog_info[subprog].changes_pkt_data) ++ clear_all_pkt_pointers(env); + clear_caller_saved_regs(env, caller->regs); + + /* All global functions return a 64-bit SCALAR_VALUE */ +@@ -9987,7 +10009,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn + } + + /* With LD_ABS/IND some JITs save/restore skb from r1. */ +- changes_data = bpf_helper_changes_pkt_data(fn->func); ++ changes_data = bpf_helper_changes_pkt_data(func_id); + if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) { + verbose(env, "kernel subsystem misconfigured func %s#%d: r1 != ctx\n", + func_id_name(func_id), func_id); +@@ -15094,6 +15116,29 @@ static int check_return_code(struct bpf_verifier_env *env) + return 0; + } + ++static void mark_subprog_changes_pkt_data(struct bpf_verifier_env *env, int off) ++{ ++ struct bpf_subprog_info *subprog; ++ ++ subprog = find_containing_subprog(env, off); ++ subprog->changes_pkt_data = true; ++} ++ ++/* 't' is an index of a call-site. ++ * 'w' is a callee entry point. ++ * Eventually this function would be called when env->cfg.insn_state[w] == EXPLORED. ++ * Rely on DFS traversal order and absence of recursive calls to guarantee that ++ * callee's change_pkt_data marks would be correct at that moment. ++ */ ++static void merge_callee_effects(struct bpf_verifier_env *env, int t, int w) ++{ ++ struct bpf_subprog_info *caller, *callee; ++ ++ caller = find_containing_subprog(env, t); ++ callee = find_containing_subprog(env, w); ++ caller->changes_pkt_data |= callee->changes_pkt_data; ++} ++ + /* non-recursive DFS pseudo code + * 1 procedure DFS-iterative(G,v): + * 2 label v as discovered +@@ -15227,6 +15272,7 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns, + bool visit_callee) + { + int ret, insn_sz; ++ int w; + + insn_sz = bpf_is_ldimm64(&insns[t]) ? 2 : 1; + ret = push_insn(t, t + insn_sz, FALLTHROUGH, env); +@@ -15238,8 +15284,10 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns, + mark_jmp_point(env, t + insn_sz); + + if (visit_callee) { ++ w = t + insns[t].imm + 1; + mark_prune_point(env, t); +- ret = push_insn(t, t + insns[t].imm + 1, BRANCH, env); ++ merge_callee_effects(env, t, w); ++ ret = push_insn(t, w, BRANCH, env); + } + return ret; + } +@@ -15291,6 +15339,8 @@ static int visit_insn(int t, struct bpf_verifier_env *env) + mark_prune_point(env, t); + mark_jmp_point(env, t); + } ++ if (bpf_helper_call(insn) && bpf_helper_changes_pkt_data(insn->imm)) ++ mark_subprog_changes_pkt_data(env, t); + if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { + struct bpf_kfunc_call_arg_meta meta; + +@@ -15412,6 +15462,7 @@ static int check_cfg(struct bpf_verifier_env *env) + } + } + ret = 0; /* cfg looks good */ ++ env->prog->aux->changes_pkt_data = env->subprog_info[0].changes_pkt_data; + + err_free: + kvfree(insn_state); +@@ -18572,6 +18623,7 @@ static int jit_subprogs(struct bpf_verifier_env *env) + } + func[i]->aux->num_exentries = num_exentries; + func[i]->aux->tail_call_reachable = env->subprog_info[i].tail_call_reachable; ++ func[i]->aux->changes_pkt_data = env->subprog_info[i].changes_pkt_data; + func[i] = bpf_int_jit_compile(func[i]); + if (!func[i]->jited) { + err = -ENOTSUPP; +@@ -19856,6 +19908,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, + } + if (tgt_prog) { + struct bpf_prog_aux *aux = tgt_prog->aux; ++ bool tgt_changes_pkt_data; + + if (bpf_prog_is_dev_bound(prog->aux) && + !bpf_prog_dev_bound_match(prog, tgt_prog)) { +@@ -19884,6 +19937,14 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, + "Extension programs should be JITed\n"); + return -EINVAL; + } ++ tgt_changes_pkt_data = aux->func ++ ? aux->func[subprog]->aux->changes_pkt_data ++ : aux->changes_pkt_data; ++ if (prog->aux->changes_pkt_data && !tgt_changes_pkt_data) { ++ bpf_log(log, ++ "Extension program changes packet data, while original does not\n"); ++ return -EINVAL; ++ } + } + if (!tgt_prog->jited) { + bpf_log(log, "Can attach to only JITed progs\n"); +@@ -20343,10 +20404,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 + if (ret < 0) + goto skip_full_check; + +- ret = check_attach_btf_id(env); +- if (ret) +- goto skip_full_check; +- + ret = resolve_pseudo_ldimm64(env); + if (ret < 0) + goto skip_full_check; +@@ -20361,6 +20418,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 + if (ret < 0) + goto skip_full_check; + ++ ret = check_attach_btf_id(env); ++ if (ret) ++ goto skip_full_check; ++ + ret = do_check_subprogs(env); + ret = ret ?: do_check_main(env); + +diff --git a/kernel/params.c b/kernel/params.c +index 2d4a0564697e83..c7aed3c51cd538 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -759,7 +759,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-static struct module_kobject * __init locate_module_kobject(const char *name) ++struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +@@ -801,7 +801,7 @@ static void __init kernel_add_sysfs_param(const char *name, + struct module_kobject *mk; + int err; + +- mk = locate_module_kobject(name); ++ mk = lookup_or_create_module_kobject(name); + if (!mk) + return; + +@@ -872,7 +872,7 @@ static void __init version_sysfs_builtin(void) + int err; + + for (vattr = __start___modver; vattr < __stop___modver; vattr++) { +- mk = locate_module_kobject(vattr->module_name); ++ mk = lookup_or_create_module_kobject(vattr->module_name); + if (mk) { + err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); + WARN_ON_ONCE(err); +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index a41c99350a5bf7..95868c31573007 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -7027,13 +7027,14 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, + /* Copy the data into the page, so we can start over. */ + ret = trace_seq_to_buffer(&iter->seq, + page_address(spd.pages[i]), +- trace_seq_used(&iter->seq)); ++ min((size_t)trace_seq_used(&iter->seq), ++ PAGE_SIZE)); + if (ret < 0) { + __free_page(spd.pages[i]); + break; + } + spd.partial[i].offset = 0; +- spd.partial[i].len = trace_seq_used(&iter->seq); ++ spd.partial[i].len = ret; + + trace_seq_init(&iter->seq); + } +diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c +index 2b948d35fb59ea..448ee37ae2450a 100644 +--- a/kernel/trace/trace_output.c ++++ b/kernel/trace/trace_output.c +@@ -950,11 +950,12 @@ enum print_line_t print_event_fields(struct trace_iterator *iter, + struct trace_event_call *call; + struct list_head *head; + ++ lockdep_assert_held_read(&trace_event_sem); ++ + /* ftrace defined events have separate call structures */ + if (event->type <= __TRACE_LAST_TYPE) { + bool found = false; + +- down_read(&trace_event_sem); + list_for_each_entry(call, &ftrace_events, list) { + if (call->event.type == event->type) { + found = true; +@@ -964,7 +965,6 @@ enum print_line_t print_event_fields(struct trace_iterator *iter, + if (call->event.type > __TRACE_LAST_TYPE) + break; + } +- up_read(&trace_event_sem); + if (!found) { + trace_seq_printf(&iter->seq, "UNKNOWN TYPE %d\n", event->type); + goto out; +diff --git a/mm/memblock.c b/mm/memblock.c +index e8a2a1537d6a85..047dce35cf6e0e 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -2122,11 +2122,14 @@ static void __init memmap_init_reserved_pages(void) + struct memblock_region *region; + phys_addr_t start, end; + int nid; ++ unsigned long max_reserved; + + /* + * set nid on all reserved pages and also treat struct + * pages for the NOMAP regions as PageReserved + */ ++repeat: ++ max_reserved = memblock.reserved.max; + for_each_mem_region(region) { + nid = memblock_get_region_node(region); + start = region->base; +@@ -2135,8 +2138,15 @@ static void __init memmap_init_reserved_pages(void) + if (memblock_is_nomap(region)) + reserve_bootmem_region(start, end, nid); + +- memblock_set_node(start, end, &memblock.reserved, nid); ++ memblock_set_node(start, region->size, &memblock.reserved, nid); + } ++ /* ++ * 'max' is changed means memblock.reserved has been doubled its ++ * array, which may result a new reserved region before current ++ * 'start'. Now we should repeat the procedure to set its node id. ++ */ ++ if (max_reserved != memblock.reserved.max) ++ goto repeat; + + /* initialize struct pages for the reserved regions */ + for_each_reserved_mem_region(region) { +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index d4dcdb2370cc98..72ee41b894a520 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7386,6 +7386,9 @@ static int l2cap_recv_frag(struct l2cap_conn *conn, struct sk_buff *skb, + return -ENOMEM; + /* Init rx_len */ + conn->rx_len = len; ++ ++ skb_set_delivery_time(conn->rx_skb, skb->tstamp, ++ skb->tstamp_type); + } + + /* Copy as much as the rx_skb can hold */ +diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c +index 6ef04f9fe481be..4fbfbafdfa0274 100644 +--- a/net/bridge/netfilter/nf_conntrack_bridge.c ++++ b/net/bridge/netfilter/nf_conntrack_bridge.c +@@ -32,7 +32,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, + struct sk_buff *)) + { + int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + unsigned int hlen, ll_rs, mtu; + ktime_t tstamp = skb->tstamp; + struct ip_frag_state state; +@@ -82,7 +82,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, + if (iter.frag) + ip_fraglist_prepare(skb, &iter); + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, data, skb); + if (err || !iter.frag) + break; +@@ -113,7 +113,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, + goto blackhole; + } + +- skb_set_delivery_time(skb2, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb2, tstamp, tstamp_type); + err = output(net, sk, data, skb2); + if (err) + goto blackhole; +diff --git a/net/core/dev.c b/net/core/dev.c +index c31a7f7bedf3db..4006fd164b7bc7 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2189,7 +2189,7 @@ EXPORT_SYMBOL(net_disable_timestamp); + static inline void net_timestamp_set(struct sk_buff *skb) + { + skb->tstamp = 0; +- skb->mono_delivery_time = 0; ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + if (static_branch_unlikely(&netstamp_needed_key)) + skb->tstamp = ktime_get_real(); + } +diff --git a/net/core/filter.c b/net/core/filter.c +index 39eef3370d800e..066277b91a1be8 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -7734,13 +7734,13 @@ BPF_CALL_3(bpf_skb_set_tstamp, struct sk_buff *, skb, + if (!tstamp) + return -EINVAL; + skb->tstamp = tstamp; +- skb->mono_delivery_time = 1; ++ skb->tstamp_type = SKB_CLOCK_MONOTONIC; + break; + case BPF_SKB_TSTAMP_UNSPEC: + if (tstamp) + return -EINVAL; + skb->tstamp = 0; +- skb->mono_delivery_time = 0; ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + break; + default: + return -EINVAL; +@@ -7868,42 +7868,37 @@ static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = { + + #endif /* CONFIG_INET */ + +-bool bpf_helper_changes_pkt_data(void *func) +-{ +- if (func == bpf_skb_vlan_push || +- func == bpf_skb_vlan_pop || +- func == bpf_skb_store_bytes || +- func == bpf_skb_change_proto || +- func == bpf_skb_change_head || +- func == sk_skb_change_head || +- func == bpf_skb_change_tail || +- func == sk_skb_change_tail || +- func == bpf_skb_adjust_room || +- func == sk_skb_adjust_room || +- func == bpf_skb_pull_data || +- func == sk_skb_pull_data || +- func == bpf_clone_redirect || +- func == bpf_l3_csum_replace || +- func == bpf_l4_csum_replace || +- func == bpf_xdp_adjust_head || +- func == bpf_xdp_adjust_meta || +- func == bpf_msg_pull_data || +- func == bpf_msg_push_data || +- func == bpf_msg_pop_data || +- func == bpf_xdp_adjust_tail || +-#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF) +- func == bpf_lwt_seg6_store_bytes || +- func == bpf_lwt_seg6_adjust_srh || +- func == bpf_lwt_seg6_action || +-#endif +-#ifdef CONFIG_INET +- func == bpf_sock_ops_store_hdr_opt || +-#endif +- func == bpf_lwt_in_push_encap || +- func == bpf_lwt_xmit_push_encap) ++bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id) ++{ ++ switch (func_id) { ++ case BPF_FUNC_clone_redirect: ++ case BPF_FUNC_l3_csum_replace: ++ case BPF_FUNC_l4_csum_replace: ++ case BPF_FUNC_lwt_push_encap: ++ case BPF_FUNC_lwt_seg6_action: ++ case BPF_FUNC_lwt_seg6_adjust_srh: ++ case BPF_FUNC_lwt_seg6_store_bytes: ++ case BPF_FUNC_msg_pop_data: ++ case BPF_FUNC_msg_pull_data: ++ case BPF_FUNC_msg_push_data: ++ case BPF_FUNC_skb_adjust_room: ++ case BPF_FUNC_skb_change_head: ++ case BPF_FUNC_skb_change_proto: ++ case BPF_FUNC_skb_change_tail: ++ case BPF_FUNC_skb_pull_data: ++ case BPF_FUNC_skb_store_bytes: ++ case BPF_FUNC_skb_vlan_pop: ++ case BPF_FUNC_skb_vlan_push: ++ case BPF_FUNC_store_hdr_opt: ++ case BPF_FUNC_xdp_adjust_head: ++ case BPF_FUNC_xdp_adjust_meta: ++ case BPF_FUNC_xdp_adjust_tail: ++ /* tail-called program could call any of the above */ ++ case BPF_FUNC_tail_call: + return true; +- +- return false; ++ default: ++ return false; ++ } + } + + const struct bpf_func_proto bpf_event_output_data_proto __weak; +@@ -9443,7 +9438,7 @@ static struct bpf_insn *bpf_convert_tstamp_read(const struct bpf_prog *prog, + TC_AT_INGRESS_MASK | SKB_MONO_DELIVERY_TIME_MASK); + *insn++ = BPF_JMP32_IMM(BPF_JNE, tmp_reg, + TC_AT_INGRESS_MASK | SKB_MONO_DELIVERY_TIME_MASK, 2); +- /* skb->tc_at_ingress && skb->mono_delivery_time, ++ /* skb->tc_at_ingress && skb->tstamp_type, + * read 0 as the (rcv) timestamp. + */ + *insn++ = BPF_MOV64_IMM(value_reg, 0); +@@ -9468,7 +9463,7 @@ static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog, + * the bpf prog is aware the tstamp could have delivery time. + * Thus, write skb->tstamp as is if tstamp_type_access is true. + * Otherwise, writing at ingress will have to clear the +- * mono_delivery_time bit also. ++ * skb->tstamp_type bit also. + */ + if (!prog->tstamp_type_access) { + __u8 tmp_reg = BPF_REG_AX; +@@ -9478,7 +9473,7 @@ static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog, + *insn++ = BPF_JMP32_IMM(BPF_JSET, tmp_reg, TC_AT_INGRESS_MASK, 1); + /* goto */ + *insn++ = BPF_JMP_A(2); +- /* : mono_delivery_time */ ++ /* : skb->tstamp_type */ + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, ~SKB_MONO_DELIVERY_TIME_MASK); + *insn++ = BPF_STX_MEM(BPF_B, skb_reg, tmp_reg, SKB_BF_MONO_TC_OFFSET); + } +diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c +index 6dd960ec558cf6..ba0455ad770193 100644 +--- a/net/ieee802154/6lowpan/reassembly.c ++++ b/net/ieee802154/6lowpan/reassembly.c +@@ -130,7 +130,7 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, + goto err; + + fq->q.stamp = skb->tstamp; +- fq->q.mono_delivery_time = skb->mono_delivery_time; ++ fq->q.tstamp_type = skb->tstamp_type; + if (frag_type == LOWPAN_DISPATCH_FRAG1) + fq->q.flags |= INET_FRAG_FIRST_IN; + +diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c +index c88c9034d63004..496308c0238485 100644 +--- a/net/ipv4/inet_fragment.c ++++ b/net/ipv4/inet_fragment.c +@@ -619,7 +619,7 @@ void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head, + skb_mark_not_on_list(head); + head->prev = NULL; + head->tstamp = q->stamp; +- head->mono_delivery_time = q->mono_delivery_time; ++ head->tstamp_type = q->tstamp_type; + + if (sk) + refcount_add(sum_truesize - head_truesize, &sk->sk_wmem_alloc); +diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c +index 877d1e03150c77..484edc8513e4b7 100644 +--- a/net/ipv4/ip_fragment.c ++++ b/net/ipv4/ip_fragment.c +@@ -360,7 +360,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) + qp->iif = dev->ifindex; + + qp->q.stamp = skb->tstamp; +- qp->q.mono_delivery_time = skb->mono_delivery_time; ++ qp->q.tstamp_type = skb->tstamp_type; + qp->q.meat += skb->len; + qp->ecn |= ecn; + add_frag_mem_limit(qp->q.fqdir, skb->truesize); +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 765bd3f2a84089..b8cfe6afc84b88 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -764,7 +764,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + { + struct iphdr *iph; + struct sk_buff *skb2; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + struct rtable *rt = skb_rtable(skb); + unsigned int mtu, hlen, ll_rs; + struct ip_fraglist_iter iter; +@@ -856,7 +856,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + } + } + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, skb); + + if (!err) +@@ -912,7 +912,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + /* + * Put this fragment into the sending queue. + */ +- skb_set_delivery_time(skb2, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb2, tstamp, tstamp_type); + err = output(net, sk, skb2); + if (err) + goto fail; +@@ -1648,7 +1648,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, + arg->csumoffset) = csum_fold(csum_add(nskb->csum, + arg->csum)); + nskb->ip_summed = CHECKSUM_NONE; +- nskb->mono_delivery_time = !!transmit_time; ++ if (transmit_time) ++ nskb->tstamp_type = SKB_CLOCK_MONOTONIC; + if (txhash) + skb_set_hash(nskb, txhash, PKT_HASH_TYPE_L4); + ip_push_pending_frames(sk, &fl4); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 3771ed22c2f56f..560273e7f77365 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1266,7 +1266,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + tp = tcp_sk(sk); + prior_wstamp = tp->tcp_wstamp_ns; + tp->tcp_wstamp_ns = max(tp->tcp_wstamp_ns, tp->tcp_clock_cache); +- skb_set_delivery_time(skb, tp->tcp_wstamp_ns, true); ++ skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); + if (clone_it) { + oskb = skb; + +@@ -1607,7 +1607,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, + + skb_split(skb, buff, len); + +- skb_set_delivery_time(buff, skb->tstamp, true); ++ skb_set_delivery_time(buff, skb->tstamp, SKB_CLOCK_MONOTONIC); + tcp_fragment_tstamp(skb, buff); + + old_factor = tcp_skb_pcount(skb); +@@ -2703,7 +2703,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, + if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { + /* "skb_mstamp_ns" is used as a start point for the retransmit timer */ + tp->tcp_wstamp_ns = tp->tcp_clock_cache; +- skb_set_delivery_time(skb, tp->tcp_wstamp_ns, true); ++ skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); + list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); + tcp_init_tso_segs(skb, mss_now); + goto repair; /* Skip network transmission */ +@@ -3688,11 +3688,11 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, + #ifdef CONFIG_SYN_COOKIES + if (unlikely(synack_type == TCP_SYNACK_COOKIE && ireq->tstamp_ok)) + skb_set_delivery_time(skb, cookie_init_timestamp(req, now), +- true); ++ SKB_CLOCK_MONOTONIC); + else + #endif + { +- skb_set_delivery_time(skb, now, true); ++ skb_set_delivery_time(skb, now, SKB_CLOCK_MONOTONIC); + if (!tcp_rsk(req)->snt_synack) /* Timestamp first SYNACK */ + tcp_rsk(req)->snt_synack = tcp_skb_timestamp_us(skb); + } +@@ -3741,7 +3741,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, + bpf_skops_write_hdr_opt((struct sock *)sk, skb, req, syn_skb, + synack_type, &opts); + +- skb_set_delivery_time(skb, now, true); ++ skb_set_delivery_time(skb, now, SKB_CLOCK_MONOTONIC); + tcp_add_tx_delay(skb, tp); + + return skb; +@@ -3923,7 +3923,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) + + err = tcp_transmit_skb(sk, syn_data, 1, sk->sk_allocation); + +- skb_set_delivery_time(syn, syn_data->skb_mstamp_ns, true); ++ skb_set_delivery_time(syn, syn_data->skb_mstamp_ns, SKB_CLOCK_MONOTONIC); + + /* Now full SYN+DATA was cloned and sent (or not), + * remove the SYN from the original skb (syn_data) +diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c +index 2ab16139c197b3..132cfc3b2c847b 100644 +--- a/net/ipv4/udp_offload.c ++++ b/net/ipv4/udp_offload.c +@@ -247,6 +247,62 @@ static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs) + return segs; + } + ++static void __udpv6_gso_segment_csum(struct sk_buff *seg, ++ struct in6_addr *oldip, ++ const struct in6_addr *newip, ++ __be16 *oldport, __be16 newport) ++{ ++ struct udphdr *uh = udp_hdr(seg); ++ ++ if (ipv6_addr_equal(oldip, newip) && *oldport == newport) ++ return; ++ ++ if (uh->check) { ++ inet_proto_csum_replace16(&uh->check, seg, oldip->s6_addr32, ++ newip->s6_addr32, true); ++ ++ inet_proto_csum_replace2(&uh->check, seg, *oldport, newport, ++ false); ++ if (!uh->check) ++ uh->check = CSUM_MANGLED_0; ++ } ++ ++ *oldip = *newip; ++ *oldport = newport; ++} ++ ++static struct sk_buff *__udpv6_gso_segment_list_csum(struct sk_buff *segs) ++{ ++ const struct ipv6hdr *iph; ++ const struct udphdr *uh; ++ struct ipv6hdr *iph2; ++ struct sk_buff *seg; ++ struct udphdr *uh2; ++ ++ seg = segs; ++ uh = udp_hdr(seg); ++ iph = ipv6_hdr(seg); ++ uh2 = udp_hdr(seg->next); ++ iph2 = ipv6_hdr(seg->next); ++ ++ if (!(*(const u32 *)&uh->source ^ *(const u32 *)&uh2->source) && ++ ipv6_addr_equal(&iph->saddr, &iph2->saddr) && ++ ipv6_addr_equal(&iph->daddr, &iph2->daddr)) ++ return segs; ++ ++ while ((seg = seg->next)) { ++ uh2 = udp_hdr(seg); ++ iph2 = ipv6_hdr(seg); ++ ++ __udpv6_gso_segment_csum(seg, &iph2->saddr, &iph->saddr, ++ &uh2->source, uh->source); ++ __udpv6_gso_segment_csum(seg, &iph2->daddr, &iph->daddr, ++ &uh2->dest, uh->dest); ++ } ++ ++ return segs; ++} ++ + static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb, + netdev_features_t features, + bool is_ipv6) +@@ -259,7 +315,10 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb, + + udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss); + +- return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb); ++ if (is_ipv6) ++ return __udpv6_gso_segment_list_csum(skb); ++ else ++ return __udpv4_gso_segment_list_csum(skb); + } + + struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index cd89a2b35dfb56..c86d5dca29df01 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -864,7 +864,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + struct rt6_info *rt = dst_rt6_info(skb_dst(skb)); + struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? + inet6_sk(skb->sk) : NULL; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + struct ip6_frag_state state; + unsigned int mtu, hlen, nexthdr_offset; + ktime_t tstamp = skb->tstamp; +@@ -958,7 +958,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + if (iter.frag) + ip6_fraglist_prepare(skb, &iter); + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, skb); + if (!err) + IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), +@@ -1019,7 +1019,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + /* + * Put this fragment into the sending queue. + */ +- skb_set_delivery_time(frag, tstamp, mono_delivery_time); ++ skb_set_delivery_time(frag, tstamp, tstamp_type); + err = output(net, sk, frag); + if (err) + goto fail; +diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c +index 857713d7a38a54..7c4af48d529e1e 100644 +--- a/net/ipv6/netfilter.c ++++ b/net/ipv6/netfilter.c +@@ -126,7 +126,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + struct sk_buff *)) + { + int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + ktime_t tstamp = skb->tstamp; + struct ip6_frag_state state; + u8 *prevhdr, nexthdr = 0; +@@ -192,7 +192,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + if (iter.frag) + ip6_fraglist_prepare(skb, &iter); + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, data, skb); + if (err || !iter.frag) + break; +@@ -225,7 +225,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + goto blackhole; + } + +- skb_set_delivery_time(skb2, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb2, tstamp, tstamp_type); + err = output(net, sk, data, skb2); + if (err) + goto blackhole; +diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c +index c78b13ea5b196a..82e51b2ec4f512 100644 +--- a/net/ipv6/netfilter/nf_conntrack_reasm.c ++++ b/net/ipv6/netfilter/nf_conntrack_reasm.c +@@ -268,7 +268,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, + fq->iif = dev->ifindex; + + fq->q.stamp = skb->tstamp; +- fq->q.mono_delivery_time = skb->mono_delivery_time; ++ fq->q.tstamp_type = skb->tstamp_type; + fq->q.meat += skb->len; + fq->ecn |= ecn; + if (payload_len > fq->q.max_size) +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 2af98edef87ee0..cb219d4bdf25ed 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -198,7 +198,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, + fq->iif = dev->ifindex; + + fq->q.stamp = skb->tstamp; +- fq->q.mono_delivery_time = skb->mono_delivery_time; ++ fq->q.tstamp_type = skb->tstamp_type; + fq->q.meat += skb->len; + fq->ecn |= ecn; + add_frag_mem_limit(fq->q.fqdir, skb->truesize); +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index f285e52b8b8579..624ab1424eba7d 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -934,7 +934,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 + mark = inet_twsk(sk)->tw_mark; + else + mark = READ_ONCE(sk->sk_mark); +- skb_set_delivery_time(buff, tcp_transmit_time(sk), true); ++ skb_set_delivery_time(buff, tcp_transmit_time(sk), SKB_CLOCK_MONOTONIC); + } + if (txhash) { + /* autoflowlabel/skb_get_hash_flowi6 rely on buff->hash */ +diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c +index b0455fda7d0baf..ac87fcff4795e8 100644 +--- a/net/sched/act_bpf.c ++++ b/net/sched/act_bpf.c +@@ -54,8 +54,8 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb, + bpf_compute_data_pointers(skb); + filter_res = bpf_prog_run(filter, skb); + } +- if (unlikely(!skb->tstamp && skb->mono_delivery_time)) +- skb->mono_delivery_time = 0; ++ if (unlikely(!skb->tstamp && skb->tstamp_type)) ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + if (skb_sk_is_prefetched(skb) && filter_res != TC_ACT_OK) + skb_orphan(skb); + +diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c +index 382c7a71f81f2d..db7151c6b70b79 100644 +--- a/net/sched/cls_bpf.c ++++ b/net/sched/cls_bpf.c +@@ -104,8 +104,8 @@ TC_INDIRECT_SCOPE int cls_bpf_classify(struct sk_buff *skb, + bpf_compute_data_pointers(skb); + filter_res = bpf_prog_run(prog->filter, skb); + } +- if (unlikely(!skb->tstamp && skb->mono_delivery_time)) +- skb->mono_delivery_time = 0; ++ if (unlikely(!skb->tstamp && skb->tstamp_type)) ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + + if (prog->exts_integrated) { + res->class = 0; +diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c +index 19901e77cd3b7f..9b36955e32b142 100644 +--- a/net/sched/sch_drr.c ++++ b/net/sched/sch_drr.c +@@ -35,6 +35,11 @@ struct drr_sched { + struct Qdisc_class_hash clhash; + }; + ++static bool cl_is_active(struct drr_class *cl) ++{ ++ return !list_empty(&cl->alist); ++} ++ + static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid) + { + struct drr_sched *q = qdisc_priv(sch); +@@ -105,6 +110,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + return -ENOBUFS; + + gnet_stats_basic_sync_init(&cl->bstats); ++ INIT_LIST_HEAD(&cl->alist); + cl->common.classid = classid; + cl->quantum = quantum; + cl->qdisc = qdisc_create_dflt(sch->dev_queue, +@@ -229,7 +235,7 @@ static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg) + { + struct drr_class *cl = (struct drr_class *)arg; + +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + } + + static int drr_dump_class(struct Qdisc *sch, unsigned long arg, +@@ -336,7 +342,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + int err = 0; +- bool first; + + cl = drr_classify(skb, sch, &err); + if (cl == NULL) { +@@ -346,7 +351,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- first = !cl->qdisc->q.qlen; + err = qdisc_enqueue(skb, cl->qdisc, to_free); + if (unlikely(err != NET_XMIT_SUCCESS)) { + if (net_xmit_drop_count(err)) { +@@ -356,7 +360,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- if (first) { ++ if (!cl_is_active(cl)) { + list_add_tail(&cl->alist, &q->active); + cl->deficit = cl->quantum; + } +@@ -390,7 +394,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch) + if (unlikely(skb == NULL)) + goto out; + if (cl->qdisc->q.qlen == 0) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + + bstats_update(&cl->bstats, skb); + qdisc_bstats_update(sch, skb); +@@ -431,7 +435,7 @@ static void drr_reset_qdisc(struct Qdisc *sch) + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) { + if (cl->qdisc->q.qlen) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + qdisc_reset(cl->qdisc); + } + } +diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c +index 9fd70462b41d5a..9da86db4d2c2fe 100644 +--- a/net/sched/sch_ets.c ++++ b/net/sched/sch_ets.c +@@ -74,6 +74,11 @@ static const struct nla_policy ets_class_policy[TCA_ETS_MAX + 1] = { + [TCA_ETS_QUANTA_BAND] = { .type = NLA_U32 }, + }; + ++static bool cl_is_active(struct ets_class *cl) ++{ ++ return !list_empty(&cl->alist); ++} ++ + static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr, + unsigned int *quantum, + struct netlink_ext_ack *extack) +@@ -293,7 +298,7 @@ static void ets_class_qlen_notify(struct Qdisc *sch, unsigned long arg) + * to remove them. + */ + if (!ets_class_is_strict(q, cl) && sch->q.qlen) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + } + + static int ets_class_dump(struct Qdisc *sch, unsigned long arg, +@@ -416,7 +421,6 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct ets_sched *q = qdisc_priv(sch); + struct ets_class *cl; + int err = 0; +- bool first; + + cl = ets_classify(skb, sch, &err); + if (!cl) { +@@ -426,7 +430,6 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- first = !cl->qdisc->q.qlen; + err = qdisc_enqueue(skb, cl->qdisc, to_free); + if (unlikely(err != NET_XMIT_SUCCESS)) { + if (net_xmit_drop_count(err)) { +@@ -436,7 +439,7 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- if (first && !ets_class_is_strict(q, cl)) { ++ if (!cl_is_active(cl) && !ets_class_is_strict(q, cl)) { + list_add_tail(&cl->alist, &q->active); + cl->deficit = cl->quantum; + } +@@ -488,7 +491,7 @@ static struct sk_buff *ets_qdisc_dequeue(struct Qdisc *sch) + if (unlikely(!skb)) + goto out; + if (cl->qdisc->q.qlen == 0) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + return ets_qdisc_dequeue_skb(sch, skb); + } + +@@ -657,7 +660,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, + } + for (i = q->nbands; i < oldbands; i++) { + if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) +- list_del(&q->classes[i].alist); ++ list_del_init(&q->classes[i].alist); + qdisc_tree_flush_backlog(q->classes[i].qdisc); + } + q->nstrict = nstrict; +@@ -713,7 +716,7 @@ static void ets_qdisc_reset(struct Qdisc *sch) + + for (band = q->nstrict; band < q->nbands; band++) { + if (q->classes[band].qdisc->q.qlen) +- list_del(&q->classes[band].alist); ++ list_del_init(&q->classes[band].alist); + } + for (band = 0; band < q->nbands; band++) + qdisc_reset(q->classes[band].qdisc); +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index 371255e624332f..5d9cccfac4a155 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -203,7 +203,10 @@ eltree_insert(struct hfsc_class *cl) + static inline void + eltree_remove(struct hfsc_class *cl) + { +- rb_erase(&cl->el_node, &cl->sched->eligible); ++ if (!RB_EMPTY_NODE(&cl->el_node)) { ++ rb_erase(&cl->el_node, &cl->sched->eligible); ++ RB_CLEAR_NODE(&cl->el_node); ++ } + } + + static inline void +@@ -1224,7 +1227,8 @@ hfsc_qlen_notify(struct Qdisc *sch, unsigned long arg) + /* vttree is now handled in update_vf() so that update_vf(cl, 0, 0) + * needs to be called explicitly to remove a class from vttree. + */ +- update_vf(cl, 0, 0); ++ if (cl->cl_nactive) ++ update_vf(cl, 0, 0); + if (cl->cl_flags & HFSC_RSC) + eltree_remove(cl); + } +@@ -1566,7 +1570,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) + return err; + } + +- if (first) { ++ if (first && !cl->cl_nactive) { + if (cl->cl_flags & HFSC_RSC) + init_ed(cl, len); + if (cl->cl_flags & HFSC_FSC) +diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c +index 19035ef8387fed..9a3f7ea80b34b9 100644 +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -1485,6 +1485,8 @@ static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) + { + struct htb_class *cl = (struct htb_class *)arg; + ++ if (!cl->prio_activity) ++ return; + htb_deactivate(qdisc_priv(sch), cl); + } + +diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c +index 546c10adcacdea..5e557b960bde33 100644 +--- a/net/sched/sch_qfq.c ++++ b/net/sched/sch_qfq.c +@@ -202,6 +202,11 @@ struct qfq_sched { + */ + enum update_reason {enqueue, requeue}; + ++static bool cl_is_active(struct qfq_class *cl) ++{ ++ return !list_empty(&cl->alist); ++} ++ + static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid) + { + struct qfq_sched *q = qdisc_priv(sch); +@@ -347,7 +352,7 @@ static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) + struct qfq_aggregate *agg = cl->agg; + + +- list_del(&cl->alist); /* remove from RR queue of the aggregate */ ++ list_del_init(&cl->alist); /* remove from RR queue of the aggregate */ + if (list_empty(&agg->active)) /* agg is now inactive */ + qfq_deactivate_agg(q, agg); + } +@@ -477,6 +482,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + gnet_stats_basic_sync_init(&cl->bstats); + cl->common.classid = classid; + cl->deficit = lmax; ++ INIT_LIST_HEAD(&cl->alist); + + cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + classid, NULL); +@@ -985,7 +991,7 @@ static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg, + cl->deficit -= (int) len; + + if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */ +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) { + cl->deficit += agg->lmax; + list_move_tail(&cl->alist, &agg->active); +@@ -1217,7 +1223,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct qfq_class *cl; + struct qfq_aggregate *agg; + int err = 0; +- bool first; + + cl = qfq_classify(skb, sch, &err); + if (cl == NULL) { +@@ -1239,7 +1244,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + + gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; +- first = !cl->qdisc->q.qlen; + err = qdisc_enqueue(skb, cl->qdisc, to_free); + if (unlikely(err != NET_XMIT_SUCCESS)) { + pr_debug("qfq_enqueue: enqueue failed %d\n", err); +@@ -1255,8 +1259,8 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, + ++sch->q.qlen; + + agg = cl->agg; +- /* if the queue was not empty, then done here */ +- if (!first) { ++ /* if the class is active, then done here */ ++ if (cl_is_active(cl)) { + if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && + list_first_entry(&agg->active, struct qfq_class, alist) + == cl && cl->deficit < len) +@@ -1418,6 +1422,8 @@ static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl = (struct qfq_class *)arg; + ++ if (list_empty(&cl->alist)) ++ return; + qfq_deactivate_class(q, cl); + } + +diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c +index 619a817ee91cb8..4c1318ce8ae58f 100644 +--- a/sound/soc/codecs/ak4613.c ++++ b/sound/soc/codecs/ak4613.c +@@ -840,14 +840,14 @@ static void ak4613_parse_of(struct ak4613_priv *priv, + /* Input 1 - 2 */ + for (i = 0; i < 2; i++) { + snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1); +- if (!of_get_property(np, prop, NULL)) ++ if (!of_property_read_bool(np, prop)) + priv->ic |= 1 << i; + } + + /* Output 1 - 6 */ + for (i = 0; i < 6; i++) { + snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1); +- if (!of_get_property(np, prop, NULL)) ++ if (!of_property_read_bool(np, prop)) + priv->oc |= 1 << i; + } + +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index e65fe3a7c3e42c..7eea70eea68b47 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -2935,7 +2935,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop) + unsigned int i, nb_controls; + int ret; + +- if (!of_property_read_bool(dev->of_node, prop)) ++ if (!of_property_present(dev->of_node, prop)) + return 0; + + strings = devm_kcalloc(dev, nb_controls_max, +@@ -3009,23 +3009,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, + if (rx_mask) + snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask); + +- if (of_property_read_bool(np, "dai-tdm-slot-num")) { +- ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); +- if (ret) +- return ret; +- +- if (slots) +- *slots = val; +- } +- +- if (of_property_read_bool(np, "dai-tdm-slot-width")) { +- ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); +- if (ret) +- return ret; ++ ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); ++ if (ret && ret != -EINVAL) ++ return ret; ++ if (!ret && slots) ++ *slots = val; + +- if (slot_width) +- *slot_width = val; +- } ++ ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); ++ if (ret && ret != -EINVAL) ++ return ret; ++ if (!ret && slot_width) ++ *slot_width = val; + + return 0; + } +@@ -3249,10 +3243,10 @@ unsigned int snd_soc_daifmt_parse_format(struct device_node *np, + * SND_SOC_DAIFMT_INV_MASK area + */ + snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix); +- bit = !!of_get_property(np, prop, NULL); ++ bit = of_property_read_bool(np, prop); + + snprintf(prop, sizeof(prop), "%sframe-inversion", prefix); +- frame = !!of_get_property(np, prop, NULL); ++ frame = of_property_read_bool(np, prop); + + switch ((bit << 4) + frame) { + case 0x11: +@@ -3289,12 +3283,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, + * check "[prefix]frame-master" + */ + snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); +- bit = !!of_get_property(np, prop, NULL); ++ bit = of_property_present(np, prop); + if (bit && bitclkmaster) + *bitclkmaster = of_parse_phandle(np, prop, 0); + + snprintf(prop, sizeof(prop), "%sframe-master", prefix); +- frame = !!of_get_property(np, prop, NULL); ++ frame = of_property_present(np, prop); + if (frame && framemaster) + *framemaster = of_parse_phandle(np, prop, 0); + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 60248a6820aacc..30e93f9aad7624 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1534,10 +1534,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, + /* + * Filter for systems with 'component_chaining' enabled. + * This helps to avoid unnecessary re-configuration of an +- * already active BE on such systems. ++ * already active BE on such systems and ensures the BE DAI ++ * widget is powered ON after hw_params() BE DAI callback. + */ + if (fe->card->component_chaining && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && ++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && ++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) + continue; + +diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c +index 68aa174be12d71..f71f6ff3e2b0f7 100644 +--- a/sound/usb/endpoint.c ++++ b/sound/usb/endpoint.c +@@ -926,14 +926,21 @@ static int endpoint_set_interface(struct snd_usb_audio *chip, + { + int altset = set ? ep->altsetting : 0; + int err; ++ int retries = 0; ++ const int max_retries = 5; + + if (ep->iface_ref->altset == altset) + return 0; + + usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n", + ep->iface, altset, ep->ep_num); ++retry: + err = usb_set_interface(chip->dev, ep->iface, altset); + if (err < 0) { ++ if (err == -EPROTO && ++retries <= max_retries) { ++ msleep(5 * (1 << (retries - 1))); ++ goto retry; ++ } + usb_audio_err_ratelimited( + chip, "%d:%d: usb_set_interface failed (%d)\n", + ep->iface, altset, err); +diff --git a/sound/usb/format.c b/sound/usb/format.c +index 3b3a5ea6fcbfc0..f33d25a4e4cc7c 100644 +--- a/sound/usb/format.c ++++ b/sound/usb/format.c +@@ -263,7 +263,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof + } + + /* Jabra Evolve 65 headset */ +- if (chip->usb_id == USB_ID(0x0b0e, 0x030b)) { ++ if (chip->usb_id == USB_ID(0x0b0e, 0x030b) || ++ chip->usb_id == USB_ID(0x0b0e, 0x030c)) { + /* only 48kHz for playback while keeping 16kHz for capture */ + if (fp->nr_rates != 1) + return set_fixed_rate(fp, 48000, SNDRV_PCM_RATE_48000); +diff --git a/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c +new file mode 100644 +index 00000000000000..7526de3790814c +--- /dev/null ++++ b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c +@@ -0,0 +1,107 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "bpf/libbpf.h" ++#include "changes_pkt_data_freplace.skel.h" ++#include "changes_pkt_data.skel.h" ++#include ++ ++static void print_verifier_log(const char *log) ++{ ++ if (env.verbosity >= VERBOSE_VERY) ++ fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log); ++} ++ ++static void test_aux(const char *main_prog_name, ++ const char *to_be_replaced, ++ const char *replacement, ++ bool expect_load) ++{ ++ struct changes_pkt_data_freplace *freplace = NULL; ++ struct bpf_program *freplace_prog = NULL; ++ struct bpf_program *main_prog = NULL; ++ LIBBPF_OPTS(bpf_object_open_opts, opts); ++ struct changes_pkt_data *main = NULL; ++ char log[16*1024]; ++ int err; ++ ++ opts.kernel_log_buf = log; ++ opts.kernel_log_size = sizeof(log); ++ if (env.verbosity >= VERBOSE_SUPER) ++ opts.kernel_log_level = 1 | 2 | 4; ++ main = changes_pkt_data__open_opts(&opts); ++ if (!ASSERT_OK_PTR(main, "changes_pkt_data__open")) ++ goto out; ++ main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name); ++ if (!ASSERT_OK_PTR(main_prog, "main_prog")) ++ goto out; ++ bpf_program__set_autoload(main_prog, true); ++ err = changes_pkt_data__load(main); ++ print_verifier_log(log); ++ if (!ASSERT_OK(err, "changes_pkt_data__load")) ++ goto out; ++ freplace = changes_pkt_data_freplace__open_opts(&opts); ++ if (!ASSERT_OK_PTR(freplace, "changes_pkt_data_freplace__open")) ++ goto out; ++ freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement); ++ if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog")) ++ goto out; ++ bpf_program__set_autoload(freplace_prog, true); ++ bpf_program__set_autoattach(freplace_prog, true); ++ bpf_program__set_attach_target(freplace_prog, ++ bpf_program__fd(main_prog), ++ to_be_replaced); ++ err = changes_pkt_data_freplace__load(freplace); ++ print_verifier_log(log); ++ if (expect_load) { ++ ASSERT_OK(err, "changes_pkt_data_freplace__load"); ++ } else { ++ ASSERT_ERR(err, "changes_pkt_data_freplace__load"); ++ ASSERT_HAS_SUBSTR(log, "Extension program changes packet data", "error log"); ++ } ++ ++out: ++ changes_pkt_data_freplace__destroy(freplace); ++ changes_pkt_data__destroy(main); ++} ++ ++/* There are two global subprograms in both changes_pkt_data.skel.h: ++ * - one changes packet data; ++ * - another does not. ++ * It is ok to freplace subprograms that change packet data with those ++ * that either do or do not. It is only ok to freplace subprograms ++ * that do not change packet data with those that do not as well. ++ * The below tests check outcomes for each combination of such freplace. ++ * Also test a case when main subprogram itself is replaced and is a single ++ * subprogram in a program. ++ */ ++void test_changes_pkt_data_freplace(void) ++{ ++ struct { ++ const char *main; ++ const char *to_be_replaced; ++ bool changes; ++ } mains[] = { ++ { "main_with_subprogs", "changes_pkt_data", true }, ++ { "main_with_subprogs", "does_not_change_pkt_data", false }, ++ { "main_changes", "main_changes", true }, ++ { "main_does_not_change", "main_does_not_change", false }, ++ }; ++ struct { ++ const char *func; ++ bool changes; ++ } replacements[] = { ++ { "changes_pkt_data", true }, ++ { "does_not_change_pkt_data", false } ++ }; ++ char buf[64]; ++ ++ for (int i = 0; i < ARRAY_SIZE(mains); ++i) { ++ for (int j = 0; j < ARRAY_SIZE(replacements); ++j) { ++ snprintf(buf, sizeof(buf), "%s_with_%s", ++ mains[i].to_be_replaced, replacements[j].func); ++ if (!test__start_subtest(buf)) ++ continue; ++ test_aux(mains[i].main, mains[i].to_be_replaced, replacements[j].func, ++ mains[i].changes || !replacements[j].changes); ++ } ++ } ++} +diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data.c b/tools/testing/selftests/bpf/progs/changes_pkt_data.c +new file mode 100644 +index 00000000000000..43cada48b28ad4 +--- /dev/null ++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data.c +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++ ++__noinline ++long changes_pkt_data(struct __sk_buff *sk) ++{ ++ return bpf_skb_pull_data(sk, 0); ++} ++ ++__noinline __weak ++long does_not_change_pkt_data(struct __sk_buff *sk) ++{ ++ return 0; ++} ++ ++SEC("?tc") ++int main_with_subprogs(struct __sk_buff *sk) ++{ ++ changes_pkt_data(sk); ++ does_not_change_pkt_data(sk); ++ return 0; ++} ++ ++SEC("?tc") ++int main_changes(struct __sk_buff *sk) ++{ ++ bpf_skb_pull_data(sk, 0); ++ return 0; ++} ++ ++SEC("?tc") ++int main_does_not_change(struct __sk_buff *sk) ++{ ++ return 0; ++} ++ ++char _license[] SEC("license") = "GPL"; +diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c +new file mode 100644 +index 00000000000000..f9a622705f1b3b +--- /dev/null ++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++ ++SEC("?freplace") ++long changes_pkt_data(struct __sk_buff *sk) ++{ ++ return bpf_skb_pull_data(sk, 0); ++} ++ ++SEC("?freplace") ++long does_not_change_pkt_data(struct __sk_buff *sk) ++{ ++ return 0; ++} ++ ++char _license[] SEC("license") = "GPL"; +diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c +index ee76b51005abe7..3c8f6646e33dae 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_sock.c ++++ b/tools/testing/selftests/bpf/progs/verifier_sock.c +@@ -50,6 +50,13 @@ struct { + __uint(map_flags, BPF_F_NO_PREALLOC); + } sk_storage_map SEC(".maps"); + ++struct { ++ __uint(type, BPF_MAP_TYPE_PROG_ARRAY); ++ __uint(max_entries, 1); ++ __uint(key_size, sizeof(__u32)); ++ __uint(value_size, sizeof(__u32)); ++} jmp_table SEC(".maps"); ++ + SEC("cgroup/skb") + __description("skb->sk: no NULL check") + __failure __msg("invalid mem access 'sock_common_or_null'") +@@ -977,4 +984,53 @@ l1_%=: r0 = *(u8*)(r7 + 0); \ + : __clobber_all); + } + ++__noinline ++long skb_pull_data2(struct __sk_buff *sk, __u32 len) ++{ ++ return bpf_skb_pull_data(sk, len); ++} ++ ++__noinline ++long skb_pull_data1(struct __sk_buff *sk, __u32 len) ++{ ++ return skb_pull_data2(sk, len); ++} ++ ++/* global function calls bpf_skb_pull_data(), which invalidates packet ++ * pointers established before global function call. ++ */ ++SEC("tc") ++__failure __msg("invalid mem access") ++int invalidate_pkt_pointers_from_global_func(struct __sk_buff *sk) ++{ ++ int *p = (void *)(long)sk->data; ++ ++ if ((void *)(p + 1) > (void *)(long)sk->data_end) ++ return TCX_DROP; ++ skb_pull_data1(sk, 0); ++ *p = 42; /* this is unsafe */ ++ return TCX_PASS; ++} ++ ++__noinline ++int tail_call(struct __sk_buff *sk) ++{ ++ bpf_tail_call_static(sk, &jmp_table, 0); ++ return 0; ++} ++ ++/* Tail calls invalidate packet pointers. */ ++SEC("tc") ++__failure __msg("invalid mem access") ++int invalidate_pkt_pointers_by_tail_call(struct __sk_buff *sk) ++{ ++ int *p = (void *)(long)sk->data; ++ ++ if ((void *)(p + 1) > (void *)(long)sk->data_end) ++ return TCX_DROP; ++ tail_call(sk); ++ *p = 42; /* this is unsafe */ ++ return TCX_PASS; ++} ++ + char _license[] SEC("license") = "GPL"; diff --git a/patch/kernel/archive/odroidxu4-6.6/patch-6.6.90-91.patch b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.90-91.patch new file mode 100644 index 000000000000..8cffc8d8b248 --- /dev/null +++ b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.90-91.patch @@ -0,0 +1,4952 @@ +diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu +index 657bdee28d845a..0426ec112155ec 100644 +--- a/Documentation/ABI/testing/sysfs-devices-system-cpu ++++ b/Documentation/ABI/testing/sysfs-devices-system-cpu +@@ -514,6 +514,7 @@ Description: information about CPUs heterogeneity. + + What: /sys/devices/system/cpu/vulnerabilities + /sys/devices/system/cpu/vulnerabilities/gather_data_sampling ++ /sys/devices/system/cpu/vulnerabilities/indirect_target_selection + /sys/devices/system/cpu/vulnerabilities/itlb_multihit + /sys/devices/system/cpu/vulnerabilities/l1tf + /sys/devices/system/cpu/vulnerabilities/mds +diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst +index ff0b440ef2dc90..d2caa390395e5b 100644 +--- a/Documentation/admin-guide/hw-vuln/index.rst ++++ b/Documentation/admin-guide/hw-vuln/index.rst +@@ -22,3 +22,4 @@ are configurable at compile, boot or run time. + srso + gather_data_sampling + reg-file-data-sampling ++ indirect-target-selection +diff --git a/Documentation/admin-guide/hw-vuln/indirect-target-selection.rst b/Documentation/admin-guide/hw-vuln/indirect-target-selection.rst +new file mode 100644 +index 00000000000000..d9ca64108d2332 +--- /dev/null ++++ b/Documentation/admin-guide/hw-vuln/indirect-target-selection.rst +@@ -0,0 +1,168 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Indirect Target Selection (ITS) ++=============================== ++ ++ITS is a vulnerability in some Intel CPUs that support Enhanced IBRS and were ++released before Alder Lake. ITS may allow an attacker to control the prediction ++of indirect branches and RETs located in the lower half of a cacheline. ++ ++ITS is assigned CVE-2024-28956 with a CVSS score of 4.7 (Medium). ++ ++Scope of Impact ++--------------- ++- **eIBRS Guest/Host Isolation**: Indirect branches in KVM/kernel may still be ++ predicted with unintended target corresponding to a branch in the guest. ++ ++- **Intra-Mode BTI**: In-kernel training such as through cBPF or other native ++ gadgets. ++ ++- **Indirect Branch Prediction Barrier (IBPB)**: After an IBPB, indirect ++ branches may still be predicted with targets corresponding to direct branches ++ executed prior to the IBPB. This is fixed by the IPU 2025.1 microcode, which ++ should be available via distro updates. Alternatively microcode can be ++ obtained from Intel's github repository [#f1]_. ++ ++Affected CPUs ++------------- ++Below is the list of ITS affected CPUs [#f2]_ [#f3]_: ++ ++ ======================== ============ ==================== =============== ++ Common name Family_Model eIBRS Intra-mode BTI ++ Guest/Host Isolation ++ ======================== ============ ==================== =============== ++ SKYLAKE_X (step >= 6) 06_55H Affected Affected ++ ICELAKE_X 06_6AH Not affected Affected ++ ICELAKE_D 06_6CH Not affected Affected ++ ICELAKE_L 06_7EH Not affected Affected ++ TIGERLAKE_L 06_8CH Not affected Affected ++ TIGERLAKE 06_8DH Not affected Affected ++ KABYLAKE_L (step >= 12) 06_8EH Affected Affected ++ KABYLAKE (step >= 13) 06_9EH Affected Affected ++ COMETLAKE 06_A5H Affected Affected ++ COMETLAKE_L 06_A6H Affected Affected ++ ROCKETLAKE 06_A7H Not affected Affected ++ ======================== ============ ==================== =============== ++ ++- All affected CPUs enumerate Enhanced IBRS feature. ++- IBPB isolation is affected on all ITS affected CPUs, and need a microcode ++ update for mitigation. ++- None of the affected CPUs enumerate BHI_CTRL which was introduced in Golden ++ Cove (Alder Lake and Sapphire Rapids). This can help guests to determine the ++ host's affected status. ++- Intel Atom CPUs are not affected by ITS. ++ ++Mitigation ++---------- ++As only the indirect branches and RETs that have their last byte of instruction ++in the lower half of the cacheline are vulnerable to ITS, the basic idea behind ++the mitigation is to not allow indirect branches in the lower half. ++ ++This is achieved by relying on existing retpoline support in the kernel, and in ++compilers. ITS-vulnerable retpoline sites are runtime patched to point to newly ++added ITS-safe thunks. These safe thunks consists of indirect branch in the ++second half of the cacheline. Not all retpoline sites are patched to thunks, if ++a retpoline site is evaluated to be ITS-safe, it is replaced with an inline ++indirect branch. ++ ++Dynamic thunks ++~~~~~~~~~~~~~~ ++From a dynamically allocated pool of safe-thunks, each vulnerable site is ++replaced with a new thunk, such that they get a unique address. This could ++improve the branch prediction accuracy. Also, it is a defense-in-depth measure ++against aliasing. ++ ++Note, for simplicity, indirect branches in eBPF programs are always replaced ++with a jump to a static thunk in __x86_indirect_its_thunk_array. If required, ++in future this can be changed to use dynamic thunks. ++ ++All vulnerable RETs are replaced with a static thunk, they do not use dynamic ++thunks. This is because RETs get their prediction from RSB mostly that does not ++depend on source address. RETs that underflow RSB may benefit from dynamic ++thunks. But, RETs significantly outnumber indirect branches, and any benefit ++from a unique source address could be outweighed by the increased icache ++footprint and iTLB pressure. ++ ++Retpoline ++~~~~~~~~~ ++Retpoline sequence also mitigates ITS-unsafe indirect branches. For this ++reason, when retpoline is enabled, ITS mitigation only relocates the RETs to ++safe thunks. Unless user requested the RSB-stuffing mitigation. ++ ++RSB Stuffing ++~~~~~~~~~~~~ ++RSB-stuffing via Call Depth Tracking is a mitigation for Retbleed RSB-underflow ++attacks. And it also mitigates RETs that are vulnerable to ITS. ++ ++Mitigation in guests ++^^^^^^^^^^^^^^^^^^^^ ++All guests deploy ITS mitigation by default, irrespective of eIBRS enumeration ++and Family/Model of the guest. This is because eIBRS feature could be hidden ++from a guest. One exception to this is when a guest enumerates BHI_DIS_S, which ++indicates that the guest is running on an unaffected host. ++ ++To prevent guests from unnecessarily deploying the mitigation on unaffected ++platforms, Intel has defined ITS_NO bit(62) in MSR IA32_ARCH_CAPABILITIES. When ++a guest sees this bit set, it should not enumerate the ITS bug. Note, this bit ++is not set by any hardware, but is **intended for VMMs to synthesize** it for ++guests as per the host's affected status. ++ ++Mitigation options ++^^^^^^^^^^^^^^^^^^ ++The ITS mitigation can be controlled using the "indirect_target_selection" ++kernel parameter. The available options are: ++ ++ ======== =================================================================== ++ on (default) Deploy the "Aligned branch/return thunks" mitigation. ++ If spectre_v2 mitigation enables retpoline, aligned-thunks are only ++ deployed for the affected RET instructions. Retpoline mitigates ++ indirect branches. ++ ++ off Disable ITS mitigation. ++ ++ vmexit Equivalent to "=on" if the CPU is affected by guest/host isolation ++ part of ITS. Otherwise, mitigation is not deployed. This option is ++ useful when host userspace is not in the threat model, and only ++ attacks from guest to host are considered. ++ ++ stuff Deploy RSB-fill mitigation when retpoline is also deployed. ++ Otherwise, deploy the default mitigation. When retpoline mitigation ++ is enabled, RSB-stuffing via Call-Depth-Tracking also mitigates ++ ITS. ++ ++ force Force the ITS bug and deploy the default mitigation. ++ ======== =================================================================== ++ ++Sysfs reporting ++--------------- ++ ++The sysfs file showing ITS mitigation status is: ++ ++ /sys/devices/system/cpu/vulnerabilities/indirect_target_selection ++ ++Note, microcode mitigation status is not reported in this file. ++ ++The possible values in this file are: ++ ++.. list-table:: ++ ++ * - Not affected ++ - The processor is not vulnerable. ++ * - Vulnerable ++ - System is vulnerable and no mitigation has been applied. ++ * - Vulnerable, KVM: Not affected ++ - System is vulnerable to intra-mode BTI, but not affected by eIBRS ++ guest/host isolation. ++ * - Mitigation: Aligned branch/return thunks ++ - The mitigation is enabled, affected indirect branches and RETs are ++ relocated to safe thunks. ++ * - Mitigation: Retpolines, Stuffing RSB ++ - The mitigation is enabled using retpoline and RSB stuffing. ++ ++References ++---------- ++.. [#f1] Microcode repository - https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files ++ ++.. [#f2] Affected Processors list - https://www.intel.com/content/www/us/en/developer/topic-technology/software-security-guidance/processors-affected-consolidated-product-cpu-model.html ++ ++.. [#f3] Affected Processors list (machine readable) - https://github.com/intel/Intel-affected-processor-list +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 184f2f96f6a547..f95734ceb82b86 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -2060,6 +2060,23 @@ + different crypto accelerators. This option can be used + to achieve best performance for particular HW. + ++ indirect_target_selection= [X86,Intel] Mitigation control for Indirect ++ Target Selection(ITS) bug in Intel CPUs. Updated ++ microcode is also required for a fix in IBPB. ++ ++ on: Enable mitigation (default). ++ off: Disable mitigation. ++ force: Force the ITS bug and deploy default ++ mitigation. ++ vmexit: Only deploy mitigation if CPU is affected by ++ guest/host isolation part of ITS. ++ stuff: Deploy RSB-fill mitigation when retpoline is ++ also deployed. Otherwise, deploy the default ++ mitigation. ++ ++ For details see: ++ Documentation/admin-guide/hw-vuln/indirect-target-selection.rst ++ + init= [KNL] + Format: + Run specified binary instead of /sbin/init as init +@@ -3331,6 +3348,7 @@ + expose users to several CPU vulnerabilities. + Equivalent to: if nokaslr then kpti=0 [ARM64] + gather_data_sampling=off [X86] ++ indirect_target_selection=off [X86] + kvm.nx_huge_pages=off [X86] + l1tf=off [X86] + mds=off [X86] +diff --git a/Makefile b/Makefile +index 587a1586e76db8..a6a1942e2d00a9 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 90 ++SUBLEVEL = 91 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi +index 6c48fa4b0d0c4f..6457d2c377017a 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi +@@ -148,6 +148,19 @@ reg_usdhc2_vmmc: regulator-usdhc2 { + startup-delay-us = <20000>; + }; + ++ reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc { ++ compatible = "regulator-gpio"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2_vsel>; ++ gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; ++ regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <1800000>; ++ states = <1800000 0x1>, ++ <3300000 0x0>; ++ regulator-name = "PMIC_USDHC_VSELECT"; ++ vin-supply = <®_nvcc_sd>; ++ }; ++ + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; +@@ -266,7 +279,7 @@ &gpio1 { + "SODIMM_19", + "", + "", +- "", ++ "PMIC_USDHC_VSELECT", + "", + "", + "", +@@ -787,6 +800,7 @@ &usdhc2 { + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_cd>; + pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_cd_sleep>; + vmmc-supply = <®_usdhc2_vmmc>; ++ vqmmc-supply = <®_usdhc2_vqmmc>; + }; + + &wdog1 { +@@ -1209,13 +1223,17 @@ pinctrl_usdhc2_pwr_en: usdhc2pwrengrp { + ; /* SODIMM 76 */ + }; + ++ pinctrl_usdhc2_vsel: usdhc2vselgrp { ++ fsl,pins = ++ ; /* PMIC_USDHC_VSELECT */ ++ }; ++ + /* + * Note: Due to ERR050080 we use discrete external on-module resistors pulling-up to the + * on-module +V3.3_1.8_SD (LDO5) rail and explicitly disable the internal pull-ups here. + */ + pinctrl_usdhc2: usdhc2grp { + fsl,pins = +- , + , /* SODIMM 78 */ + , /* SODIMM 74 */ + , /* SODIMM 80 */ +@@ -1226,7 +1244,6 @@ pinctrl_usdhc2: usdhc2grp { + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = +- , + , + , + , +@@ -1237,7 +1254,6 @@ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = +- , + , + , + , +@@ -1249,7 +1265,6 @@ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + /* Avoid backfeeding with removed card power */ + pinctrl_usdhc2_sleep: usdhc2slpgrp { + fsl,pins = +- , + , + , + , +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index 2a4e686e633c62..8a6b7feca3e428 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -81,6 +81,7 @@ + #define ARM_CPU_PART_CORTEX_A78AE 0xD42 + #define ARM_CPU_PART_CORTEX_X1 0xD44 + #define ARM_CPU_PART_CORTEX_A510 0xD46 ++#define ARM_CPU_PART_CORTEX_X1C 0xD4C + #define ARM_CPU_PART_CORTEX_A520 0xD80 + #define ARM_CPU_PART_CORTEX_A710 0xD47 + #define ARM_CPU_PART_CORTEX_A715 0xD4D +@@ -166,6 +167,7 @@ + #define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE) + #define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1) + #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510) ++#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C) + #define MIDR_CORTEX_A520 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A520) + #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710) + #define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715) +diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h +index 0ccf51afde31a6..12c0278294e3f6 100644 +--- a/arch/arm64/include/asm/insn.h ++++ b/arch/arm64/include/asm/insn.h +@@ -687,6 +687,7 @@ u32 aarch64_insn_gen_cas(enum aarch64_insn_register result, + } + #endif + u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type); ++u32 aarch64_insn_gen_dsb(enum aarch64_insn_mb_type type); + + s32 aarch64_get_branch_offset(u32 insn); + u32 aarch64_set_branch_offset(u32 insn, s32 offset); +diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spectre.h +index 0c2b47673922e3..32475d19c15f44 100644 +--- a/arch/arm64/include/asm/spectre.h ++++ b/arch/arm64/include/asm/spectre.h +@@ -97,6 +97,9 @@ enum mitigation_state arm64_get_meltdown_state(void); + + enum mitigation_state arm64_get_spectre_bhb_state(void); + bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope); ++extern bool __nospectre_bhb; ++u8 get_spectre_bhb_loop_value(void); ++bool is_spectre_bhb_fw_mitigated(void); + void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused); + bool try_emulate_el1_ssbs(struct pt_regs *regs, u32 instr); + +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index edc4c727783d82..28c48bc9c09538 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -891,6 +891,7 @@ static u8 spectre_bhb_loop_affected(void) + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78AE), + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C), + MIDR_ALL_VERSIONS(MIDR_CORTEX_X1), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X1C), + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), + MIDR_ALL_VERSIONS(MIDR_CORTEX_X2), + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), +@@ -998,6 +999,11 @@ bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, + return true; + } + ++u8 get_spectre_bhb_loop_value(void) ++{ ++ return max_bhb_k; ++} ++ + static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot) + { + const char *v = arm64_get_bp_hardening_vector(slot); +@@ -1015,7 +1021,7 @@ static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot) + isb(); + } + +-static bool __read_mostly __nospectre_bhb; ++bool __read_mostly __nospectre_bhb; + static int __init parse_spectre_bhb_param(char *str) + { + __nospectre_bhb = true; +@@ -1093,6 +1099,11 @@ void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry) + update_mitigation_state(&spectre_bhb_state, state); + } + ++bool is_spectre_bhb_fw_mitigated(void) ++{ ++ return test_bit(BHB_FW, &system_bhb_mitigations); ++} ++ + /* Patched to NOP when enabled */ + void noinstr spectre_bhb_patch_loop_mitigation_enable(struct alt_instr *alt, + __le32 *origptr, +diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c +index a635ab83fee359..7232b1e70a125f 100644 +--- a/arch/arm64/lib/insn.c ++++ b/arch/arm64/lib/insn.c +@@ -5,6 +5,7 @@ + * + * Copyright (C) 2014-2016 Zi Shen Lim + */ ++#include + #include + #include + #include +@@ -1471,43 +1472,41 @@ u32 aarch64_insn_gen_extr(enum aarch64_insn_variant variant, + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, Rm); + } + +-u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type) ++static u32 __get_barrier_crm_val(enum aarch64_insn_mb_type type) + { +- u32 opt; +- u32 insn; +- + switch (type) { + case AARCH64_INSN_MB_SY: +- opt = 0xf; +- break; ++ return 0xf; + case AARCH64_INSN_MB_ST: +- opt = 0xe; +- break; ++ return 0xe; + case AARCH64_INSN_MB_LD: +- opt = 0xd; +- break; ++ return 0xd; + case AARCH64_INSN_MB_ISH: +- opt = 0xb; +- break; ++ return 0xb; + case AARCH64_INSN_MB_ISHST: +- opt = 0xa; +- break; ++ return 0xa; + case AARCH64_INSN_MB_ISHLD: +- opt = 0x9; +- break; ++ return 0x9; + case AARCH64_INSN_MB_NSH: +- opt = 0x7; +- break; ++ return 0x7; + case AARCH64_INSN_MB_NSHST: +- opt = 0x6; +- break; ++ return 0x6; + case AARCH64_INSN_MB_NSHLD: +- opt = 0x5; +- break; ++ return 0x5; + default: +- pr_err("%s: unknown dmb type %d\n", __func__, type); ++ pr_err("%s: unknown barrier type %d\n", __func__, type); + return AARCH64_BREAK_FAULT; + } ++} ++ ++u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type) ++{ ++ u32 opt; ++ u32 insn; ++ ++ opt = __get_barrier_crm_val(type); ++ if (opt == AARCH64_BREAK_FAULT) ++ return AARCH64_BREAK_FAULT; + + insn = aarch64_insn_get_dmb_value(); + insn &= ~GENMASK(11, 8); +@@ -1515,3 +1514,18 @@ u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type) + + return insn; + } ++ ++u32 aarch64_insn_gen_dsb(enum aarch64_insn_mb_type type) ++{ ++ u32 opt, insn; ++ ++ opt = __get_barrier_crm_val(type); ++ if (opt == AARCH64_BREAK_FAULT) ++ return AARCH64_BREAK_FAULT; ++ ++ insn = aarch64_insn_get_dsb_base_value(); ++ insn &= ~GENMASK(11, 8); ++ insn |= (opt << 8); ++ ++ return insn; ++} +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 5074bd1d37b5f6..75523c1be07350 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -7,6 +7,7 @@ + + #define pr_fmt(fmt) "bpf_jit: " fmt + ++#include + #include + #include + #include +@@ -17,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -653,7 +655,51 @@ static void build_plt(struct jit_ctx *ctx) + plt->target = (u64)&dummy_tramp; + } + +-static void build_epilogue(struct jit_ctx *ctx) ++/* Clobbers BPF registers 1-4, aka x0-x3 */ ++static void __maybe_unused build_bhb_mitigation(struct jit_ctx *ctx) ++{ ++ const u8 r1 = bpf2a64[BPF_REG_1]; /* aka x0 */ ++ u8 k = get_spectre_bhb_loop_value(); ++ ++ if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY) || ++ cpu_mitigations_off() || __nospectre_bhb || ++ arm64_get_spectre_v2_state() == SPECTRE_VULNERABLE) ++ return; ++ ++ if (capable(CAP_SYS_ADMIN)) ++ return; ++ ++ if (supports_clearbhb(SCOPE_SYSTEM)) { ++ emit(aarch64_insn_gen_hint(AARCH64_INSN_HINT_CLEARBHB), ctx); ++ return; ++ } ++ ++ if (k) { ++ emit_a64_mov_i64(r1, k, ctx); ++ emit(A64_B(1), ctx); ++ emit(A64_SUBS_I(true, r1, r1, 1), ctx); ++ emit(A64_B_(A64_COND_NE, -2), ctx); ++ emit(aarch64_insn_gen_dsb(AARCH64_INSN_MB_ISH), ctx); ++ emit(aarch64_insn_get_isb_value(), ctx); ++ } ++ ++ if (is_spectre_bhb_fw_mitigated()) { ++ emit(A64_ORR_I(false, r1, AARCH64_INSN_REG_ZR, ++ ARM_SMCCC_ARCH_WORKAROUND_3), ctx); ++ switch (arm_smccc_1_1_get_conduit()) { ++ case SMCCC_CONDUIT_HVC: ++ emit(aarch64_insn_get_hvc_value(), ctx); ++ break; ++ case SMCCC_CONDUIT_SMC: ++ emit(aarch64_insn_get_smc_value(), ctx); ++ break; ++ default: ++ pr_err_once("Firmware mitigation enabled with unknown conduit\n"); ++ } ++ } ++} ++ ++static void build_epilogue(struct jit_ctx *ctx, bool was_classic) + { + const u8 r0 = bpf2a64[BPF_REG_0]; + const u8 r6 = bpf2a64[BPF_REG_6]; +@@ -675,10 +721,13 @@ static void build_epilogue(struct jit_ctx *ctx) + emit(A64_POP(r8, r9, A64_SP), ctx); + emit(A64_POP(r6, r7, A64_SP), ctx); + ++ if (was_classic) ++ build_bhb_mitigation(ctx); ++ + /* Restore FP/LR registers */ + emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); + +- /* Set return value */ ++ /* Move the return value from bpf:r0 (aka x7) to x0 */ + emit(A64_MOV(1, A64_R(0), r0), ctx); + + /* Authenticate lr */ +@@ -1586,7 +1635,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + } + + ctx.epilogue_offset = ctx.idx; +- build_epilogue(&ctx); ++ build_epilogue(&ctx, was_classic); + build_plt(&ctx); + + extable_align = __alignof__(struct exception_table_entry); +@@ -1622,7 +1671,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + goto out_off; + } + +- build_epilogue(&ctx); ++ build_epilogue(&ctx, was_classic); + build_plt(&ctx); + + /* 3. Extra pass to validate JITed code. */ +diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h +index 4a2b40ce39e091..841612913f0d1b 100644 +--- a/arch/mips/include/asm/ptrace.h ++++ b/arch/mips/include/asm/ptrace.h +@@ -65,7 +65,8 @@ static inline void instruction_pointer_set(struct pt_regs *regs, + + /* Query offset/name of register from its name/offset */ + extern int regs_query_register_offset(const char *name); +-#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) ++#define MAX_REG_OFFSET \ ++ (offsetof(struct pt_regs, __last) - sizeof(unsigned long)) + + /** + * regs_get_register() - get register value from its offset +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index d874ea22512b5c..4372657ab0d6fa 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -2610,6 +2610,17 @@ config MITIGATION_SPECTRE_BHI + indirect branches. + See + ++config MITIGATION_ITS ++ bool "Enable Indirect Target Selection mitigation" ++ depends on CPU_SUP_INTEL && X86_64 ++ depends on RETPOLINE && RETHUNK ++ default y ++ help ++ Enable Indirect Target Selection (ITS) mitigation. ITS is a bug in ++ BPU on some Intel CPUs that may allow Spectre V2 style attacks. If ++ disabled, mitigation cannot be enabled via cmdline. ++ See ++ + endif + + config ARCH_HAS_ADD_PAGES +diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S +index 2192b6c33ea009..1f9e508ac075c3 100644 +--- a/arch/x86/entry/entry_64.S ++++ b/arch/x86/entry/entry_64.S +@@ -1569,7 +1569,9 @@ SYM_CODE_END(rewind_stack_and_make_dead) + * ORC to unwind properly. + * + * The alignment is for performance and not for safety, and may be safely +- * refactored in the future if needed. ++ * refactored in the future if needed. The .skips are for safety, to ensure ++ * that all RETs are in the second half of a cacheline to mitigate Indirect ++ * Target Selection, rather than taking the slowpath via its_return_thunk. + */ + SYM_FUNC_START(clear_bhb_loop) + push %rbp +@@ -1579,10 +1581,22 @@ SYM_FUNC_START(clear_bhb_loop) + call 1f + jmp 5f + .align 64, 0xcc ++ /* ++ * Shift instructions so that the RET is in the upper half of the ++ * cacheline and don't take the slowpath to its_return_thunk. ++ */ ++ .skip 32 - (.Lret1 - 1f), 0xcc + ANNOTATE_INTRA_FUNCTION_CALL + 1: call 2f +- RET ++.Lret1: RET + .align 64, 0xcc ++ /* ++ * As above shift instructions for RET at .Lret2 as well. ++ * ++ * This should be ideally be: .skip 32 - (.Lret2 - 2f), 0xcc ++ * but some Clang versions (e.g. 18) don't like this. ++ */ ++ .skip 32 - 18, 0xcc + 2: movl $5, %eax + 3: jmp 4f + nop +@@ -1590,7 +1604,7 @@ SYM_FUNC_START(clear_bhb_loop) + jnz 3b + sub $1, %ecx + jnz 1b +- RET ++.Lret2: RET + 5: lfence + pop %rbp + RET +diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h +index cb9ce0f9e78e05..6740b839153a04 100644 +--- a/arch/x86/include/asm/alternative.h ++++ b/arch/x86/include/asm/alternative.h +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #define ALT_FLAGS_SHIFT 16 + +@@ -130,6 +131,37 @@ static __always_inline int x86_call_depth_emit_accounting(u8 **pprog, + } + #endif + ++#ifdef CONFIG_MITIGATION_ITS ++extern void its_init_mod(struct module *mod); ++extern void its_fini_mod(struct module *mod); ++extern void its_free_mod(struct module *mod); ++extern u8 *its_static_thunk(int reg); ++#else /* CONFIG_MITIGATION_ITS */ ++static inline void its_init_mod(struct module *mod) { } ++static inline void its_fini_mod(struct module *mod) { } ++static inline void its_free_mod(struct module *mod) { } ++static inline u8 *its_static_thunk(int reg) ++{ ++ WARN_ONCE(1, "ITS not compiled in"); ++ ++ return NULL; ++} ++#endif ++ ++#if defined(CONFIG_RETHUNK) && defined(CONFIG_OBJTOOL) ++extern bool cpu_wants_rethunk(void); ++extern bool cpu_wants_rethunk_at(void *addr); ++#else ++static __always_inline bool cpu_wants_rethunk(void) ++{ ++ return false; ++} ++static __always_inline bool cpu_wants_rethunk_at(void *addr) ++{ ++ return false; ++} ++#endif ++ + #ifdef CONFIG_SMP + extern void alternatives_smp_module_add(struct module *mod, char *name, + void *locks, void *locks_end, +diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h +index 55d18eef6775a6..8a2482651a6f1e 100644 +--- a/arch/x86/include/asm/cpufeatures.h ++++ b/arch/x86/include/asm/cpufeatures.h +@@ -468,6 +468,7 @@ + #define X86_FEATURE_BHI_CTRL (21*32+ 2) /* "" BHI_DIS_S HW control available */ + #define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* "" BHI_DIS_S HW control enabled */ + #define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* "" Clear branch history at vmexit using SW loop */ ++#define X86_FEATURE_INDIRECT_THUNK_ITS (21*32 + 5) /* "" Use thunk for indirect branches in lower half of cacheline */ + + /* + * BUG word(s) +@@ -518,4 +519,6 @@ + #define X86_BUG_RFDS X86_BUG(1*32 + 2) /* CPU is vulnerable to Register File Data Sampling */ + #define X86_BUG_BHI X86_BUG(1*32 + 3) /* CPU is affected by Branch History Injection */ + #define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */ ++#define X86_BUG_ITS X86_BUG(1*32 + 5) /* CPU is affected by Indirect Target Selection */ ++#define X86_BUG_ITS_NATIVE_ONLY X86_BUG(1*32 + 6) /* CPU is affected by ITS, VMX is not affected */ + #endif /* _ASM_X86_CPUFEATURES_H */ +diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h +index 0ee6ed0ff2bf20..79c35947e20cb7 100644 +--- a/arch/x86/include/asm/microcode.h ++++ b/arch/x86/include/asm/microcode.h +@@ -17,10 +17,12 @@ struct ucode_cpu_info { + void load_ucode_bsp(void); + void load_ucode_ap(void); + void microcode_bsp_resume(void); ++bool __init microcode_loader_disabled(void); + #else + static inline void load_ucode_bsp(void) { } + static inline void load_ucode_ap(void) { } + static inline void microcode_bsp_resume(void) { } ++static inline bool __init microcode_loader_disabled(void) { return false; } + #endif + + extern unsigned long initrd_start_early; +diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h +index 623bb48774d44c..9fbad4cb971bff 100644 +--- a/arch/x86/include/asm/msr-index.h ++++ b/arch/x86/include/asm/msr-index.h +@@ -180,6 +180,14 @@ + * VERW clears CPU Register + * File. + */ ++#define ARCH_CAP_ITS_NO BIT_ULL(62) /* ++ * Not susceptible to ++ * Indirect Target Selection. ++ * This bit is not set by ++ * HW, but is synthesized by ++ * VMMs for guests to know ++ * their affected status. ++ */ + + #define ARCH_CAP_XAPIC_DISABLE BIT(21) /* + * IA32_XAPIC_DISABLE_STATUS MSR +diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h +index ee642d26e30457..bc4fa6d09d29d9 100644 +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -219,9 +219,8 @@ + .endm + + /* +- * Equivalent to -mindirect-branch-cs-prefix; emit the 5 byte jmp/call +- * to the retpoline thunk with a CS prefix when the register requires +- * a RAX prefix byte to encode. Also see apply_retpolines(). ++ * Emits a conditional CS prefix that is compatible with ++ * -mindirect-branch-cs-prefix. + */ + .macro __CS_PREFIX reg:req + .irp rs,r8,r9,r10,r11,r12,r13,r14,r15 +@@ -365,10 +364,14 @@ + ".long 999b\n\t" \ + ".popsection\n\t" + ++#define ITS_THUNK_SIZE 64 ++ + typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE]; ++typedef u8 its_thunk_t[ITS_THUNK_SIZE]; + extern retpoline_thunk_t __x86_indirect_thunk_array[]; + extern retpoline_thunk_t __x86_indirect_call_thunk_array[]; + extern retpoline_thunk_t __x86_indirect_jump_thunk_array[]; ++extern its_thunk_t __x86_indirect_its_thunk_array[]; + + #ifdef CONFIG_RETHUNK + extern void __x86_return_thunk(void); +@@ -392,6 +395,12 @@ static inline void srso_return_thunk(void) {} + static inline void srso_alias_return_thunk(void) {} + #endif + ++#ifdef CONFIG_MITIGATION_ITS ++extern void its_return_thunk(void); ++#else ++static inline void its_return_thunk(void) {} ++#endif ++ + extern void retbleed_return_thunk(void); + extern void srso_return_thunk(void); + extern void srso_alias_return_thunk(void); +@@ -412,11 +421,6 @@ extern void (*x86_return_thunk)(void); + #ifdef CONFIG_CALL_DEPTH_TRACKING + extern void __x86_return_skl(void); + +-static inline void x86_set_skl_return_thunk(void) +-{ +- x86_return_thunk = &__x86_return_skl; +-} +- + #define CALL_DEPTH_ACCOUNT \ + ALTERNATIVE("", \ + __stringify(INCREMENT_CALL_DEPTH), \ +@@ -429,7 +433,6 @@ DECLARE_PER_CPU(u64, __x86_stuffs_count); + DECLARE_PER_CPU(u64, __x86_ctxsw_count); + #endif + #else +-static inline void x86_set_skl_return_thunk(void) {} + + #define CALL_DEPTH_ACCOUNT "" + +@@ -454,20 +457,23 @@ static inline void x86_set_skl_return_thunk(void) {} + + #ifdef CONFIG_X86_64 + ++/* ++ * Emits a conditional CS prefix that is compatible with ++ * -mindirect-branch-cs-prefix. ++ */ ++#define __CS_PREFIX(reg) \ ++ ".irp rs,r8,r9,r10,r11,r12,r13,r14,r15\n" \ ++ ".ifc \\rs," reg "\n" \ ++ ".byte 0x2e\n" \ ++ ".endif\n" \ ++ ".endr\n" ++ + /* + * Inline asm uses the %V modifier which is only in newer GCC + * which is ensured when CONFIG_RETPOLINE is defined. + */ +-# define CALL_NOSPEC \ +- ALTERNATIVE_2( \ +- ANNOTATE_RETPOLINE_SAFE \ +- "call *%[thunk_target]\n", \ +- "call __x86_indirect_thunk_%V[thunk_target]\n", \ +- X86_FEATURE_RETPOLINE, \ +- "lfence;\n" \ +- ANNOTATE_RETPOLINE_SAFE \ +- "call *%[thunk_target]\n", \ +- X86_FEATURE_RETPOLINE_LFENCE) ++#define CALL_NOSPEC __CS_PREFIX("%V[thunk_target]") \ ++ "call __x86_indirect_thunk_%V[thunk_target]\n" + + # define THUNK_TARGET(addr) [thunk_target] "r" (addr) + +diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c +index aae7456ece0700..4817e424d69658 100644 +--- a/arch/x86/kernel/alternative.c ++++ b/arch/x86/kernel/alternative.c +@@ -18,6 +18,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -30,6 +32,8 @@ + #include + #include + #include ++#include ++#include + + int __read_mostly alternatives_patched; + +@@ -123,6 +127,135 @@ const unsigned char * const x86_nops[ASM_NOP_MAX+1] = + #endif + }; + ++#ifdef CONFIG_MITIGATION_ITS ++ ++#ifdef CONFIG_MODULES ++static struct module *its_mod; ++static void *its_page; ++static unsigned int its_offset; ++ ++/* Initialize a thunk with the "jmp *reg; int3" instructions. */ ++static void *its_init_thunk(void *thunk, int reg) ++{ ++ u8 *bytes = thunk; ++ int i = 0; ++ ++ if (reg >= 8) { ++ bytes[i++] = 0x41; /* REX.B prefix */ ++ reg -= 8; ++ } ++ bytes[i++] = 0xff; ++ bytes[i++] = 0xe0 + reg; /* jmp *reg */ ++ bytes[i++] = 0xcc; ++ ++ return thunk; ++} ++ ++void its_init_mod(struct module *mod) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return; ++ ++ mutex_lock(&text_mutex); ++ its_mod = mod; ++ its_page = NULL; ++} ++ ++void its_fini_mod(struct module *mod) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return; ++ ++ WARN_ON_ONCE(its_mod != mod); ++ ++ its_mod = NULL; ++ its_page = NULL; ++ mutex_unlock(&text_mutex); ++ ++ for (int i = 0; i < mod->its_num_pages; i++) { ++ void *page = mod->its_page_array[i]; ++ set_memory_rox((unsigned long)page, 1); ++ } ++} ++ ++void its_free_mod(struct module *mod) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return; ++ ++ for (int i = 0; i < mod->its_num_pages; i++) { ++ void *page = mod->its_page_array[i]; ++ module_memfree(page); ++ } ++ kfree(mod->its_page_array); ++} ++ ++DEFINE_FREE(its_execmem, void *, if (_T) module_memfree(_T)); ++ ++static void *its_alloc(void) ++{ ++ void *page __free(its_execmem) = module_alloc(PAGE_SIZE); ++ ++ if (!page) ++ return NULL; ++ ++ if (its_mod) { ++ void *tmp = krealloc(its_mod->its_page_array, ++ (its_mod->its_num_pages+1) * sizeof(void *), ++ GFP_KERNEL); ++ if (!tmp) ++ return NULL; ++ ++ its_mod->its_page_array = tmp; ++ its_mod->its_page_array[its_mod->its_num_pages++] = page; ++ } ++ ++ return no_free_ptr(page); ++} ++ ++static void *its_allocate_thunk(int reg) ++{ ++ int size = 3 + (reg / 8); ++ void *thunk; ++ ++ if (!its_page || (its_offset + size - 1) >= PAGE_SIZE) { ++ its_page = its_alloc(); ++ if (!its_page) { ++ pr_err("ITS page allocation failed\n"); ++ return NULL; ++ } ++ memset(its_page, INT3_INSN_OPCODE, PAGE_SIZE); ++ its_offset = 32; ++ } ++ ++ /* ++ * If the indirect branch instruction will be in the lower half ++ * of a cacheline, then update the offset to reach the upper half. ++ */ ++ if ((its_offset + size - 1) % 64 < 32) ++ its_offset = ((its_offset - 1) | 0x3F) + 33; ++ ++ thunk = its_page + its_offset; ++ its_offset += size; ++ ++ set_memory_rw((unsigned long)its_page, 1); ++ thunk = its_init_thunk(thunk, reg); ++ set_memory_rox((unsigned long)its_page, 1); ++ ++ return thunk; ++} ++ ++#else /* CONFIG_MODULES */ ++ ++static void *its_allocate_thunk(int reg) ++{ ++ return NULL; ++} ++ ++#endif /* CONFIG_MODULES */ ++ ++#endif /* CONFIG_MITIGATION_ITS */ ++ + /* + * Fill the buffer with a single effective instruction of size @len. + * +@@ -521,7 +654,8 @@ static int emit_indirect(int op, int reg, u8 *bytes) + return i; + } + +-static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 *bytes) ++static int __emit_trampoline(void *addr, struct insn *insn, u8 *bytes, ++ void *call_dest, void *jmp_dest) + { + u8 op = insn->opcode.bytes[0]; + int i = 0; +@@ -542,7 +676,7 @@ static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 + switch (op) { + case CALL_INSN_OPCODE: + __text_gen_insn(bytes+i, op, addr+i, +- __x86_indirect_call_thunk_array[reg], ++ call_dest, + CALL_INSN_SIZE); + i += CALL_INSN_SIZE; + break; +@@ -550,7 +684,7 @@ static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 + case JMP32_INSN_OPCODE: + clang_jcc: + __text_gen_insn(bytes+i, op, addr+i, +- __x86_indirect_jump_thunk_array[reg], ++ jmp_dest, + JMP32_INSN_SIZE); + i += JMP32_INSN_SIZE; + break; +@@ -565,6 +699,39 @@ static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 + return i; + } + ++static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 *bytes) ++{ ++ return __emit_trampoline(addr, insn, bytes, ++ __x86_indirect_call_thunk_array[reg], ++ __x86_indirect_jump_thunk_array[reg]); ++} ++ ++#ifdef CONFIG_MITIGATION_ITS ++static int emit_its_trampoline(void *addr, struct insn *insn, int reg, u8 *bytes) ++{ ++ u8 *thunk = __x86_indirect_its_thunk_array[reg]; ++ u8 *tmp = its_allocate_thunk(reg); ++ ++ if (tmp) ++ thunk = tmp; ++ ++ return __emit_trampoline(addr, insn, bytes, thunk, thunk); ++} ++ ++/* Check if an indirect branch is at ITS-unsafe address */ ++static bool cpu_wants_indirect_its_thunk_at(unsigned long addr, int reg) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return false; ++ ++ /* Indirect branch opcode is 2 or 3 bytes depending on reg */ ++ addr += 1 + reg / 8; ++ ++ /* Lower-half of the cacheline? */ ++ return !(addr & 0x20); ++} ++#endif ++ + /* + * Rewrite the compiler generated retpoline thunk calls. + * +@@ -639,6 +806,15 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes) + bytes[i++] = 0xe8; /* LFENCE */ + } + ++#ifdef CONFIG_MITIGATION_ITS ++ /* ++ * Check if the address of last byte of emitted-indirect is in ++ * lower-half of the cacheline. Such branches need ITS mitigation. ++ */ ++ if (cpu_wants_indirect_its_thunk_at((unsigned long)addr + i, reg)) ++ return emit_its_trampoline(addr, insn, reg, bytes); ++#endif ++ + ret = emit_indirect(op, reg, bytes + i); + if (ret < 0) + return ret; +@@ -710,6 +886,21 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) + + #ifdef CONFIG_RETHUNK + ++bool cpu_wants_rethunk(void) ++{ ++ return cpu_feature_enabled(X86_FEATURE_RETHUNK); ++} ++ ++bool cpu_wants_rethunk_at(void *addr) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ return false; ++ if (x86_return_thunk != its_return_thunk) ++ return true; ++ ++ return !((unsigned long)addr & 0x20); ++} ++ + /* + * Rewrite the compiler generated return thunk tail-calls. + * +@@ -726,7 +917,7 @@ static int patch_return(void *addr, struct insn *insn, u8 *bytes) + int i = 0; + + /* Patch the custom return thunks... */ +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) { ++ if (cpu_wants_rethunk_at(addr)) { + i = JMP32_INSN_SIZE; + __text_gen_insn(bytes, JMP32_INSN_OPCODE, addr, x86_return_thunk, i); + } else { +@@ -743,7 +934,7 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end) + { + s32 *s; + +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk()) + static_call_force_reinit(); + + for (s = start; s < end; s++) { +@@ -1258,6 +1449,13 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, + static void poison_cfi(void *addr) { } + #endif + ++u8 *its_static_thunk(int reg) ++{ ++ u8 *thunk = __x86_indirect_its_thunk_array[reg]; ++ ++ return thunk; ++} ++ + #endif + + void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, +@@ -1575,6 +1773,8 @@ static noinline void __init alt_reloc_selftest(void) + + void __init alternative_instructions(void) + { ++ u64 ibt; ++ + int3_selftest(); + + /* +@@ -1612,6 +1812,9 @@ void __init alternative_instructions(void) + */ + paravirt_set_cap(); + ++ /* Keep CET-IBT disabled until caller/callee are patched */ ++ ibt = ibt_save(/*disable*/ true); ++ + /* + * First patch paravirt functions, such that we overwrite the indirect + * call with the direct call. +@@ -1645,6 +1848,8 @@ void __init alternative_instructions(void) + */ + apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end); + ++ ibt_restore(ibt); ++ + #ifdef CONFIG_SMP + /* Patch to UP if other cpus not imminent. */ + if (!noreplace_smp && (num_present_cpus() == 1 || setup_max_cpus <= 1)) { +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 78545f7e9cc6ca..07b45bbf6348de 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -49,6 +49,7 @@ static void __init srbds_select_mitigation(void); + static void __init l1d_flush_select_mitigation(void); + static void __init srso_select_mitigation(void); + static void __init gds_select_mitigation(void); ++static void __init its_select_mitigation(void); + + /* The base value of the SPEC_CTRL MSR without task-specific bits set */ + u64 x86_spec_ctrl_base; +@@ -67,6 +68,14 @@ static DEFINE_MUTEX(spec_ctrl_mutex); + + void (*x86_return_thunk)(void) __ro_after_init = __x86_return_thunk; + ++static void __init set_return_thunk(void *thunk) ++{ ++ if (x86_return_thunk != __x86_return_thunk) ++ pr_warn("x86/bugs: return thunk changed\n"); ++ ++ x86_return_thunk = thunk; ++} ++ + /* Update SPEC_CTRL MSR and its cached copy unconditionally */ + static void update_spec_ctrl(u64 val) + { +@@ -175,6 +184,7 @@ void __init cpu_select_mitigations(void) + */ + srso_select_mitigation(); + gds_select_mitigation(); ++ its_select_mitigation(); + } + + /* +@@ -1102,7 +1112,7 @@ static void __init retbleed_select_mitigation(void) + setup_force_cpu_cap(X86_FEATURE_RETHUNK); + setup_force_cpu_cap(X86_FEATURE_UNRET); + +- x86_return_thunk = retbleed_return_thunk; ++ set_return_thunk(retbleed_return_thunk); + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && + boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) +@@ -1136,7 +1146,9 @@ static void __init retbleed_select_mitigation(void) + case RETBLEED_MITIGATION_STUFF: + setup_force_cpu_cap(X86_FEATURE_RETHUNK); + setup_force_cpu_cap(X86_FEATURE_CALL_DEPTH); +- x86_set_skl_return_thunk(); ++#ifdef CONFIG_CALL_DEPTH_TRACKING ++ set_return_thunk(&__x86_return_skl); ++#endif + break; + + default: +@@ -1170,6 +1182,146 @@ static void __init retbleed_select_mitigation(void) + pr_info("%s\n", retbleed_strings[retbleed_mitigation]); + } + ++#undef pr_fmt ++#define pr_fmt(fmt) "ITS: " fmt ++ ++enum its_mitigation_cmd { ++ ITS_CMD_OFF, ++ ITS_CMD_ON, ++ ITS_CMD_VMEXIT, ++ ITS_CMD_RSB_STUFF, ++}; ++ ++enum its_mitigation { ++ ITS_MITIGATION_OFF, ++ ITS_MITIGATION_VMEXIT_ONLY, ++ ITS_MITIGATION_ALIGNED_THUNKS, ++ ITS_MITIGATION_RETPOLINE_STUFF, ++}; ++ ++static const char * const its_strings[] = { ++ [ITS_MITIGATION_OFF] = "Vulnerable", ++ [ITS_MITIGATION_VMEXIT_ONLY] = "Mitigation: Vulnerable, KVM: Not affected", ++ [ITS_MITIGATION_ALIGNED_THUNKS] = "Mitigation: Aligned branch/return thunks", ++ [ITS_MITIGATION_RETPOLINE_STUFF] = "Mitigation: Retpolines, Stuffing RSB", ++}; ++ ++static enum its_mitigation its_mitigation __ro_after_init = ITS_MITIGATION_ALIGNED_THUNKS; ++ ++static enum its_mitigation_cmd its_cmd __ro_after_init = ++ IS_ENABLED(CONFIG_MITIGATION_ITS) ? ITS_CMD_ON : ITS_CMD_OFF; ++ ++static int __init its_parse_cmdline(char *str) ++{ ++ if (!str) ++ return -EINVAL; ++ ++ if (!IS_ENABLED(CONFIG_MITIGATION_ITS)) { ++ pr_err("Mitigation disabled at compile time, ignoring option (%s)", str); ++ return 0; ++ } ++ ++ if (!strcmp(str, "off")) { ++ its_cmd = ITS_CMD_OFF; ++ } else if (!strcmp(str, "on")) { ++ its_cmd = ITS_CMD_ON; ++ } else if (!strcmp(str, "force")) { ++ its_cmd = ITS_CMD_ON; ++ setup_force_cpu_bug(X86_BUG_ITS); ++ } else if (!strcmp(str, "vmexit")) { ++ its_cmd = ITS_CMD_VMEXIT; ++ } else if (!strcmp(str, "stuff")) { ++ its_cmd = ITS_CMD_RSB_STUFF; ++ } else { ++ pr_err("Ignoring unknown indirect_target_selection option (%s).", str); ++ } ++ ++ return 0; ++} ++early_param("indirect_target_selection", its_parse_cmdline); ++ ++static void __init its_select_mitigation(void) ++{ ++ enum its_mitigation_cmd cmd = its_cmd; ++ ++ if (!boot_cpu_has_bug(X86_BUG_ITS) || cpu_mitigations_off()) { ++ its_mitigation = ITS_MITIGATION_OFF; ++ return; ++ } ++ ++ /* Retpoline+CDT mitigates ITS, bail out */ ++ if (boot_cpu_has(X86_FEATURE_RETPOLINE) && ++ boot_cpu_has(X86_FEATURE_CALL_DEPTH)) { ++ its_mitigation = ITS_MITIGATION_RETPOLINE_STUFF; ++ goto out; ++ } ++ ++ /* Exit early to avoid irrelevant warnings */ ++ if (cmd == ITS_CMD_OFF) { ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (spectre_v2_enabled == SPECTRE_V2_NONE) { ++ pr_err("WARNING: Spectre-v2 mitigation is off, disabling ITS\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (!IS_ENABLED(CONFIG_RETPOLINE) || !IS_ENABLED(CONFIG_RETHUNK)) { ++ pr_err("WARNING: ITS mitigation depends on retpoline and rethunk support\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (IS_ENABLED(CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B)) { ++ pr_err("WARNING: ITS mitigation is not compatible with CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) { ++ pr_err("WARNING: ITS mitigation is not compatible with lfence mitigation\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ ++ if (cmd == ITS_CMD_RSB_STUFF && ++ (!boot_cpu_has(X86_FEATURE_RETPOLINE) || !IS_ENABLED(CONFIG_CALL_DEPTH_TRACKING))) { ++ pr_err("RSB stuff mitigation not supported, using default\n"); ++ cmd = ITS_CMD_ON; ++ } ++ ++ switch (cmd) { ++ case ITS_CMD_OFF: ++ its_mitigation = ITS_MITIGATION_OFF; ++ break; ++ case ITS_CMD_VMEXIT: ++ if (boot_cpu_has_bug(X86_BUG_ITS_NATIVE_ONLY)) { ++ its_mitigation = ITS_MITIGATION_VMEXIT_ONLY; ++ goto out; ++ } ++ fallthrough; ++ case ITS_CMD_ON: ++ its_mitigation = ITS_MITIGATION_ALIGNED_THUNKS; ++ if (!boot_cpu_has(X86_FEATURE_RETPOLINE)) ++ setup_force_cpu_cap(X86_FEATURE_INDIRECT_THUNK_ITS); ++ setup_force_cpu_cap(X86_FEATURE_RETHUNK); ++ set_return_thunk(its_return_thunk); ++ break; ++ case ITS_CMD_RSB_STUFF: ++ its_mitigation = ITS_MITIGATION_RETPOLINE_STUFF; ++ setup_force_cpu_cap(X86_FEATURE_RETHUNK); ++ setup_force_cpu_cap(X86_FEATURE_CALL_DEPTH); ++#ifdef CONFIG_CALL_DEPTH_TRACKING ++ set_return_thunk(&__x86_return_skl); ++#endif ++ if (retbleed_mitigation == RETBLEED_MITIGATION_NONE) { ++ retbleed_mitigation = RETBLEED_MITIGATION_STUFF; ++ pr_info("Retbleed mitigation updated to stuffing\n"); ++ } ++ break; ++ } ++out: ++ pr_info("%s\n", its_strings[its_mitigation]); ++} ++ + #undef pr_fmt + #define pr_fmt(fmt) "Spectre V2 : " fmt + +@@ -1677,10 +1829,11 @@ static void __init bhi_select_mitigation(void) + return; + } + +- if (spec_ctrl_bhi_dis()) ++ if (!IS_ENABLED(CONFIG_X86_64)) + return; + +- if (!IS_ENABLED(CONFIG_X86_64)) ++ /* Mitigate in hardware if supported */ ++ if (spec_ctrl_bhi_dis()) + return; + + /* Mitigate KVM by default */ +@@ -2606,10 +2759,10 @@ static void __init srso_select_mitigation(void) + + if (boot_cpu_data.x86 == 0x19) { + setup_force_cpu_cap(X86_FEATURE_SRSO_ALIAS); +- x86_return_thunk = srso_alias_return_thunk; ++ set_return_thunk(srso_alias_return_thunk); + } else { + setup_force_cpu_cap(X86_FEATURE_SRSO); +- x86_return_thunk = srso_return_thunk; ++ set_return_thunk(srso_return_thunk); + } + if (has_microcode) + srso_mitigation = SRSO_MITIGATION_SAFE_RET; +@@ -2793,6 +2946,11 @@ static ssize_t rfds_show_state(char *buf) + return sysfs_emit(buf, "%s\n", rfds_strings[rfds_mitigation]); + } + ++static ssize_t its_show_state(char *buf) ++{ ++ return sysfs_emit(buf, "%s\n", its_strings[its_mitigation]); ++} ++ + static char *stibp_state(void) + { + if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) && +@@ -2975,6 +3133,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr + case X86_BUG_RFDS: + return rfds_show_state(buf); + ++ case X86_BUG_ITS: ++ return its_show_state(buf); ++ + default: + break; + } +@@ -3054,4 +3215,9 @@ ssize_t cpu_show_reg_file_data_sampling(struct device *dev, struct device_attrib + { + return cpu_show_common(dev, attr, buf, X86_BUG_RFDS); + } ++ ++ssize_t cpu_show_indirect_target_selection(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return cpu_show_common(dev, attr, buf, X86_BUG_ITS); ++} + #endif +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index a844110691f978..067e31fb9e165d 100644 +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -1272,6 +1272,10 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { + #define GDS BIT(6) + /* CPU is affected by Register File Data Sampling */ + #define RFDS BIT(7) ++/* CPU is affected by Indirect Target Selection */ ++#define ITS BIT(8) ++/* CPU is affected by Indirect Target Selection, but guest-host isolation is not affected */ ++#define ITS_NATIVE_ONLY BIT(9) + + static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { + VULNBL_INTEL_STEPPINGS(IVYBRIDGE, X86_STEPPING_ANY, SRBDS), +@@ -1283,22 +1287,25 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { + VULNBL_INTEL_STEPPINGS(BROADWELL_G, X86_STEPPING_ANY, SRBDS), + VULNBL_INTEL_STEPPINGS(BROADWELL_X, X86_STEPPING_ANY, MMIO), + VULNBL_INTEL_STEPPINGS(BROADWELL, X86_STEPPING_ANY, SRBDS), +- VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), ++ VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x0, 0x5), MMIO | RETBLEED | GDS), ++ VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | ITS), + VULNBL_INTEL_STEPPINGS(SKYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), + VULNBL_INTEL_STEPPINGS(SKYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), +- VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), +- VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPINGS(0x0, 0xb), MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS | ITS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPINGS(0x0, 0xc), MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS | ITS), + VULNBL_INTEL_STEPPINGS(CANNONLAKE_L, X86_STEPPING_ANY, RETBLEED), +- VULNBL_INTEL_STEPPINGS(ICELAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(ICELAKE_D, X86_STEPPING_ANY, MMIO | GDS), +- VULNBL_INTEL_STEPPINGS(ICELAKE_X, X86_STEPPING_ANY, MMIO | GDS), +- VULNBL_INTEL_STEPPINGS(COMETLAKE, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPINGS(0x0, 0x0), MMIO | RETBLEED), +- VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(TIGERLAKE_L, X86_STEPPING_ANY, GDS), +- VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS), ++ VULNBL_INTEL_STEPPINGS(ICELAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(ICELAKE_D, X86_STEPPING_ANY, MMIO | GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(ICELAKE_X, X86_STEPPING_ANY, MMIO | GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(COMETLAKE, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS | ITS), ++ VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPINGS(0x0, 0x0), MMIO | RETBLEED | ITS), ++ VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS | ITS), ++ VULNBL_INTEL_STEPPINGS(TIGERLAKE_L, X86_STEPPING_ANY, GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS | ITS | ITS_NATIVE_ONLY), + VULNBL_INTEL_STEPPINGS(LAKEFIELD, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED), +- VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), ++ VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | ITS | ITS_NATIVE_ONLY), + VULNBL_INTEL_STEPPINGS(ALDERLAKE, X86_STEPPING_ANY, RFDS), + VULNBL_INTEL_STEPPINGS(ALDERLAKE_L, X86_STEPPING_ANY, RFDS), + VULNBL_INTEL_STEPPINGS(RAPTORLAKE, X86_STEPPING_ANY, RFDS), +@@ -1362,6 +1369,32 @@ static bool __init vulnerable_to_rfds(u64 x86_arch_cap_msr) + return cpu_matches(cpu_vuln_blacklist, RFDS); + } + ++static bool __init vulnerable_to_its(u64 x86_arch_cap_msr) ++{ ++ /* The "immunity" bit trumps everything else: */ ++ if (x86_arch_cap_msr & ARCH_CAP_ITS_NO) ++ return false; ++ if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ return false; ++ ++ /* None of the affected CPUs have BHI_CTRL */ ++ if (boot_cpu_has(X86_FEATURE_BHI_CTRL)) ++ return false; ++ ++ /* ++ * If a VMM did not expose ITS_NO, assume that a guest could ++ * be running on a vulnerable hardware or may migrate to such ++ * hardware. ++ */ ++ if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) ++ return true; ++ ++ if (cpu_matches(cpu_vuln_blacklist, ITS)) ++ return true; ++ ++ return false; ++} ++ + static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + { + u64 x86_arch_cap_msr = x86_read_arch_cap_msr(); +@@ -1476,9 +1509,12 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + if (vulnerable_to_rfds(x86_arch_cap_msr)) + setup_force_cpu_bug(X86_BUG_RFDS); + +- /* When virtualized, eIBRS could be hidden, assume vulnerable */ +- if (!(x86_arch_cap_msr & ARCH_CAP_BHI_NO) && +- !cpu_matches(cpu_vuln_whitelist, NO_BHI) && ++ /* ++ * Intel parts with eIBRS are vulnerable to BHI attacks. Parts with ++ * BHI_NO still need to use the BHI mitigation to prevent Intra-mode ++ * attacks. When virtualized, eIBRS could be hidden, assume vulnerable. ++ */ ++ if (!cpu_matches(cpu_vuln_whitelist, NO_BHI) && + (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED) || + boot_cpu_has(X86_FEATURE_HYPERVISOR))) + setup_force_cpu_bug(X86_BUG_BHI); +@@ -1486,6 +1522,12 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + if (cpu_has(c, X86_FEATURE_AMD_IBPB) && !cpu_has(c, X86_FEATURE_AMD_IBPB_RET)) + setup_force_cpu_bug(X86_BUG_IBPB_NO_RET); + ++ if (vulnerable_to_its(x86_arch_cap_msr)) { ++ setup_force_cpu_bug(X86_BUG_ITS); ++ if (cpu_matches(cpu_vuln_blacklist, ITS_NATIVE_ONLY)) ++ setup_force_cpu_bug(X86_BUG_ITS_NATIVE_ONLY); ++ } ++ + if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN)) + return; + +diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c +index ce78e39004e0ea..9b0570f769eb3d 100644 +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -1102,15 +1102,17 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz + + static int __init save_microcode_in_initrd(void) + { +- unsigned int cpuid_1_eax = native_cpuid_eax(1); + struct cpuinfo_x86 *c = &boot_cpu_data; + struct cont_desc desc = { 0 }; ++ unsigned int cpuid_1_eax; + enum ucode_state ret; + struct cpio_data cp; + +- if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) ++ if (microcode_loader_disabled() || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) + return 0; + ++ cpuid_1_eax = native_cpuid_eax(1); ++ + if (!find_blobs_in_containers(&cp)) + return -EINVAL; + +diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c +index c15c7b862bec1c..5b47c320f17a6d 100644 +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -43,8 +43,8 @@ + + #define DRIVER_VERSION "2.2" + +-static struct microcode_ops *microcode_ops; +-bool dis_ucode_ldr = true; ++static struct microcode_ops *microcode_ops; ++static bool dis_ucode_ldr = false; + + bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV); + module_param(force_minrev, bool, S_IRUSR | S_IWUSR); +@@ -91,6 +91,9 @@ static bool amd_check_current_patch_level(void) + u32 lvl, dummy, i; + u32 *levels; + ++ if (x86_cpuid_vendor() != X86_VENDOR_AMD) ++ return false; ++ + native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); + + levels = final_levels; +@@ -102,27 +105,29 @@ static bool amd_check_current_patch_level(void) + return false; + } + +-static bool __init check_loader_disabled_bsp(void) ++bool __init microcode_loader_disabled(void) + { +- static const char *__dis_opt_str = "dis_ucode_ldr"; +- const char *cmdline = boot_command_line; +- const char *option = __dis_opt_str; ++ if (dis_ucode_ldr) ++ return true; + + /* +- * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not +- * completely accurate as xen pv guests don't see that CPUID bit set but +- * that's good enough as they don't land on the BSP path anyway. ++ * Disable when: ++ * ++ * 1) The CPU does not support CPUID. ++ * ++ * 2) Bit 31 in CPUID[1]:ECX is clear ++ * The bit is reserved for hypervisor use. This is still not ++ * completely accurate as XEN PV guests don't see that CPUID bit ++ * set, but that's good enough as they don't land on the BSP ++ * path anyway. ++ * ++ * 3) Certain AMD patch levels are not allowed to be ++ * overwritten. + */ +- if (native_cpuid_ecx(1) & BIT(31)) +- return true; +- +- if (x86_cpuid_vendor() == X86_VENDOR_AMD) { +- if (amd_check_current_patch_level()) +- return true; +- } +- +- if (cmdline_find_option_bool(cmdline, option) <= 0) +- dis_ucode_ldr = false; ++ if (!have_cpuid_p() || ++ native_cpuid_ecx(1) & BIT(31) || ++ amd_check_current_patch_level()) ++ dis_ucode_ldr = true; + + return dis_ucode_ldr; + } +@@ -132,7 +137,10 @@ void __init load_ucode_bsp(void) + unsigned int cpuid_1_eax; + bool intel = true; + +- if (!have_cpuid_p()) ++ if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0) ++ dis_ucode_ldr = true; ++ ++ if (microcode_loader_disabled()) + return; + + cpuid_1_eax = native_cpuid_eax(1); +@@ -153,9 +161,6 @@ void __init load_ucode_bsp(void) + return; + } + +- if (check_loader_disabled_bsp()) +- return; +- + if (intel) + load_ucode_intel_bsp(&early_data); + else +@@ -166,6 +171,11 @@ void load_ucode_ap(void) + { + unsigned int cpuid_1_eax; + ++ /* ++ * Can't use microcode_loader_disabled() here - .init section ++ * hell. It doesn't have to either - the BSP variant must've ++ * parsed cmdline already anyway. ++ */ + if (dis_ucode_ldr) + return; + +@@ -817,7 +827,7 @@ static int __init microcode_init(void) + struct cpuinfo_x86 *c = &boot_cpu_data; + int error; + +- if (dis_ucode_ldr) ++ if (microcode_loader_disabled()) + return -EINVAL; + + if (c->x86_vendor == X86_VENDOR_INTEL) +diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c +index 9d7baf2573bcde..4e5a71796fbdb1 100644 +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -389,7 +389,7 @@ static int __init save_builtin_microcode(void) + if (xchg(&ucode_patch_va, NULL) != UCODE_BSP_LOADED) + return 0; + +- if (dis_ucode_ldr || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ if (microcode_loader_disabled() || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return 0; + + uci.mc = get_microcode_blob(&uci, true); +diff --git a/arch/x86/kernel/cpu/microcode/internal.h b/arch/x86/kernel/cpu/microcode/internal.h +index 21776c529fa97a..54f2b9582a7cec 100644 +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -94,7 +94,6 @@ static inline unsigned int x86_cpuid_family(void) + return x86_family(eax); + } + +-extern bool dis_ucode_ldr; + extern bool force_minrev; + + #ifdef CONFIG_CPU_SUP_AMD +diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c +index 12df54ff0e8171..50f8c8a8483be2 100644 +--- a/arch/x86/kernel/ftrace.c ++++ b/arch/x86/kernel/ftrace.c +@@ -363,7 +363,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) + goto fail; + + ip = trampoline + size; +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk_at(ip)) + __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, x86_return_thunk, JMP32_INSN_SIZE); + else + memcpy(ip, retq, sizeof(retq)); +diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c +index de001b2146abf3..375f2d7f1762d4 100644 +--- a/arch/x86/kernel/head32.c ++++ b/arch/x86/kernel/head32.c +@@ -145,10 +145,6 @@ void __init __no_stack_protector mk_early_pgtbl_32(void) + *ptr = (unsigned long)ptep + PAGE_OFFSET; + + #ifdef CONFIG_MICROCODE_INITRD32 +- /* Running on a hypervisor? */ +- if (native_cpuid_ecx(1) & BIT(31)) +- return; +- + params = (struct boot_params *)__pa_nodebug(&boot_params); + if (!params->hdr.ramdisk_size || !params->hdr.ramdisk_image) + return; +diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c +index 5f71a0cf4399a5..cfb7163cf90e95 100644 +--- a/arch/x86/kernel/module.c ++++ b/arch/x86/kernel/module.c +@@ -312,6 +312,9 @@ int module_finalize(const Elf_Ehdr *hdr, + void *pseg = (void *)para->sh_addr; + apply_paravirt(pseg, pseg + para->sh_size); + } ++ ++ its_init_mod(me); ++ + if (retpolines || cfi) { + void *rseg = NULL, *cseg = NULL; + unsigned int rsize = 0, csize = 0; +@@ -332,6 +335,9 @@ int module_finalize(const Elf_Ehdr *hdr, + void *rseg = (void *)retpolines->sh_addr; + apply_retpolines(rseg, rseg + retpolines->sh_size); + } ++ ++ its_fini_mod(me); ++ + if (returns) { + void *rseg = (void *)returns->sh_addr; + apply_returns(rseg, rseg + returns->sh_size); +@@ -379,4 +385,5 @@ int module_finalize(const Elf_Ehdr *hdr, + void module_arch_cleanup(struct module *mod) + { + alternatives_smp_module_del(mod); ++ its_free_mod(mod); + } +diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c +index 07961b362e2a0c..bcea882e022f50 100644 +--- a/arch/x86/kernel/static_call.c ++++ b/arch/x86/kernel/static_call.c +@@ -81,7 +81,7 @@ static void __ref __static_call_transform(void *insn, enum insn_type type, + break; + + case RET: +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk_at(insn)) + code = text_gen_insn(JMP32_INSN_OPCODE, insn, x86_return_thunk); + else + code = &retinsn; +@@ -90,7 +90,7 @@ static void __ref __static_call_transform(void *insn, enum insn_type type, + case JCC: + if (!func) { + func = __static_call_return; +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk()) + func = x86_return_thunk; + } + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 60eb8baa44d7b7..c57d5df1abc603 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -541,4 +541,14 @@ INIT_PER_CPU(irq_stack_backing_store); + "SRSO function pair won't alias"); + #endif + ++#if defined(CONFIG_MITIGATION_ITS) && !defined(CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B) ++. = ASSERT(__x86_indirect_its_thunk_rax & 0x20, "__x86_indirect_thunk_rax not in second half of cacheline"); ++. = ASSERT(((__x86_indirect_its_thunk_rcx - __x86_indirect_its_thunk_rax) % 64) == 0, "Indirect thunks are not cacheline apart"); ++. = ASSERT(__x86_indirect_its_thunk_array == __x86_indirect_its_thunk_rax, "Gap in ITS thunk array"); ++#endif ++ ++#if defined(CONFIG_MITIGATION_ITS) && !defined(CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B) ++. = ASSERT(its_return_thunk & 0x20, "its_return_thunk not in second half of cacheline"); ++#endif ++ + #endif /* CONFIG_X86_64 */ +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 1eeb01afa40ba9..55185670e0e566 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1621,7 +1621,7 @@ static bool kvm_is_immutable_feature_msr(u32 msr) + ARCH_CAP_PSCHANGE_MC_NO | ARCH_CAP_TSX_CTRL_MSR | ARCH_CAP_TAA_NO | \ + ARCH_CAP_SBDR_SSDP_NO | ARCH_CAP_FBSDP_NO | ARCH_CAP_PSDP_NO | \ + ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO | ARCH_CAP_GDS_NO | \ +- ARCH_CAP_RFDS_NO | ARCH_CAP_RFDS_CLEAR | ARCH_CAP_BHI_NO) ++ ARCH_CAP_RFDS_NO | ARCH_CAP_RFDS_CLEAR | ARCH_CAP_BHI_NO | ARCH_CAP_ITS_NO) + + static u64 kvm_get_arch_capabilities(void) + { +@@ -1655,6 +1655,8 @@ static u64 kvm_get_arch_capabilities(void) + data |= ARCH_CAP_MDS_NO; + if (!boot_cpu_has_bug(X86_BUG_RFDS)) + data |= ARCH_CAP_RFDS_NO; ++ if (!boot_cpu_has_bug(X86_BUG_ITS)) ++ data |= ARCH_CAP_ITS_NO; + + if (!boot_cpu_has(X86_FEATURE_RTM)) { + /* +diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S +index ffa51f392e17a3..91ce427d5af191 100644 +--- a/arch/x86/lib/retpoline.S ++++ b/arch/x86/lib/retpoline.S +@@ -360,6 +360,45 @@ SYM_FUNC_END(__x86_return_skl) + + #endif /* CONFIG_CALL_DEPTH_TRACKING */ + ++#ifdef CONFIG_MITIGATION_ITS ++ ++.macro ITS_THUNK reg ++ ++SYM_INNER_LABEL(__x86_indirect_its_thunk_\reg, SYM_L_GLOBAL) ++ UNWIND_HINT_UNDEFINED ++ ANNOTATE_NOENDBR ++ ANNOTATE_RETPOLINE_SAFE ++ jmp *%\reg ++ int3 ++ .align 32, 0xcc /* fill to the end of the line */ ++ .skip 32, 0xcc /* skip to the next upper half */ ++.endm ++ ++/* ITS mitigation requires thunks be aligned to upper half of cacheline */ ++.align 64, 0xcc ++.skip 32, 0xcc ++SYM_CODE_START(__x86_indirect_its_thunk_array) ++ ++#define GEN(reg) ITS_THUNK reg ++#include ++#undef GEN ++ ++ .align 64, 0xcc ++SYM_CODE_END(__x86_indirect_its_thunk_array) ++ ++.align 64, 0xcc ++.skip 32, 0xcc ++SYM_CODE_START(its_return_thunk) ++ UNWIND_HINT_FUNC ++ ANNOTATE_NOENDBR ++ ANNOTATE_UNRET_SAFE ++ ret ++ int3 ++SYM_CODE_END(its_return_thunk) ++EXPORT_SYMBOL(its_return_thunk) ++ ++#endif /* CONFIG_MITIGATION_ITS */ ++ + /* + * This function name is magical and is used by -mfunction-return=thunk-extern + * for the compiler to generate JMPs to it. +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index 4872bb082b1935..20ce6a1bd6c57d 100644 +--- a/arch/x86/mm/tlb.c ++++ b/arch/x86/mm/tlb.c +@@ -630,7 +630,11 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, + + choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush); + +- /* Let nmi_uaccess_okay() know that we're changing CR3. */ ++ /* ++ * Indicate that CR3 is about to change. nmi_uaccess_okay() ++ * and others are sensitive to the window where mm_cpumask(), ++ * CR3 and cpu_tlbstate.loaded_mm are not all in sync. ++ */ + this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING); + barrier(); + } +@@ -900,8 +904,16 @@ static void flush_tlb_func(void *info) + + static bool should_flush_tlb(int cpu, void *data) + { ++ struct mm_struct *loaded_mm = per_cpu(cpu_tlbstate.loaded_mm, cpu); + struct flush_tlb_info *info = data; + ++ /* ++ * Order the 'loaded_mm' and 'is_lazy' against their ++ * write ordering in switch_mm_irqs_off(). Ensure ++ * 'is_lazy' is at least as new as 'loaded_mm'. ++ */ ++ smp_rmb(); ++ + /* Lazy TLB will get flushed at the next context switch. */ + if (per_cpu(cpu_tlbstate_shared.is_lazy, cpu)) + return false; +@@ -910,8 +922,15 @@ static bool should_flush_tlb(int cpu, void *data) + if (!info->mm) + return true; + ++ /* ++ * While switching, the remote CPU could have state from ++ * either the prev or next mm. Assume the worst and flush. ++ */ ++ if (loaded_mm == LOADED_MM_SWITCHING) ++ return true; ++ + /* The target mm is loaded, and the CPU is not lazy. */ +- if (per_cpu(cpu_tlbstate.loaded_mm, cpu) == info->mm) ++ if (loaded_mm == info->mm) + return true; + + /* In cpumask, but not the loaded mm? Periodically remove by flushing. */ +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index a50c99e9b5c01f..07592eef253c21 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -37,6 +37,8 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len) + #define EMIT2(b1, b2) EMIT((b1) + ((b2) << 8), 2) + #define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3) + #define EMIT4(b1, b2, b3, b4) EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4) ++#define EMIT5(b1, b2, b3, b4, b5) \ ++ do { EMIT1(b1); EMIT4(b2, b3, b4, b5); } while (0) + + #define EMIT1_off32(b1, off) \ + do { EMIT1(b1); EMIT(off, 4); } while (0) +@@ -470,7 +472,11 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip) + { + u8 *prog = *pprog; + +- if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) { ++ if (IS_ENABLED(CONFIG_MITIGATION_ITS) && ++ cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) { ++ OPTIMIZER_HIDE_VAR(reg); ++ emit_jump(&prog, its_static_thunk(reg), ip); ++ } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) { + EMIT_LFENCE(); + EMIT2(0xFF, 0xE0 + reg); + } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) { +@@ -492,7 +498,7 @@ static void emit_return(u8 **pprog, u8 *ip) + { + u8 *prog = *pprog; + +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) { ++ if (cpu_wants_rethunk()) { + emit_jump(&prog, x86_return_thunk, ip); + } else { + EMIT1(0xC3); /* ret */ +@@ -1072,6 +1078,48 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op) + #define RESTORE_TAIL_CALL_CNT(stack) \ + EMIT3_off32(0x48, 0x8B, 0x85, -round_up(stack, 8) - 8) + ++static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip, ++ struct bpf_prog *bpf_prog) ++{ ++ u8 *prog = *pprog; ++ u8 *func; ++ ++ if (cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP)) { ++ /* The clearing sequence clobbers eax and ecx. */ ++ EMIT1(0x50); /* push rax */ ++ EMIT1(0x51); /* push rcx */ ++ ip += 2; ++ ++ func = (u8 *)clear_bhb_loop; ++ ip += x86_call_depth_emit_accounting(&prog, func); ++ ++ if (emit_call(&prog, func, ip)) ++ return -EINVAL; ++ EMIT1(0x59); /* pop rcx */ ++ EMIT1(0x58); /* pop rax */ ++ } ++ /* Insert IBHF instruction */ ++ if ((cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP) && ++ cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) || ++ cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_HW)) { ++ /* ++ * Add an Indirect Branch History Fence (IBHF). IBHF acts as a ++ * fence preventing branch history from before the fence from ++ * affecting indirect branches after the fence. This is ++ * specifically used in cBPF jitted code to prevent Intra-mode ++ * BHI attacks. The IBHF instruction is designed to be a NOP on ++ * hardware that doesn't need or support it. The REP and REX.W ++ * prefixes are required by the microcode, and they also ensure ++ * that the NOP is unlikely to be used in existing code. ++ * ++ * IBHF is not a valid instruction in 32-bit mode. ++ */ ++ EMIT5(0xF3, 0x48, 0x0F, 0x1E, 0xF8); /* ibhf */ ++ } ++ *pprog = prog; ++ return 0; ++} ++ + static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image, + int oldproglen, struct jit_context *ctx, bool jmp_padding) + { +@@ -1945,6 +1993,15 @@ st: if (is_imm8(insn->off)) + seen_exit = true; + /* Update cleanup_addr */ + ctx->cleanup_addr = proglen; ++ ++ if (bpf_prog_was_classic(bpf_prog) && ++ !capable(CAP_SYS_ADMIN)) { ++ u8 *ip = image + addrs[i - 1]; ++ ++ if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog)) ++ return -EINVAL; ++ } ++ + pop_callee_regs(&prog, callee_regs_used); + EMIT1(0xC9); /* leave */ + emit_return(&prog, image + addrs[i - 1] + (prog - temp)); +diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c +index ef427ee787a99b..a5cfc1bfad51fb 100644 +--- a/drivers/base/cpu.c ++++ b/drivers/base/cpu.c +@@ -566,6 +566,7 @@ CPU_SHOW_VULN_FALLBACK(retbleed); + CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow); + CPU_SHOW_VULN_FALLBACK(gds); + CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling); ++CPU_SHOW_VULN_FALLBACK(indirect_target_selection); + + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); + static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); +@@ -581,6 +582,7 @@ static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); + static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL); + static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL); + static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL); ++static DEVICE_ATTR(indirect_target_selection, 0444, cpu_show_indirect_target_selection, NULL); + + static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_meltdown.attr, +@@ -597,6 +599,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_spec_rstack_overflow.attr, + &dev_attr_gather_data_sampling.attr, + &dev_attr_reg_file_data_sampling.attr, ++ &dev_attr_indirect_target_selection.attr, + NULL + }; + +diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c +index 39f7c2d736d169..b603c25f3dfaac 100644 +--- a/drivers/clocksource/i8253.c ++++ b/drivers/clocksource/i8253.c +@@ -103,7 +103,7 @@ int __init clocksource_i8253_init(void) + #ifdef CONFIG_CLKEVT_I8253 + void clockevent_i8253_disable(void) + { +- raw_spin_lock(&i8253_lock); ++ guard(raw_spinlock_irqsave)(&i8253_lock); + + /* + * Writing the MODE register should stop the counter, according to +@@ -132,8 +132,6 @@ void clockevent_i8253_disable(void) + outb_p(0, PIT_CH0); + + outb_p(0x30, PIT_MODE); +- +- raw_spin_unlock(&i8253_lock); + } + + static int pit_shutdown(struct clock_event_device *evt) +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c +index 30210613dc5c47..2f3054ed7b1b5b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c +@@ -42,7 +42,12 @@ static void hdp_v4_0_flush_hdp(struct amdgpu_device *adev, + { + if (!ring || !ring->funcs->emit_wreg) { + WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); +- RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); + } else { + amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c +index d3962d46908811..40705e13ca567b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c +@@ -33,7 +33,12 @@ static void hdp_v5_0_flush_hdp(struct amdgpu_device *adev, + { + if (!ring || !ring->funcs->emit_wreg) { + WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); +- RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); + } else { + amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c +index f52552c5fa27b6..6b9f2e1d9d690d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c +@@ -34,7 +34,17 @@ static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev, + if (!ring || !ring->funcs->emit_wreg) { + WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, + 0); +- RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ if (amdgpu_sriov_vf(adev)) { ++ /* this is fine because SR_IOV doesn't remap the register */ ++ RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ } else { ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); ++ } + } else { + amdgpu_ring_emit_wreg(ring, + (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c +index b6d71ec1debf9a..0d0c568f383931 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c +@@ -33,7 +33,12 @@ static void hdp_v6_0_flush_hdp(struct amdgpu_device *adev, + { + if (!ring || !ring->funcs->emit_wreg) { + WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); +- RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); + } else { + amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index e6bc590533194d..f6017be8f9957e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -610,15 +610,21 @@ static void dm_crtc_high_irq(void *interrupt_params) + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); + + if (acrtc->dm_irq_params.stream && +- acrtc->dm_irq_params.vrr_params.supported && +- acrtc->dm_irq_params.freesync_config.state == +- VRR_STATE_ACTIVE_VARIABLE) { ++ acrtc->dm_irq_params.vrr_params.supported) { ++ bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; ++ bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; ++ bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE; ++ + mod_freesync_handle_v_update(adev->dm.freesync_module, + acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params); + +- dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc->dm_irq_params.stream, +- &acrtc->dm_irq_params.vrr_params.adjust); ++ /* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */ ++ if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { ++ dc_stream_adjust_vmin_vmax(adev->dm.dc, ++ acrtc->dm_irq_params.stream, ++ &acrtc->dm_irq_params.vrr_params.adjust); ++ } + } + + /* +@@ -11049,7 +11055,7 @@ int amdgpu_dm_process_dmub_aux_transfer_sync( + * Transient states before tunneling is enabled could + * lead to this error. We can ignore this for now. + */ +- if (p_notify->result != AUX_RET_ERROR_PROTOCOL_ERROR) { ++ if (p_notify->result == AUX_RET_ERROR_PROTOCOL_ERROR) { + DRM_WARN("DPIA AUX failed on 0x%x(%d), error %d\n", + payload->address, payload->length, + p_notify->result); +@@ -11058,22 +11064,14 @@ int amdgpu_dm_process_dmub_aux_transfer_sync( + goto out; + } + ++ payload->reply[0] = adev->dm.dmub_notify->aux_reply.command & 0xF; ++ if (adev->dm.dmub_notify->aux_reply.command & 0xF0) ++ /* The reply is stored in the top nibble of the command. */ ++ payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF; + +- payload->reply[0] = adev->dm.dmub_notify->aux_reply.command; +- if (!payload->write && p_notify->aux_reply.length && +- (payload->reply[0] == AUX_TRANSACTION_REPLY_AUX_ACK)) { +- +- if (payload->length != p_notify->aux_reply.length) { +- DRM_WARN("invalid read length %d from DPIA AUX 0x%x(%d)!\n", +- p_notify->aux_reply.length, +- payload->address, payload->length); +- *operation_result = AUX_RET_ERROR_INVALID_REPLY; +- goto out; +- } +- ++ if (!payload->write && p_notify->aux_reply.length) + memcpy(payload->data, p_notify->aux_reply.data, + p_notify->aux_reply.length); +- } + + /* success */ + ret = p_notify->aux_reply.length; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index 5858e288b3fd66..c0cacd501c83eb 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -48,6 +48,9 @@ + + #define PEAK_FACTOR_X1000 1006 + ++/* ++ * This function handles both native AUX and I2C-Over-AUX transactions. ++ */ + static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) + { +@@ -84,15 +87,25 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + if (adev->dm.aux_hpd_discon_quirk) { + if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE && + operation_result == AUX_RET_ERROR_HPD_DISCON) { +- result = 0; ++ result = msg->size; + operation_result = AUX_RET_SUCCESS; + } + } + +- if (payload.write && result >= 0) +- result = msg->size; ++ /* ++ * result equals to 0 includes the cases of AUX_DEFER/I2C_DEFER ++ */ ++ if (payload.write && result >= 0) { ++ if (result) { ++ /*one byte indicating partially written bytes. Force 0 to retry*/ ++ drm_info(adev_to_drm(adev), "amdgpu: AUX partially written\n"); ++ result = 0; ++ } else if (!payload.reply[0]) ++ /*I2C_ACK|AUX_ACK*/ ++ result = msg->size; ++ } + +- if (result < 0) ++ if (result < 0) { + switch (operation_result) { + case AUX_RET_SUCCESS: + break; +@@ -111,6 +124,13 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + break; + } + ++ drm_info(adev_to_drm(adev), "amdgpu: DP AUX transfer fail:%d\n", operation_result); ++ } ++ ++ if (payload.reply[0]) ++ drm_info(adev_to_drm(adev), "amdgpu: AUX reply command not ACK: 0x%02x.", ++ payload.reply[0]); ++ + return result; + } + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 37fe54c34b141c..0d69098eddd90f 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -979,27 +979,28 @@ static const struct panel_desc auo_g070vvn01 = { + }, + }; + +-static const struct drm_display_mode auo_g101evn010_mode = { +- .clock = 68930, +- .hdisplay = 1280, +- .hsync_start = 1280 + 82, +- .hsync_end = 1280 + 82 + 2, +- .htotal = 1280 + 82 + 2 + 84, +- .vdisplay = 800, +- .vsync_start = 800 + 8, +- .vsync_end = 800 + 8 + 2, +- .vtotal = 800 + 8 + 2 + 6, ++static const struct display_timing auo_g101evn010_timing = { ++ .pixelclock = { 64000000, 68930000, 85000000 }, ++ .hactive = { 1280, 1280, 1280 }, ++ .hfront_porch = { 8, 64, 256 }, ++ .hback_porch = { 8, 64, 256 }, ++ .hsync_len = { 40, 168, 767 }, ++ .vactive = { 800, 800, 800 }, ++ .vfront_porch = { 4, 8, 100 }, ++ .vback_porch = { 4, 8, 100 }, ++ .vsync_len = { 8, 16, 223 }, + }; + + static const struct panel_desc auo_g101evn010 = { +- .modes = &auo_g101evn010_mode, +- .num_modes = 1, ++ .timings = &auo_g101evn010_timing, ++ .num_timings = 1, + .bpc = 6, + .size = { + .width = 216, + .height = 135, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, + }; + +diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c +index 5b729013fd26f5..41493cf3d03b81 100644 +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -289,11 +289,16 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +-/* If the current address or return address have changed, then the GPU +- * has probably made progress and we should delay the reset. This +- * could fail if the GPU got in an infinite loop in the CL, but that +- * is pretty unlikely outside of an i-g-t testcase. +- */ ++static void ++v3d_sched_skip_reset(struct drm_sched_job *sched_job) ++{ ++ struct drm_gpu_scheduler *sched = sched_job->sched; ++ ++ spin_lock(&sched->job_list_lock); ++ list_add(&sched_job->list, &sched->pending_list); ++ spin_unlock(&sched->job_list_lock); ++} ++ + static enum drm_gpu_sched_stat + v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q, + u32 *timedout_ctca, u32 *timedout_ctra) +@@ -303,9 +308,16 @@ v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q, + u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(q)); + u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(q)); + ++ /* If the current address or return address have changed, then the GPU ++ * has probably made progress and we should delay the reset. This ++ * could fail if the GPU got in an infinite loop in the CL, but that ++ * is pretty unlikely outside of an i-g-t testcase. ++ */ + if (*timedout_ctca != ctca || *timedout_ctra != ctra) { + *timedout_ctca = ctca; + *timedout_ctra = ctra; ++ ++ v3d_sched_skip_reset(sched_job); + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +@@ -345,11 +357,13 @@ v3d_csd_job_timedout(struct drm_sched_job *sched_job) + struct v3d_dev *v3d = job->base.v3d; + u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4); + +- /* If we've made progress, skip reset and let the timer get +- * rearmed. ++ /* If we've made progress, skip reset, add the job to the pending ++ * list, and let the timer get rearmed. + */ + if (job->timedout_batches != batches) { + job->timedout_batches = batches; ++ ++ v3d_sched_skip_reset(sched_job); + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c +index d054721859b3b5..99b05548b7bdbb 100644 +--- a/drivers/iio/accel/adis16201.c ++++ b/drivers/iio/accel/adis16201.c +@@ -211,9 +211,9 @@ static const struct iio_chan_spec adis16201_channels[] = { + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12), + ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X, +- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), ++ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), + ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y, +- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), ++ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), + IIO_CHAN_SOFT_TIMESTAMP(7) + }; + +diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c +index 0c9225d18fb29b..4973e8da5399d7 100644 +--- a/drivers/iio/accel/adxl355_core.c ++++ b/drivers/iio/accel/adxl355_core.c +@@ -231,7 +231,7 @@ struct adxl355_data { + u8 transf_buf[3]; + struct { + u8 buf[14]; +- s64 ts; ++ aligned_s64 ts; + } buffer; + } __aligned(IIO_DMA_MINALIGN); + }; +diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c +index 484fe2e9fb1742..3a55475691de39 100644 +--- a/drivers/iio/accel/adxl367.c ++++ b/drivers/iio/accel/adxl367.c +@@ -620,18 +620,14 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) + if (ret) + return ret; + ++ st->odr = odr; ++ + /* Activity timers depend on ODR */ + ret = _adxl367_set_act_time_ms(st, st->act_time_ms); + if (ret) + return ret; + +- ret = _adxl367_set_inact_time_ms(st, st->inact_time_ms); +- if (ret) +- return ret; +- +- st->odr = odr; +- +- return 0; ++ return _adxl367_set_inact_time_ms(st, st->inact_time_ms); + } + + static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) +diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c +index 287a0591533b6a..67c96572cecc40 100644 +--- a/drivers/iio/adc/ad7606_spi.c ++++ b/drivers/iio/adc/ad7606_spi.c +@@ -127,7 +127,7 @@ static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) + { + .tx_buf = &st->d16[0], + .len = 2, +- .cs_change = 0, ++ .cs_change = 1, + }, { + .rx_buf = &st->d16[1], + .len = 2, +diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c +index 97d162a3cba4ea..49a2588e7431ed 100644 +--- a/drivers/iio/adc/dln2-adc.c ++++ b/drivers/iio/adc/dln2-adc.c +@@ -483,7 +483,7 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p) + struct iio_dev *indio_dev = pf->indio_dev; + struct { + __le16 values[DLN2_ADC_MAX_CHANNELS]; +- int64_t timestamp_space; ++ aligned_s64 timestamp_space; + } data; + struct dln2_adc_get_all_vals dev_data; + struct dln2_adc *dln2 = iio_priv(indio_dev); +diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c +index 929cba215d99ab..7b4eb4a200df81 100644 +--- a/drivers/iio/adc/rockchip_saradc.c ++++ b/drivers/iio/adc/rockchip_saradc.c +@@ -485,15 +485,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev) + if (info->reset) + rockchip_saradc_reset_controller(info->reset); + +- /* +- * Use a default value for the converter clock. +- * This may become user-configurable in the future. +- */ +- ret = clk_set_rate(info->clk, info->data->clk_rate); +- if (ret < 0) +- return dev_err_probe(&pdev->dev, ret, +- "failed to set adc clk rate\n"); +- + ret = regulator_enable(info->vref); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, +@@ -520,6 +511,14 @@ static int rockchip_saradc_probe(struct platform_device *pdev) + if (IS_ERR(info->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), + "failed to get adc clock\n"); ++ /* ++ * Use a default value for the converter clock. ++ * This may become user-configurable in the future. ++ */ ++ ret = clk_set_rate(info->clk, info->data->clk_rate); ++ if (ret < 0) ++ return dev_err_probe(&pdev->dev, ret, ++ "failed to set adc clk rate\n"); + + platform_set_drvdata(pdev, indio_dev); + +diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +index 066fe561c5e88d..b8119fa4768eb8 100644 +--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c ++++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +@@ -370,6 +370,9 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) + if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK)) + return 0; + ++ if (!pattern_len) ++ pattern_len = ST_LSM6DSX_SAMPLE_SIZE; ++ + fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) * + ST_LSM6DSX_CHAN_SIZE; + fifo_len = (fifo_len / pattern_len) * pattern_len; +@@ -601,6 +604,9 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) + if (!fifo_len) + return 0; + ++ if (!pattern_len) ++ pattern_len = ST_LSM6DSX_TAGGED_SAMPLE_SIZE; ++ + for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { + err = st_lsm6dsx_read_block(hw, + ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR, +diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c +index c28a7a6dea5f12..555a61e2f3fdd1 100644 +--- a/drivers/iio/temperature/maxim_thermocouple.c ++++ b/drivers/iio/temperature/maxim_thermocouple.c +@@ -121,9 +121,9 @@ static const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = { + struct maxim_thermocouple_data { + struct spi_device *spi; + const struct maxim_thermocouple_chip *chip; ++ char tc_type; + + u8 buffer[16] __aligned(IIO_DMA_MINALIGN); +- char tc_type; + }; + + static int maxim_thermocouple_read(struct maxim_thermocouple_data *data, +diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c +index b91467c8e6c402..c65321964131cf 100644 +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -77,12 +77,13 @@ + * xbox d-pads should map to buttons, as is required for DDR pads + * but we map them to axes when possible to simplify things + */ +-#define MAP_DPAD_TO_BUTTONS (1 << 0) +-#define MAP_TRIGGERS_TO_BUTTONS (1 << 1) +-#define MAP_STICKS_TO_NULL (1 << 2) +-#define MAP_SELECT_BUTTON (1 << 3) +-#define MAP_PADDLES (1 << 4) +-#define MAP_PROFILE_BUTTON (1 << 5) ++#define MAP_DPAD_TO_BUTTONS BIT(0) ++#define MAP_TRIGGERS_TO_BUTTONS BIT(1) ++#define MAP_STICKS_TO_NULL BIT(2) ++#define MAP_SHARE_BUTTON BIT(3) ++#define MAP_PADDLES BIT(4) ++#define MAP_PROFILE_BUTTON BIT(5) ++#define MAP_SHARE_OFFSET BIT(6) + + #define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \ + MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL) +@@ -135,7 +136,7 @@ static const struct xpad_device { + { 0x03f0, 0x048D, "HyperX Clutch", 0, XTYPE_XBOX360 }, /* wireless */ + { 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, + { 0x03f0, 0x07A0, "HyperX Clutch Gladiate RGB", 0, XTYPE_XBOXONE }, +- { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, /* v2 */ ++ { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, /* v2 */ + { 0x03f0, 0x09B4, "HyperX Clutch Tanto", 0, XTYPE_XBOXONE }, + { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, + { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, +@@ -159,7 +160,7 @@ static const struct xpad_device { + { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, + { 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE }, + { 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE }, +- { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, ++ { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SHARE_BUTTON | MAP_SHARE_OFFSET, XTYPE_XBOXONE }, + { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, + { 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 }, + { 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 }, +@@ -205,13 +206,13 @@ static const struct xpad_device { + { 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 }, + { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 }, + { 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, +- { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, ++ { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", 0, XTYPE_XBOX360 }, + { 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, + { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, + { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 }, + { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, + { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 }, +- { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", 0, XTYPE_XBOXONE }, ++ { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x0b05, 0x1abb, "ASUS ROG RAIKIRI PRO", 0, XTYPE_XBOXONE }, + { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX }, + { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX }, +@@ -240,7 +241,7 @@ static const struct xpad_device { + { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, +- { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", XTYPE_XBOXONE }, ++ { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, +@@ -386,10 +387,11 @@ static const struct xpad_device { + { 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 }, ++ { 0x2dc8, 0x310b, "8BitDo Ultimate 2 Wireless Controller", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x6001, "8BitDo SN30 Pro", 0, XTYPE_XBOX360 }, + { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, + { 0x2e24, 0x1688, "Hyperkin X91 X-Box One pad", 0, XTYPE_XBOXONE }, +- { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, ++ { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, +@@ -1025,7 +1027,7 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha + * The report format was gleaned from + * https://github.com/kylelemons/xbox/blob/master/xbox.go + */ +-static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) ++static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, u32 len) + { + struct input_dev *dev = xpad->dev; + bool do_sync = false; +@@ -1066,8 +1068,12 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char + /* menu/view buttons */ + input_report_key(dev, BTN_START, data[4] & BIT(2)); + input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); +- if (xpad->mapping & MAP_SELECT_BUTTON) +- input_report_key(dev, KEY_RECORD, data[22] & BIT(0)); ++ if (xpad->mapping & MAP_SHARE_BUTTON) { ++ if (xpad->mapping & MAP_SHARE_OFFSET) ++ input_report_key(dev, KEY_RECORD, data[len - 26] & BIT(0)); ++ else ++ input_report_key(dev, KEY_RECORD, data[len - 18] & BIT(0)); ++ } + + /* buttons A,B,X,Y */ + input_report_key(dev, BTN_A, data[4] & BIT(4)); +@@ -1215,7 +1221,7 @@ static void xpad_irq_in(struct urb *urb) + xpad360w_process_packet(xpad, 0, xpad->idata); + break; + case XTYPE_XBOXONE: +- xpadone_process_packet(xpad, 0, xpad->idata); ++ xpadone_process_packet(xpad, 0, xpad->idata, urb->actual_length); + break; + default: + xpad_process_packet(xpad, 0, xpad->idata); +@@ -1972,7 +1978,7 @@ static int xpad_init_input(struct usb_xpad *xpad) + xpad->xtype == XTYPE_XBOXONE) { + for (i = 0; xpad360_btn[i] >= 0; i++) + input_set_capability(input_dev, EV_KEY, xpad360_btn[i]); +- if (xpad->mapping & MAP_SELECT_BUTTON) ++ if (xpad->mapping & MAP_SHARE_BUTTON) + input_set_capability(input_dev, EV_KEY, KEY_RECORD); + } else { + for (i = 0; xpad_btn[i] >= 0; i++) +diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c +index 4364c3401ff1c6..486ca8ff86f830 100644 +--- a/drivers/input/keyboard/mtk-pmic-keys.c ++++ b/drivers/input/keyboard/mtk-pmic-keys.c +@@ -147,8 +147,8 @@ static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys, + u32 value, mask; + int error; + +- kregs_home = keys->keys[MTK_PMIC_HOMEKEY_INDEX].regs; +- kregs_pwr = keys->keys[MTK_PMIC_PWRKEY_INDEX].regs; ++ kregs_home = ®s->keys_regs[MTK_PMIC_HOMEKEY_INDEX]; ++ kregs_pwr = ®s->keys_regs[MTK_PMIC_PWRKEY_INDEX]; + + error = of_property_read_u32(keys->dev->of_node, "power-off-time-sec", + &long_press_debounce); +diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c +index 26677432ac8361..3ca6642601c7d5 100644 +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -163,6 +163,7 @@ static const char * const topbuttonpad_pnp_ids[] = { + + static const char * const smbus_pnp_ids[] = { + /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ ++ "DLL060d", /* Dell Precision M3800 */ + "LEN0048", /* X1 Carbon 3 */ + "LEN0046", /* X250 */ + "LEN0049", /* Yoga 11e */ +@@ -189,11 +190,15 @@ static const char * const smbus_pnp_ids[] = { + "LEN2054", /* E480 */ + "LEN2055", /* E580 */ + "LEN2068", /* T14 Gen 1 */ ++ "SYN1221", /* TUXEDO InfinityBook Pro 14 v5 */ ++ "SYN3003", /* HP EliteBook 850 G1 */ + "SYN3015", /* HP EliteBook 840 G2 */ + "SYN3052", /* HP EliteBook 840 G4 */ + "SYN3221", /* HP 15-ay000 */ + "SYN323d", /* HP Spectre X360 13-w013dx */ + "SYN3257", /* HP Envy 13-ad105ng */ ++ "TOS01f6", /* Dynabook Portege X30L-G */ ++ "TOS0213", /* Dynabook Portege X30-D */ + NULL + }; + +diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c +index db5a885ecd7285..a74b34d8df2a22 100644 +--- a/drivers/input/touchscreen/cyttsp5.c ++++ b/drivers/input/touchscreen/cyttsp5.c +@@ -580,7 +580,7 @@ static int cyttsp5_power_control(struct cyttsp5 *ts, bool on) + int rc; + + SET_CMD_REPORT_TYPE(cmd[0], 0); +- SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP); ++ SET_CMD_REPORT_ID(cmd[0], state); + SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER); + + rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd)); +@@ -865,13 +865,16 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq, + ts->input->phys = ts->phys; + input_set_drvdata(ts->input, ts); + +- /* Reset the gpio to be in a reset state */ ++ /* Assert gpio to be in a reset state */ + ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(dev, "Failed to request reset gpio, error %d\n", error); + return error; + } ++ ++ fsleep(10); /* Ensure long-enough reset pulse (minimum 10us). */ ++ + gpiod_set_value_cansleep(ts->reset_gpio, 0); + + /* Need a delay to have device up */ +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 319bd10548e9ad..7a33da2dd64b12 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -1242,7 +1242,7 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile, + + t = dm_get_live_table(md, &srcu_idx); + if (!t) +- return 0; ++ goto put_live_table; + + for (unsigned int i = 0; i < t->num_targets; i++) { + struct dm_target *ti = dm_table_get_target(t, i); +@@ -1253,6 +1253,7 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile, + (void *)key); + } + ++put_live_table: + dm_put_live_table(md, srcu_idx); + return 0; + } +diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c +index 2a258986eed02b..ba7f7de25c8529 100644 +--- a/drivers/net/can/m_can/m_can.c ++++ b/drivers/net/can/m_can/m_can.c +@@ -2125,9 +2125,9 @@ EXPORT_SYMBOL_GPL(m_can_class_register); + + void m_can_class_unregister(struct m_can_classdev *cdev) + { ++ unregister_candev(cdev->net); + if (cdev->is_peripheral) + can_rx_offload_del(&cdev->offload); +- unregister_candev(cdev->net); + } + EXPORT_SYMBOL_GPL(m_can_class_unregister); + +diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +index 6fecfe4cd08041..21ae3a89924e97 100644 +--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c ++++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +@@ -75,6 +75,24 @@ static const struct can_bittiming_const mcp251xfd_data_bittiming_const = { + .brp_inc = 1, + }; + ++/* The datasheet of the mcp2518fd (DS20006027B) specifies a range of ++ * [-64,63] for TDCO, indicating a relative TDCO. ++ * ++ * Manual tests have shown, that using a relative TDCO configuration ++ * results in bus off, while an absolute configuration works. ++ * ++ * For TDCO use the max value (63) from the data sheet, but 0 as the ++ * minimum. ++ */ ++static const struct can_tdc_const mcp251xfd_tdc_const = { ++ .tdcv_min = 0, ++ .tdcv_max = 63, ++ .tdco_min = 0, ++ .tdco_max = 63, ++ .tdcf_min = 0, ++ .tdcf_max = 0, ++}; ++ + static const char *__mcp251xfd_get_model_str(enum mcp251xfd_model model) + { + switch (model) { +@@ -510,8 +528,7 @@ static int mcp251xfd_set_bittiming(const struct mcp251xfd_priv *priv) + { + const struct can_bittiming *bt = &priv->can.bittiming; + const struct can_bittiming *dbt = &priv->can.data_bittiming; +- u32 val = 0; +- s8 tdco; ++ u32 tdcmod, val = 0; + int err; + + /* CAN Control Register +@@ -575,11 +592,16 @@ static int mcp251xfd_set_bittiming(const struct mcp251xfd_priv *priv) + return err; + + /* Transmitter Delay Compensation */ +- tdco = clamp_t(int, dbt->brp * (dbt->prop_seg + dbt->phase_seg1), +- -64, 63); +- val = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, +- MCP251XFD_REG_TDC_TDCMOD_AUTO) | +- FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, tdco); ++ if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_AUTO) ++ tdcmod = MCP251XFD_REG_TDC_TDCMOD_AUTO; ++ else if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_MANUAL) ++ tdcmod = MCP251XFD_REG_TDC_TDCMOD_MANUAL; ++ else ++ tdcmod = MCP251XFD_REG_TDC_TDCMOD_DISABLED; ++ ++ val = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, tdcmod) | ++ FIELD_PREP(MCP251XFD_REG_TDC_TDCV_MASK, priv->can.tdc.tdcv) | ++ FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, priv->can.tdc.tdco); + + return regmap_write(priv->map_reg, MCP251XFD_REG_TDC, val); + } +@@ -2083,10 +2105,12 @@ static int mcp251xfd_probe(struct spi_device *spi) + priv->can.do_get_berr_counter = mcp251xfd_get_berr_counter; + priv->can.bittiming_const = &mcp251xfd_bittiming_const; + priv->can.data_bittiming_const = &mcp251xfd_data_bittiming_const; ++ priv->can.tdc_const = &mcp251xfd_tdc_const; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO | +- CAN_CTRLMODE_CC_LEN8_DLC; ++ CAN_CTRLMODE_CC_LEN8_DLC | CAN_CTRLMODE_TDC_AUTO | ++ CAN_CTRLMODE_TDC_MANUAL; + set_bit(MCP251XFD_FLAGS_DOWN, priv->flags); + priv->ndev = ndev; + priv->spi = spi; +@@ -2179,8 +2203,8 @@ static void mcp251xfd_remove(struct spi_device *spi) + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); + struct net_device *ndev = priv->ndev; + +- can_rx_offload_del(&priv->offload); + mcp251xfd_unregister(priv); ++ can_rx_offload_del(&priv->offload); + spi->max_speed_hz = priv->spi_max_speed_hz_orig; + free_candev(ndev); + } +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index cfcda893f1a16d..d2ff2c2fcbbfc4 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -373,15 +373,17 @@ static void b53_enable_vlan(struct b53_device *dev, int port, bool enable, + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); + } + ++ vc1 &= ~VC1_RX_MCST_FWD_EN; ++ + if (enable) { + vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; +- vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; ++ vc1 |= VC1_RX_MCST_UNTAG_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + if (enable_filtering) { + vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; + vc5 |= VC5_DROP_VTABLE_MISS; + } else { +- vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; ++ vc4 |= VC4_NO_ING_VID_CHK << VC4_ING_VID_CHECK_S; + vc5 &= ~VC5_DROP_VTABLE_MISS; + } + +@@ -393,7 +395,7 @@ static void b53_enable_vlan(struct b53_device *dev, int port, bool enable, + + } else { + vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); +- vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); ++ vc1 &= ~VC1_RX_MCST_UNTAG_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc5 &= ~VC5_DROP_VTABLE_MISS; + +@@ -1519,12 +1521,21 @@ int b53_vlan_add(struct dsa_switch *ds, int port, + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + struct b53_vlan *vl; ++ u16 old_pvid, new_pvid; + int err; + + err = b53_vlan_prepare(ds, port, vlan); + if (err) + return err; + ++ b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &old_pvid); ++ if (pvid) ++ new_pvid = vlan->vid; ++ else if (!pvid && vlan->vid == old_pvid) ++ new_pvid = b53_default_pvid(dev); ++ else ++ new_pvid = old_pvid; ++ + vl = &dev->vlans[vlan->vid]; + + b53_get_vlan_entry(dev, vlan->vid, vl); +@@ -1541,10 +1552,10 @@ int b53_vlan_add(struct dsa_switch *ds, int port, + b53_set_vlan_entry(dev, vlan->vid, vl); + b53_fast_age_vlan(dev, vlan->vid); + +- if (pvid && !dsa_is_cpu_port(ds, port)) { ++ if (!dsa_is_cpu_port(ds, port) && new_pvid != old_pvid) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), +- vlan->vid); +- b53_fast_age_vlan(dev, vlan->vid); ++ new_pvid); ++ b53_fast_age_vlan(dev, old_pvid); + } + + return 0; +@@ -1956,7 +1967,7 @@ EXPORT_SYMBOL(b53_br_join); + void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) + { + struct b53_device *dev = ds->priv; +- struct b53_vlan *vl = &dev->vlans[0]; ++ struct b53_vlan *vl; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; + unsigned int i; + u16 pvlan, reg, pvid; +@@ -1982,6 +1993,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) + dev->ports[port].vlan_ctl_mask = pvlan; + + pvid = b53_default_pvid(dev); ++ vl = &dev->vlans[pvid]; + + /* Make this port join all VLANs without VLAN entries */ + if (is58xx(dev)) { +@@ -1990,12 +2002,12 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) + if (!(reg & BIT(cpu_port))) + reg |= BIT(cpu_port); + b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, reg); +- } else { +- b53_get_vlan_entry(dev, pvid, vl); +- vl->members |= BIT(port) | BIT(cpu_port); +- vl->untag |= BIT(port) | BIT(cpu_port); +- b53_set_vlan_entry(dev, pvid, vl); + } ++ ++ b53_get_vlan_entry(dev, pvid, vl); ++ vl->members |= BIT(port) | BIT(cpu_port); ++ vl->untag |= BIT(port) | BIT(cpu_port); ++ b53_set_vlan_entry(dev, pvid, vl); + } + EXPORT_SYMBOL(b53_br_leave); + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index d2ec8f642c2fa0..c6ccfbd4226570 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3117,11 +3117,19 @@ static int mtk_dma_init(struct mtk_eth *eth) + static void mtk_dma_free(struct mtk_eth *eth) + { + const struct mtk_soc_data *soc = eth->soc; +- int i; ++ int i, j, txqs = 1; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) ++ txqs = MTK_QDMA_NUM_QUEUES; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ ++ for (j = 0; j < txqs; j++) ++ netdev_tx_reset_subqueue(eth->netdev[i], j); ++ } + +- for (i = 0; i < MTK_MAX_DEVS; i++) +- if (eth->netdev[i]) +- netdev_reset_queue(eth->netdev[i]); + if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) { + dma_free_coherent(eth->dma_dev, + MTK_QDMA_RING_SIZE * soc->txrx.txd_size, +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index c6b0637e61debd..6e2d0fda3ba4aa 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -4156,7 +4156,8 @@ static void nvme_fw_act_work(struct work_struct *work) + msleep(100); + } + +- if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) ++ if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING) || ++ !nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) + return; + + nvme_unquiesce_io_queues(ctrl); +diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c +index 727b956aa23172..f667b3b62f1883 100644 +--- a/drivers/staging/axis-fifo/axis-fifo.c ++++ b/drivers/staging/axis-fifo/axis-fifo.c +@@ -398,16 +398,14 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, + + bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET); + if (!bytes_available) { +- dev_err(fifo->dt_device, "received a packet of length 0 - fifo core will be reset\n"); +- reset_ip_core(fifo); ++ dev_err(fifo->dt_device, "received a packet of length 0\n"); + ret = -EIO; + goto end_unlock; + } + + if (bytes_available > len) { +- dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu) - fifo core will be reset\n", ++ dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n", + bytes_available, len); +- reset_ip_core(fifo); + ret = -EINVAL; + goto end_unlock; + } +@@ -416,8 +414,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, + /* this probably can't happen unless IP + * registers were previously mishandled + */ +- dev_err(fifo->dt_device, "received a packet that isn't word-aligned - fifo core will be reset\n"); +- reset_ip_core(fifo); ++ dev_err(fifo->dt_device, "received a packet that isn't word-aligned\n"); + ret = -EIO; + goto end_unlock; + } +@@ -438,7 +435,6 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, + + if (copy_to_user(buf + copied * sizeof(u32), tmp_buf, + copy * sizeof(u32))) { +- reset_ip_core(fifo); + ret = -EFAULT; + goto end_unlock; + } +@@ -547,7 +543,6 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf, + + if (copy_from_user(tmp_buf, buf + copied * sizeof(u32), + copy * sizeof(u32))) { +- reset_ip_core(fifo); + ret = -EFAULT; + goto end_unlock; + } +@@ -780,9 +775,6 @@ static int axis_fifo_parse_dt(struct axis_fifo *fifo) + goto end; + } + +- /* IP sets TDFV to fifo depth - 4 so we will do the same */ +- fifo->tx_fifo_depth -= 4; +- + ret = get_dts_property(fifo, "xlnx,use-rx-data", &fifo->has_rx_fifo); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,use-rx-data property\n"); +diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c +index 6c14d7bcdd6750..081b17f498638b 100644 +--- a/drivers/staging/iio/adc/ad7816.c ++++ b/drivers/staging/iio/adc/ad7816.c +@@ -136,7 +136,7 @@ static ssize_t ad7816_store_mode(struct device *dev, + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7816_chip_info *chip = iio_priv(indio_dev); + +- if (strcmp(buf, "full")) { ++ if (strcmp(buf, "full") == 0) { + gpiod_set_value(chip->rdwr_pin, 1); + chip->mode = AD7816_FULL; + } else { +diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c +index 4b67749edb9974..601a60a2802240 100644 +--- a/drivers/usb/cdns3/cdnsp-gadget.c ++++ b/drivers/usb/cdns3/cdnsp-gadget.c +@@ -138,6 +138,26 @@ static void cdnsp_clear_port_change_bit(struct cdnsp_device *pdev, + (portsc & PORT_CHANGE_BITS), port_regs); + } + ++static void cdnsp_set_apb_timeout_value(struct cdnsp_device *pdev) ++{ ++ struct cdns *cdns = dev_get_drvdata(pdev->dev); ++ __le32 __iomem *reg; ++ void __iomem *base; ++ u32 offset = 0; ++ u32 val; ++ ++ if (!cdns->override_apb_timeout) ++ return; ++ ++ base = &pdev->cap_regs->hc_capbase; ++ offset = cdnsp_find_next_ext_cap(base, offset, D_XEC_PRE_REGS_CAP); ++ reg = base + offset + REG_CHICKEN_BITS_3_OFFSET; ++ ++ val = le32_to_cpu(readl(reg)); ++ val = CHICKEN_APB_TIMEOUT_SET(val, cdns->override_apb_timeout); ++ writel(cpu_to_le32(val), reg); ++} ++ + static void cdnsp_set_chicken_bits_2(struct cdnsp_device *pdev, u32 bit) + { + __le32 __iomem *reg; +@@ -1776,6 +1796,8 @@ static void cdnsp_get_rev_cap(struct cdnsp_device *pdev) + reg += cdnsp_find_next_ext_cap(reg, 0, RTL_REV_CAP); + pdev->rev_cap = reg; + ++ pdev->rtl_revision = readl(&pdev->rev_cap->rtl_revision); ++ + dev_info(pdev->dev, "Rev: %08x/%08x, eps: %08x, buff: %08x/%08x\n", + readl(&pdev->rev_cap->ctrl_revision), + readl(&pdev->rev_cap->rtl_revision), +@@ -1801,6 +1823,15 @@ static int cdnsp_gen_setup(struct cdnsp_device *pdev) + pdev->hci_version = HC_VERSION(pdev->hcc_params); + pdev->hcc_params = readl(&pdev->cap_regs->hcc_params); + ++ /* ++ * Override the APB timeout value to give the controller more time for ++ * enabling UTMI clock and synchronizing APB and UTMI clock domains. ++ * This fix is platform specific and is required to fixes issue with ++ * reading incorrect value from PORTSC register after resuming ++ * from L1 state. ++ */ ++ cdnsp_set_apb_timeout_value(pdev); ++ + cdnsp_get_rev_cap(pdev); + + /* Make sure the Device Controller is halted. */ +diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h +index 9a5577a772af62..ed84dbb9fd6fbc 100644 +--- a/drivers/usb/cdns3/cdnsp-gadget.h ++++ b/drivers/usb/cdns3/cdnsp-gadget.h +@@ -520,6 +520,9 @@ struct cdnsp_rev_cap { + #define REG_CHICKEN_BITS_2_OFFSET 0x48 + #define CHICKEN_XDMA_2_TP_CACHE_DIS BIT(28) + ++#define REG_CHICKEN_BITS_3_OFFSET 0x4C ++#define CHICKEN_APB_TIMEOUT_SET(p, val) (((p) & ~GENMASK(21, 0)) | (val)) ++ + /* XBUF Extended Capability ID. */ + #define XBUF_CAP_ID 0xCB + #define XBUF_RX_TAG_MASK_0_OFFSET 0x1C +@@ -1359,6 +1362,7 @@ struct cdnsp_port { + * @rev_cap: Controller Capabilities Registers. + * @hcs_params1: Cached register copies of read-only HCSPARAMS1 + * @hcc_params: Cached register copies of read-only HCCPARAMS1 ++ * @rtl_revision: Cached controller rtl revision. + * @setup: Temporary buffer for setup packet. + * @ep0_preq: Internal allocated request used during enumeration. + * @ep0_stage: ep0 stage during enumeration process. +@@ -1413,6 +1417,8 @@ struct cdnsp_device { + __u32 hcs_params1; + __u32 hcs_params3; + __u32 hcc_params; ++ #define RTL_REVISION_NEW_LPM 0x2700 ++ __u32 rtl_revision; + /* Lock used in interrupt thread context. */ + spinlock_t lock; + struct usb_ctrlrequest setup; +diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c +index 0725668ffea4c8..159c2eae26608c 100644 +--- a/drivers/usb/cdns3/cdnsp-pci.c ++++ b/drivers/usb/cdns3/cdnsp-pci.c +@@ -33,6 +33,8 @@ + #define CDNS_DRD_ID 0x0100 + #define CDNS_DRD_IF (PCI_CLASS_SERIAL_USB << 8 | 0x80) + ++#define CHICKEN_APB_TIMEOUT_VALUE 0x1C20 ++ + static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev) + { + /* +@@ -144,6 +146,14 @@ static int cdnsp_pci_probe(struct pci_dev *pdev, + cdnsp->otg_irq = pdev->irq; + } + ++ /* ++ * Cadence PCI based platform require some longer timeout for APB ++ * to fixes domain clock synchronization issue after resuming ++ * controller from L1 state. ++ */ ++ cdnsp->override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE; ++ pci_set_drvdata(pdev, cdnsp); ++ + if (pci_is_enabled(func)) { + cdnsp->dev = dev; + cdnsp->gadget_init = cdnsp_gadget_init; +@@ -153,8 +163,6 @@ static int cdnsp_pci_probe(struct pci_dev *pdev, + goto free_cdnsp; + } + +- pci_set_drvdata(pdev, cdnsp); +- + device_wakeup_enable(&pdev->dev); + if (pci_dev_run_wake(pdev)) + pm_runtime_put_noidle(&pdev->dev); +diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c +index 1d18d5002ef01d..080a3f17a35dd7 100644 +--- a/drivers/usb/cdns3/cdnsp-ring.c ++++ b/drivers/usb/cdns3/cdnsp-ring.c +@@ -308,7 +308,8 @@ static bool cdnsp_ring_ep_doorbell(struct cdnsp_device *pdev, + + writel(db_value, reg_addr); + +- cdnsp_force_l0_go(pdev); ++ if (pdev->rtl_revision < RTL_REVISION_NEW_LPM) ++ cdnsp_force_l0_go(pdev); + + /* Doorbell was set. */ + return true; +diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h +index 57d47348dc193b..ac30ee21309d02 100644 +--- a/drivers/usb/cdns3/core.h ++++ b/drivers/usb/cdns3/core.h +@@ -79,6 +79,8 @@ struct cdns3_platform_data { + * @pdata: platform data from glue layer + * @lock: spinlock structure + * @xhci_plat_data: xhci private data structure pointer ++ * @override_apb_timeout: hold value of APB timeout. For value 0 the default ++ * value in CHICKEN_BITS_3 will be preserved. + * @gadget_init: pointer to gadget initialization function + */ + struct cdns { +@@ -117,6 +119,7 @@ struct cdns { + struct cdns3_platform_data *pdata; + spinlock_t lock; + struct xhci_plat_priv *xhci_plat_data; ++ u32 override_apb_timeout; + + int (*gadget_init)(struct cdns *cdns); + }; +diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c +index c2e666e82857c1..2f92905e05cad0 100644 +--- a/drivers/usb/class/usbtmc.c ++++ b/drivers/usb/class/usbtmc.c +@@ -482,6 +482,7 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) + u8 *buffer; + u8 tag; + int rv; ++ long wait_rv; + + dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", + data->iin_ep_present); +@@ -511,16 +512,17 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) + } + + if (data->iin_ep_present) { +- rv = wait_event_interruptible_timeout( ++ wait_rv = wait_event_interruptible_timeout( + data->waitq, + atomic_read(&data->iin_data_valid) != 0, + file_data->timeout); +- if (rv < 0) { +- dev_dbg(dev, "wait interrupted %d\n", rv); ++ if (wait_rv < 0) { ++ dev_dbg(dev, "wait interrupted %ld\n", wait_rv); ++ rv = wait_rv; + goto exit; + } + +- if (rv == 0) { ++ if (wait_rv == 0) { + dev_dbg(dev, "wait timed out\n"); + rv = -ETIMEDOUT; + goto exit; +@@ -539,6 +541,8 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) + + dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)*stb, rv); + ++ rv = 0; ++ + exit: + /* bump interrupt bTag */ + data->iin_bTag += 1; +@@ -602,9 +606,9 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, + { + struct usbtmc_device_data *data = file_data->data; + struct device *dev = &data->intf->dev; +- int rv; + u32 timeout; + unsigned long expire; ++ long wait_rv; + + if (!data->iin_ep_present) { + dev_dbg(dev, "no interrupt endpoint present\n"); +@@ -618,25 +622,24 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, + + mutex_unlock(&data->io_mutex); + +- rv = wait_event_interruptible_timeout( +- data->waitq, +- atomic_read(&file_data->srq_asserted) != 0 || +- atomic_read(&file_data->closing), +- expire); ++ wait_rv = wait_event_interruptible_timeout( ++ data->waitq, ++ atomic_read(&file_data->srq_asserted) != 0 || ++ atomic_read(&file_data->closing), ++ expire); + + mutex_lock(&data->io_mutex); + + /* Note! disconnect or close could be called in the meantime */ + if (atomic_read(&file_data->closing) || data->zombie) +- rv = -ENODEV; ++ return -ENODEV; + +- if (rv < 0) { +- /* dev can be invalid now! */ +- pr_debug("%s - wait interrupted %d\n", __func__, rv); +- return rv; ++ if (wait_rv < 0) { ++ dev_dbg(dev, "%s - wait interrupted %ld\n", __func__, wait_rv); ++ return wait_rv; + } + +- if (rv == 0) { ++ if (wait_rv == 0) { + dev_dbg(dev, "%s - wait timed out\n", __func__); + return -ETIMEDOUT; + } +@@ -830,6 +833,7 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, + unsigned long expire; + int bufcount = 1; + int again = 0; ++ long wait_rv; + + /* mutex already locked */ + +@@ -942,19 +946,24 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, + if (!(flags & USBTMC_FLAG_ASYNC)) { + dev_dbg(dev, "%s: before wait time %lu\n", + __func__, expire); +- retval = wait_event_interruptible_timeout( ++ wait_rv = wait_event_interruptible_timeout( + file_data->wait_bulk_in, + usbtmc_do_transfer(file_data), + expire); + +- dev_dbg(dev, "%s: wait returned %d\n", +- __func__, retval); ++ dev_dbg(dev, "%s: wait returned %ld\n", ++ __func__, wait_rv); ++ ++ if (wait_rv < 0) { ++ retval = wait_rv; ++ goto error; ++ } + +- if (retval <= 0) { +- if (retval == 0) +- retval = -ETIMEDOUT; ++ if (wait_rv == 0) { ++ retval = -ETIMEDOUT; + goto error; + } ++ + } + + urb = usb_get_from_anchor(&file_data->in_anchor); +@@ -1380,7 +1389,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, + if (!buffer) + return -ENOMEM; + +- mutex_lock(&data->io_mutex); ++ retval = mutex_lock_interruptible(&data->io_mutex); ++ if (retval < 0) ++ goto exit_nolock; ++ + if (data->zombie) { + retval = -ENODEV; + goto exit; +@@ -1503,6 +1515,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, + + exit: + mutex_unlock(&data->io_mutex); ++exit_nolock: + kfree(buffer); + return retval; + } +diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c +index 69ce7d384ba8bb..4f326988be867c 100644 +--- a/drivers/usb/gadget/composite.c ++++ b/drivers/usb/gadget/composite.c +@@ -2011,15 +2011,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + + if (f->get_status) { + status = f->get_status(f); ++ + if (status < 0) + break; +- } else { +- /* Set D0 and D1 bits based on func wakeup capability */ +- if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { +- status |= USB_INTRF_STAT_FUNC_RW_CAP; +- if (f->func_wakeup_armed) +- status |= USB_INTRF_STAT_FUNC_RW; +- } ++ ++ /* if D5 is not set, then device is not wakeup capable */ ++ if (!(f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP)) ++ status &= ~(USB_INTRF_STAT_FUNC_RW_CAP | USB_INTRF_STAT_FUNC_RW); + } + + put_unaligned_le16(status & 0x0000ffff, req->buf); +diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c +index f55f60639e4251..2afc30de54ce2d 100644 +--- a/drivers/usb/gadget/function/f_ecm.c ++++ b/drivers/usb/gadget/function/f_ecm.c +@@ -892,6 +892,12 @@ static void ecm_resume(struct usb_function *f) + gether_resume(&ecm->port); + } + ++static int ecm_get_status(struct usb_function *f) ++{ ++ return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) | ++ USB_INTRF_STAT_FUNC_RW_CAP; ++} ++ + static void ecm_free(struct usb_function *f) + { + struct f_ecm *ecm; +@@ -960,6 +966,7 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) + ecm->port.func.disable = ecm_disable; + ecm->port.func.free_func = ecm_free; + ecm->port.func.suspend = ecm_suspend; ++ ecm->port.func.get_status = ecm_get_status; + ecm->port.func.resume = ecm_resume; + + return &ecm->port.func; +diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c +index 7aa46d426f31b2..9bb54da8a6ae15 100644 +--- a/drivers/usb/gadget/udc/tegra-xudc.c ++++ b/drivers/usb/gadget/udc/tegra-xudc.c +@@ -1749,6 +1749,10 @@ static int __tegra_xudc_ep_disable(struct tegra_xudc_ep *ep) + val = xudc_readl(xudc, CTRL); + val &= ~CTRL_RUN; + xudc_writel(xudc, val, CTRL); ++ ++ val = xudc_readl(xudc, ST); ++ if (val & ST_RC) ++ xudc_writel(xudc, ST_RC, ST); + } + + dev_info(xudc->dev, "ep %u disabled\n", ep->index); +diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c +index 3dec5dd3a0d5ca..712389599d468c 100644 +--- a/drivers/usb/host/uhci-platform.c ++++ b/drivers/usb/host/uhci-platform.c +@@ -121,7 +121,7 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) + } + + /* Get and enable clock if any specified */ +- uhci->clk = devm_clk_get(&pdev->dev, NULL); ++ uhci->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(uhci->clk)) { + ret = PTR_ERR(uhci->clk); + goto err_rmr; +diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c +index 76f228e7443cb6..89b3079194d7b3 100644 +--- a/drivers/usb/host/xhci-tegra.c ++++ b/drivers/usb/host/xhci-tegra.c +@@ -1363,6 +1363,7 @@ static void tegra_xhci_id_work(struct work_struct *work) + tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(tegra->padctl, + tegra->otg_usb2_port); + ++ pm_runtime_get_sync(tegra->dev); + if (tegra->host_mode) { + /* switch to host mode */ + if (tegra->otg_usb3_port >= 0) { +@@ -1392,6 +1393,7 @@ static void tegra_xhci_id_work(struct work_struct *work) + } + + tegra_xhci_set_port_power(tegra, true, true); ++ pm_runtime_mark_last_busy(tegra->dev); + + } else { + if (tegra->otg_usb3_port >= 0) +@@ -1399,6 +1401,7 @@ static void tegra_xhci_id_work(struct work_struct *work) + + tegra_xhci_set_port_power(tegra, true, false); + } ++ pm_runtime_put_autosuspend(tegra->dev); + } + + #if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_PM_SLEEP) +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 790aadab72a31b..bfcbccb400c3a8 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -5102,7 +5102,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, + case SNK_TRY_WAIT_DEBOUNCE: + if (!tcpm_port_is_sink(port)) { + port->max_wait = 0; +- tcpm_set_state(port, SRC_TRYWAIT, 0); ++ tcpm_set_state(port, SRC_TRYWAIT, PD_T_PD_DEBOUNCE); + } + break; + case SRC_TRY_WAIT: +diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c +index 2431febc461516..8c19081c325542 100644 +--- a/drivers/usb/typec/ucsi/displayport.c ++++ b/drivers/usb/typec/ucsi/displayport.c +@@ -296,6 +296,8 @@ void ucsi_displayport_remove_partner(struct typec_altmode *alt) + if (!dp) + return; + ++ cancel_work_sync(&dp->work); ++ + dp->data.conf = 0; + dp->data.status = 0; + dp->initialized = false; +diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c +index 0b3bd9a7575e5f..5770f3b374ece3 100644 +--- a/drivers/xen/swiotlb-xen.c ++++ b/drivers/xen/swiotlb-xen.c +@@ -216,6 +216,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, + * buffering it. + */ + if (dma_capable(dev, dev_addr, size, true) && ++ !dma_kmalloc_needs_bounce(dev, size, dir) && + !range_straddles_page_boundary(phys, size) && + !xen_arch_need_swiotlb(dev, phys, dev_addr) && + !is_swiotlb_force_bounce(dev)) +diff --git a/drivers/xen/xenbus/xenbus.h b/drivers/xen/xenbus/xenbus.h +index 2754bdfadcb89c..4ba73320694a4c 100644 +--- a/drivers/xen/xenbus/xenbus.h ++++ b/drivers/xen/xenbus/xenbus.h +@@ -77,6 +77,7 @@ enum xb_req_state { + struct xb_req_data { + struct list_head list; + wait_queue_head_t wq; ++ struct kref kref; + struct xsd_sockmsg msg; + uint32_t caller_req_id; + enum xsd_sockmsg_type type; +@@ -103,6 +104,7 @@ int xb_init_comms(void); + void xb_deinit_comms(void); + int xs_watch_msg(struct xs_watch_event *event); + void xs_request_exit(struct xb_req_data *req); ++void xs_free_req(struct kref *kref); + + int xenbus_match(struct device *_dev, struct device_driver *_drv); + int xenbus_dev_probe(struct device *_dev); +diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c +index e5fda0256feb3d..82df2da1b880b8 100644 +--- a/drivers/xen/xenbus/xenbus_comms.c ++++ b/drivers/xen/xenbus/xenbus_comms.c +@@ -309,8 +309,8 @@ static int process_msg(void) + virt_wmb(); + req->state = xb_req_state_got_reply; + req->cb(req); +- } else +- kfree(req); ++ } ++ kref_put(&req->kref, xs_free_req); + } + + mutex_unlock(&xs_response_mutex); +@@ -386,14 +386,13 @@ static int process_writes(void) + state.req->msg.type = XS_ERROR; + state.req->err = err; + list_del(&state.req->list); +- if (state.req->state == xb_req_state_aborted) +- kfree(state.req); +- else { ++ if (state.req->state != xb_req_state_aborted) { + /* write err, then update state */ + virt_wmb(); + state.req->state = xb_req_state_got_reply; + wake_up(&state.req->wq); + } ++ kref_put(&state.req->kref, xs_free_req); + + mutex_unlock(&xb_write_mutex); + +diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c +index 0792fda49a15f3..c495cff3da308b 100644 +--- a/drivers/xen/xenbus/xenbus_dev_frontend.c ++++ b/drivers/xen/xenbus/xenbus_dev_frontend.c +@@ -406,7 +406,7 @@ void xenbus_dev_queue_reply(struct xb_req_data *req) + mutex_unlock(&u->reply_mutex); + + kfree(req->body); +- kfree(req); ++ kref_put(&req->kref, xs_free_req); + + kref_put(&u->kref, xenbus_file_free); + +diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c +index 028a182bcc9e83..f84c87ee283958 100644 +--- a/drivers/xen/xenbus/xenbus_xs.c ++++ b/drivers/xen/xenbus/xenbus_xs.c +@@ -112,6 +112,12 @@ static void xs_suspend_exit(void) + wake_up_all(&xs_state_enter_wq); + } + ++void xs_free_req(struct kref *kref) ++{ ++ struct xb_req_data *req = container_of(kref, struct xb_req_data, kref); ++ kfree(req); ++} ++ + static uint32_t xs_request_enter(struct xb_req_data *req) + { + uint32_t rq_id; +@@ -237,6 +243,12 @@ static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg) + req->caller_req_id = req->msg.req_id; + req->msg.req_id = xs_request_enter(req); + ++ /* ++ * Take 2nd ref. One for this thread, and the second for the ++ * xenbus_thread. ++ */ ++ kref_get(&req->kref); ++ + mutex_lock(&xb_write_mutex); + list_add_tail(&req->list, &xb_write_list); + notify = list_is_singular(&xb_write_list); +@@ -261,8 +273,8 @@ static void *xs_wait_for_reply(struct xb_req_data *req, struct xsd_sockmsg *msg) + if (req->state == xb_req_state_queued || + req->state == xb_req_state_wait_reply) + req->state = xb_req_state_aborted; +- else +- kfree(req); ++ ++ kref_put(&req->kref, xs_free_req); + mutex_unlock(&xb_write_mutex); + + return ret; +@@ -291,6 +303,7 @@ int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void *par) + req->cb = xenbus_dev_queue_reply; + req->par = par; + req->user_req = true; ++ kref_init(&req->kref); + + xs_send(req, msg); + +@@ -319,6 +332,7 @@ static void *xs_talkv(struct xenbus_transaction t, + req->num_vecs = num_vecs; + req->cb = xs_wake_up; + req->user_req = false; ++ kref_init(&req->kref); + + msg.req_id = 0; + msg.tx_id = t.id; +diff --git a/fs/namespace.c b/fs/namespace.c +index 5a885d35efe937..450f4198b8cdd8 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -633,7 +633,7 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq) + return 0; + mnt = real_mount(bastard); + mnt_add_count(mnt, 1); +- smp_mb(); // see mntput_no_expire() ++ smp_mb(); // see mntput_no_expire() and do_umount() + if (likely(!read_seqretry(&mount_lock, seq))) + return 0; + if (bastard->mnt_flags & MNT_SYNC_UMOUNT) { +@@ -1786,6 +1786,7 @@ static int do_umount(struct mount *mnt, int flags) + umount_tree(mnt, UMOUNT_PROPAGATE); + retval = 0; + } else { ++ smp_mb(); // paired with __legitimize_mnt() + shrink_submounts(mnt); + retval = -EBUSY; + if (!propagate_mount_busy(mnt, 2)) { +diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c +index cbe3c12ff5f75c..b246e53271114d 100644 +--- a/fs/ocfs2/journal.c ++++ b/fs/ocfs2/journal.c +@@ -174,7 +174,7 @@ int ocfs2_recovery_init(struct ocfs2_super *osb) + struct ocfs2_recovery_map *rm; + + mutex_init(&osb->recovery_lock); +- osb->disable_recovery = 0; ++ osb->recovery_state = OCFS2_REC_ENABLED; + osb->recovery_thread_task = NULL; + init_waitqueue_head(&osb->recovery_event); + +@@ -190,31 +190,53 @@ int ocfs2_recovery_init(struct ocfs2_super *osb) + return 0; + } + +-/* we can't grab the goofy sem lock from inside wait_event, so we use +- * memory barriers to make sure that we'll see the null task before +- * being woken up */ + static int ocfs2_recovery_thread_running(struct ocfs2_super *osb) + { +- mb(); + return osb->recovery_thread_task != NULL; + } + +-void ocfs2_recovery_exit(struct ocfs2_super *osb) ++static void ocfs2_recovery_disable(struct ocfs2_super *osb, ++ enum ocfs2_recovery_state state) + { +- struct ocfs2_recovery_map *rm; +- +- /* disable any new recovery threads and wait for any currently +- * running ones to exit. Do this before setting the vol_state. */ + mutex_lock(&osb->recovery_lock); +- osb->disable_recovery = 1; ++ /* ++ * If recovery thread is not running, we can directly transition to ++ * final state. ++ */ ++ if (!ocfs2_recovery_thread_running(osb)) { ++ osb->recovery_state = state + 1; ++ goto out_lock; ++ } ++ osb->recovery_state = state; ++ /* Wait for recovery thread to acknowledge state transition */ ++ wait_event_cmd(osb->recovery_event, ++ !ocfs2_recovery_thread_running(osb) || ++ osb->recovery_state >= state + 1, ++ mutex_unlock(&osb->recovery_lock), ++ mutex_lock(&osb->recovery_lock)); ++out_lock: + mutex_unlock(&osb->recovery_lock); +- wait_event(osb->recovery_event, !ocfs2_recovery_thread_running(osb)); + +- /* At this point, we know that no more recovery threads can be +- * launched, so wait for any recovery completion work to +- * complete. */ ++ /* ++ * At this point we know that no more recovery work can be queued so ++ * wait for any recovery completion work to complete. ++ */ + if (osb->ocfs2_wq) + flush_workqueue(osb->ocfs2_wq); ++} ++ ++void ocfs2_recovery_disable_quota(struct ocfs2_super *osb) ++{ ++ ocfs2_recovery_disable(osb, OCFS2_REC_QUOTA_WANT_DISABLE); ++} ++ ++void ocfs2_recovery_exit(struct ocfs2_super *osb) ++{ ++ struct ocfs2_recovery_map *rm; ++ ++ /* disable any new recovery threads and wait for any currently ++ * running ones to exit. Do this before setting the vol_state. */ ++ ocfs2_recovery_disable(osb, OCFS2_REC_WANT_DISABLE); + + /* + * Now that recovery is shut down, and the osb is about to be +@@ -1472,6 +1494,18 @@ static int __ocfs2_recovery_thread(void *arg) + } + } + restart: ++ if (quota_enabled) { ++ mutex_lock(&osb->recovery_lock); ++ /* Confirm that recovery thread will no longer recover quotas */ ++ if (osb->recovery_state == OCFS2_REC_QUOTA_WANT_DISABLE) { ++ osb->recovery_state = OCFS2_REC_QUOTA_DISABLED; ++ wake_up(&osb->recovery_event); ++ } ++ if (osb->recovery_state >= OCFS2_REC_QUOTA_DISABLED) ++ quota_enabled = 0; ++ mutex_unlock(&osb->recovery_lock); ++ } ++ + status = ocfs2_super_lock(osb, 1); + if (status < 0) { + mlog_errno(status); +@@ -1569,27 +1603,29 @@ static int __ocfs2_recovery_thread(void *arg) + + ocfs2_free_replay_slots(osb); + osb->recovery_thread_task = NULL; +- mb(); /* sync with ocfs2_recovery_thread_running */ ++ if (osb->recovery_state == OCFS2_REC_WANT_DISABLE) ++ osb->recovery_state = OCFS2_REC_DISABLED; + wake_up(&osb->recovery_event); + + mutex_unlock(&osb->recovery_lock); + +- if (quota_enabled) +- kfree(rm_quota); ++ kfree(rm_quota); + + return status; + } + + void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num) + { ++ int was_set = -1; ++ + mutex_lock(&osb->recovery_lock); ++ if (osb->recovery_state < OCFS2_REC_WANT_DISABLE) ++ was_set = ocfs2_recovery_map_set(osb, node_num); + + trace_ocfs2_recovery_thread(node_num, osb->node_num, +- osb->disable_recovery, osb->recovery_thread_task, +- osb->disable_recovery ? +- -1 : ocfs2_recovery_map_set(osb, node_num)); ++ osb->recovery_state, osb->recovery_thread_task, was_set); + +- if (osb->disable_recovery) ++ if (osb->recovery_state >= OCFS2_REC_WANT_DISABLE) + goto out; + + if (osb->recovery_thread_task) +diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h +index e3c3a35dc5e0e7..6397170f302f22 100644 +--- a/fs/ocfs2/journal.h ++++ b/fs/ocfs2/journal.h +@@ -148,6 +148,7 @@ void ocfs2_wait_for_recovery(struct ocfs2_super *osb); + + int ocfs2_recovery_init(struct ocfs2_super *osb); + void ocfs2_recovery_exit(struct ocfs2_super *osb); ++void ocfs2_recovery_disable_quota(struct ocfs2_super *osb); + + int ocfs2_compute_replay_slots(struct ocfs2_super *osb); + void ocfs2_free_replay_slots(struct ocfs2_super *osb); +diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h +index 8fe826143d7bf4..5e3ebbab698ad1 100644 +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -308,6 +308,21 @@ enum ocfs2_journal_trigger_type { + void ocfs2_initialize_journal_triggers(struct super_block *sb, + struct ocfs2_triggers triggers[]); + ++enum ocfs2_recovery_state { ++ OCFS2_REC_ENABLED = 0, ++ OCFS2_REC_QUOTA_WANT_DISABLE, ++ /* ++ * Must be OCFS2_REC_QUOTA_WANT_DISABLE + 1 for ++ * ocfs2_recovery_disable_quota() to work. ++ */ ++ OCFS2_REC_QUOTA_DISABLED, ++ OCFS2_REC_WANT_DISABLE, ++ /* ++ * Must be OCFS2_REC_WANT_DISABLE + 1 for ocfs2_recovery_exit() to work ++ */ ++ OCFS2_REC_DISABLED, ++}; ++ + struct ocfs2_journal; + struct ocfs2_slot_info; + struct ocfs2_recovery_map; +@@ -370,7 +385,7 @@ struct ocfs2_super + struct ocfs2_recovery_map *recovery_map; + struct ocfs2_replay_map *replay_map; + struct task_struct *recovery_thread_task; +- int disable_recovery; ++ enum ocfs2_recovery_state recovery_state; + wait_queue_head_t checkpoint_event; + struct ocfs2_journal *journal; + unsigned long osb_commit_interval; +diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c +index 4b4fa58cd32ff0..0ca8975a1df479 100644 +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -453,8 +453,7 @@ struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery( + + /* Sync changes in local quota file into global quota file and + * reinitialize local quota file. +- * The function expects local quota file to be already locked and +- * s_umount locked in shared mode. */ ++ * The function expects local quota file to be already locked. */ + static int ocfs2_recover_local_quota_file(struct inode *lqinode, + int type, + struct ocfs2_quota_recovery *rec) +@@ -585,7 +584,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, + { + unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, + LOCAL_GROUP_QUOTA_SYSTEM_INODE }; +- struct super_block *sb = osb->sb; + struct ocfs2_local_disk_dqinfo *ldinfo; + struct buffer_head *bh; + handle_t *handle; +@@ -597,7 +595,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, + printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for " + "slot %u\n", osb->dev_str, slot_num); + +- down_read(&sb->s_umount); + for (type = 0; type < OCFS2_MAXQUOTAS; type++) { + if (list_empty(&(rec->r_list[type]))) + continue; +@@ -674,7 +671,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, + break; + } + out: +- up_read(&sb->s_umount); + kfree(rec); + return status; + } +@@ -840,8 +836,7 @@ static int ocfs2_local_free_info(struct super_block *sb, int type) + ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); + + /* +- * s_umount held in exclusive mode protects us against racing with +- * recovery thread... ++ * ocfs2_dismount_volume() has already aborted quota recovery... + */ + if (oinfo->dqi_rec) { + ocfs2_free_quota_recovery(oinfo->dqi_rec); +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index 84fa585c6513a5..e585e77cdc88e1 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -1870,6 +1870,9 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) + /* Orphan scan should be stopped as early as possible */ + ocfs2_orphan_scan_stop(osb); + ++ /* Stop quota recovery so that we can disable quotas */ ++ ocfs2_recovery_disable_quota(osb); ++ + ocfs2_disable_quotas(osb); + + /* All dquots should be freed by now */ +diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c +index 9c0ef4195b5829..74979466729535 100644 +--- a/fs/smb/client/cached_dir.c ++++ b/fs/smb/client/cached_dir.c +@@ -29,7 +29,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, + { + struct cached_fid *cfid; + +- spin_lock(&cfids->cfid_list_lock); + list_for_each_entry(cfid, &cfids->entries, entry) { + if (!strcmp(cfid->path, path)) { + /* +@@ -38,25 +37,20 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, + * being deleted due to a lease break. + */ + if (!cfid->time || !cfid->has_lease) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + kref_get(&cfid->refcount); +- spin_unlock(&cfids->cfid_list_lock); + return cfid; + } + } + if (lookup_only) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + if (cfids->num_entries >= max_cached_dirs) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + cfid = init_cached_dir(path); + if (cfid == NULL) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + cfid->cfids = cfids; +@@ -74,7 +68,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, + */ + cfid->has_lease = true; + +- spin_unlock(&cfids->cfid_list_lock); + return cfid; + } + +@@ -185,8 +178,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + if (!utf16_path) + return -ENOMEM; + ++ spin_lock(&cfids->cfid_list_lock); + cfid = find_or_create_cached_dir(cfids, path, lookup_only, tcon->max_cached_dirs); + if (cfid == NULL) { ++ spin_unlock(&cfids->cfid_list_lock); + kfree(utf16_path); + return -ENOENT; + } +@@ -195,7 +190,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + * Otherwise, it is either a new entry or laundromat worker removed it + * from @cfids->entries. Caller will put last reference if the latter. + */ +- spin_lock(&cfids->cfid_list_lock); + if (cfid->has_lease && cfid->time) { + spin_unlock(&cfids->cfid_list_lock); + *ret_cfid = cfid; +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index 5a5277b4b53b11..72294764d4c20c 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -1496,7 +1496,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req) + + if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) < + sizeof(struct create_lease_v2) - 4) +- return NULL; ++ goto err_out; + + memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); + lreq->req_state = lc->lcontext.LeaseState; +@@ -1512,7 +1512,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req) + + if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) < + sizeof(struct create_lease)) +- return NULL; ++ goto err_out; + + memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); + lreq->req_state = lc->lcontext.LeaseState; +@@ -1521,6 +1521,9 @@ struct lease_ctx_info *parse_lease_state(void *open_req) + lreq->version = 1; + } + return lreq; ++err_out: ++ kfree(lreq); ++ return NULL; + } + + /** +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 13750a5e5ba02e..9bd817427a345a 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -632,6 +632,11 @@ smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls) + return name; + } + ++ if (*name == '\0') { ++ kfree(name); ++ return ERR_PTR(-EINVAL); ++ } ++ + if (*name == '\\') { + pr_err("not allow directory name included leading slash\n"); + kfree(name); +diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c +index fa5b7e63eb832e..f6616d687365a3 100644 +--- a/fs/smb/server/vfs.c ++++ b/fs/smb/server/vfs.c +@@ -443,6 +443,13 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + goto out; + } + ++ if (v_len <= *pos) { ++ pr_err("stream write position %lld is out of bounds (stream length: %zd)\n", ++ *pos, v_len); ++ err = -EINVAL; ++ goto out; ++ } ++ + if (v_len < size) { + wbuf = kvzalloc(size, GFP_KERNEL); + if (!wbuf) { +diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c +index 271a23abc82fdd..002f0864abee62 100644 +--- a/fs/smb/server/vfs_cache.c ++++ b/fs/smb/server/vfs_cache.c +@@ -644,21 +644,40 @@ __close_file_table_ids(struct ksmbd_file_table *ft, + bool (*skip)(struct ksmbd_tree_connect *tcon, + struct ksmbd_file *fp)) + { +- unsigned int id; +- struct ksmbd_file *fp; +- int num = 0; ++ struct ksmbd_file *fp; ++ unsigned int id = 0; ++ int num = 0; ++ ++ while (1) { ++ write_lock(&ft->lock); ++ fp = idr_get_next(ft->idr, &id); ++ if (!fp) { ++ write_unlock(&ft->lock); ++ break; ++ } + +- idr_for_each_entry(ft->idr, fp, id) { +- if (skip(tcon, fp)) ++ if (skip(tcon, fp) || ++ !atomic_dec_and_test(&fp->refcount)) { ++ id++; ++ write_unlock(&ft->lock); + continue; ++ } + + set_close_state_blocked_works(fp); ++ idr_remove(ft->idr, fp->volatile_id); ++ fp->volatile_id = KSMBD_NO_FID; ++ write_unlock(&ft->lock); ++ ++ down_write(&fp->f_ci->m_lock); ++ list_del_init(&fp->node); ++ up_write(&fp->f_ci->m_lock); + +- if (!atomic_dec_and_test(&fp->refcount)) +- continue; + __ksmbd_close_fd(ft, fp); ++ + num++; ++ id++; + } ++ + return num; + } + +diff --git a/include/linux/cpu.h b/include/linux/cpu.h +index a7d91a167a8b64..20db7fc0651f3c 100644 +--- a/include/linux/cpu.h ++++ b/include/linux/cpu.h +@@ -77,6 +77,8 @@ extern ssize_t cpu_show_gds(struct device *dev, + struct device_attribute *attr, char *buf); + extern ssize_t cpu_show_reg_file_data_sampling(struct device *dev, + struct device_attribute *attr, char *buf); ++extern ssize_t cpu_show_indirect_target_selection(struct device *dev, ++ struct device_attribute *attr, char *buf); + + extern __printf(4, 5) + struct device *cpu_device_create(struct device *parent, void *drvdata, +diff --git a/include/linux/module.h b/include/linux/module.h +index f2a8624eef1eca..f58d1eb260fa9e 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -572,6 +572,11 @@ struct module { + atomic_t refcnt; + #endif + ++#ifdef CONFIG_MITIGATION_ITS ++ int its_num_pages; ++ void **its_page_array; ++#endif ++ + #ifdef CONFIG_CONSTRUCTORS + /* Constructor functions. */ + ctor_fn_t *ctors; +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 337a9d1c558f3c..0b0a172337dbac 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -3614,6 +3614,17 @@ static inline void netdev_tx_reset_queue(struct netdev_queue *q) + #endif + } + ++/** ++ * netdev_tx_reset_subqueue - reset the BQL stats and state of a netdev queue ++ * @dev: network device ++ * @qid: stack index of the queue to reset ++ */ ++static inline void netdev_tx_reset_subqueue(const struct net_device *dev, ++ u32 qid) ++{ ++ netdev_tx_reset_queue(netdev_get_tx_queue(dev, qid)); ++} ++ + /** + * netdev_reset_queue - reset the packets and bytes count of a network device + * @dev_queue: network device +@@ -3623,7 +3634,7 @@ static inline void netdev_tx_reset_queue(struct netdev_queue *q) + */ + static inline void netdev_reset_queue(struct net_device *dev_queue) + { +- netdev_tx_reset_queue(netdev_get_tx_queue(dev_queue, 0)); ++ netdev_tx_reset_subqueue(dev_queue, 0); + } + + /** +diff --git a/include/linux/types.h b/include/linux/types.h +index 253168bb3fe15c..78d87c751ff58c 100644 +--- a/include/linux/types.h ++++ b/include/linux/types.h +@@ -115,8 +115,9 @@ typedef u64 u_int64_t; + typedef s64 int64_t; + #endif + +-/* this is a special 64bit data type that is 8-byte aligned */ ++/* These are the special 64-bit data types that are 8-byte aligned */ + #define aligned_u64 __aligned_u64 ++#define aligned_s64 __aligned_s64 + #define aligned_be64 __aligned_be64 + #define aligned_le64 __aligned_le64 + +diff --git a/include/uapi/linux/types.h b/include/uapi/linux/types.h +index 6375a06840520d..48b933938877d9 100644 +--- a/include/uapi/linux/types.h ++++ b/include/uapi/linux/types.h +@@ -53,6 +53,7 @@ typedef __u32 __bitwise __wsum; + * No conversions are necessary between 32-bit user-space and a 64-bit kernel. + */ + #define __aligned_u64 __u64 __attribute__((aligned(8))) ++#define __aligned_s64 __s64 __attribute__((aligned(8))) + #define __aligned_be64 __be64 __attribute__((aligned(8))) + #define __aligned_le64 __le64 __attribute__((aligned(8))) + +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index 3ce93418e0151d..db592fa549b738 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -422,24 +422,6 @@ static struct io_kiocb *__io_prep_linked_timeout(struct io_kiocb *req) + return req->link; + } + +-static inline struct io_kiocb *io_prep_linked_timeout(struct io_kiocb *req) +-{ +- if (likely(!(req->flags & REQ_F_ARM_LTIMEOUT))) +- return NULL; +- return __io_prep_linked_timeout(req); +-} +- +-static noinline void __io_arm_ltimeout(struct io_kiocb *req) +-{ +- io_queue_linked_timeout(__io_prep_linked_timeout(req)); +-} +- +-static inline void io_arm_ltimeout(struct io_kiocb *req) +-{ +- if (unlikely(req->flags & REQ_F_ARM_LTIMEOUT)) +- __io_arm_ltimeout(req); +-} +- + static void io_prep_async_work(struct io_kiocb *req) + { + const struct io_issue_def *def = &io_issue_defs[req->opcode]; +@@ -493,7 +475,6 @@ static void io_prep_async_link(struct io_kiocb *req) + + static void io_queue_iowq(struct io_kiocb *req) + { +- struct io_kiocb *link = io_prep_linked_timeout(req); + struct io_uring_task *tctx = req->task->io_uring; + + BUG_ON(!tctx); +@@ -518,8 +499,6 @@ static void io_queue_iowq(struct io_kiocb *req) + + trace_io_uring_queue_async_work(req, io_wq_is_hashed(&req->work)); + io_wq_enqueue(tctx->io_wq, &req->work); +- if (link) +- io_queue_linked_timeout(link); + } + + static __cold void io_queue_deferred(struct io_ring_ctx *ctx) +@@ -940,6 +919,14 @@ static bool __io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u + { + bool filled; + ++ /* ++ * If multishot has already posted deferred completions, ensure that ++ * those are flushed first before posting this one. If not, CQEs ++ * could get reordered. ++ */ ++ if (!wq_list_empty(&ctx->submit_state.compl_reqs)) ++ __io_submit_flush_completions(ctx); ++ + io_cq_lock(ctx); + filled = io_fill_cqe_aux(ctx, user_data, res, cflags); + if (!filled && allow_overflow) +@@ -1863,17 +1850,24 @@ static bool io_assign_file(struct io_kiocb *req, const struct io_issue_def *def, + return !!req->file; + } + ++#define REQ_ISSUE_SLOW_FLAGS (REQ_F_CREDS | REQ_F_ARM_LTIMEOUT) ++ + static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags) + { + const struct io_issue_def *def = &io_issue_defs[req->opcode]; + const struct cred *creds = NULL; ++ struct io_kiocb *link = NULL; + int ret; + + if (unlikely(!io_assign_file(req, def, issue_flags))) + return -EBADF; + +- if (unlikely((req->flags & REQ_F_CREDS) && req->creds != current_cred())) +- creds = override_creds(req->creds); ++ if (unlikely(req->flags & REQ_ISSUE_SLOW_FLAGS)) { ++ if ((req->flags & REQ_F_CREDS) && req->creds != current_cred()) ++ creds = override_creds(req->creds); ++ if (req->flags & REQ_F_ARM_LTIMEOUT) ++ link = __io_prep_linked_timeout(req); ++ } + + if (!def->audit_skip) + audit_uring_entry(req->opcode); +@@ -1883,8 +1877,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags) + if (!def->audit_skip) + audit_uring_exit(!ret, ret); + +- if (creds) +- revert_creds(creds); ++ if (unlikely(creds || link)) { ++ if (creds) ++ revert_creds(creds); ++ if (link) ++ io_queue_linked_timeout(link); ++ } + + if (ret == IOU_OK) { + if (issue_flags & IO_URING_F_COMPLETE_DEFER) +@@ -1939,8 +1937,6 @@ void io_wq_submit_work(struct io_wq_work *work) + else + req_ref_get(req); + +- io_arm_ltimeout(req); +- + /* either cancelled or io-wq is dying, so don't touch tctx->iowq */ + if (work->flags & IO_WQ_WORK_CANCEL) { + fail: +@@ -2036,15 +2032,11 @@ struct file *io_file_get_normal(struct io_kiocb *req, int fd) + static void io_queue_async(struct io_kiocb *req, int ret) + __must_hold(&req->ctx->uring_lock) + { +- struct io_kiocb *linked_timeout; +- + if (ret != -EAGAIN || (req->flags & REQ_F_NOWAIT)) { + io_req_defer_failed(req, ret); + return; + } + +- linked_timeout = io_prep_linked_timeout(req); +- + switch (io_arm_poll_handler(req, 0)) { + case IO_APOLL_READY: + io_kbuf_recycle(req, 0); +@@ -2057,9 +2049,6 @@ static void io_queue_async(struct io_kiocb *req, int ret) + case IO_APOLL_OK: + break; + } +- +- if (linked_timeout) +- io_queue_linked_timeout(linked_timeout); + } + + static inline void io_queue_sqe(struct io_kiocb *req) +@@ -2073,9 +2062,7 @@ static inline void io_queue_sqe(struct io_kiocb *req) + * We async punt it if the file wasn't marked NOWAIT, or if the file + * doesn't support non-blocking read/write attempts + */ +- if (likely(!ret)) +- io_arm_ltimeout(req); +- else ++ if (unlikely(ret)) + io_queue_async(req, ret); + } + +diff --git a/kernel/params.c b/kernel/params.c +index c7aed3c51cd538..e39ac5420cd6dc 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -945,7 +945,9 @@ struct kset *module_kset; + static void module_kobj_release(struct kobject *kobj) + { + struct module_kobject *mk = to_module_kobject(kobj); +- complete(mk->kobj_completion); ++ ++ if (mk->kobj_completion) ++ complete(mk->kobj_completion); + } + + const struct kobj_type module_ktype = { +diff --git a/net/can/gw.c b/net/can/gw.c +index 37528826935e74..e65500c52bf5c7 100644 +--- a/net/can/gw.c ++++ b/net/can/gw.c +@@ -130,7 +130,7 @@ struct cgw_job { + u32 handled_frames; + u32 dropped_frames; + u32 deleted_frames; +- struct cf_mod mod; ++ struct cf_mod __rcu *cf_mod; + union { + /* CAN frame data source */ + struct net_device *dev; +@@ -459,6 +459,7 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + struct cgw_job *gwj = (struct cgw_job *)data; + struct canfd_frame *cf; + struct sk_buff *nskb; ++ struct cf_mod *mod; + int modidx = 0; + + /* process strictly Classic CAN or CAN FD frames */ +@@ -506,7 +507,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + * When there is at least one modification function activated, + * we need to copy the skb as we want to modify skb->data. + */ +- if (gwj->mod.modfunc[0]) ++ mod = rcu_dereference(gwj->cf_mod); ++ if (mod->modfunc[0]) + nskb = skb_copy(skb, GFP_ATOMIC); + else + nskb = skb_clone(skb, GFP_ATOMIC); +@@ -529,8 +531,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + cf = (struct canfd_frame *)nskb->data; + + /* perform preprocessed modification functions if there are any */ +- while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx]) +- (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod); ++ while (modidx < MAX_MODFUNCTIONS && mod->modfunc[modidx]) ++ (*mod->modfunc[modidx++])(cf, mod); + + /* Has the CAN frame been modified? */ + if (modidx) { +@@ -546,11 +548,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + } + + /* check for checksum updates */ +- if (gwj->mod.csumfunc.crc8) +- (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8); ++ if (mod->csumfunc.crc8) ++ (*mod->csumfunc.crc8)(cf, &mod->csum.crc8); + +- if (gwj->mod.csumfunc.xor) +- (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); ++ if (mod->csumfunc.xor) ++ (*mod->csumfunc.xor)(cf, &mod->csum.xor); + } + + /* clear the skb timestamp if not configured the other way */ +@@ -581,9 +583,20 @@ static void cgw_job_free_rcu(struct rcu_head *rcu_head) + { + struct cgw_job *gwj = container_of(rcu_head, struct cgw_job, rcu); + ++ /* cgw_job::cf_mod is always accessed from the same cgw_job object within ++ * the same RCU read section. Once cgw_job is scheduled for removal, ++ * cf_mod can also be removed without mandating an additional grace period. ++ */ ++ kfree(rcu_access_pointer(gwj->cf_mod)); + kmem_cache_free(cgw_cache, gwj); + } + ++/* Return cgw_job::cf_mod with RTNL protected section */ ++static struct cf_mod *cgw_job_cf_mod(struct cgw_job *gwj) ++{ ++ return rcu_dereference_protected(gwj->cf_mod, rtnl_is_locked()); ++} ++ + static int cgw_notifier(struct notifier_block *nb, + unsigned long msg, void *ptr) + { +@@ -616,6 +629,7 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, + { + struct rtcanmsg *rtcan; + struct nlmsghdr *nlh; ++ struct cf_mod *mod; + + nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtcan), flags); + if (!nlh) +@@ -650,82 +664,83 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, + goto cancel; + } + ++ mod = cgw_job_cf_mod(gwj); + if (gwj->flags & CGW_FLAGS_CAN_FD) { + struct cgw_fdframe_mod mb; + +- if (gwj->mod.modtype.and) { +- memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.and; ++ if (mod->modtype.and) { ++ memcpy(&mb.cf, &mod->modframe.and, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.and; + if (nla_put(skb, CGW_FDMOD_AND, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.or) { +- memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.or; ++ if (mod->modtype.or) { ++ memcpy(&mb.cf, &mod->modframe.or, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.or; + if (nla_put(skb, CGW_FDMOD_OR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.xor) { +- memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.xor; ++ if (mod->modtype.xor) { ++ memcpy(&mb.cf, &mod->modframe.xor, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.xor; + if (nla_put(skb, CGW_FDMOD_XOR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.set) { +- memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.set; ++ if (mod->modtype.set) { ++ memcpy(&mb.cf, &mod->modframe.set, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.set; + if (nla_put(skb, CGW_FDMOD_SET, sizeof(mb), &mb) < 0) + goto cancel; + } + } else { + struct cgw_frame_mod mb; + +- if (gwj->mod.modtype.and) { +- memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.and; ++ if (mod->modtype.and) { ++ memcpy(&mb.cf, &mod->modframe.and, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.and; + if (nla_put(skb, CGW_MOD_AND, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.or) { +- memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.or; ++ if (mod->modtype.or) { ++ memcpy(&mb.cf, &mod->modframe.or, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.or; + if (nla_put(skb, CGW_MOD_OR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.xor) { +- memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.xor; ++ if (mod->modtype.xor) { ++ memcpy(&mb.cf, &mod->modframe.xor, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.xor; + if (nla_put(skb, CGW_MOD_XOR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.set) { +- memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.set; ++ if (mod->modtype.set) { ++ memcpy(&mb.cf, &mod->modframe.set, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.set; + if (nla_put(skb, CGW_MOD_SET, sizeof(mb), &mb) < 0) + goto cancel; + } + } + +- if (gwj->mod.uid) { +- if (nla_put_u32(skb, CGW_MOD_UID, gwj->mod.uid) < 0) ++ if (mod->uid) { ++ if (nla_put_u32(skb, CGW_MOD_UID, mod->uid) < 0) + goto cancel; + } + +- if (gwj->mod.csumfunc.crc8) { ++ if (mod->csumfunc.crc8) { + if (nla_put(skb, CGW_CS_CRC8, CGW_CS_CRC8_LEN, +- &gwj->mod.csum.crc8) < 0) ++ &mod->csum.crc8) < 0) + goto cancel; + } + +- if (gwj->mod.csumfunc.xor) { ++ if (mod->csumfunc.xor) { + if (nla_put(skb, CGW_CS_XOR, CGW_CS_XOR_LEN, +- &gwj->mod.csum.xor) < 0) ++ &mod->csum.xor) < 0) + goto cancel; + } + +@@ -1059,7 +1074,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + struct net *net = sock_net(skb->sk); + struct rtcanmsg *r; + struct cgw_job *gwj; +- struct cf_mod mod; ++ struct cf_mod *mod; + struct can_can_gw ccgw; + u8 limhops = 0; + int err = 0; +@@ -1078,37 +1093,48 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + if (r->gwtype != CGW_TYPE_CAN_CAN) + return -EINVAL; + +- err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops); ++ mod = kmalloc(sizeof(*mod), GFP_KERNEL); ++ if (!mod) ++ return -ENOMEM; ++ ++ err = cgw_parse_attr(nlh, mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops); + if (err < 0) +- return err; ++ goto out_free_cf; + +- if (mod.uid) { ++ if (mod->uid) { + ASSERT_RTNL(); + + /* check for updating an existing job with identical uid */ + hlist_for_each_entry(gwj, &net->can.cgw_list, list) { +- if (gwj->mod.uid != mod.uid) ++ struct cf_mod *old_cf; ++ ++ old_cf = cgw_job_cf_mod(gwj); ++ if (old_cf->uid != mod->uid) + continue; + + /* interfaces & filters must be identical */ +- if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw))) +- return -EINVAL; ++ if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw))) { ++ err = -EINVAL; ++ goto out_free_cf; ++ } + +- /* update modifications with disabled softirq & quit */ +- local_bh_disable(); +- memcpy(&gwj->mod, &mod, sizeof(mod)); +- local_bh_enable(); ++ rcu_assign_pointer(gwj->cf_mod, mod); ++ kfree_rcu_mightsleep(old_cf); + return 0; + } + } + + /* ifindex == 0 is not allowed for job creation */ +- if (!ccgw.src_idx || !ccgw.dst_idx) +- return -ENODEV; ++ if (!ccgw.src_idx || !ccgw.dst_idx) { ++ err = -ENODEV; ++ goto out_free_cf; ++ } + + gwj = kmem_cache_alloc(cgw_cache, GFP_KERNEL); +- if (!gwj) +- return -ENOMEM; ++ if (!gwj) { ++ err = -ENOMEM; ++ goto out_free_cf; ++ } + + gwj->handled_frames = 0; + gwj->dropped_frames = 0; +@@ -1118,7 +1144,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + gwj->limit_hops = limhops; + + /* insert already parsed information */ +- memcpy(&gwj->mod, &mod, sizeof(mod)); ++ RCU_INIT_POINTER(gwj->cf_mod, mod); + memcpy(&gwj->ccgw, &ccgw, sizeof(ccgw)); + + err = -ENODEV; +@@ -1152,9 +1178,11 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + if (!err) + hlist_add_head_rcu(&gwj->list, &net->can.cgw_list); + out: +- if (err) ++ if (err) { + kmem_cache_free(cgw_cache, gwj); +- ++out_free_cf: ++ kfree(mod); ++ } + return err; + } + +@@ -1214,19 +1242,22 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, + + /* remove only the first matching entry */ + hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) { ++ struct cf_mod *cf_mod; ++ + if (gwj->flags != r->flags) + continue; + + if (gwj->limit_hops != limhops) + continue; + ++ cf_mod = cgw_job_cf_mod(gwj); + /* we have a match when uid is enabled and identical */ +- if (gwj->mod.uid || mod.uid) { +- if (gwj->mod.uid != mod.uid) ++ if (cf_mod->uid || mod.uid) { ++ if (cf_mod->uid != mod.uid) + continue; + } else { + /* no uid => check for identical modifications */ +- if (memcmp(&gwj->mod, &mod, sizeof(mod))) ++ if (memcmp(cf_mod, &mod, sizeof(mod))) + continue; + } + +diff --git a/net/core/filter.c b/net/core/filter.c +index 066277b91a1be8..5143c8a9e52cab 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -2507,6 +2507,7 @@ int skb_do_redirect(struct sk_buff *skb) + goto out_drop; + skb->dev = dev; + dev_sw_netstats_rx_add(dev, skb->len); ++ skb_scrub_packet(skb, false); + return -EAGAIN; + } + return flags & BPF_F_NEIGH ? +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index bb9add46e382a6..231fa4dc6cde4a 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3189,16 +3189,13 @@ static void add_v4_addrs(struct inet6_dev *idev) + struct in6_addr addr; + struct net_device *dev; + struct net *net = dev_net(idev->dev); +- int scope, plen, offset = 0; ++ int scope, plen; + u32 pflags = 0; + + ASSERT_RTNL(); + + memset(&addr, 0, sizeof(struct in6_addr)); +- /* in case of IP6GRE the dev_addr is an IPv6 and therefore we use only the last 4 bytes */ +- if (idev->dev->addr_len == sizeof(struct in6_addr)) +- offset = sizeof(struct in6_addr) - 4; +- memcpy(&addr.s6_addr32[3], idev->dev->dev_addr + offset, 4); ++ memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4); + + if (!(idev->dev->flags & IFF_POINTOPOINT) && idev->dev->type == ARPHRD_SIT) { + scope = IPV6_ADDR_COMPATv4; +@@ -3508,7 +3505,13 @@ static void addrconf_gre_config(struct net_device *dev) + return; + } + +- if (dev->type == ARPHRD_ETHER) { ++ /* Generate the IPv6 link-local address using addrconf_addr_gen(), ++ * unless we have an IPv4 GRE device not bound to an IP address and ++ * which is in EUI64 mode (as __ipv6_isatap_ifid() would fail in this ++ * case). Such devices fall back to add_v4_addrs() instead. ++ */ ++ if (!(dev->type == ARPHRD_IPGRE && *(__be32 *)dev->dev_addr == 0 && ++ idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64)) { + addrconf_addr_gen(idev, true); + return; + } +diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h +index 20aad81fcad7e6..c2d88b1b06b872 100644 +--- a/net/netfilter/ipset/ip_set_hash_gen.h ++++ b/net/netfilter/ipset/ip_set_hash_gen.h +@@ -63,7 +63,7 @@ struct hbucket { + #define ahash_sizeof_regions(htable_bits) \ + (ahash_numof_locks(htable_bits) * sizeof(struct ip_set_region)) + #define ahash_region(n, htable_bits) \ +- ((n) % ahash_numof_locks(htable_bits)) ++ ((n) / jhash_size(HTABLE_REGION_BITS)) + #define ahash_bucket_start(h, htable_bits) \ + ((htable_bits) < HTABLE_REGION_BITS ? 0 \ + : (h) * jhash_size(HTABLE_REGION_BITS)) +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index 5cd511162bc038..0103c4a4d10a55 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -119,13 +119,12 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + return false; + } + +-/* Get route to daddr, update *saddr, optionally bind route to saddr */ ++/* Get route to daddr, optionally bind route to saddr */ + static struct rtable *do_output_route4(struct net *net, __be32 daddr, +- int rt_mode, __be32 *saddr) ++ int rt_mode, __be32 *ret_saddr) + { + struct flowi4 fl4; + struct rtable *rt; +- bool loop = false; + + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = daddr; +@@ -135,23 +134,17 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr, + retry: + rt = ip_route_output_key(net, &fl4); + if (IS_ERR(rt)) { +- /* Invalid saddr ? */ +- if (PTR_ERR(rt) == -EINVAL && *saddr && +- rt_mode & IP_VS_RT_MODE_CONNECT && !loop) { +- *saddr = 0; +- flowi4_update_output(&fl4, 0, daddr, 0); +- goto retry; +- } + IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", &daddr); + return NULL; +- } else if (!*saddr && rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) { ++ } ++ if (rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) { + ip_rt_put(rt); +- *saddr = fl4.saddr; + flowi4_update_output(&fl4, 0, daddr, fl4.saddr); +- loop = true; ++ rt_mode = 0; + goto retry; + } +- *saddr = fl4.saddr; ++ if (ret_saddr) ++ *ret_saddr = fl4.saddr; + return rt; + } + +@@ -344,19 +337,15 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb, + if (ret_saddr) + *ret_saddr = dest_dst->dst_saddr.ip; + } else { +- __be32 saddr = htonl(INADDR_ANY); +- + noref = 0; + + /* For such unconfigured boxes avoid many route lookups + * for performance reasons because we do not remember saddr + */ + rt_mode &= ~IP_VS_RT_MODE_CONNECT; +- rt = do_output_route4(net, daddr, rt_mode, &saddr); ++ rt = do_output_route4(net, daddr, rt_mode, ret_saddr); + if (!rt) + goto err_unreach; +- if (ret_saddr) +- *ret_saddr = saddr; + } + + local = (rt->rt_flags & RTCF_LOCAL) ? 1 : 0; +diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c +index 6c5afb4ad67bb6..10c646b32b9d08 100644 +--- a/net/openvswitch/actions.c ++++ b/net/openvswitch/actions.c +@@ -959,8 +959,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, + upcall.cmd = OVS_PACKET_CMD_ACTION; + upcall.mru = OVS_CB(skb)->mru; + +- for (a = nla_data(attr), rem = nla_len(attr); rem > 0; +- a = nla_next(a, &rem)) { ++ nla_for_each_nested(a, attr, rem) { + switch (nla_type(a)) { + case OVS_USERSPACE_ATTR_USERDATA: + upcall.userdata = a; +diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c +index 9a3f7ea80b34b9..716da8c6b3def3 100644 +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -348,7 +348,8 @@ static void htb_add_to_wait_tree(struct htb_sched *q, + */ + static inline void htb_next_rb_node(struct rb_node **n) + { +- *n = rb_next(*n); ++ if (*n) ++ *n = rb_next(*n); + } + + /** +@@ -609,8 +610,8 @@ static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) + */ + static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) + { +- WARN_ON(!cl->prio_activity); +- ++ if (!cl->prio_activity) ++ return; + htb_deactivate_prios(q, cl); + cl->prio_activity = 0; + } +@@ -1485,8 +1486,6 @@ static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) + { + struct htb_class *cl = (struct htb_class *)arg; + +- if (!cl->prio_activity) +- return; + htb_deactivate(qdisc_priv(sch), cl); + } + +@@ -1740,8 +1739,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg, + if (cl->parent) + cl->parent->children--; + +- if (cl->prio_activity) +- htb_deactivate(q, cl); ++ htb_deactivate(q, cl); + + if (cl->cmode != HTB_CAN_SEND) + htb_safe_rb_erase(&cl->pq_node, +@@ -1949,8 +1947,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, + /* turn parent into inner node */ + qdisc_purge_queue(parent->leaf.q); + parent_qdisc = parent->leaf.q; +- if (parent->prio_activity) +- htb_deactivate(q, parent); ++ htb_deactivate(q, parent); + + /* remove from evt list because of level change */ + if (parent->cmode != HTB_CAN_SEND) { +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index ce622a287abc6b..6db8c9a2a7a2b8 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -2511,7 +2511,7 @@ cfg80211_defrag_mle(const struct element *mle, const u8 *ie, size_t ielen, + /* Required length for first defragmentation */ + buf_len = mle->datalen - 1; + for_each_element(elem, mle->data + mle->datalen, +- ielen - sizeof(*mle) + mle->datalen) { ++ ie + ielen - mle->data - mle->datalen) { + if (elem->id != WLAN_EID_FRAGMENT) + break; + diff --git a/patch/kernel/archive/odroidxu4-6.6/patch-6.6.91-92.patch b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.91-92.patch new file mode 100644 index 000000000000..08903ea07d30 --- /dev/null +++ b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.91-92.patch @@ -0,0 +1,4627 @@ +diff --git a/Makefile b/Makefile +index a6a1942e2d00a9..51d975b3555195 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 91 ++SUBLEVEL = 92 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 75523c1be07350..d8012d1a2e152d 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -2001,7 +2001,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, + emit(A64_STR64I(A64_R(20), A64_SP, regs_off + 8), ctx); + + if (flags & BPF_TRAMP_F_CALL_ORIG) { +- emit_addr_mov_i64(A64_R(0), (const u64)im, ctx); ++ /* for the first pass, assume the worst case */ ++ if (!ctx->image) ++ ctx->idx += 4; ++ else ++ emit_a64_mov_i64(A64_R(0), (const u64)im, ctx); + emit_call((const u64)__bpf_tramp_enter, ctx); + } + +@@ -2045,7 +2049,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, + + if (flags & BPF_TRAMP_F_CALL_ORIG) { + im->ip_epilogue = ctx->image + ctx->idx; +- emit_addr_mov_i64(A64_R(0), (const u64)im, ctx); ++ /* for the first pass, assume the worst case */ ++ if (!ctx->image) ++ ctx->idx += 4; ++ else ++ emit_a64_mov_i64(A64_R(0), (const u64)im, ctx); + emit_call((const u64)__bpf_tramp_exit, ctx); + } + +diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile +index 81e8089c9c4f18..9c6aff9376ec0b 100644 +--- a/arch/loongarch/Makefile ++++ b/arch/loongarch/Makefile +@@ -43,7 +43,7 @@ endif + + ifdef CONFIG_64BIT + ld-emul = $(64bit-emul) +-cflags-y += -mabi=lp64s ++cflags-y += -mabi=lp64s -mcmodel=normal + endif + + cflags-y += -pipe -msoft-float +diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h +index a5b63c84f8541a..e5d21e836d993c 100644 +--- a/arch/loongarch/include/asm/ptrace.h ++++ b/arch/loongarch/include/asm/ptrace.h +@@ -55,7 +55,7 @@ static inline void instruction_pointer_set(struct pt_regs *regs, unsigned long v + + /* Query offset/name of register from its name/offset */ + extern int regs_query_register_offset(const char *name); +-#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) ++#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last) - sizeof(unsigned long)) + + /** + * regs_get_register() - get register value from its offset +diff --git a/arch/loongarch/include/asm/uprobes.h b/arch/loongarch/include/asm/uprobes.h +index c8f59983f702df..d01b6704e1d8e6 100644 +--- a/arch/loongarch/include/asm/uprobes.h ++++ b/arch/loongarch/include/asm/uprobes.h +@@ -15,7 +15,6 @@ typedef u32 uprobe_opcode_t; + #define UPROBE_XOLBP_INSN larch_insn_gen_break(BRK_UPROBE_XOLBP) + + struct arch_uprobe { +- unsigned long resume_era; + u32 insn[2]; + u32 ixol[2]; + bool simulate; +diff --git a/arch/loongarch/kernel/kfpu.c b/arch/loongarch/kernel/kfpu.c +index ec5b28e570c963..4c476904227f95 100644 +--- a/arch/loongarch/kernel/kfpu.c ++++ b/arch/loongarch/kernel/kfpu.c +@@ -18,11 +18,28 @@ static unsigned int euen_mask = CSR_EUEN_FPEN; + static DEFINE_PER_CPU(bool, in_kernel_fpu); + static DEFINE_PER_CPU(unsigned int, euen_current); + ++static inline void fpregs_lock(void) ++{ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); ++ else ++ local_bh_disable(); ++} ++ ++static inline void fpregs_unlock(void) ++{ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); ++ else ++ local_bh_enable(); ++} ++ + void kernel_fpu_begin(void) + { + unsigned int *euen_curr; + +- preempt_disable(); ++ if (!irqs_disabled()) ++ fpregs_lock(); + + WARN_ON(this_cpu_read(in_kernel_fpu)); + +@@ -73,7 +90,8 @@ void kernel_fpu_end(void) + + this_cpu_write(in_kernel_fpu, false); + +- preempt_enable(); ++ if (!irqs_disabled()) ++ fpregs_unlock(); + } + EXPORT_SYMBOL_GPL(kernel_fpu_end); + +diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c +index e7015f7b70e37c..a3732f754b5d8f 100644 +--- a/arch/loongarch/kernel/time.c ++++ b/arch/loongarch/kernel/time.c +@@ -110,7 +110,7 @@ static unsigned long __init get_loops_per_jiffy(void) + return lpj; + } + +-static long init_offset __nosavedata; ++static long init_offset; + + void save_counter(void) + { +diff --git a/arch/loongarch/kernel/uprobes.c b/arch/loongarch/kernel/uprobes.c +index 87abc7137b738e..6022eb0f71dbce 100644 +--- a/arch/loongarch/kernel/uprobes.c ++++ b/arch/loongarch/kernel/uprobes.c +@@ -42,7 +42,6 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) + utask->autask.saved_trap_nr = current->thread.trap_nr; + current->thread.trap_nr = UPROBE_TRAP_NR; + instruction_pointer_set(regs, utask->xol_vaddr); +- user_enable_single_step(current); + + return 0; + } +@@ -53,13 +52,7 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) + + WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); + current->thread.trap_nr = utask->autask.saved_trap_nr; +- +- if (auprobe->simulate) +- instruction_pointer_set(regs, auprobe->resume_era); +- else +- instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE); +- +- user_disable_single_step(current); ++ instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE); + + return 0; + } +@@ -70,7 +63,6 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) + + current->thread.trap_nr = utask->autask.saved_trap_nr; + instruction_pointer_set(regs, utask->vaddr); +- user_disable_single_step(current); + } + + bool arch_uprobe_xol_was_trapped(struct task_struct *t) +@@ -90,7 +82,6 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) + + insn.word = auprobe->insn[0]; + arch_simulate_insn(insn, regs); +- auprobe->resume_era = regs->csr_era; + + return true; + } +diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c +index 1e0590542f987c..e7b7346592cb2a 100644 +--- a/arch/loongarch/power/hibernate.c ++++ b/arch/loongarch/power/hibernate.c +@@ -2,6 +2,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -14,6 +15,7 @@ struct pt_regs saved_regs; + + void save_processor_state(void) + { ++ save_counter(); + saved_crmd = csr_read32(LOONGARCH_CSR_CRMD); + saved_prmd = csr_read32(LOONGARCH_CSR_PRMD); + saved_euen = csr_read32(LOONGARCH_CSR_EUEN); +@@ -26,6 +28,7 @@ void save_processor_state(void) + + void restore_processor_state(void) + { ++ sync_counter(); + csr_write32(saved_crmd, LOONGARCH_CSR_CRMD); + csr_write32(saved_prmd, LOONGARCH_CSR_PRMD); + csr_write32(saved_euen, LOONGARCH_CSR_EUEN); +diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c +index 4817e424d69658..8e6cad42b296ee 100644 +--- a/arch/x86/kernel/alternative.c ++++ b/arch/x86/kernel/alternative.c +@@ -730,7 +730,15 @@ static bool cpu_wants_indirect_its_thunk_at(unsigned long addr, int reg) + /* Lower-half of the cacheline? */ + return !(addr & 0x20); + } +-#endif ++ ++u8 *its_static_thunk(int reg) ++{ ++ u8 *thunk = __x86_indirect_its_thunk_array[reg]; ++ ++ return thunk; ++} ++ ++#endif /* CONFIG_MITIGATION_ITS */ + + /* + * Rewrite the compiler generated retpoline thunk calls. +@@ -1449,13 +1457,6 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, + static void poison_cfi(void *addr) { } + #endif + +-u8 *its_static_thunk(int reg) +-{ +- u8 *thunk = __x86_indirect_its_thunk_array[reg]; +- +- return thunk; +-} +- + #endif + + void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, +diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c +index b42111a24cc28d..8e38c51359d05a 100644 +--- a/arch/x86/kvm/smm.c ++++ b/arch/x86/kvm/smm.c +@@ -131,6 +131,7 @@ void kvm_smm_changed(struct kvm_vcpu *vcpu, bool entering_smm) + + kvm_mmu_reset_context(vcpu); + } ++EXPORT_SYMBOL_GPL(kvm_smm_changed); + + void process_smi(struct kvm_vcpu *vcpu) + { +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index 29c1be65cb71a0..c84a1451f194c4 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -2211,12 +2211,6 @@ static int shutdown_interception(struct kvm_vcpu *vcpu) + struct kvm_run *kvm_run = vcpu->run; + struct vcpu_svm *svm = to_svm(vcpu); + +- /* +- * The VM save area has already been encrypted so it +- * cannot be reinitialized - just terminate. +- */ +- if (sev_es_guest(vcpu->kvm)) +- return -EINVAL; + + /* + * VMCB is undefined after a SHUTDOWN intercept. INIT the vCPU to put +@@ -2225,9 +2219,18 @@ static int shutdown_interception(struct kvm_vcpu *vcpu) + * userspace. At a platform view, INIT is acceptable behavior as + * there exist bare metal platforms that automatically INIT the CPU + * in response to shutdown. ++ * ++ * The VM save area for SEV-ES guests has already been encrypted so it ++ * cannot be reinitialized, i.e. synthesizing INIT is futile. + */ +- clear_page(svm->vmcb); +- kvm_vcpu_reset(vcpu, true); ++ if (!sev_es_guest(vcpu->kvm)) { ++ clear_page(svm->vmcb); ++#ifdef CONFIG_KVM_SMM ++ if (is_smm(vcpu)) ++ kvm_smm_changed(vcpu, false); ++#endif ++ kvm_vcpu_reset(vcpu, true); ++ } + + kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; + return 0; +diff --git a/block/bio.c b/block/bio.c +index 4a8e7616995718..b197abbaebc464 100644 +--- a/block/bio.c ++++ b/block/bio.c +@@ -600,7 +600,7 @@ struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask) + { + struct bio *bio; + +- if (nr_vecs > UIO_MAXIOV) ++ if (nr_vecs > BIO_MAX_INLINE_VECS) + return NULL; + return kmalloc(struct_size(bio, bi_inline_vecs, nr_vecs), gfp_mask); + } +diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c +index f73ce6e13065dd..54676e3d82dd59 100644 +--- a/drivers/acpi/pptt.c ++++ b/drivers/acpi/pptt.c +@@ -231,16 +231,18 @@ static int acpi_pptt_leaf_node(struct acpi_table_header *table_hdr, + sizeof(struct acpi_table_pptt)); + proc_sz = sizeof(struct acpi_pptt_processor); + +- while ((unsigned long)entry + proc_sz < table_end) { ++ /* ignore subtable types that are smaller than a processor node */ ++ while ((unsigned long)entry + proc_sz <= table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; ++ + if (entry->type == ACPI_PPTT_TYPE_PROCESSOR && + cpu_node->parent == node_entry) + return 0; + if (entry->length == 0) + return 0; ++ + entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry, + entry->length); +- + } + return 1; + } +@@ -273,15 +275,18 @@ static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_he + proc_sz = sizeof(struct acpi_pptt_processor); + + /* find the processor structure associated with this cpuid */ +- while ((unsigned long)entry + proc_sz < table_end) { ++ while ((unsigned long)entry + proc_sz <= table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; + + if (entry->length == 0) { + pr_warn("Invalid zero length subtable\n"); + break; + } ++ /* entry->length may not equal proc_sz, revalidate the processor structure length */ + if (entry->type == ACPI_PPTT_TYPE_PROCESSOR && + acpi_cpu_id == cpu_node->acpi_processor_id && ++ (unsigned long)entry + entry->length <= table_end && ++ entry->length == proc_sz + cpu_node->number_of_priv_resources * sizeof(u32) && + acpi_pptt_leaf_node(table_hdr, cpu_node)) { + return (struct acpi_pptt_processor *)entry; + } +diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c +index a4274d8c7faaf3..f0d0c5a6d5127a 100644 +--- a/drivers/bluetooth/btnxpuart.c ++++ b/drivers/bluetooth/btnxpuart.c +@@ -601,8 +601,10 @@ static int nxp_download_firmware(struct hci_dev *hdev) + &nxpdev->tx_state), + msecs_to_jiffies(60000)); + +- release_firmware(nxpdev->fw); +- memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); ++ if (nxpdev->fw && strlen(nxpdev->fw_name)) { ++ release_firmware(nxpdev->fw); ++ memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); ++ } + + if (err == 0) { + bt_dev_err(hdev, "FW Download Timeout. offset: %d", +diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h +index 369496a6aebf13..27e61ddfb62298 100644 +--- a/drivers/char/tpm/tpm_tis_core.h ++++ b/drivers/char/tpm/tpm_tis_core.h +@@ -54,7 +54,7 @@ enum tis_int_flags { + enum tis_defaults { + TIS_MEM_LEN = 0x5000, + TIS_SHORT_TIMEOUT = 750, /* ms */ +- TIS_LONG_TIMEOUT = 2000, /* 2 sec */ ++ TIS_LONG_TIMEOUT = 4000, /* 4 secs */ + TIS_TIMEOUT_MIN_ATML = 14700, /* usecs */ + TIS_TIMEOUT_MAX_ATML = 15000, /* usecs */ + }; +diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c +index eb8b733065b24d..9093f751f1336a 100644 +--- a/drivers/dma-buf/dma-resv.c ++++ b/drivers/dma-buf/dma-resv.c +@@ -313,8 +313,9 @@ void dma_resv_add_fence(struct dma_resv *obj, struct dma_fence *fence, + count++; + + dma_resv_list_set(fobj, i, fence, usage); +- /* pointer update must be visible before we extend the num_fences */ +- smp_store_mb(fobj->num_fences, count); ++ /* fence update must be visible before we extend the num_fences */ ++ smp_wmb(); ++ fobj->num_fences = count; + } + EXPORT_SYMBOL(dma_resv_add_fence); + +diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c +index 78b8a97b236376..ffe621695e472b 100644 +--- a/drivers/dma/dmatest.c ++++ b/drivers/dma/dmatest.c +@@ -827,9 +827,9 @@ static int dmatest_func(void *data) + } else { + dma_async_issue_pending(chan); + +- wait_event_timeout(thread->done_wait, +- done->done, +- msecs_to_jiffies(params->timeout)); ++ wait_event_freezable_timeout(thread->done_wait, ++ done->done, ++ msecs_to_jiffies(params->timeout)); + + status = dma_async_is_tx_complete(chan, cookie, NULL, + NULL); +diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c +index 786afb256b6e0d..92e86ae9db29d7 100644 +--- a/drivers/dma/idxd/init.c ++++ b/drivers/dma/idxd/init.c +@@ -145,6 +145,25 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd) + pci_free_irq_vectors(pdev); + } + ++static void idxd_clean_wqs(struct idxd_device *idxd) ++{ ++ struct idxd_wq *wq; ++ struct device *conf_dev; ++ int i; ++ ++ for (i = 0; i < idxd->max_wqs; i++) { ++ wq = idxd->wqs[i]; ++ if (idxd->hw.wq_cap.op_config) ++ bitmap_free(wq->opcap_bmap); ++ kfree(wq->wqcfg); ++ conf_dev = wq_confdev(wq); ++ put_device(conf_dev); ++ kfree(wq); ++ } ++ bitmap_free(idxd->wq_enable_map); ++ kfree(idxd->wqs); ++} ++ + static int idxd_setup_wqs(struct idxd_device *idxd) + { + struct device *dev = &idxd->pdev->dev; +@@ -159,8 +178,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + + idxd->wq_enable_map = bitmap_zalloc_node(idxd->max_wqs, GFP_KERNEL, dev_to_node(dev)); + if (!idxd->wq_enable_map) { +- kfree(idxd->wqs); +- return -ENOMEM; ++ rc = -ENOMEM; ++ goto err_bitmap; + } + + for (i = 0; i < idxd->max_wqs; i++) { +@@ -179,10 +198,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + conf_dev->bus = &dsa_bus_type; + conf_dev->type = &idxd_wq_device_type; + rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id); +- if (rc < 0) { +- put_device(conf_dev); ++ if (rc < 0) + goto err; +- } + + mutex_init(&wq->wq_lock); + init_waitqueue_head(&wq->err_queue); +@@ -193,7 +210,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; + wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev)); + if (!wq->wqcfg) { +- put_device(conf_dev); + rc = -ENOMEM; + goto err; + } +@@ -201,9 +217,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + if (idxd->hw.wq_cap.op_config) { + wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL); + if (!wq->opcap_bmap) { +- put_device(conf_dev); + rc = -ENOMEM; +- goto err; ++ goto err_opcap_bmap; + } + bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS); + } +@@ -214,15 +229,46 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + + return 0; + +- err: ++err_opcap_bmap: ++ kfree(wq->wqcfg); ++ ++err: ++ put_device(conf_dev); ++ kfree(wq); ++ + while (--i >= 0) { + wq = idxd->wqs[i]; ++ if (idxd->hw.wq_cap.op_config) ++ bitmap_free(wq->opcap_bmap); ++ kfree(wq->wqcfg); + conf_dev = wq_confdev(wq); + put_device(conf_dev); ++ kfree(wq); ++ + } ++ bitmap_free(idxd->wq_enable_map); ++ ++err_bitmap: ++ kfree(idxd->wqs); ++ + return rc; + } + ++static void idxd_clean_engines(struct idxd_device *idxd) ++{ ++ struct idxd_engine *engine; ++ struct device *conf_dev; ++ int i; ++ ++ for (i = 0; i < idxd->max_engines; i++) { ++ engine = idxd->engines[i]; ++ conf_dev = engine_confdev(engine); ++ put_device(conf_dev); ++ kfree(engine); ++ } ++ kfree(idxd->engines); ++} ++ + static int idxd_setup_engines(struct idxd_device *idxd) + { + struct idxd_engine *engine; +@@ -253,6 +299,7 @@ static int idxd_setup_engines(struct idxd_device *idxd) + rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id); + if (rc < 0) { + put_device(conf_dev); ++ kfree(engine); + goto err; + } + +@@ -266,10 +313,26 @@ static int idxd_setup_engines(struct idxd_device *idxd) + engine = idxd->engines[i]; + conf_dev = engine_confdev(engine); + put_device(conf_dev); ++ kfree(engine); + } ++ kfree(idxd->engines); ++ + return rc; + } + ++static void idxd_clean_groups(struct idxd_device *idxd) ++{ ++ struct idxd_group *group; ++ int i; ++ ++ for (i = 0; i < idxd->max_groups; i++) { ++ group = idxd->groups[i]; ++ put_device(group_confdev(group)); ++ kfree(group); ++ } ++ kfree(idxd->groups); ++} ++ + static int idxd_setup_groups(struct idxd_device *idxd) + { + struct device *dev = &idxd->pdev->dev; +@@ -300,6 +363,7 @@ static int idxd_setup_groups(struct idxd_device *idxd) + rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id); + if (rc < 0) { + put_device(conf_dev); ++ kfree(group); + goto err; + } + +@@ -324,20 +388,18 @@ static int idxd_setup_groups(struct idxd_device *idxd) + while (--i >= 0) { + group = idxd->groups[i]; + put_device(group_confdev(group)); ++ kfree(group); + } ++ kfree(idxd->groups); ++ + return rc; + } + + static void idxd_cleanup_internals(struct idxd_device *idxd) + { +- int i; +- +- for (i = 0; i < idxd->max_groups; i++) +- put_device(group_confdev(idxd->groups[i])); +- for (i = 0; i < idxd->max_engines; i++) +- put_device(engine_confdev(idxd->engines[i])); +- for (i = 0; i < idxd->max_wqs; i++) +- put_device(wq_confdev(idxd->wqs[i])); ++ idxd_clean_groups(idxd); ++ idxd_clean_engines(idxd); ++ idxd_clean_wqs(idxd); + destroy_workqueue(idxd->wq); + } + +@@ -380,7 +442,7 @@ static int idxd_init_evl(struct idxd_device *idxd) + static int idxd_setup_internals(struct idxd_device *idxd) + { + struct device *dev = &idxd->pdev->dev; +- int rc, i; ++ int rc; + + init_waitqueue_head(&idxd->cmd_waitq); + +@@ -411,14 +473,11 @@ static int idxd_setup_internals(struct idxd_device *idxd) + err_evl: + destroy_workqueue(idxd->wq); + err_wkq_create: +- for (i = 0; i < idxd->max_groups; i++) +- put_device(group_confdev(idxd->groups[i])); ++ idxd_clean_groups(idxd); + err_group: +- for (i = 0; i < idxd->max_engines; i++) +- put_device(engine_confdev(idxd->engines[i])); ++ idxd_clean_engines(idxd); + err_engine: +- for (i = 0; i < idxd->max_wqs; i++) +- put_device(wq_confdev(idxd->wqs[i])); ++ idxd_clean_wqs(idxd); + err_wqs: + return rc; + } +@@ -518,6 +577,17 @@ static void idxd_read_caps(struct idxd_device *idxd) + idxd->hw.iaa_cap.bits = ioread64(idxd->reg_base + IDXD_IAACAP_OFFSET); + } + ++static void idxd_free(struct idxd_device *idxd) ++{ ++ if (!idxd) ++ return; ++ ++ put_device(idxd_confdev(idxd)); ++ bitmap_free(idxd->opcap_bmap); ++ ida_free(&idxd_ida, idxd->id); ++ kfree(idxd); ++} ++ + static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_data *data) + { + struct device *dev = &pdev->dev; +@@ -535,28 +605,34 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_d + idxd_dev_set_type(&idxd->idxd_dev, idxd->data->type); + idxd->id = ida_alloc(&idxd_ida, GFP_KERNEL); + if (idxd->id < 0) +- return NULL; ++ goto err_ida; + + idxd->opcap_bmap = bitmap_zalloc_node(IDXD_MAX_OPCAP_BITS, GFP_KERNEL, dev_to_node(dev)); +- if (!idxd->opcap_bmap) { +- ida_free(&idxd_ida, idxd->id); +- return NULL; +- } ++ if (!idxd->opcap_bmap) ++ goto err_opcap; + + device_initialize(conf_dev); + conf_dev->parent = dev; + conf_dev->bus = &dsa_bus_type; + conf_dev->type = idxd->data->dev_type; + rc = dev_set_name(conf_dev, "%s%d", idxd->data->name_prefix, idxd->id); +- if (rc < 0) { +- put_device(conf_dev); +- return NULL; +- } ++ if (rc < 0) ++ goto err_name; + + spin_lock_init(&idxd->dev_lock); + spin_lock_init(&idxd->cmd_lock); + + return idxd; ++ ++err_name: ++ put_device(conf_dev); ++ bitmap_free(idxd->opcap_bmap); ++err_opcap: ++ ida_free(&idxd_ida, idxd->id); ++err_ida: ++ kfree(idxd); ++ ++ return NULL; + } + + static int idxd_enable_system_pasid(struct idxd_device *idxd) +@@ -778,7 +854,7 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + err: + pci_iounmap(pdev, idxd->reg_base); + err_iomap: +- put_device(idxd_confdev(idxd)); ++ idxd_free(idxd); + err_idxd_alloc: + pci_disable_device(pdev); + return rc; +@@ -815,7 +891,6 @@ static void idxd_shutdown(struct pci_dev *pdev) + static void idxd_remove(struct pci_dev *pdev) + { + struct idxd_device *idxd = pci_get_drvdata(pdev); +- struct idxd_irq_entry *irq_entry; + + idxd_unregister_devices(idxd); + /* +@@ -828,20 +903,12 @@ static void idxd_remove(struct pci_dev *pdev) + get_device(idxd_confdev(idxd)); + device_unregister(idxd_confdev(idxd)); + idxd_shutdown(pdev); +- if (device_pasid_enabled(idxd)) +- idxd_disable_system_pasid(idxd); + idxd_device_remove_debugfs(idxd); +- +- irq_entry = idxd_get_ie(idxd, 0); +- free_irq(irq_entry->vector, irq_entry); +- pci_free_irq_vectors(pdev); ++ idxd_cleanup(idxd); + pci_iounmap(pdev, idxd->reg_base); +- if (device_user_pasid_enabled(idxd)) +- idxd_disable_sva(pdev); +- pci_disable_device(pdev); +- destroy_workqueue(idxd->wq); +- perfmon_pmu_remove(idxd); + put_device(idxd_confdev(idxd)); ++ idxd_free(idxd); ++ pci_disable_device(pdev); + } + + static struct pci_driver idxd_pci_driver = { +diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c +index 02a1ab04f498e5..418e1774af1e5e 100644 +--- a/drivers/dma/ti/k3-udma.c ++++ b/drivers/dma/ti/k3-udma.c +@@ -1091,8 +1091,11 @@ static void udma_check_tx_completion(struct work_struct *work) + u32 residue_diff; + ktime_t time_diff; + unsigned long delay; ++ unsigned long flags; + + while (1) { ++ spin_lock_irqsave(&uc->vc.lock, flags); ++ + if (uc->desc) { + /* Get previous residue and time stamp */ + residue_diff = uc->tx_drain.residue; +@@ -1127,6 +1130,8 @@ static void udma_check_tx_completion(struct work_struct *work) + break; + } + ++ spin_unlock_irqrestore(&uc->vc.lock, flags); ++ + usleep_range(ktime_to_us(delay), + ktime_to_us(delay) + 10); + continue; +@@ -1143,6 +1148,8 @@ static void udma_check_tx_completion(struct work_struct *work) + + break; + } ++ ++ spin_unlock_irqrestore(&uc->vc.lock, flags); + } + + static irqreturn_t udma_ring_irq_handler(int irq, void *data) +@@ -4214,7 +4221,6 @@ static struct dma_chan *udma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) + { + struct udma_dev *ud = ofdma->of_dma_data; +- dma_cap_mask_t mask = ud->ddev.cap_mask; + struct udma_filter_param filter_param; + struct dma_chan *chan; + +@@ -4246,7 +4252,7 @@ static struct dma_chan *udma_of_xlate(struct of_phandle_args *dma_spec, + } + } + +- chan = __dma_request_channel(&mask, udma_dma_filter_fn, &filter_param, ++ chan = __dma_request_channel(&ud->ddev.cap_mask, udma_dma_filter_fn, &filter_param, + ofdma->of_node); + if (!chan) { + dev_err(ud->dev, "get channel fail in %s.\n", __func__); +diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig +index ea0f5083ac47f1..9a41c1c91f71af 100644 +--- a/drivers/firmware/arm_scmi/Kconfig ++++ b/drivers/firmware/arm_scmi/Kconfig +@@ -55,6 +55,20 @@ config ARM_SCMI_RAW_MODE_SUPPORT_COEX + operate normally, thing which could make an SCMI test suite using the + SCMI Raw mode support unreliable. If unsure, say N. + ++config ARM_SCMI_DEBUG_COUNTERS ++ bool "Enable SCMI communication debug metrics tracking" ++ select ARM_SCMI_NEED_DEBUGFS ++ depends on DEBUG_FS ++ default n ++ help ++ Enables tracking of some key communication metrics for debug ++ purposes. It may track metrics like how many messages were sent ++ or received, were there any failures, what kind of failures, ..etc. ++ ++ Enable this option to create a new debugfs directory which contains ++ such useful debug counters. This can be helpful for debugging and ++ SCMI monitoring. ++ + config ARM_SCMI_HAVE_TRANSPORT + bool + help +diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h +index 039f686f4580d1..6c223487121544 100644 +--- a/drivers/firmware/arm_scmi/common.h ++++ b/drivers/firmware/arm_scmi/common.h +@@ -303,6 +303,41 @@ extern const struct scmi_desc scmi_optee_desc; + + void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); + ++enum debug_counters { ++ SENT_OK, ++ SENT_FAIL, ++ SENT_FAIL_POLLING_UNSUPPORTED, ++ SENT_FAIL_CHANNEL_NOT_FOUND, ++ RESPONSE_OK, ++ NOTIFICATION_OK, ++ DELAYED_RESPONSE_OK, ++ XFERS_RESPONSE_TIMEOUT, ++ XFERS_RESPONSE_POLLED_TIMEOUT, ++ RESPONSE_POLLED_OK, ++ ERR_MSG_UNEXPECTED, ++ ERR_MSG_INVALID, ++ ERR_MSG_NOMEM, ++ ERR_PROTOCOL, ++ SCMI_DEBUG_COUNTERS_LAST ++}; ++ ++static inline void scmi_inc_count(atomic_t *arr, int stat) ++{ ++ if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) ++ atomic_inc(&arr[stat]); ++} ++ ++enum scmi_bad_msg { ++ MSG_UNEXPECTED = -1, ++ MSG_INVALID = -2, ++ MSG_UNKNOWN = -3, ++ MSG_NOMEM = -4, ++ MSG_MBOX_SPURIOUS = -5, ++}; ++ ++void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, ++ enum scmi_bad_msg err); ++ + /* shmem related declarations */ + struct scmi_shared_mem; + +diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c +index efa9698c876a09..65d1e66a347d75 100644 +--- a/drivers/firmware/arm_scmi/driver.c ++++ b/drivers/firmware/arm_scmi/driver.c +@@ -108,12 +108,14 @@ struct scmi_protocol_instance { + * @name: Name of this SCMI instance + * @type: Type of this SCMI instance + * @is_atomic: Flag to state if the transport of this instance is atomic ++ * @counters: An array of atomic_c's used for tracking statistics (if enabled) + */ + struct scmi_debug_info { + struct dentry *top_dentry; + const char *name; + const char *type; + bool is_atomic; ++ atomic_t counters[SCMI_DEBUG_COUNTERS_LAST]; + }; + + /** +@@ -687,6 +689,45 @@ scmi_xfer_lookup_unlocked(struct scmi_xfers_info *minfo, u16 xfer_id) + return xfer ?: ERR_PTR(-EINVAL); + } + ++/** ++ * scmi_bad_message_trace - A helper to trace weird messages ++ * ++ * @cinfo: A reference to the channel descriptor on which the message was ++ * received ++ * @msg_hdr: Message header to track ++ * @err: A specific error code used as a status value in traces. ++ * ++ * This helper can be used to trace any kind of weird, incomplete, unexpected, ++ * timed-out message that arrives and as such, can be traced only referring to ++ * the header content, since the payload is missing/unreliable. ++ */ ++void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, ++ enum scmi_bad_msg err) ++{ ++ char *tag; ++ struct scmi_info *info = handle_to_scmi_info(cinfo->handle); ++ ++ switch (MSG_XTRACT_TYPE(msg_hdr)) { ++ case MSG_TYPE_COMMAND: ++ tag = "!RESP"; ++ break; ++ case MSG_TYPE_DELAYED_RESP: ++ tag = "!DLYD"; ++ break; ++ case MSG_TYPE_NOTIFICATION: ++ tag = "!NOTI"; ++ break; ++ default: ++ tag = "!UNKN"; ++ break; ++ } ++ ++ trace_scmi_msg_dump(info->id, cinfo->id, ++ MSG_XTRACT_PROT_ID(msg_hdr), ++ MSG_XTRACT_ID(msg_hdr), tag, ++ MSG_XTRACT_TOKEN(msg_hdr), err, NULL, 0); ++} ++ + /** + * scmi_msg_response_validate - Validate message type against state of related + * xfer +@@ -813,6 +854,10 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) + "Message for %d type %d is not expected!\n", + xfer_id, msg_type); + spin_unlock_irqrestore(&minfo->xfer_lock, flags); ++ ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNEXPECTED); ++ scmi_inc_count(info->dbg->counters, ERR_MSG_UNEXPECTED); ++ + return xfer; + } + refcount_inc(&xfer->users); +@@ -837,6 +882,11 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) + dev_err(cinfo->dev, + "Invalid message type:%d for %d - HDR:0x%X state:%d\n", + msg_type, xfer_id, msg_hdr, xfer->state); ++ ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_INVALID); ++ scmi_inc_count(info->dbg->counters, ERR_MSG_INVALID); ++ ++ + /* On error the refcount incremented above has to be dropped */ + __scmi_xfer_put(minfo, xfer); + xfer = ERR_PTR(-EINVAL); +@@ -878,6 +928,10 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, + if (IS_ERR(xfer)) { + dev_err(dev, "failed to get free message slot (%ld)\n", + PTR_ERR(xfer)); ++ ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_NOMEM); ++ scmi_inc_count(info->dbg->counters, ERR_MSG_NOMEM); ++ + scmi_clear_channel(info, cinfo); + return; + } +@@ -892,6 +946,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, + trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, + xfer->hdr.id, "NOTI", xfer->hdr.seq, + xfer->hdr.status, xfer->rx.buf, xfer->rx.len); ++ scmi_inc_count(info->dbg->counters, NOTIFICATION_OK); + + scmi_notify(cinfo->handle, xfer->hdr.protocol_id, + xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts); +@@ -951,8 +1006,10 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo, + if (xfer->hdr.type == MSG_TYPE_DELAYED_RESP) { + scmi_clear_channel(info, cinfo); + complete(xfer->async_done); ++ scmi_inc_count(info->dbg->counters, DELAYED_RESPONSE_OK); + } else { + complete(&xfer->done); ++ scmi_inc_count(info->dbg->counters, RESPONSE_OK); + } + + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { +@@ -997,6 +1054,7 @@ void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv) + break; + default: + WARN_ONCE(1, "received unknown msg_type:%d\n", msg_type); ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNKNOWN); + break; + } + } +@@ -1017,7 +1075,8 @@ static void xfer_put(const struct scmi_protocol_handle *ph, + } + + static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, +- struct scmi_xfer *xfer, ktime_t stop) ++ struct scmi_xfer *xfer, ktime_t stop, ++ bool *ooo) + { + struct scmi_info *info = handle_to_scmi_info(cinfo->handle); + +@@ -1026,7 +1085,7 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, + * in case of out-of-order receptions of delayed responses + */ + return info->desc->ops->poll_done(cinfo, xfer) || +- try_wait_for_completion(&xfer->done) || ++ (*ooo = try_wait_for_completion(&xfer->done)) || + ktime_after(ktime_get(), stop); + } + +@@ -1035,6 +1094,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + struct scmi_xfer *xfer, unsigned int timeout_ms) + { + int ret = 0; ++ struct scmi_info *info = handle_to_scmi_info(cinfo->handle); + + if (xfer->hdr.poll_completion) { + /* +@@ -1042,26 +1102,27 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + * itself to support synchronous commands replies. + */ + if (!desc->sync_cmds_completed_on_ret) { ++ bool ooo = false; ++ + /* + * Poll on xfer using transport provided .poll_done(); + * assumes no completion interrupt was available. + */ + ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms); + +- spin_until_cond(scmi_xfer_done_no_timeout(cinfo, +- xfer, stop)); +- if (ktime_after(ktime_get(), stop)) { ++ spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer, ++ stop, &ooo)); ++ if (!ooo && !info->desc->ops->poll_done(cinfo, xfer)) { + dev_err(dev, + "timed out in resp(caller: %pS) - polling\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; ++ scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_POLLED_TIMEOUT); + } + } + + if (!ret) { + unsigned long flags; +- struct scmi_info *info = +- handle_to_scmi_info(cinfo->handle); + + /* + * Do not fetch_response if an out-of-order delayed +@@ -1081,6 +1142,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + "RESP" : "resp", + xfer->hdr.seq, xfer->hdr.status, + xfer->rx.buf, xfer->rx.len); ++ scmi_inc_count(info->dbg->counters, RESPONSE_POLLED_OK); + + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { + struct scmi_info *info = +@@ -1098,6 +1160,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + dev_err(dev, "timed out in resp(caller: %pS)\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; ++ scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_TIMEOUT); + } + } + +@@ -1181,13 +1244,15 @@ static int do_xfer(const struct scmi_protocol_handle *ph, + !is_transport_polling_capable(info->desc)) { + dev_warn_once(dev, + "Polling mode is not supported by transport.\n"); ++ scmi_inc_count(info->dbg->counters, SENT_FAIL_POLLING_UNSUPPORTED); + return -EINVAL; + } + + cinfo = idr_find(&info->tx_idr, pi->proto->id); +- if (unlikely(!cinfo)) ++ if (unlikely(!cinfo)) { ++ scmi_inc_count(info->dbg->counters, SENT_FAIL_CHANNEL_NOT_FOUND); + return -EINVAL; +- ++ } + /* True ONLY if also supported by transport. */ + if (is_polling_enabled(cinfo, info->desc)) + xfer->hdr.poll_completion = true; +@@ -1219,16 +1284,20 @@ static int do_xfer(const struct scmi_protocol_handle *ph, + ret = info->desc->ops->send_message(cinfo, xfer); + if (ret < 0) { + dev_dbg(dev, "Failed to send message %d\n", ret); ++ scmi_inc_count(info->dbg->counters, SENT_FAIL); + return ret; + } + + trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, + xfer->hdr.id, "CMND", xfer->hdr.seq, + xfer->hdr.status, xfer->tx.buf, xfer->tx.len); ++ scmi_inc_count(info->dbg->counters, SENT_OK); + + ret = scmi_wait_for_message_response(cinfo, xfer); +- if (!ret && xfer->hdr.status) ++ if (!ret && xfer->hdr.status) { + ret = scmi_to_linux_errno(xfer->hdr.status); ++ scmi_inc_count(info->dbg->counters, ERR_PROTOCOL); ++ } + + if (info->desc->ops->mark_txdone) + info->desc->ops->mark_txdone(cinfo, ret, xfer); +diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c +index 8e513f70b75d4c..f1d5e3fba35e07 100644 +--- a/drivers/firmware/arm_scmi/mailbox.c ++++ b/drivers/firmware/arm_scmi/mailbox.c +@@ -58,6 +58,9 @@ static void rx_callback(struct mbox_client *cl, void *m) + */ + if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { + dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); ++ scmi_bad_message_trace(smbox->cinfo, ++ shmem_read_header(smbox->shmem), ++ MSG_MBOX_SPURIOUS); + return; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index d59e8536192ca9..c5d706a4c7b4a7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -788,6 +788,7 @@ struct amdgpu_device { + bool need_swiotlb; + bool accel_working; + struct notifier_block acpi_nb; ++ struct notifier_block pm_nb; + struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS]; + struct debugfs_blob_wrapper debugfs_vbios_blob; + struct debugfs_blob_wrapper debugfs_discovery_blob; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 10f5a3d0f59163..f8058dd5356a13 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -141,6 +141,10 @@ const char *amdgpu_asic_name[] = { + "LAST", + }; + ++static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev); ++static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode, ++ void *data); ++ + /** + * DOC: pcie_replay_count + * +@@ -3920,6 +3924,11 @@ int amdgpu_device_init(struct amdgpu_device *adev, + + amdgpu_device_check_iommu_direct_map(adev); + ++ adev->pm_nb.notifier_call = amdgpu_device_pm_notifier; ++ r = register_pm_notifier(&adev->pm_nb); ++ if (r) ++ goto failed; ++ + return 0; + + release_ras_con: +@@ -3981,6 +3990,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) + flush_delayed_work(&adev->delayed_init_work); + adev->shutdown = true; + ++ unregister_pm_notifier(&adev->pm_nb); ++ + /* make sure IB test finished before entering exclusive mode + * to avoid preemption on IB test + */ +@@ -4107,6 +4118,33 @@ static int amdgpu_device_evict_resources(struct amdgpu_device *adev) + /* + * Suspend & resume. + */ ++/** ++ * amdgpu_device_pm_notifier - Notification block for Suspend/Hibernate events ++ * @nb: notifier block ++ * @mode: suspend mode ++ * @data: data ++ * ++ * This function is called when the system is about to suspend or hibernate. ++ * It is used to set the appropriate flags so that eviction can be optimized ++ * in the pm prepare callback. ++ */ ++static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode, ++ void *data) ++{ ++ struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, pm_nb); ++ ++ switch (mode) { ++ case PM_HIBERNATION_PREPARE: ++ adev->in_s4 = true; ++ break; ++ case PM_POST_HIBERNATION: ++ adev->in_s4 = false; ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++ + /** + * amdgpu_device_prepare - prepare for device suspend + * +@@ -4551,6 +4589,8 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, + retry: + amdgpu_amdkfd_pre_reset(adev); + ++ amdgpu_device_stop_pending_resets(adev); ++ + if (from_hypervisor) + r = amdgpu_virt_request_full_gpu(adev, true); + else +@@ -5347,11 +5387,12 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, + tmp_adev->asic_reset_res = r; + } + +- /* +- * Drop all pending non scheduler resets. Scheduler resets +- * were already dropped during drm_sched_stop +- */ +- amdgpu_device_stop_pending_resets(tmp_adev); ++ if (!amdgpu_sriov_vf(tmp_adev)) ++ /* ++ * Drop all pending non scheduler resets. Scheduler resets ++ * were already dropped during drm_sched_stop ++ */ ++ amdgpu_device_stop_pending_resets(tmp_adev); + } + + /* Actual ASIC resets if needed.*/ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index bacf2e5de2abce..940411f8e99be0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -2463,7 +2463,6 @@ static int amdgpu_pmops_freeze(struct device *dev) + struct amdgpu_device *adev = drm_to_adev(drm_dev); + int r; + +- adev->in_s4 = true; + r = amdgpu_device_suspend(drm_dev, true); + if (r) + return r; +@@ -2476,13 +2475,8 @@ static int amdgpu_pmops_freeze(struct device *dev) + static int amdgpu_pmops_thaw(struct device *dev) + { + struct drm_device *drm_dev = dev_get_drvdata(dev); +- struct amdgpu_device *adev = drm_to_adev(drm_dev); +- int r; +- +- r = amdgpu_device_resume(drm_dev, true); +- adev->in_s4 = false; + +- return r; ++ return amdgpu_device_resume(drm_dev, true); + } + + static int amdgpu_pmops_poweroff(struct device *dev) +@@ -2495,9 +2489,6 @@ static int amdgpu_pmops_poweroff(struct device *dev) + static int amdgpu_pmops_restore(struct device *dev) + { + struct drm_device *drm_dev = dev_get_drvdata(dev); +- struct amdgpu_device *adev = drm_to_adev(drm_dev); +- +- adev->in_s4 = false; + + return amdgpu_device_resume(drm_dev, true); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +index 22575422ca7ec1..7cb4b4118335a6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +@@ -32,6 +32,7 @@ + + #include "amdgpu.h" + #include "amdgpu_ras.h" ++#include "amdgpu_reset.h" + #include "vi.h" + #include "soc15.h" + #include "nv.h" +@@ -468,7 +469,7 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + return -EINVAL; + + if (pf2vf_info->size > 1024) { +- DRM_ERROR("invalid pf2vf message size\n"); ++ dev_err(adev->dev, "invalid pf2vf message size: 0x%x\n", pf2vf_info->size); + return -EINVAL; + } + +@@ -479,7 +480,9 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + adev->virt.fw_reserve.p_pf2vf, pf2vf_info->size, + adev->virt.fw_reserve.checksum_key, checksum); + if (checksum != checkval) { +- DRM_ERROR("invalid pf2vf message\n"); ++ dev_err(adev->dev, ++ "invalid pf2vf message: header checksum=0x%x calculated checksum=0x%x\n", ++ checksum, checkval); + return -EINVAL; + } + +@@ -493,7 +496,9 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + adev->virt.fw_reserve.p_pf2vf, pf2vf_info->size, + 0, checksum); + if (checksum != checkval) { +- DRM_ERROR("invalid pf2vf message\n"); ++ dev_err(adev->dev, ++ "invalid pf2vf message: header checksum=0x%x calculated checksum=0x%x\n", ++ checksum, checkval); + return -EINVAL; + } + +@@ -529,7 +534,7 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->uuid; + break; + default: +- DRM_ERROR("invalid pf2vf version\n"); ++ dev_err(adev->dev, "invalid pf2vf version: 0x%x\n", pf2vf_info->version); + return -EINVAL; + } + +@@ -628,8 +633,21 @@ static void amdgpu_virt_update_vf2pf_work_item(struct work_struct *work) + int ret; + + ret = amdgpu_virt_read_pf2vf_data(adev); +- if (ret) ++ if (ret) { ++ adev->virt.vf2pf_update_retry_cnt++; ++ if ((adev->virt.vf2pf_update_retry_cnt >= AMDGPU_VF2PF_UPDATE_MAX_RETRY_LIMIT) && ++ amdgpu_sriov_runtime(adev) && !amdgpu_in_reset(adev)) { ++ if (amdgpu_reset_domain_schedule(adev->reset_domain, ++ &adev->virt.flr_work)) ++ return; ++ else ++ dev_err(adev->dev, "Failed to queue work! at %s", __func__); ++ } ++ + goto out; ++ } ++ ++ adev->virt.vf2pf_update_retry_cnt = 0; + amdgpu_virt_write_vf2pf_data(adev); + + out: +@@ -650,6 +668,7 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) + adev->virt.fw_reserve.p_pf2vf = NULL; + adev->virt.fw_reserve.p_vf2pf = NULL; + adev->virt.vf2pf_update_interval_ms = 0; ++ adev->virt.vf2pf_update_retry_cnt = 0; + + if (adev->mman.fw_vram_usage_va && adev->mman.drv_vram_usage_va) { + DRM_WARN("Currently fw_vram and drv_vram should not have values at the same time!"); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +index 23b6efa9d25df8..891713757a8f5a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +@@ -51,6 +51,8 @@ + /* tonga/fiji use this offset */ + #define mmBIF_IOV_FUNC_IDENTIFIER 0x1503 + ++#define AMDGPU_VF2PF_UPDATE_MAX_RETRY_LIMIT 30 ++ + enum amdgpu_sriov_vf_mode { + SRIOV_VF_MODE_BARE_METAL = 0, + SRIOV_VF_MODE_ONE_VF, +@@ -253,6 +255,7 @@ struct amdgpu_virt { + /* vf2pf message */ + struct delayed_work vf2pf_work; + uint32_t vf2pf_update_interval_ms; ++ int vf2pf_update_retry_cnt; + + /* multimedia bandwidth config */ + bool is_mm_bw_enabled; +diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +index 63725b2ebc0373..37ac6d8ff81362 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c ++++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +@@ -276,6 +276,8 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work) + timeout -= 10; + } while (timeout > 1); + ++ dev_warn(adev->dev, "waiting IDH_FLR_NOTIFICATION_CMPL timeout\n"); ++ + flr_done: + atomic_set(&adev->reset_domain->in_gpu_reset, 0); + up_write(&adev->reset_domain->sem); +diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +index 6a68ee946f1cc3..96edd5d11326dd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c ++++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +@@ -298,6 +298,8 @@ static void xgpu_nv_mailbox_flr_work(struct work_struct *work) + timeout -= 10; + } while (timeout > 1); + ++ dev_warn(adev->dev, "waiting IDH_FLR_NOTIFICATION_CMPL timeout\n"); ++ + flr_done: + atomic_set(&adev->reset_domain->in_gpu_reset, 0); + up_write(&adev->reset_domain->sem); +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index f6017be8f9957e..bcf0dc05c76765 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -11069,7 +11069,8 @@ int amdgpu_dm_process_dmub_aux_transfer_sync( + /* The reply is stored in the top nibble of the command. */ + payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF; + +- if (!payload->write && p_notify->aux_reply.length) ++ /*write req may receive a byte indicating partially written number as well*/ ++ if (p_notify->aux_reply.length) + memcpy(payload->data, p_notify->aux_reply.data, + p_notify->aux_reply.length); + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index c0cacd501c83eb..2698e5c74ddfda 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -59,6 +59,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + enum aux_return_code_type operation_result; + struct amdgpu_device *adev; + struct ddc_service *ddc; ++ uint8_t copy[16]; + + if (WARN_ON(msg->size > 16)) + return -E2BIG; +@@ -74,6 +75,11 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + (msg->request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0; + payload.defer_delay = 0; + ++ if (payload.write) { ++ memcpy(copy, msg->buffer, msg->size); ++ payload.data = copy; ++ } ++ + result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, + &operation_result); + +@@ -97,9 +103,9 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + */ + if (payload.write && result >= 0) { + if (result) { +- /*one byte indicating partially written bytes. Force 0 to retry*/ +- drm_info(adev_to_drm(adev), "amdgpu: AUX partially written\n"); +- result = 0; ++ /*one byte indicating partially written bytes*/ ++ drm_dbg_dp(adev_to_drm(adev), "amdgpu: AUX partially written\n"); ++ result = payload.data[0]; + } else if (!payload.reply[0]) + /*I2C_ACK|AUX_ACK*/ + result = msg->size; +@@ -124,11 +130,11 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + break; + } + +- drm_info(adev_to_drm(adev), "amdgpu: DP AUX transfer fail:%d\n", operation_result); ++ drm_dbg_dp(adev_to_drm(adev), "amdgpu: DP AUX transfer fail:%d\n", operation_result); + } + + if (payload.reply[0]) +- drm_info(adev_to_drm(adev), "amdgpu: AUX reply command not ACK: 0x%02x.", ++ drm_dbg_dp(adev_to_drm(adev), "amdgpu: AUX reply command not ACK: 0x%02x.", + payload.reply[0]); + + return result; +diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c +index 3b81468a1df297..0bf70664c35ee1 100644 +--- a/drivers/hid/hid-thrustmaster.c ++++ b/drivers/hid/hid-thrustmaster.c +@@ -174,6 +174,7 @@ static void thrustmaster_interrupts(struct hid_device *hdev) + u8 ep_addr[2] = {b_ep, 0}; + + if (!usb_check_int_endpoints(usbif, ep_addr)) { ++ kfree(send_buf); + hid_err(hdev, "Unexpected non-int endpoint\n"); + return; + } +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index ad74cbc9a0aa59..45de01dea4b1c0 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -142,11 +142,12 @@ static int uclogic_input_configured(struct hid_device *hdev, + suffix = "System Control"; + break; + } +- } +- +- if (suffix) ++ } else { + hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s %s", hdev->name, suffix); ++ if (!hi->input->name) ++ return -ENOMEM; ++ } + + return 0; + } +diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c +index 47e1bd8de9fcf0..53026356475ac1 100644 +--- a/drivers/hv/channel.c ++++ b/drivers/hv/channel.c +@@ -1113,68 +1113,10 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, + EXPORT_SYMBOL(vmbus_sendpacket); + + /* +- * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer +- * packets using a GPADL Direct packet type. This interface allows you +- * to control notifying the host. This will be useful for sending +- * batched data. Also the sender can control the send flags +- * explicitly. +- */ +-int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, +- struct hv_page_buffer pagebuffers[], +- u32 pagecount, void *buffer, u32 bufferlen, +- u64 requestid) +-{ +- int i; +- struct vmbus_channel_packet_page_buffer desc; +- u32 descsize; +- u32 packetlen; +- u32 packetlen_aligned; +- struct kvec bufferlist[3]; +- u64 aligned_data = 0; +- +- if (pagecount > MAX_PAGE_BUFFER_COUNT) +- return -EINVAL; +- +- /* +- * Adjust the size down since vmbus_channel_packet_page_buffer is the +- * largest size we support +- */ +- descsize = sizeof(struct vmbus_channel_packet_page_buffer) - +- ((MAX_PAGE_BUFFER_COUNT - pagecount) * +- sizeof(struct hv_page_buffer)); +- packetlen = descsize + bufferlen; +- packetlen_aligned = ALIGN(packetlen, sizeof(u64)); +- +- /* Setup the descriptor */ +- desc.type = VM_PKT_DATA_USING_GPA_DIRECT; +- desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; +- desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ +- desc.length8 = (u16)(packetlen_aligned >> 3); +- desc.transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */ +- desc.reserved = 0; +- desc.rangecount = pagecount; +- +- for (i = 0; i < pagecount; i++) { +- desc.range[i].len = pagebuffers[i].len; +- desc.range[i].offset = pagebuffers[i].offset; +- desc.range[i].pfn = pagebuffers[i].pfn; +- } +- +- bufferlist[0].iov_base = &desc; +- bufferlist[0].iov_len = descsize; +- bufferlist[1].iov_base = buffer; +- bufferlist[1].iov_len = bufferlen; +- bufferlist[2].iov_base = &aligned_data; +- bufferlist[2].iov_len = (packetlen_aligned - packetlen); +- +- return hv_ringbuffer_write(channel, bufferlist, 3, requestid, NULL); +-} +-EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); +- +-/* +- * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet ++ * vmbus_sendpacket_mpb_desc - Send one or more multi-page buffer packets + * using a GPADL Direct packet type. +- * The buffer includes the vmbus descriptor. ++ * The desc argument must include space for the VMBus descriptor. The ++ * rangecount field must already be set. + */ + int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + struct vmbus_packet_mpb_array *desc, +@@ -1196,7 +1138,6 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + desc->length8 = (u16)(packetlen_aligned >> 3); + desc->transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */ + desc->reserved = 0; +- desc->rangecount = 1; + + bufferlist[0].iov_base = desc; + bufferlist[0].iov_len = desc_size; +diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c +index 98648c679a55c1..2ace3aafe49788 100644 +--- a/drivers/iio/adc/ad7266.c ++++ b/drivers/iio/adc/ad7266.c +@@ -44,7 +44,7 @@ struct ad7266_state { + */ + struct { + __be16 sample[2]; +- s64 timestamp; ++ aligned_s64 timestamp; + } data __aligned(IIO_DMA_MINALIGN); + }; + +diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c +index 74b0c85944bd61..967f06cd3f94e7 100644 +--- a/drivers/iio/adc/ad7768-1.c ++++ b/drivers/iio/adc/ad7768-1.c +@@ -169,7 +169,7 @@ struct ad7768_state { + union { + struct { + __be32 chan; +- s64 timestamp; ++ aligned_s64 timestamp; + } scan; + __be32 d32; + u8 d8[2]; +diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c +index 814ce0aad1cccd..4085a36cd1db75 100644 +--- a/drivers/iio/chemical/sps30.c ++++ b/drivers/iio/chemical/sps30.c +@@ -108,7 +108,7 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p) + int ret; + struct { + s32 data[4]; /* PM1, PM2P5, PM4, PM10 */ +- s64 ts; ++ aligned_s64 ts; + } scan; + + mutex_lock(&state->lock); +diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c +index fec87c9030abdc..fffd144d509eb0 100644 +--- a/drivers/infiniband/sw/rxe/rxe_cq.c ++++ b/drivers/infiniband/sw/rxe/rxe_cq.c +@@ -56,11 +56,8 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, + + err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, udata, + cq->queue->buf, cq->queue->buf_size, &cq->queue->ip); +- if (err) { +- vfree(cq->queue->buf); +- kfree(cq->queue); ++ if (err) + return err; +- } + + cq->is_user = uresp; + +diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c +index 1a367e64bc3b1d..843e50b5a0ec57 100644 +--- a/drivers/net/dsa/sja1105/sja1105_main.c ++++ b/drivers/net/dsa/sja1105/sja1105_main.c +@@ -2076,6 +2076,7 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port, + switch (state) { + case BR_STATE_DISABLED: + case BR_STATE_BLOCKING: ++ case BR_STATE_LISTENING: + /* From UM10944 description of DRPDTAG (why put this there?): + * "Management traffic flows to the port regardless of the state + * of the INGRESS flag". So BPDUs are still be allowed to pass. +@@ -2085,11 +2086,6 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port, + mac[port].egress = false; + mac[port].dyn_learn = false; + break; +- case BR_STATE_LISTENING: +- mac[port].ingress = true; +- mac[port].egress = false; +- mac[port].dyn_learn = false; +- break; + case BR_STATE_LEARNING: + mac[port].ingress = true; + mac[port].egress = false; +diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c +index 4325d0ace1f268..6f45f4d9fba71f 100644 +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -1016,22 +1016,15 @@ static void macb_update_stats(struct macb *bp) + + static int macb_halt_tx(struct macb *bp) + { +- unsigned long halt_time, timeout; +- u32 status; ++ u32 status; + + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT)); + +- timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT); +- do { +- halt_time = jiffies; +- status = macb_readl(bp, TSR); +- if (!(status & MACB_BIT(TGO))) +- return 0; +- +- udelay(250); +- } while (time_before(halt_time, timeout)); +- +- return -ETIMEDOUT; ++ /* Poll TSR until TGO is cleared or timeout. */ ++ return read_poll_timeout_atomic(macb_readl, status, ++ !(status & MACB_BIT(TGO)), ++ 250, MACB_HALT_TIMEOUT, false, ++ bp, TSR); + } + + static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budget) +diff --git a/drivers/net/ethernet/engleder/tsnep_hw.h b/drivers/net/ethernet/engleder/tsnep_hw.h +index 55e1caf193a69d..64c97eb66f6715 100644 +--- a/drivers/net/ethernet/engleder/tsnep_hw.h ++++ b/drivers/net/ethernet/engleder/tsnep_hw.h +@@ -181,6 +181,8 @@ struct tsnep_gcl_operation { + #define TSNEP_DESC_SIZE 256 + #define TSNEP_DESC_SIZE_DATA_AFTER 2048 + #define TSNEP_DESC_OFFSET 128 ++#define TSNEP_DESC_SIZE_DATA_AFTER_INLINE (64 - sizeof(struct tsnep_tx_desc) + \ ++ sizeof_field(struct tsnep_tx_desc, tx)) + #define TSNEP_DESC_OWNER_COUNTER_MASK 0xC0000000 + #define TSNEP_DESC_OWNER_COUNTER_SHIFT 30 + #define TSNEP_DESC_LENGTH_MASK 0x00003FFF +diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c +index 4f36b29d66c860..215ae6745932ae 100644 +--- a/drivers/net/ethernet/engleder/tsnep_main.c ++++ b/drivers/net/ethernet/engleder/tsnep_main.c +@@ -51,12 +51,24 @@ + #define TSNEP_COALESCE_USECS_MAX ((ECM_INT_DELAY_MASK >> ECM_INT_DELAY_SHIFT) * \ + ECM_INT_DELAY_BASE_US + ECM_INT_DELAY_BASE_US - 1) + +-#define TSNEP_TX_TYPE_SKB BIT(0) +-#define TSNEP_TX_TYPE_SKB_FRAG BIT(1) +-#define TSNEP_TX_TYPE_XDP_TX BIT(2) +-#define TSNEP_TX_TYPE_XDP_NDO BIT(3) +-#define TSNEP_TX_TYPE_XDP (TSNEP_TX_TYPE_XDP_TX | TSNEP_TX_TYPE_XDP_NDO) +-#define TSNEP_TX_TYPE_XSK BIT(4) ++/* mapping type */ ++#define TSNEP_TX_TYPE_MAP BIT(0) ++#define TSNEP_TX_TYPE_MAP_PAGE BIT(1) ++#define TSNEP_TX_TYPE_INLINE BIT(2) ++/* buffer type */ ++#define TSNEP_TX_TYPE_SKB BIT(8) ++#define TSNEP_TX_TYPE_SKB_MAP (TSNEP_TX_TYPE_SKB | TSNEP_TX_TYPE_MAP) ++#define TSNEP_TX_TYPE_SKB_INLINE (TSNEP_TX_TYPE_SKB | TSNEP_TX_TYPE_INLINE) ++#define TSNEP_TX_TYPE_SKB_FRAG BIT(9) ++#define TSNEP_TX_TYPE_SKB_FRAG_MAP_PAGE (TSNEP_TX_TYPE_SKB_FRAG | TSNEP_TX_TYPE_MAP_PAGE) ++#define TSNEP_TX_TYPE_SKB_FRAG_INLINE (TSNEP_TX_TYPE_SKB_FRAG | TSNEP_TX_TYPE_INLINE) ++#define TSNEP_TX_TYPE_XDP_TX BIT(10) ++#define TSNEP_TX_TYPE_XDP_NDO BIT(11) ++#define TSNEP_TX_TYPE_XDP_NDO_MAP_PAGE (TSNEP_TX_TYPE_XDP_NDO | TSNEP_TX_TYPE_MAP_PAGE) ++#define TSNEP_TX_TYPE_XDP (TSNEP_TX_TYPE_XDP_TX | TSNEP_TX_TYPE_XDP_NDO) ++#define TSNEP_TX_TYPE_XSK BIT(12) ++#define TSNEP_TX_TYPE_TSTAMP BIT(13) ++#define TSNEP_TX_TYPE_SKB_TSTAMP (TSNEP_TX_TYPE_SKB | TSNEP_TX_TYPE_TSTAMP) + + #define TSNEP_XDP_TX BIT(0) + #define TSNEP_XDP_REDIRECT BIT(1) +@@ -375,8 +387,7 @@ static void tsnep_tx_activate(struct tsnep_tx *tx, int index, int length, + if (entry->skb) { + entry->properties = length & TSNEP_DESC_LENGTH_MASK; + entry->properties |= TSNEP_DESC_INTERRUPT_FLAG; +- if ((entry->type & TSNEP_TX_TYPE_SKB) && +- (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS)) ++ if ((entry->type & TSNEP_TX_TYPE_SKB_TSTAMP) == TSNEP_TX_TYPE_SKB_TSTAMP) + entry->properties |= TSNEP_DESC_EXTENDED_WRITEBACK_FLAG; + + /* toggle user flag to prevent false acknowledge +@@ -416,6 +427,8 @@ static void tsnep_tx_activate(struct tsnep_tx *tx, int index, int length, + entry->properties |= TSNEP_TX_DESC_OWNER_USER_FLAG; + entry->desc->more_properties = + __cpu_to_le32(entry->len & TSNEP_DESC_LENGTH_MASK); ++ if (entry->type & TSNEP_TX_TYPE_INLINE) ++ entry->properties |= TSNEP_TX_DESC_DATA_AFTER_DESC_FLAG; + + /* descriptor properties shall be written last, because valid data is + * signaled there +@@ -433,39 +446,83 @@ static int tsnep_tx_desc_available(struct tsnep_tx *tx) + return tx->read - tx->write - 1; + } + +-static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count) ++static int tsnep_tx_map_frag(skb_frag_t *frag, struct tsnep_tx_entry *entry, ++ struct device *dmadev, dma_addr_t *dma) ++{ ++ unsigned int len; ++ int mapped; ++ ++ len = skb_frag_size(frag); ++ if (likely(len > TSNEP_DESC_SIZE_DATA_AFTER_INLINE)) { ++ *dma = skb_frag_dma_map(dmadev, frag, 0, len, DMA_TO_DEVICE); ++ if (dma_mapping_error(dmadev, *dma)) ++ return -ENOMEM; ++ entry->type = TSNEP_TX_TYPE_SKB_FRAG_MAP_PAGE; ++ mapped = 1; ++ } else { ++ void *fragdata = skb_frag_address_safe(frag); ++ ++ if (likely(fragdata)) { ++ memcpy(&entry->desc->tx, fragdata, len); ++ } else { ++ struct page *page = skb_frag_page(frag); ++ ++ fragdata = kmap_local_page(page); ++ memcpy(&entry->desc->tx, fragdata + skb_frag_off(frag), ++ len); ++ kunmap_local(fragdata); ++ } ++ entry->type = TSNEP_TX_TYPE_SKB_FRAG_INLINE; ++ mapped = 0; ++ } ++ ++ return mapped; ++} ++ ++static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count, ++ bool do_tstamp) + { + struct device *dmadev = tx->adapter->dmadev; + struct tsnep_tx_entry *entry; + unsigned int len; +- dma_addr_t dma; + int map_len = 0; +- int i; ++ dma_addr_t dma; ++ int i, mapped; + + for (i = 0; i < count; i++) { + entry = &tx->entry[(tx->write + i) & TSNEP_RING_MASK]; + + if (!i) { + len = skb_headlen(skb); +- dma = dma_map_single(dmadev, skb->data, len, +- DMA_TO_DEVICE); ++ if (likely(len > TSNEP_DESC_SIZE_DATA_AFTER_INLINE)) { ++ dma = dma_map_single(dmadev, skb->data, len, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dmadev, dma)) ++ return -ENOMEM; ++ entry->type = TSNEP_TX_TYPE_SKB_MAP; ++ mapped = 1; ++ } else { ++ memcpy(&entry->desc->tx, skb->data, len); ++ entry->type = TSNEP_TX_TYPE_SKB_INLINE; ++ mapped = 0; ++ } + +- entry->type = TSNEP_TX_TYPE_SKB; ++ if (do_tstamp) ++ entry->type |= TSNEP_TX_TYPE_TSTAMP; + } else { +- len = skb_frag_size(&skb_shinfo(skb)->frags[i - 1]); +- dma = skb_frag_dma_map(dmadev, +- &skb_shinfo(skb)->frags[i - 1], +- 0, len, DMA_TO_DEVICE); ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; + +- entry->type = TSNEP_TX_TYPE_SKB_FRAG; ++ len = skb_frag_size(frag); ++ mapped = tsnep_tx_map_frag(frag, entry, dmadev, &dma); ++ if (mapped < 0) ++ return mapped; + } +- if (dma_mapping_error(dmadev, dma)) +- return -ENOMEM; + + entry->len = len; +- dma_unmap_addr_set(entry, dma, dma); +- +- entry->desc->tx = __cpu_to_le64(dma); ++ if (likely(mapped)) { ++ dma_unmap_addr_set(entry, dma, dma); ++ entry->desc->tx = __cpu_to_le64(dma); ++ } + + map_len += len; + } +@@ -484,13 +541,12 @@ static int tsnep_tx_unmap(struct tsnep_tx *tx, int index, int count) + entry = &tx->entry[(index + i) & TSNEP_RING_MASK]; + + if (entry->len) { +- if (entry->type & TSNEP_TX_TYPE_SKB) ++ if (entry->type & TSNEP_TX_TYPE_MAP) + dma_unmap_single(dmadev, + dma_unmap_addr(entry, dma), + dma_unmap_len(entry, len), + DMA_TO_DEVICE); +- else if (entry->type & +- (TSNEP_TX_TYPE_SKB_FRAG | TSNEP_TX_TYPE_XDP_NDO)) ++ else if (entry->type & TSNEP_TX_TYPE_MAP_PAGE) + dma_unmap_page(dmadev, + dma_unmap_addr(entry, dma), + dma_unmap_len(entry, len), +@@ -506,11 +562,12 @@ static int tsnep_tx_unmap(struct tsnep_tx *tx, int index, int count) + static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, + struct tsnep_tx *tx) + { +- int count = 1; + struct tsnep_tx_entry *entry; ++ bool do_tstamp = false; ++ int count = 1; + int length; +- int i; + int retval; ++ int i; + + if (skb_shinfo(skb)->nr_frags > 0) + count += skb_shinfo(skb)->nr_frags; +@@ -527,7 +584,13 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, + entry = &tx->entry[tx->write]; + entry->skb = skb; + +- retval = tsnep_tx_map(skb, tx, count); ++ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && ++ tx->adapter->hwtstamp_config.tx_type == HWTSTAMP_TX_ON) { ++ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; ++ do_tstamp = true; ++ } ++ ++ retval = tsnep_tx_map(skb, tx, count, do_tstamp); + if (retval < 0) { + tsnep_tx_unmap(tx, tx->write, count); + dev_kfree_skb_any(entry->skb); +@@ -539,9 +602,6 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, + } + length = retval; + +- if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) +- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; +- + for (i = 0; i < count; i++) + tsnep_tx_activate(tx, (tx->write + i) & TSNEP_RING_MASK, length, + i == count - 1); +@@ -586,7 +646,7 @@ static int tsnep_xdp_tx_map(struct xdp_frame *xdpf, struct tsnep_tx *tx, + if (dma_mapping_error(dmadev, dma)) + return -ENOMEM; + +- entry->type = TSNEP_TX_TYPE_XDP_NDO; ++ entry->type = TSNEP_TX_TYPE_XDP_NDO_MAP_PAGE; + } else { + page = unlikely(frag) ? skb_frag_page(frag) : + virt_to_page(xdpf->data); +@@ -792,8 +852,7 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget) + + length = tsnep_tx_unmap(tx, tx->read, count); + +- if ((entry->type & TSNEP_TX_TYPE_SKB) && +- (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS) && ++ if (((entry->type & TSNEP_TX_TYPE_SKB_TSTAMP) == TSNEP_TX_TYPE_SKB_TSTAMP) && + (__le32_to_cpu(entry->desc_wb->properties) & + TSNEP_DESC_EXTENDED_WRITEBACK_FLAG)) { + struct skb_shared_hwtstamps hwtstamps; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +index 52792546fe00dd..339be6950c0395 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +@@ -707,6 +707,11 @@ int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) + + if (!is_lmac_valid(cgx, lmac_id)) + return -ENODEV; ++ ++ /* pass lmac as 0 for CGX_CMR_RX_STAT9-12 */ ++ if (idx >= CGX_RX_STAT_GLOBAL_INDEX) ++ lmac_id = 0; ++ + *rx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_STAT0 + (idx * 8)); + return 0; + } +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +index 6cc7a78968fc1c..74953f67a2bf9c 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +@@ -533,7 +533,8 @@ static int cn10k_mcs_write_tx_secy(struct otx2_nic *pfvf, + if (sw_tx_sc->encrypt) + sectag_tci |= (MCS_TCI_E | MCS_TCI_C); + +- policy = FIELD_PREP(MCS_TX_SECY_PLCY_MTU, secy->netdev->mtu); ++ policy = FIELD_PREP(MCS_TX_SECY_PLCY_MTU, ++ pfvf->netdev->mtu + OTX2_ETH_HLEN); + /* Write SecTag excluding AN bits(1..0) */ + policy |= FIELD_PREP(MCS_TX_SECY_PLCY_ST_TCI, sectag_tci >> 2); + policy |= FIELD_PREP(MCS_TX_SECY_PLCY_ST_OFFSET, tag_offset); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c6ccfbd4226570..cb8efc952dfda9 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4628,7 +4628,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + } + + if (mtk_is_netsys_v3_or_greater(mac->hw) && +- MTK_HAS_CAPS(mac->hw->soc->caps, MTK_ESW_BIT) && ++ MTK_HAS_CAPS(mac->hw->soc->caps, MTK_ESW) && + id == MTK_GMAC1_ID) { + mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | + MAC_SYM_PAUSE | +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 8a892614015cd9..d9dc7280302eb7 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -4136,6 +4136,10 @@ static netdev_features_t mlx5e_fix_uplink_rep_features(struct net_device *netdev + if (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + netdev_warn(netdev, "Disabling HW_VLAN CTAG FILTERING, not supported in switchdev mode\n"); + ++ features &= ~NETIF_F_HW_MACSEC; ++ if (netdev->features & NETIF_F_HW_MACSEC) ++ netdev_warn(netdev, "Disabling HW MACsec offload, not supported in switchdev mode\n"); ++ + return features; + } + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +index d15aa6b25a8884..0534b10e29c5c4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +@@ -3013,6 +3013,9 @@ static int mlxsw_sp_neigh_rif_made_sync(struct mlxsw_sp *mlxsw_sp, + .rif = rif, + }; + ++ if (!mlxsw_sp_dev_lower_is_port(mlxsw_sp_rif_dev(rif))) ++ return 0; ++ + neigh_for_each(&arp_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms); + if (rms.err) + goto err_arp; +diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c +index 99df00c30b8c6c..b5d744d2586f72 100644 +--- a/drivers/net/ethernet/qlogic/qede/qede_main.c ++++ b/drivers/net/ethernet/qlogic/qede/qede_main.c +@@ -203,7 +203,7 @@ static struct pci_driver qede_pci_driver = { + }; + + static struct qed_eth_cb_ops qede_ll_ops = { +- { ++ .common = { + #ifdef CONFIG_RFS_ACCEL + .arfs_filter_op = qede_arfs_filter_op, + #endif +diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +index 28d24d59efb84f..d57b976b904095 100644 +--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c ++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +@@ -1484,8 +1484,11 @@ static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_o + } + + cmd_op = (cmd.rsp.arg[0] & 0xff); +- if (cmd.rsp.arg[0] >> 25 == 2) +- return 2; ++ if (cmd.rsp.arg[0] >> 25 == 2) { ++ ret = 2; ++ goto out; ++ } ++ + if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) + set_bit(QLC_BC_VF_STATE, &vf->state); + else +diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h +index 810977952f950b..4c12067b07f05e 100644 +--- a/drivers/net/hyperv/hyperv_net.h ++++ b/drivers/net/hyperv/hyperv_net.h +@@ -158,7 +158,6 @@ struct hv_netvsc_packet { + u8 cp_partial; /* partial copy into send buffer */ + + u8 rmsg_size; /* RNDIS header and PPI size */ +- u8 rmsg_pgcnt; /* page count of RNDIS header and PPI */ + u8 page_buf_cnt; + + u16 q_idx; +@@ -893,6 +892,18 @@ struct nvsp_message { + sizeof(struct nvsp_message)) + #define NETVSC_MIN_IN_MSG_SIZE sizeof(struct vmpacket_descriptor) + ++/* Maximum # of contiguous data ranges that can make up a trasmitted packet. ++ * Typically it's the max SKB fragments plus 2 for the rndis packet and the ++ * linear portion of the SKB. But if MAX_SKB_FRAGS is large, the value may ++ * need to be limited to MAX_PAGE_BUFFER_COUNT, which is the max # of entries ++ * in a GPA direct packet sent to netvsp over VMBus. ++ */ ++#if MAX_SKB_FRAGS + 2 < MAX_PAGE_BUFFER_COUNT ++#define MAX_DATA_RANGES (MAX_SKB_FRAGS + 2) ++#else ++#define MAX_DATA_RANGES MAX_PAGE_BUFFER_COUNT ++#endif ++ + /* Estimated requestor size: + * out_ring_size/min_out_msg_size + in_ring_size/min_in_msg_size + */ +diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c +index b2f27e505f76c6..61584b40cb0386 100644 +--- a/drivers/net/hyperv/netvsc.c ++++ b/drivers/net/hyperv/netvsc.c +@@ -945,8 +945,7 @@ static void netvsc_copy_to_send_buf(struct netvsc_device *net_device, + + pend_size; + int i; + u32 padding = 0; +- u32 page_count = packet->cp_partial ? packet->rmsg_pgcnt : +- packet->page_buf_cnt; ++ u32 page_count = packet->cp_partial ? 1 : packet->page_buf_cnt; + u32 remain; + + /* Add padding */ +@@ -1047,6 +1046,42 @@ static int netvsc_dma_map(struct hv_device *hv_dev, + return 0; + } + ++/* Build an "array" of mpb entries describing the data to be transferred ++ * over VMBus. After the desc header fields, each "array" entry is variable ++ * size, and each entry starts after the end of the previous entry. The ++ * "offset" and "len" fields for each entry imply the size of the entry. ++ * ++ * The pfns are in HV_HYP_PAGE_SIZE, because all communication with Hyper-V ++ * uses that granularity, even if the system page size of the guest is larger. ++ * Each entry in the input "pb" array must describe a contiguous range of ++ * guest physical memory so that the pfns are sequential if the range crosses ++ * a page boundary. The offset field must be < HV_HYP_PAGE_SIZE. ++ */ ++static inline void netvsc_build_mpb_array(struct hv_page_buffer *pb, ++ u32 page_buffer_count, ++ struct vmbus_packet_mpb_array *desc, ++ u32 *desc_size) ++{ ++ struct hv_mpb_array *mpb_entry = &desc->range; ++ int i, j; ++ ++ for (i = 0; i < page_buffer_count; i++) { ++ u32 offset = pb[i].offset; ++ u32 len = pb[i].len; ++ ++ mpb_entry->offset = offset; ++ mpb_entry->len = len; ++ ++ for (j = 0; j < HVPFN_UP(offset + len); j++) ++ mpb_entry->pfn_array[j] = pb[i].pfn + j; ++ ++ mpb_entry = (struct hv_mpb_array *)&mpb_entry->pfn_array[j]; ++ } ++ ++ desc->rangecount = page_buffer_count; ++ *desc_size = (char *)mpb_entry - (char *)desc; ++} ++ + static inline int netvsc_send_pkt( + struct hv_device *device, + struct hv_netvsc_packet *packet, +@@ -1089,8 +1124,11 @@ static inline int netvsc_send_pkt( + + packet->dma_range = NULL; + if (packet->page_buf_cnt) { ++ struct vmbus_channel_packet_page_buffer desc; ++ u32 desc_size; ++ + if (packet->cp_partial) +- pb += packet->rmsg_pgcnt; ++ pb++; + + ret = netvsc_dma_map(ndev_ctx->device_ctx, packet, pb); + if (ret) { +@@ -1098,11 +1136,12 @@ static inline int netvsc_send_pkt( + goto exit; + } + +- ret = vmbus_sendpacket_pagebuffer(out_channel, +- pb, packet->page_buf_cnt, +- &nvmsg, sizeof(nvmsg), +- req_id); +- ++ netvsc_build_mpb_array(pb, packet->page_buf_cnt, ++ (struct vmbus_packet_mpb_array *)&desc, ++ &desc_size); ++ ret = vmbus_sendpacket_mpb_desc(out_channel, ++ (struct vmbus_packet_mpb_array *)&desc, ++ desc_size, &nvmsg, sizeof(nvmsg), req_id); + if (ret) + netvsc_dma_unmap(ndev_ctx->device_ctx, packet); + } else { +@@ -1251,7 +1290,7 @@ int netvsc_send(struct net_device *ndev, + packet->send_buf_index = section_index; + + if (packet->cp_partial) { +- packet->page_buf_cnt -= packet->rmsg_pgcnt; ++ packet->page_buf_cnt--; + packet->total_data_buflen = msd_len + packet->rmsg_size; + } else { + packet->page_buf_cnt = 0; +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index 8698d2db3dc8e1..ce6ac26131b347 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -325,43 +325,10 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, + return txq; + } + +-static u32 fill_pg_buf(unsigned long hvpfn, u32 offset, u32 len, +- struct hv_page_buffer *pb) +-{ +- int j = 0; +- +- hvpfn += offset >> HV_HYP_PAGE_SHIFT; +- offset = offset & ~HV_HYP_PAGE_MASK; +- +- while (len > 0) { +- unsigned long bytes; +- +- bytes = HV_HYP_PAGE_SIZE - offset; +- if (bytes > len) +- bytes = len; +- pb[j].pfn = hvpfn; +- pb[j].offset = offset; +- pb[j].len = bytes; +- +- offset += bytes; +- len -= bytes; +- +- if (offset == HV_HYP_PAGE_SIZE && len) { +- hvpfn++; +- offset = 0; +- j++; +- } +- } +- +- return j + 1; +-} +- + static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, + struct hv_netvsc_packet *packet, + struct hv_page_buffer *pb) + { +- u32 slots_used = 0; +- char *data = skb->data; + int frags = skb_shinfo(skb)->nr_frags; + int i; + +@@ -370,28 +337,27 @@ static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, + * 2. skb linear data + * 3. skb fragment data + */ +- slots_used += fill_pg_buf(virt_to_hvpfn(hdr), +- offset_in_hvpage(hdr), +- len, +- &pb[slots_used]); + ++ pb[0].offset = offset_in_hvpage(hdr); ++ pb[0].len = len; ++ pb[0].pfn = virt_to_hvpfn(hdr); + packet->rmsg_size = len; +- packet->rmsg_pgcnt = slots_used; + +- slots_used += fill_pg_buf(virt_to_hvpfn(data), +- offset_in_hvpage(data), +- skb_headlen(skb), +- &pb[slots_used]); ++ pb[1].offset = offset_in_hvpage(skb->data); ++ pb[1].len = skb_headlen(skb); ++ pb[1].pfn = virt_to_hvpfn(skb->data); + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; ++ struct hv_page_buffer *cur_pb = &pb[i + 2]; ++ u64 pfn = page_to_hvpfn(skb_frag_page(frag)); ++ u32 offset = skb_frag_off(frag); + +- slots_used += fill_pg_buf(page_to_hvpfn(skb_frag_page(frag)), +- skb_frag_off(frag), +- skb_frag_size(frag), +- &pb[slots_used]); ++ cur_pb->offset = offset_in_hvpage(offset); ++ cur_pb->len = skb_frag_size(frag); ++ cur_pb->pfn = pfn + (offset >> HV_HYP_PAGE_SHIFT); + } +- return slots_used; ++ return frags + 2; + } + + static int count_skb_frag_slots(struct sk_buff *skb) +@@ -482,7 +448,7 @@ static int netvsc_xmit(struct sk_buff *skb, struct net_device *net, bool xdp_tx) + struct net_device *vf_netdev; + u32 rndis_msg_size; + u32 hash; +- struct hv_page_buffer pb[MAX_PAGE_BUFFER_COUNT]; ++ struct hv_page_buffer pb[MAX_DATA_RANGES]; + + /* If VF is present and up then redirect packets to it. + * Skip the VF if it is marked down or has no carrier. +diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c +index af95947a87c552..09144f0ec2aa4f 100644 +--- a/drivers/net/hyperv/rndis_filter.c ++++ b/drivers/net/hyperv/rndis_filter.c +@@ -226,8 +226,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, + struct rndis_request *req) + { + struct hv_netvsc_packet *packet; +- struct hv_page_buffer page_buf[2]; +- struct hv_page_buffer *pb = page_buf; ++ struct hv_page_buffer pb; + int ret; + + /* Setup the packet to send it */ +@@ -236,27 +235,14 @@ static int rndis_filter_send_request(struct rndis_device *dev, + packet->total_data_buflen = req->request_msg.msg_len; + packet->page_buf_cnt = 1; + +- pb[0].pfn = virt_to_phys(&req->request_msg) >> +- HV_HYP_PAGE_SHIFT; +- pb[0].len = req->request_msg.msg_len; +- pb[0].offset = offset_in_hvpage(&req->request_msg); +- +- /* Add one page_buf when request_msg crossing page boundary */ +- if (pb[0].offset + pb[0].len > HV_HYP_PAGE_SIZE) { +- packet->page_buf_cnt++; +- pb[0].len = HV_HYP_PAGE_SIZE - +- pb[0].offset; +- pb[1].pfn = virt_to_phys((void *)&req->request_msg +- + pb[0].len) >> HV_HYP_PAGE_SHIFT; +- pb[1].offset = 0; +- pb[1].len = req->request_msg.msg_len - +- pb[0].len; +- } ++ pb.pfn = virt_to_phys(&req->request_msg) >> HV_HYP_PAGE_SHIFT; ++ pb.len = req->request_msg.msg_len; ++ pb.offset = offset_in_hvpage(&req->request_msg); + + trace_rndis_send(dev->ndev, 0, &req->request_msg); + + rcu_read_lock_bh(); +- ret = netvsc_send(dev->ndev, packet, NULL, pb, NULL, false); ++ ret = netvsc_send(dev->ndev, packet, NULL, &pb, NULL, false); + rcu_read_unlock_bh(); + + return ret; +diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c +index cd048659706436..b7e100710601a5 100644 +--- a/drivers/net/wireless/mediatek/mt76/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/dma.c +@@ -957,6 +957,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev) + int i; + + mt76_worker_disable(&dev->tx_worker); ++ napi_disable(&dev->tx_napi); + netif_napi_del(&dev->tx_napi); + + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index fdde38903ebcd5..1e5c8220e365ca 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -386,7 +386,7 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, __le32 *dbbuf_db, + * as it only leads to a small amount of wasted memory for the lifetime of + * the I/O. + */ +-static int nvme_pci_npages_prp(void) ++static __always_inline int nvme_pci_npages_prp(void) + { + unsigned max_bytes = (NVME_MAX_KB_SZ * 1024) + NVME_CTRL_PAGE_SIZE; + unsigned nprps = DIV_ROUND_UP(max_bytes, NVME_CTRL_PAGE_SIZE); +@@ -1107,7 +1107,9 @@ static void nvme_poll_irqdisable(struct nvme_queue *nvmeq) + WARN_ON_ONCE(test_bit(NVMEQ_POLLED, &nvmeq->flags)); + + disable_irq(pci_irq_vector(pdev, nvmeq->cq_vector)); ++ spin_lock(&nvmeq->cq_poll_lock); + nvme_poll_cq(nvmeq, NULL); ++ spin_unlock(&nvmeq->cq_poll_lock); + enable_irq(pci_irq_vector(pdev, nvmeq->cq_vector)); + } + +diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +index 6387c0d34c551c..aa578be2bcb6df 100644 +--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c ++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +@@ -101,7 +101,6 @@ struct rcar_gen3_phy { + struct rcar_gen3_chan *ch; + u32 int_enable_bits; + bool initialized; +- bool otg_initialized; + bool powered; + }; + +@@ -309,16 +308,15 @@ static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch) + return false; + } + +-static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch) ++static bool rcar_gen3_is_any_otg_rphy_initialized(struct rcar_gen3_chan *ch) + { +- int i; +- +- for (i = 0; i < NUM_OF_PHYS; i++) { +- if (ch->rphys[i].otg_initialized) +- return false; ++ for (enum rcar_gen3_phy_index i = PHY_INDEX_BOTH_HC; i <= PHY_INDEX_EHCI; ++ i++) { ++ if (ch->rphys[i].initialized) ++ return true; + } + +- return true; ++ return false; + } + + static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch) +@@ -340,7 +338,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, + bool is_b_device; + enum phy_mode cur_mode, new_mode; + +- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) ++ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) + return -EIO; + + if (sysfs_streq(buf, "host")) +@@ -378,7 +376,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, + { + struct rcar_gen3_chan *ch = dev_get_drvdata(dev); + +- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) ++ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) + return -EIO; + + return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : +@@ -391,6 +389,9 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) + void __iomem *usb2_base = ch->base; + u32 val; + ++ if (!ch->is_otg_channel || rcar_gen3_is_any_otg_rphy_initialized(ch)) ++ return; ++ + /* Should not use functions of read-modify-write a register */ + val = readl(usb2_base + USB2_LINECTRL1); + val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN | +@@ -451,16 +452,16 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) + val = readl(usb2_base + USB2_INT_ENABLE); + val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits; + writel(val, usb2_base + USB2_INT_ENABLE); +- writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); +- writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); +- +- /* Initialize otg part */ +- if (channel->is_otg_channel) { +- if (rcar_gen3_needs_init_otg(channel)) +- rcar_gen3_init_otg(channel); +- rphy->otg_initialized = true; ++ ++ if (!rcar_gen3_is_any_rphy_initialized(channel)) { ++ writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); ++ writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); + } + ++ /* Initialize otg part (only if we initialize a PHY with IRQs). */ ++ if (rphy->int_enable_bits) ++ rcar_gen3_init_otg(channel); ++ + rphy->initialized = true; + + return 0; +@@ -475,9 +476,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) + + rphy->initialized = false; + +- if (channel->is_otg_channel) +- rphy->otg_initialized = false; +- + val = readl(usb2_base + USB2_INT_ENABLE); + val &= ~rphy->int_enable_bits; + if (!rcar_gen3_is_any_rphy_initialized(channel)) +diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c +index fae6242aa730e0..23a23f2d64e586 100644 +--- a/drivers/phy/tegra/xusb-tegra186.c ++++ b/drivers/phy/tegra/xusb-tegra186.c +@@ -237,6 +237,8 @@ + #define DATA0_VAL_PD BIT(1) + #define USE_XUSB_AO BIT(4) + ++#define TEGRA_UTMI_PAD_MAX 4 ++ + #define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \ + { \ + .name = _name, \ +@@ -269,7 +271,7 @@ struct tegra186_xusb_padctl { + + /* UTMI bias and tracking */ + struct clk *usb2_trk_clk; +- unsigned int bias_pad_enable; ++ DECLARE_BITMAP(utmi_pad_enabled, TEGRA_UTMI_PAD_MAX); + + /* padctl context */ + struct tegra186_xusb_padctl_context context; +@@ -603,12 +605,8 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) + u32 value; + int err; + +- mutex_lock(&padctl->lock); +- +- if (priv->bias_pad_enable++ > 0) { +- mutex_unlock(&padctl->lock); ++ if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX)) + return; +- } + + err = clk_prepare_enable(priv->usb2_trk_clk); + if (err < 0) +@@ -658,8 +656,6 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) + } else { + clk_disable_unprepare(priv->usb2_trk_clk); + } +- +- mutex_unlock(&padctl->lock); + } + + static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) +@@ -667,17 +663,8 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) + struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); + u32 value; + +- mutex_lock(&padctl->lock); +- +- if (WARN_ON(priv->bias_pad_enable == 0)) { +- mutex_unlock(&padctl->lock); +- return; +- } +- +- if (--priv->bias_pad_enable > 0) { +- mutex_unlock(&padctl->lock); ++ if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX)) + return; +- } + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + value |= USB2_PD_TRK; +@@ -690,13 +677,13 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) + clk_disable_unprepare(priv->usb2_trk_clk); + } + +- mutex_unlock(&padctl->lock); + } + + static void tegra186_utmi_pad_power_on(struct phy *phy) + { + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; ++ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); + struct tegra_xusb_usb2_port *port; + struct device *dev = padctl->dev; + unsigned int index = lane->index; +@@ -705,9 +692,16 @@ static void tegra186_utmi_pad_power_on(struct phy *phy) + if (!phy) + return; + ++ mutex_lock(&padctl->lock); ++ if (test_bit(index, priv->utmi_pad_enabled)) { ++ mutex_unlock(&padctl->lock); ++ return; ++ } ++ + port = tegra_xusb_find_usb2_port(padctl, index); + if (!port) { + dev_err(dev, "no port found for USB2 lane %u\n", index); ++ mutex_unlock(&padctl->lock); + return; + } + +@@ -724,18 +718,28 @@ static void tegra186_utmi_pad_power_on(struct phy *phy) + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + value &= ~USB2_OTG_PD_DR; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); ++ ++ set_bit(index, priv->utmi_pad_enabled); ++ mutex_unlock(&padctl->lock); + } + + static void tegra186_utmi_pad_power_down(struct phy *phy) + { + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; ++ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); + unsigned int index = lane->index; + u32 value; + + if (!phy) + return; + ++ mutex_lock(&padctl->lock); ++ if (!test_bit(index, priv->utmi_pad_enabled)) { ++ mutex_unlock(&padctl->lock); ++ return; ++ } ++ + dev_dbg(padctl->dev, "power down UTMI pad %u\n", index); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); +@@ -748,7 +752,11 @@ static void tegra186_utmi_pad_power_down(struct phy *phy) + + udelay(2); + ++ clear_bit(index, priv->utmi_pad_enabled); ++ + tegra186_utmi_bias_pad_power_off(padctl); ++ ++ mutex_unlock(&padctl->lock); + } + + static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl, +diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c +index 983a6e6173bd21..3a04a56ca52de9 100644 +--- a/drivers/phy/tegra/xusb.c ++++ b/drivers/phy/tegra/xusb.c +@@ -548,16 +548,16 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port, + + err = dev_set_name(&port->dev, "%s-%u", name, index); + if (err < 0) +- goto unregister; ++ goto put_device; + + err = device_add(&port->dev); + if (err < 0) +- goto unregister; ++ goto put_device; + + return 0; + +-unregister: +- device_unregister(&port->dev); ++put_device: ++ put_device(&port->dev); + return err; + } + +diff --git a/drivers/platform/x86/amd/pmc/pmc-quirks.c b/drivers/platform/x86/amd/pmc/pmc-quirks.c +index b4f49720c87f62..2e3f6fc67c568d 100644 +--- a/drivers/platform/x86/amd/pmc/pmc-quirks.c ++++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c +@@ -217,6 +217,13 @@ static const struct dmi_system_id fwbug_list[] = { + DMI_MATCH(DMI_BIOS_VERSION, "03.05"), + } + }, ++ { ++ .ident = "MECHREVO Wujie 14X (GX4HRXL)", ++ .driver_data = &quirk_spurious_8042, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"), ++ } ++ }, + {} + }; + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 222e429931ef9e..2c894ea8aa8174 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -4404,7 +4404,8 @@ static int asus_wmi_add(struct platform_device *pdev) + goto fail_leds; + + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result); +- if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) ++ if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) == ++ (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) + asus->driver->wlan_ctrl_by_user = 1; + + if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) { +diff --git a/drivers/regulator/max20086-regulator.c b/drivers/regulator/max20086-regulator.c +index 32f47b896fd1e2..ebfbcadbca5295 100644 +--- a/drivers/regulator/max20086-regulator.c ++++ b/drivers/regulator/max20086-regulator.c +@@ -132,7 +132,7 @@ static int max20086_regulators_register(struct max20086 *chip) + + static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on) + { +- struct of_regulator_match matches[MAX20086_MAX_REGULATORS] = { }; ++ struct of_regulator_match *matches; + struct device_node *node; + unsigned int i; + int ret; +@@ -143,6 +143,11 @@ static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on) + return -ENODEV; + } + ++ matches = devm_kcalloc(chip->dev, chip->info->num_outputs, ++ sizeof(*matches), GFP_KERNEL); ++ if (!matches) ++ return -ENOMEM; ++ + for (i = 0; i < chip->info->num_outputs; ++i) + matches[i].name = max20086_output_names[i]; + +diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c +index 203df5e53b1a84..9bbabae253e53b 100644 +--- a/drivers/scsi/sd_zbc.c ++++ b/drivers/scsi/sd_zbc.c +@@ -202,6 +202,7 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, + unsigned int nr_zones, size_t *buflen) + { + struct request_queue *q = sdkp->disk->queue; ++ unsigned int max_segments; + size_t bufsize; + void *buf; + +@@ -213,12 +214,15 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, + * Furthermore, since the report zone command cannot be split, make + * sure that the allocated buffer can always be mapped by limiting the + * number of pages allocated to the HBA max segments limit. ++ * Since max segments can be larger than the max inline bio vectors, ++ * further limit the allocated buffer to BIO_MAX_INLINE_VECS. + */ + nr_zones = min(nr_zones, sdkp->zone_info.nr_zones); + bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE); + bufsize = min_t(size_t, bufsize, + queue_max_hw_sectors(q) << SECTOR_SHIFT); +- bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); ++ max_segments = min(BIO_MAX_INLINE_VECS, queue_max_segments(q)); ++ bufsize = min_t(size_t, bufsize, max_segments << PAGE_SHIFT); + + while (bufsize >= SECTOR_SIZE) { + buf = kvzalloc(bufsize, GFP_KERNEL | __GFP_NORETRY); +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index b8186feccdf5aa..48b0ca92b44fb3 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1819,6 +1819,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) + return SCSI_MLQUEUE_DEVICE_BUSY; + } + ++ payload->rangecount = 1; + payload->range.len = length; + payload->range.offset = offset_in_hvpg; + +diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c +index bbf2015d8e5cce..69b6c87c5525e0 100644 +--- a/drivers/spi/spi-loopback-test.c ++++ b/drivers/spi/spi-loopback-test.c +@@ -421,7 +421,7 @@ MODULE_LICENSE("GPL"); + static void spi_test_print_hex_dump(char *pre, const void *ptr, size_t len) + { + /* limit the hex_dump */ +- if (len < 1024) { ++ if (len <= 1024) { + print_hex_dump(KERN_INFO, pre, + DUMP_PREFIX_OFFSET, 16, 1, + ptr, len, 0); +diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c +index 147d7052794f77..8d7ce4c556aa1d 100644 +--- a/drivers/spi/spi-tegra114.c ++++ b/drivers/spi/spi-tegra114.c +@@ -728,9 +728,9 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi) + u32 inactive_cycles; + u8 cs_state; + +- if ((setup->unit && setup->unit != SPI_DELAY_UNIT_SCK) || +- (hold->unit && hold->unit != SPI_DELAY_UNIT_SCK) || +- (inactive->unit && inactive->unit != SPI_DELAY_UNIT_SCK)) { ++ if ((setup->value && setup->unit != SPI_DELAY_UNIT_SCK) || ++ (hold->value && hold->unit != SPI_DELAY_UNIT_SCK) || ++ (inactive->value && inactive->unit != SPI_DELAY_UNIT_SCK)) { + dev_err(&spi->dev, + "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n", + SPI_DELAY_UNIT_SCK); +diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c +index b7dada064890bd..90536f47906c33 100644 +--- a/drivers/usb/gadget/function/f_midi2.c ++++ b/drivers/usb/gadget/function/f_midi2.c +@@ -475,7 +475,7 @@ static void reply_ump_stream_ep_info(struct f_midi2_ep *ep) + /* reply a UMP EP device info */ + static void reply_ump_stream_ep_device(struct f_midi2_ep *ep) + { +- struct snd_ump_stream_msg_devince_info rep = { ++ struct snd_ump_stream_msg_device_info rep = { + .type = UMP_MSG_TYPE_STREAM, + .status = UMP_STREAM_MSG_STATUS_DEVICE_INFO, + .manufacture_id = ep->info.manufacturer, +diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c +index 8c19081c325542..e3b5fa3b5f955d 100644 +--- a/drivers/usb/typec/ucsi/displayport.c ++++ b/drivers/usb/typec/ucsi/displayport.c +@@ -54,7 +54,8 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) + u8 cur = 0; + int ret; + +- mutex_lock(&dp->con->lock); ++ if (!ucsi_con_mutex_lock(dp->con)) ++ return -ENOTCONN; + + if (!dp->override && dp->initialized) { + const struct typec_altmode *p = typec_altmode_get_partner(alt); +@@ -100,7 +101,7 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) + schedule_work(&dp->work); + ret = 0; + err_unlock: +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + + return ret; + } +@@ -112,7 +113,8 @@ static int ucsi_displayport_exit(struct typec_altmode *alt) + u64 command; + int ret = 0; + +- mutex_lock(&dp->con->lock); ++ if (!ucsi_con_mutex_lock(dp->con)) ++ return -ENOTCONN; + + if (!dp->override) { + const struct typec_altmode *p = typec_altmode_get_partner(alt); +@@ -144,7 +146,7 @@ static int ucsi_displayport_exit(struct typec_altmode *alt) + schedule_work(&dp->work); + + out_unlock: +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + + return ret; + } +@@ -202,20 +204,21 @@ static int ucsi_displayport_vdm(struct typec_altmode *alt, + int cmd = PD_VDO_CMD(header); + int svdm_version; + +- mutex_lock(&dp->con->lock); ++ if (!ucsi_con_mutex_lock(dp->con)) ++ return -ENOTCONN; + + if (!dp->override && dp->initialized) { + const struct typec_altmode *p = typec_altmode_get_partner(alt); + + dev_warn(&p->dev, + "firmware doesn't support alternate mode overriding\n"); +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + return -EOPNOTSUPP; + } + + svdm_version = typec_altmode_get_svdm_version(alt); + if (svdm_version < 0) { +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + return svdm_version; + } + +@@ -259,7 +262,7 @@ static int ucsi_displayport_vdm(struct typec_altmode *alt, + break; + } + +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + + return 0; + } +diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c +index 29a04d6795012d..ea98bc5674940d 100644 +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -1559,6 +1559,40 @@ void ucsi_set_drvdata(struct ucsi *ucsi, void *data) + } + EXPORT_SYMBOL_GPL(ucsi_set_drvdata); + ++/** ++ * ucsi_con_mutex_lock - Acquire the connector mutex ++ * @con: The connector interface to lock ++ * ++ * Returns true on success, false if the connector is disconnected ++ */ ++bool ucsi_con_mutex_lock(struct ucsi_connector *con) ++{ ++ bool mutex_locked = false; ++ bool connected = true; ++ ++ while (connected && !mutex_locked) { ++ mutex_locked = mutex_trylock(&con->lock) != 0; ++ connected = con->status.flags & UCSI_CONSTAT_CONNECTED; ++ if (connected && !mutex_locked) ++ msleep(20); ++ } ++ ++ connected = connected && con->partner; ++ if (!connected && mutex_locked) ++ mutex_unlock(&con->lock); ++ ++ return connected; ++} ++ ++/** ++ * ucsi_con_mutex_unlock - Release the connector mutex ++ * @con: The connector interface to unlock ++ */ ++void ucsi_con_mutex_unlock(struct ucsi_connector *con) ++{ ++ mutex_unlock(&con->lock); ++} ++ + /** + * ucsi_create - Allocate UCSI instance + * @dev: Device interface to the PPM (Platform Policy Manager) +diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h +index 921ef0e115cffc..3bb23a2ea547ac 100644 +--- a/drivers/usb/typec/ucsi/ucsi.h ++++ b/drivers/usb/typec/ucsi/ucsi.h +@@ -79,6 +79,8 @@ int ucsi_register(struct ucsi *ucsi); + void ucsi_unregister(struct ucsi *ucsi); + void *ucsi_get_drvdata(struct ucsi *ucsi); + void ucsi_set_drvdata(struct ucsi *ucsi, void *data); ++bool ucsi_con_mutex_lock(struct ucsi_connector *con); ++void ucsi_con_mutex_unlock(struct ucsi_connector *con); + + void ucsi_connector_change(struct ucsi *ucsi, u8 num); + +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index fb2c8d14327ae1..3ff7d2e47c7e90 100644 +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -110,25 +110,6 @@ static struct linux_binfmt elf_format = { + + #define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE)) + +-static int set_brk(unsigned long start, unsigned long end, int prot) +-{ +- start = ELF_PAGEALIGN(start); +- end = ELF_PAGEALIGN(end); +- if (end > start) { +- /* +- * Map the last of the bss segment. +- * If the header is requesting these pages to be +- * executable, honour that (ppc32 needs this). +- */ +- int error = vm_brk_flags(start, end - start, +- prot & PROT_EXEC ? VM_EXEC : 0); +- if (error) +- return error; +- } +- current->mm->start_brk = current->mm->brk = end; +- return 0; +-} +- + /* We need to explicitly zero any fractional pages + after the data section (i.e. bss). This would + contain the junk from the file that should not +@@ -406,6 +387,51 @@ static unsigned long elf_map(struct file *filep, unsigned long addr, + return(map_addr); + } + ++static unsigned long elf_load(struct file *filep, unsigned long addr, ++ const struct elf_phdr *eppnt, int prot, int type, ++ unsigned long total_size) ++{ ++ unsigned long zero_start, zero_end; ++ unsigned long map_addr; ++ ++ if (eppnt->p_filesz) { ++ map_addr = elf_map(filep, addr, eppnt, prot, type, total_size); ++ if (BAD_ADDR(map_addr)) ++ return map_addr; ++ if (eppnt->p_memsz > eppnt->p_filesz) { ++ zero_start = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) + ++ eppnt->p_filesz; ++ zero_end = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) + ++ eppnt->p_memsz; ++ ++ /* Zero the end of the last mapped page */ ++ padzero(zero_start); ++ } ++ } else { ++ map_addr = zero_start = ELF_PAGESTART(addr); ++ zero_end = zero_start + ELF_PAGEOFFSET(eppnt->p_vaddr) + ++ eppnt->p_memsz; ++ } ++ if (eppnt->p_memsz > eppnt->p_filesz) { ++ /* ++ * Map the last of the segment. ++ * If the header is requesting these pages to be ++ * executable, honour that (ppc32 needs this). ++ */ ++ int error; ++ ++ zero_start = ELF_PAGEALIGN(zero_start); ++ zero_end = ELF_PAGEALIGN(zero_end); ++ ++ error = vm_brk_flags(zero_start, zero_end - zero_start, ++ prot & PROT_EXEC ? VM_EXEC : 0); ++ if (error) ++ map_addr = error; ++ } ++ return map_addr; ++} ++ ++ + static unsigned long total_mapping_size(const struct elf_phdr *phdr, int nr) + { + elf_addr_t min_addr = -1; +@@ -828,8 +854,8 @@ static int load_elf_binary(struct linux_binprm *bprm) + unsigned long error; + struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; + struct elf_phdr *elf_property_phdata = NULL; +- unsigned long elf_bss, elf_brk; +- int bss_prot = 0; ++ unsigned long elf_brk; ++ bool brk_moved = false; + int retval, i; + unsigned long elf_entry; + unsigned long e_entry; +@@ -1021,7 +1047,6 @@ static int load_elf_binary(struct linux_binprm *bprm) + if (retval < 0) + goto out_free_dentry; + +- elf_bss = 0; + elf_brk = 0; + + start_code = ~0UL; +@@ -1041,33 +1066,6 @@ static int load_elf_binary(struct linux_binprm *bprm) + if (elf_ppnt->p_type != PT_LOAD) + continue; + +- if (unlikely (elf_brk > elf_bss)) { +- unsigned long nbyte; +- +- /* There was a PT_LOAD segment with p_memsz > p_filesz +- before this one. Map anonymous pages, if needed, +- and clear the area. */ +- retval = set_brk(elf_bss + load_bias, +- elf_brk + load_bias, +- bss_prot); +- if (retval) +- goto out_free_dentry; +- nbyte = ELF_PAGEOFFSET(elf_bss); +- if (nbyte) { +- nbyte = ELF_MIN_ALIGN - nbyte; +- if (nbyte > elf_brk - elf_bss) +- nbyte = elf_brk - elf_bss; +- if (clear_user((void __user *)elf_bss + +- load_bias, nbyte)) { +- /* +- * This bss-zeroing can fail if the ELF +- * file specifies odd protections. So +- * we don't check the return value +- */ +- } +- } +- } +- + elf_prot = make_prot(elf_ppnt->p_flags, &arch_state, + !!interpreter, false); + +@@ -1095,15 +1093,49 @@ static int load_elf_binary(struct linux_binprm *bprm) + * Header for ET_DYN binaries to calculate the + * randomization (load_bias) for all the LOAD + * Program Headers. ++ */ ++ ++ /* ++ * Calculate the entire size of the ELF mapping ++ * (total_size), used for the initial mapping, ++ * due to load_addr_set which is set to true later ++ * once the initial mapping is performed. ++ * ++ * Note that this is only sensible when the LOAD ++ * segments are contiguous (or overlapping). If ++ * used for LOADs that are far apart, this would ++ * cause the holes between LOADs to be mapped, ++ * running the risk of having the mapping fail, ++ * as it would be larger than the ELF file itself. ++ * ++ * As a result, only ET_DYN does this, since ++ * some ET_EXEC (e.g. ia64) may have large virtual ++ * memory holes between LOADs. ++ * ++ */ ++ total_size = total_mapping_size(elf_phdata, ++ elf_ex->e_phnum); ++ if (!total_size) { ++ retval = -EINVAL; ++ goto out_free_dentry; ++ } ++ ++ /* Calculate any requested alignment. */ ++ alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); ++ ++ /** ++ * DOC: PIE handling + * +- * There are effectively two types of ET_DYN +- * binaries: programs (i.e. PIE: ET_DYN with INTERP) +- * and loaders (ET_DYN without INTERP, since they +- * _are_ the ELF interpreter). The loaders must +- * be loaded away from programs since the program +- * may otherwise collide with the loader (especially +- * for ET_EXEC which does not have a randomized +- * position). For example to handle invocations of ++ * There are effectively two types of ET_DYN ELF ++ * binaries: programs (i.e. PIE: ET_DYN with ++ * PT_INTERP) and loaders (i.e. static PIE: ET_DYN ++ * without PT_INTERP, usually the ELF interpreter ++ * itself). Loaders must be loaded away from programs ++ * since the program may otherwise collide with the ++ * loader (especially for ET_EXEC which does not have ++ * a randomized position). ++ * ++ * For example, to handle invocations of + * "./ld.so someprog" to test out a new version of + * the loader, the subsequent program that the + * loader loads must avoid the loader itself, so +@@ -1116,17 +1148,49 @@ static int load_elf_binary(struct linux_binprm *bprm) + * ELF_ET_DYN_BASE and loaders are loaded into the + * independently randomized mmap region (0 load_bias + * without MAP_FIXED nor MAP_FIXED_NOREPLACE). ++ * ++ * See below for "brk" handling details, which is ++ * also affected by program vs loader and ASLR. + */ + if (interpreter) { ++ /* On ET_DYN with PT_INTERP, we do the ASLR. */ + load_bias = ELF_ET_DYN_BASE; + if (current->flags & PF_RANDOMIZE) + load_bias += arch_mmap_rnd(); +- alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); ++ /* Adjust alignment as requested. */ + if (alignment) + load_bias &= ~(alignment - 1); + elf_flags |= MAP_FIXED_NOREPLACE; +- } else +- load_bias = 0; ++ } else { ++ /* ++ * For ET_DYN without PT_INTERP, we rely on ++ * the architectures's (potentially ASLR) mmap ++ * base address (via a load_bias of 0). ++ * ++ * When a large alignment is requested, we ++ * must do the allocation at address "0" right ++ * now to discover where things will load so ++ * that we can adjust the resulting alignment. ++ * In this case (load_bias != 0), we can use ++ * MAP_FIXED_NOREPLACE to make sure the mapping ++ * doesn't collide with anything. ++ */ ++ if (alignment > ELF_MIN_ALIGN) { ++ load_bias = elf_load(bprm->file, 0, elf_ppnt, ++ elf_prot, elf_flags, total_size); ++ if (BAD_ADDR(load_bias)) { ++ retval = IS_ERR_VALUE(load_bias) ? ++ PTR_ERR((void*)load_bias) : -EINVAL; ++ goto out_free_dentry; ++ } ++ vm_munmap(load_bias, total_size); ++ /* Adjust alignment as requested. */ ++ if (alignment) ++ load_bias &= ~(alignment - 1); ++ elf_flags |= MAP_FIXED_NOREPLACE; ++ } else ++ load_bias = 0; ++ } + + /* + * Since load_bias is used for all subsequent loading +@@ -1136,34 +1200,9 @@ static int load_elf_binary(struct linux_binprm *bprm) + * is then page aligned. + */ + load_bias = ELF_PAGESTART(load_bias - vaddr); +- +- /* +- * Calculate the entire size of the ELF mapping +- * (total_size), used for the initial mapping, +- * due to load_addr_set which is set to true later +- * once the initial mapping is performed. +- * +- * Note that this is only sensible when the LOAD +- * segments are contiguous (or overlapping). If +- * used for LOADs that are far apart, this would +- * cause the holes between LOADs to be mapped, +- * running the risk of having the mapping fail, +- * as it would be larger than the ELF file itself. +- * +- * As a result, only ET_DYN does this, since +- * some ET_EXEC (e.g. ia64) may have large virtual +- * memory holes between LOADs. +- * +- */ +- total_size = total_mapping_size(elf_phdata, +- elf_ex->e_phnum); +- if (!total_size) { +- retval = -EINVAL; +- goto out_free_dentry; +- } + } + +- error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, ++ error = elf_load(bprm->file, load_bias + vaddr, elf_ppnt, + elf_prot, elf_flags, total_size); + if (BAD_ADDR(error)) { + retval = IS_ERR_VALUE(error) ? +@@ -1211,41 +1250,23 @@ static int load_elf_binary(struct linux_binprm *bprm) + + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + +- if (k > elf_bss) +- elf_bss = k; + if ((elf_ppnt->p_flags & PF_X) && end_code < k) + end_code = k; + if (end_data < k) + end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; +- if (k > elf_brk) { +- bss_prot = elf_prot; ++ if (k > elf_brk) + elf_brk = k; +- } + } + + e_entry = elf_ex->e_entry + load_bias; + phdr_addr += load_bias; +- elf_bss += load_bias; + elf_brk += load_bias; + start_code += load_bias; + end_code += load_bias; + start_data += load_bias; + end_data += load_bias; + +- /* Calling set_brk effectively mmaps the pages that we need +- * for the bss and break sections. We must do this before +- * mapping in the interpreter, to make sure it doesn't wind +- * up getting placed where the bss needs to go. +- */ +- retval = set_brk(elf_bss, elf_brk, bss_prot); +- if (retval) +- goto out_free_dentry; +- if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { +- retval = -EFAULT; /* Nobody gets to see this, but.. */ +- goto out_free_dentry; +- } +- + if (interpreter) { + elf_entry = load_elf_interp(interp_elf_ex, + interpreter, +@@ -1301,24 +1322,44 @@ static int load_elf_binary(struct linux_binprm *bprm) + mm->end_data = end_data; + mm->start_stack = bprm->p; + +- if ((current->flags & PF_RANDOMIZE) && (snapshot_randomize_va_space > 1)) { ++ /** ++ * DOC: "brk" handling ++ * ++ * For architectures with ELF randomization, when executing a ++ * loader directly (i.e. static PIE: ET_DYN without PT_INTERP), ++ * move the brk area out of the mmap region and into the unused ++ * ELF_ET_DYN_BASE region. Since "brk" grows up it may collide ++ * early with the stack growing down or other regions being put ++ * into the mmap region by the kernel (e.g. vdso). ++ * ++ * In the CONFIG_COMPAT_BRK case, though, everything is turned ++ * off because we're not allowed to move the brk at all. ++ */ ++ if (!IS_ENABLED(CONFIG_COMPAT_BRK) && ++ IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && ++ elf_ex->e_type == ET_DYN && !interpreter) { ++ elf_brk = ELF_ET_DYN_BASE; ++ /* This counts as moving the brk, so let brk(2) know. */ ++ brk_moved = true; ++ } ++ mm->start_brk = mm->brk = ELF_PAGEALIGN(elf_brk); ++ ++ if ((current->flags & PF_RANDOMIZE) && snapshot_randomize_va_space > 1) { + /* +- * For architectures with ELF randomization, when executing +- * a loader directly (i.e. no interpreter listed in ELF +- * headers), move the brk area out of the mmap region +- * (since it grows up, and may collide early with the stack +- * growing down), and into the unused ELF_ET_DYN_BASE region. ++ * If we didn't move the brk to ELF_ET_DYN_BASE (above), ++ * leave a gap between .bss and brk. + */ +- if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && +- elf_ex->e_type == ET_DYN && !interpreter) { +- mm->brk = mm->start_brk = ELF_ET_DYN_BASE; +- } ++ if (!brk_moved) ++ mm->brk = mm->start_brk = mm->brk + PAGE_SIZE; + + mm->brk = mm->start_brk = arch_randomize_brk(mm); ++ brk_moved = true; ++ } ++ + #ifdef compat_brk_randomized ++ if (brk_moved) + current->brk_randomized = 1; + #endif +- } + + if (current->personality & MMAP_PAGE_ZERO) { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index af03a1c6ba768c..ef77d420851040 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -164,6 +164,14 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, + ei = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_extent_item); + num_refs = btrfs_extent_refs(leaf, ei); ++ if (unlikely(num_refs == 0)) { ++ ret = -EUCLEAN; ++ btrfs_err(fs_info, ++ "unexpected zero reference count for extent item (%llu %u %llu)", ++ key.objectid, key.type, key.offset); ++ btrfs_abort_transaction(trans, ret); ++ goto out_free; ++ } + extent_flags = btrfs_extent_flags(leaf, ei); + } else { + ret = -EUCLEAN; +@@ -177,8 +185,6 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, + + goto out_free; + } +- +- BUG_ON(num_refs == 0); + } else { + num_refs = 0; + extent_flags = 0; +@@ -208,10 +214,19 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, + goto search_again; + } + spin_lock(&head->lock); +- if (head->extent_op && head->extent_op->update_flags) ++ if (head->extent_op && head->extent_op->update_flags) { + extent_flags |= head->extent_op->flags_to_set; +- else +- BUG_ON(num_refs == 0); ++ } else if (unlikely(num_refs == 0)) { ++ spin_unlock(&head->lock); ++ mutex_unlock(&head->mutex); ++ spin_unlock(&delayed_refs->lock); ++ ret = -EUCLEAN; ++ btrfs_err(fs_info, ++ "unexpected zero reference count for extent %llu (%s)", ++ bytenr, metadata ? "metadata" : "data"); ++ btrfs_abort_transaction(trans, ret); ++ goto out_free; ++ } + + num_refs += head->ref_mod; + spin_unlock(&head->lock); +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 4b12e45f575394..c140427e322ced 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -6880,10 +6880,18 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, + struct nfs4_unlockdata *p; + struct nfs4_state *state = lsp->ls_state; + struct inode *inode = state->inode; ++ struct nfs_lock_context *l_ctx; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) + return NULL; ++ l_ctx = nfs_get_lock_context(ctx); ++ if (!IS_ERR(l_ctx)) { ++ p->l_ctx = l_ctx; ++ } else { ++ kfree(p); ++ return NULL; ++ } + p->arg.fh = NFS_FH(inode); + p->arg.fl = &p->fl; + p->arg.seqid = seqid; +@@ -6891,7 +6899,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, + p->lsp = lsp; + /* Ensure we don't close file until we're done freeing locks! */ + p->ctx = get_nfs_open_context(ctx); +- p->l_ctx = nfs_get_lock_context(ctx); + locks_init_lock(&p->fl); + locks_copy_lock(&p->fl, fl); + p->server = NFS_SERVER(inode); +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index fe83c681e3fe03..73aa5a63afe3fb 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -732,6 +732,14 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, + return remaining; + } + ++static void pnfs_reset_return_info(struct pnfs_layout_hdr *lo) ++{ ++ struct pnfs_layout_segment *lseg; ++ ++ list_for_each_entry(lseg, &lo->plh_return_segs, pls_list) ++ pnfs_set_plh_return_info(lo, lseg->pls_range.iomode, 0); ++} ++ + static void + pnfs_free_returned_lsegs(struct pnfs_layout_hdr *lo, + struct list_head *free_me, +@@ -1180,6 +1188,7 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo, + pnfs_mark_matching_lsegs_invalid(lo, &freeme, range, seq); + pnfs_free_returned_lsegs(lo, &freeme, range, seq); + pnfs_set_layout_stateid(lo, stateid, NULL, true); ++ pnfs_reset_return_info(lo); + } else + pnfs_mark_layout_stateid_invalid(lo, &freeme); + out_unlock: +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index 4536b6fcfa0256..3e88e8b3c16ec2 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -2979,7 +2979,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, + /* Eventually save off posix specific response info and timestaps */ + + err_free_rsp_buf: +- free_rsp_buf(resp_buftype, rsp); ++ free_rsp_buf(resp_buftype, rsp_iov.iov_base); + kfree(pc_buf); + err_free_req: + cifs_small_buf_release(req); +diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c +index 4f33a4a4888613..b4071c9cf8c951 100644 +--- a/fs/udf/truncate.c ++++ b/fs/udf/truncate.c +@@ -115,7 +115,7 @@ void udf_truncate_tail_extent(struct inode *inode) + } + /* This inode entry is in-memory only and thus we don't have to mark + * the inode dirty */ +- if (ret == 0) ++ if (ret >= 0) + iinfo->i_lenExtents = inode->i_size; + brelse(epos.bh); + } +diff --git a/fs/xattr.c b/fs/xattr.c +index c20046548f218e..5fed22c22a2be8 100644 +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -1291,6 +1291,15 @@ static bool xattr_is_trusted(const char *name) + return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); + } + ++static bool xattr_is_maclabel(const char *name) ++{ ++ const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; ++ ++ return !strncmp(name, XATTR_SECURITY_PREFIX, ++ XATTR_SECURITY_PREFIX_LEN) && ++ security_ismaclabel(suffix); ++} ++ + /** + * simple_xattr_list - list all xattr objects + * @inode: inode from which to get the xattrs +@@ -1323,6 +1332,17 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, + if (err) + return err; + ++ err = security_inode_listsecurity(inode, buffer, remaining_size); ++ if (err < 0) ++ return err; ++ ++ if (buffer) { ++ if (remaining_size < err) ++ return -ERANGE; ++ buffer += err; ++ } ++ remaining_size -= err; ++ + read_lock(&xattrs->lock); + for (rbp = rb_first(&xattrs->rb_root); rbp; rbp = rb_next(rbp)) { + xattr = rb_entry(rbp, struct simple_xattr, rb_node); +@@ -1331,6 +1351,10 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, + if (!trusted && xattr_is_trusted(xattr->name)) + continue; + ++ /* skip MAC labels; these are provided by LSM above */ ++ if (xattr_is_maclabel(xattr->name)) ++ continue; ++ + err = xattr_list_one(&buffer, &remaining_size, xattr->name); + if (err) + break; +diff --git a/include/linux/bio.h b/include/linux/bio.h +index 0286bada25ce72..b893418c3cc022 100644 +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -11,6 +11,7 @@ + #include + + #define BIO_MAX_VECS 256U ++#define BIO_MAX_INLINE_VECS UIO_MAXIOV + + struct queue_limits; + +diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h +index 3e7fc905478984..b5bf5315ca8c10 100644 +--- a/include/linux/hyperv.h ++++ b/include/linux/hyperv.h +@@ -1224,13 +1224,6 @@ extern int vmbus_sendpacket(struct vmbus_channel *channel, + enum vmbus_packet_type type, + u32 flags); + +-extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, +- struct hv_page_buffer pagebuffers[], +- u32 pagecount, +- void *buffer, +- u32 bufferlen, +- u64 requestid); +- + extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + struct vmbus_packet_mpb_array *mpb, + u32 desc_size, +diff --git a/include/linux/tpm.h b/include/linux/tpm.h +index 5f4998626a9889..bf8a4ec8a01c1f 100644 +--- a/include/linux/tpm.h ++++ b/include/linux/tpm.h +@@ -181,7 +181,7 @@ enum tpm2_const { + + enum tpm2_timeouts { + TPM2_TIMEOUT_A = 750, +- TPM2_TIMEOUT_B = 2000, ++ TPM2_TIMEOUT_B = 4000, + TPM2_TIMEOUT_C = 200, + TPM2_TIMEOUT_D = 30, + TPM2_DURATION_SHORT = 20, +diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h +index 4ec2a948ae3dbb..3287988a6a9878 100644 +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -1029,6 +1029,21 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct qdisc_skb_head *qh) + return skb; + } + ++static inline struct sk_buff *qdisc_dequeue_internal(struct Qdisc *sch, bool direct) ++{ ++ struct sk_buff *skb; ++ ++ skb = __skb_dequeue(&sch->gso_skb); ++ if (skb) { ++ sch->q.qlen--; ++ return skb; ++ } ++ if (direct) ++ return __qdisc_dequeue_head(&sch->q); ++ else ++ return sch->dequeue(sch); ++} ++ + static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch) + { + struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); +diff --git a/include/sound/ump_msg.h b/include/sound/ump_msg.h +index 72f60ddfea7535..9556b4755a1ed8 100644 +--- a/include/sound/ump_msg.h ++++ b/include/sound/ump_msg.h +@@ -604,7 +604,7 @@ struct snd_ump_stream_msg_ep_info { + } __packed; + + /* UMP Stream Message: Device Info Notification (128bit) */ +-struct snd_ump_stream_msg_devince_info { ++struct snd_ump_stream_msg_device_info { + #ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; +@@ -754,7 +754,7 @@ struct snd_ump_stream_msg_fb_name { + union snd_ump_stream_msg { + struct snd_ump_stream_msg_ep_discovery ep_discovery; + struct snd_ump_stream_msg_ep_info ep_info; +- struct snd_ump_stream_msg_devince_info device_info; ++ struct snd_ump_stream_msg_device_info device_info; + struct snd_ump_stream_msg_stream_cfg stream_cfg; + struct snd_ump_stream_msg_fb_discovery fb_discovery; + struct snd_ump_stream_msg_fb_info fb_info; +diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c +index 3646426c69e253..ad8b62202bdc46 100644 +--- a/kernel/cgroup/cpuset.c ++++ b/kernel/cgroup/cpuset.c +@@ -1229,9 +1229,11 @@ static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus) + + if (top_cs) { + /* +- * Percpu kthreads in top_cpuset are ignored ++ * PF_NO_SETAFFINITY tasks are ignored. ++ * All per cpu kthreads should have PF_NO_SETAFFINITY ++ * flag set, see kthread_set_per_cpu(). + */ +- if (kthread_is_per_cpu(task)) ++ if (task->flags & PF_NO_SETAFFINITY) + continue; + cpumask_andnot(new_cpus, possible_mask, cs->subparts_cpus); + } else { +diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c +index 4376887e0d8aab..c9b0533407edeb 100644 +--- a/kernel/trace/trace_dynevent.c ++++ b/kernel/trace/trace_dynevent.c +@@ -16,7 +16,7 @@ + #include "trace_output.h" /* for trace_event_sem */ + #include "trace_dynevent.h" + +-static DEFINE_MUTEX(dyn_event_ops_mutex); ++DEFINE_MUTEX(dyn_event_ops_mutex); + static LIST_HEAD(dyn_event_ops_list); + + bool trace_event_dyn_try_get_ref(struct trace_event_call *dyn_call) +@@ -125,6 +125,20 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type + return ret; + } + ++/* ++ * Locked version of event creation. The event creation must be protected by ++ * dyn_event_ops_mutex because of protecting trace_probe_log. ++ */ ++int dyn_event_create(const char *raw_command, struct dyn_event_operations *type) ++{ ++ int ret; ++ ++ mutex_lock(&dyn_event_ops_mutex); ++ ret = type->create(raw_command); ++ mutex_unlock(&dyn_event_ops_mutex); ++ return ret; ++} ++ + static int create_dyn_event(const char *raw_command) + { + struct dyn_event_operations *ops; +diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h +index 936477a111d3e7..beee3f8d754444 100644 +--- a/kernel/trace/trace_dynevent.h ++++ b/kernel/trace/trace_dynevent.h +@@ -100,6 +100,7 @@ void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos); + void dyn_event_seq_stop(struct seq_file *m, void *v); + int dyn_events_release_all(struct dyn_event_operations *type); + int dyn_event_release(const char *raw_command, struct dyn_event_operations *type); ++int dyn_event_create(const char *raw_command, struct dyn_event_operations *type); + + /* + * for_each_dyn_event - iterate over the dyn_event list +diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c +index 76abc9a45f971a..2c233c0d38fa95 100644 +--- a/kernel/trace/trace_events_trigger.c ++++ b/kernel/trace/trace_events_trigger.c +@@ -1554,7 +1554,7 @@ stacktrace_trigger(struct event_trigger_data *data, + struct trace_event_file *file = data->private_data; + + if (file) +- __trace_stack(file->tr, tracing_gen_ctx(), STACK_SKIP); ++ __trace_stack(file->tr, tracing_gen_ctx_dec(), STACK_SKIP); + else + trace_dump_stack(STACK_SKIP); + } +diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c +index 69e92c7359fb9a..44ae51d1dc45d8 100644 +--- a/kernel/trace/trace_functions.c ++++ b/kernel/trace/trace_functions.c +@@ -561,11 +561,7 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip, + + static __always_inline void trace_stack(struct trace_array *tr) + { +- unsigned int trace_ctx; +- +- trace_ctx = tracing_gen_ctx(); +- +- __trace_stack(tr, trace_ctx, FTRACE_STACK_SKIP); ++ __trace_stack(tr, tracing_gen_ctx_dec(), FTRACE_STACK_SKIP); + } + + static void +diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c +index 508c10414a9343..46491f3c1569cd 100644 +--- a/kernel/trace/trace_kprobe.c ++++ b/kernel/trace/trace_kprobe.c +@@ -1004,7 +1004,7 @@ static int create_or_delete_trace_kprobe(const char *raw_command) + if (raw_command[0] == '-') + return dyn_event_release(raw_command, &trace_kprobe_ops); + +- ret = trace_kprobe_create(raw_command); ++ ret = dyn_event_create(raw_command, &trace_kprobe_ops); + return ret == -ECANCELED ? -EINVAL : ret; + } + +diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c +index 606190239c8776..694f32d843d90c 100644 +--- a/kernel/trace/trace_probe.c ++++ b/kernel/trace/trace_probe.c +@@ -153,9 +153,12 @@ static const struct fetch_type *find_fetch_type(const char *type, unsigned long + } + + static struct trace_probe_log trace_probe_log; ++extern struct mutex dyn_event_ops_mutex; + + void trace_probe_log_init(const char *subsystem, int argc, const char **argv) + { ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + trace_probe_log.subsystem = subsystem; + trace_probe_log.argc = argc; + trace_probe_log.argv = argv; +@@ -164,11 +167,15 @@ void trace_probe_log_init(const char *subsystem, int argc, const char **argv) + + void trace_probe_log_clear(void) + { ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + memset(&trace_probe_log, 0, sizeof(trace_probe_log)); + } + + void trace_probe_log_set_index(int index) + { ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + trace_probe_log.index = index; + } + +@@ -177,6 +184,8 @@ void __trace_probe_log_err(int offset, int err_type) + char *command, *p; + int i, len = 0, pos = 0; + ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + if (!trace_probe_log.argv) + return; + +diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c +index 79f8da7e3cd492..ecf04e81ddf705 100644 +--- a/kernel/trace/trace_uprobe.c ++++ b/kernel/trace/trace_uprobe.c +@@ -730,7 +730,7 @@ static int create_or_delete_trace_uprobe(const char *raw_command) + if (raw_command[0] == '-') + return dyn_event_release(raw_command, &trace_uprobe_ops); + +- ret = trace_uprobe_create(raw_command); ++ ret = dyn_event_create(raw_command, &trace_uprobe_ops); + return ret == -ECANCELED ? -EINVAL : ret; + } + +diff --git a/mm/memblock.c b/mm/memblock.c +index 047dce35cf6e0e..0695284232f3c6 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -460,7 +460,14 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, + min(new_area_start, memblock.current_limit), + new_alloc_size, PAGE_SIZE); + +- new_array = addr ? __va(addr) : NULL; ++ if (addr) { ++ /* The memory may not have been accepted, yet. */ ++ accept_memory(addr, addr + new_alloc_size); ++ ++ new_array = __va(addr); ++ } else { ++ new_array = NULL; ++ } + } + if (!addr) { + pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", +diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c +index 9beed7c71a8e91..aab16690545207 100644 +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -1735,8 +1735,12 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) + if (PageHWPoison(page)) { + if (WARN_ON(folio_test_lru(folio))) + folio_isolate_lru(folio); +- if (folio_mapped(folio)) ++ if (folio_mapped(folio)) { ++ folio_lock(folio); + try_to_unmap(folio, TTU_IGNORE_MLOCK); ++ folio_unlock(folio); ++ } ++ + continue; + } + +diff --git a/mm/migrate.c b/mm/migrate.c +index 1004b1def1c201..4ed47088521746 100644 +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -1504,6 +1504,7 @@ struct migrate_pages_stats { + int nr_thp_succeeded; /* THP migrated successfully */ + int nr_thp_failed; /* THP failed to be migrated */ + int nr_thp_split; /* THP split before migrating */ ++ int nr_split; /* Large folio (include THP) split before migrating */ + }; + + /* +@@ -1623,6 +1624,7 @@ static int migrate_pages_batch(struct list_head *from, + int nr_retry_pages = 0; + int pass = 0; + bool is_thp = false; ++ bool is_large = false; + struct folio *folio, *folio2, *dst = NULL, *dst2; + int rc, rc_saved = 0, nr_pages; + LIST_HEAD(unmap_folios); +@@ -1638,7 +1640,8 @@ static int migrate_pages_batch(struct list_head *from, + nr_retry_pages = 0; + + list_for_each_entry_safe(folio, folio2, from, lru) { +- is_thp = folio_test_large(folio) && folio_test_pmd_mappable(folio); ++ is_large = folio_test_large(folio); ++ is_thp = is_large && folio_test_pmd_mappable(folio); + nr_pages = folio_nr_pages(folio); + + cond_resched(); +@@ -1658,6 +1661,7 @@ static int migrate_pages_batch(struct list_head *from, + stats->nr_thp_failed++; + if (!try_split_folio(folio, split_folios)) { + stats->nr_thp_split++; ++ stats->nr_split++; + continue; + } + stats->nr_failed_pages += nr_pages; +@@ -1686,11 +1690,12 @@ static int migrate_pages_batch(struct list_head *from, + nr_failed++; + stats->nr_thp_failed += is_thp; + /* Large folio NUMA faulting doesn't split to retry. */ +- if (folio_test_large(folio) && !nosplit) { ++ if (is_large && !nosplit) { + int ret = try_split_folio(folio, split_folios); + + if (!ret) { + stats->nr_thp_split += is_thp; ++ stats->nr_split += is_large; + break; + } else if (reason == MR_LONGTERM_PIN && + ret == -EAGAIN) { +@@ -1836,6 +1841,7 @@ static int migrate_pages_sync(struct list_head *from, new_folio_t get_new_folio, + stats->nr_succeeded += astats.nr_succeeded; + stats->nr_thp_succeeded += astats.nr_thp_succeeded; + stats->nr_thp_split += astats.nr_thp_split; ++ stats->nr_split += astats.nr_split; + if (rc < 0) { + stats->nr_failed_pages += astats.nr_failed_pages; + stats->nr_thp_failed += astats.nr_thp_failed; +@@ -1843,7 +1849,11 @@ static int migrate_pages_sync(struct list_head *from, new_folio_t get_new_folio, + return rc; + } + stats->nr_thp_failed += astats.nr_thp_split; +- nr_failed += astats.nr_thp_split; ++ /* ++ * Do not count rc, as pages will be retried below. ++ * Count nr_split only, since it includes nr_thp_split. ++ */ ++ nr_failed += astats.nr_split; + /* + * Fall back to migrate all failed folios one by one synchronously. All + * failed folios except split THPs will be retried, so their failure +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index bc62bb2a3b132e..74737c35082b45 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -303,7 +303,6 @@ EXPORT_SYMBOL(nr_online_nodes); + static bool page_contains_unaccepted(struct page *page, unsigned int order); + static void accept_page(struct page *page, unsigned int order); + static bool cond_accept_memory(struct zone *zone, unsigned int order); +-static inline bool has_unaccepted_memory(void); + static bool __free_unaccepted(struct page *page); + + int page_group_by_mobility_disabled __read_mostly; +@@ -6586,9 +6585,6 @@ bool has_managed_dma(void) + + #ifdef CONFIG_UNACCEPTED_MEMORY + +-/* Counts number of zones with unaccepted pages. */ +-static DEFINE_STATIC_KEY_FALSE(zones_with_unaccepted_pages); +- + static bool lazy_accept = true; + + static int __init accept_memory_parse(char *p) +@@ -6624,7 +6620,6 @@ static bool try_to_accept_memory_one(struct zone *zone) + { + unsigned long flags; + struct page *page; +- bool last; + + spin_lock_irqsave(&zone->lock, flags); + page = list_first_entry_or_null(&zone->unaccepted_pages, +@@ -6635,7 +6630,6 @@ static bool try_to_accept_memory_one(struct zone *zone) + } + + list_del(&page->lru); +- last = list_empty(&zone->unaccepted_pages); + + __mod_zone_freepage_state(zone, -MAX_ORDER_NR_PAGES, MIGRATE_MOVABLE); + __mod_zone_page_state(zone, NR_UNACCEPTED, -MAX_ORDER_NR_PAGES); +@@ -6645,9 +6639,6 @@ static bool try_to_accept_memory_one(struct zone *zone) + + __free_pages_ok(page, MAX_ORDER, FPI_TO_TAIL); + +- if (last) +- static_branch_dec(&zones_with_unaccepted_pages); +- + return true; + } + +@@ -6656,9 +6647,6 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order) + long to_accept, wmark; + bool ret = false; + +- if (!has_unaccepted_memory()) +- return false; +- + if (list_empty(&zone->unaccepted_pages)) + return false; + +@@ -6688,30 +6676,20 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order) + return ret; + } + +-static inline bool has_unaccepted_memory(void) +-{ +- return static_branch_unlikely(&zones_with_unaccepted_pages); +-} +- + static bool __free_unaccepted(struct page *page) + { + struct zone *zone = page_zone(page); + unsigned long flags; +- bool first = false; + + if (!lazy_accept) + return false; + + spin_lock_irqsave(&zone->lock, flags); +- first = list_empty(&zone->unaccepted_pages); + list_add_tail(&page->lru, &zone->unaccepted_pages); + __mod_zone_freepage_state(zone, MAX_ORDER_NR_PAGES, MIGRATE_MOVABLE); + __mod_zone_page_state(zone, NR_UNACCEPTED, MAX_ORDER_NR_PAGES); + spin_unlock_irqrestore(&zone->lock, flags); + +- if (first) +- static_branch_inc(&zones_with_unaccepted_pages); +- + return true; + } + +@@ -6731,11 +6709,6 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order) + return false; + } + +-static inline bool has_unaccepted_memory(void) +-{ +- return false; +-} +- + static bool __free_unaccepted(struct page *page) + { + BUILD_BUG(); +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 29e420e9754bb3..589c3a481e4c10 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -7605,11 +7605,16 @@ static void add_device_complete(struct hci_dev *hdev, void *data, int err) + struct mgmt_cp_add_device *cp = cmd->param; + + if (!err) { ++ struct hci_conn_params *params; ++ ++ params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, ++ le_addr_type(cp->addr.type)); ++ + device_added(cmd->sk, hdev, &cp->addr.bdaddr, cp->addr.type, + cp->action); + device_flags_changed(NULL, hdev, &cp->addr.bdaddr, + cp->addr.type, hdev->conn_flags, +- PTR_UINT(cmd->user_data)); ++ params ? params->flags : 0); + } + + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_ADD_DEVICE, +@@ -7712,8 +7717,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, + goto unlock; + } + +- cmd->user_data = UINT_PTR(current_flags); +- + err = hci_cmd_sync_queue(hdev, add_device_sync, cmd, + add_device_complete); + if (err < 0) { +diff --git a/net/mac80211/main.c b/net/mac80211/main.c +index d1046f495e63ff..3a6fff98748b86 100644 +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1186,10 +1186,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) + return -EINVAL; + } + +- local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + +- sizeof(void *) * channels, GFP_KERNEL); ++ local->int_scan_req = kzalloc(struct_size(local->int_scan_req, ++ channels, channels), ++ GFP_KERNEL); + if (!local->int_scan_req) + return -ENOMEM; ++ local->int_scan_req->n_channels = channels; + + eth_broadcast_addr(local->int_scan_req->bssid); + +diff --git a/net/mctp/device.c b/net/mctp/device.c +index 85cc5f31f1e7c0..8d1386601bbe06 100644 +--- a/net/mctp/device.c ++++ b/net/mctp/device.c +@@ -20,8 +20,7 @@ + #include + + struct mctp_dump_cb { +- int h; +- int idx; ++ unsigned long ifindex; + size_t a_idx; + }; + +@@ -115,43 +114,36 @@ static int mctp_dump_addrinfo(struct sk_buff *skb, struct netlink_callback *cb) + { + struct mctp_dump_cb *mcb = (void *)cb->ctx; + struct net *net = sock_net(skb->sk); +- struct hlist_head *head; + struct net_device *dev; + struct ifaddrmsg *hdr; + struct mctp_dev *mdev; +- int ifindex; +- int idx = 0, rc; +- +- hdr = nlmsg_data(cb->nlh); +- // filter by ifindex if requested +- ifindex = hdr->ifa_index; ++ int ifindex = 0, rc; ++ ++ /* Filter by ifindex if a header is provided */ ++ if (cb->nlh->nlmsg_len >= nlmsg_msg_size(sizeof(*hdr))) { ++ hdr = nlmsg_data(cb->nlh); ++ ifindex = hdr->ifa_index; ++ } else { ++ if (cb->strict_check) { ++ NL_SET_ERR_MSG(cb->extack, "mctp: Invalid header for addr dump request"); ++ return -EINVAL; ++ } ++ } + + rcu_read_lock(); +- for (; mcb->h < NETDEV_HASHENTRIES; mcb->h++, mcb->idx = 0) { +- idx = 0; +- head = &net->dev_index_head[mcb->h]; +- hlist_for_each_entry_rcu(dev, head, index_hlist) { +- if (idx >= mcb->idx && +- (ifindex == 0 || ifindex == dev->ifindex)) { +- mdev = __mctp_dev_get(dev); +- if (mdev) { +- rc = mctp_dump_dev_addrinfo(mdev, +- skb, cb); +- mctp_dev_put(mdev); +- // Error indicates full buffer, this +- // callback will get retried. +- if (rc < 0) +- goto out; +- } +- } +- idx++; +- // reset for next iteration +- mcb->a_idx = 0; +- } ++ for_each_netdev_dump(net, dev, mcb->ifindex) { ++ if (ifindex && ifindex != dev->ifindex) ++ continue; ++ mdev = __mctp_dev_get(dev); ++ if (!mdev) ++ continue; ++ rc = mctp_dump_dev_addrinfo(mdev, skb, cb); ++ mctp_dev_put(mdev); ++ if (rc < 0) ++ break; ++ mcb->a_idx = 0; + } +-out: + rcu_read_unlock(); +- mcb->idx = idx; + + return skb->len; + } +@@ -525,9 +517,12 @@ static struct notifier_block mctp_dev_nb = { + }; + + static const struct rtnl_msg_handler mctp_device_rtnl_msg_handlers[] = { +- {THIS_MODULE, PF_MCTP, RTM_NEWADDR, mctp_rtm_newaddr, NULL, 0}, +- {THIS_MODULE, PF_MCTP, RTM_DELADDR, mctp_rtm_deladdr, NULL, 0}, +- {THIS_MODULE, PF_MCTP, RTM_GETADDR, NULL, mctp_dump_addrinfo, 0}, ++ {.owner = THIS_MODULE, .protocol = PF_MCTP, .msgtype = RTM_NEWADDR, ++ .doit = mctp_rtm_newaddr}, ++ {.owner = THIS_MODULE, .protocol = PF_MCTP, .msgtype = RTM_DELADDR, ++ .doit = mctp_rtm_deladdr}, ++ {.owner = THIS_MODULE, .protocol = PF_MCTP, .msgtype = RTM_GETADDR, ++ .dumpit = mctp_dump_addrinfo}, + }; + + int __init mctp_device_init(void) +diff --git a/net/mctp/route.c b/net/mctp/route.c +index d3c1f54386efc1..009ba5edbd5254 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -274,8 +274,10 @@ static void mctp_flow_prepare_output(struct sk_buff *skb, struct mctp_dev *dev) + + key = flow->key; + +- if (WARN_ON(key->dev && key->dev != dev)) ++ if (key->dev) { ++ WARN_ON(key->dev != dev); + return; ++ } + + mctp_dev_set_key(dev, key); + } +diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c +index 5f2e0681574567..63c02040b426ae 100644 +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -168,7 +168,7 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt, + + qlen = sch->q.qlen; + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, true); + + dropped += qdisc_pkt_len(skb); + qdisc_qstats_backlog_dec(sch, skb); +diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c +index f59a2cb2c803d7..91f5ef6be0f231 100644 +--- a/net/sched/sch_fq.c ++++ b/net/sched/sch_fq.c +@@ -901,7 +901,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt, + sch_tree_lock(sch); + } + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = fq_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + if (!skb) + break; +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 9330923a624c02..47b5a056165cb0 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -431,7 +431,7 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt, + + while (sch->q.qlen > sch->limit || + q->memory_usage > q->memory_limit) { +- struct sk_buff *skb = fq_codel_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + q->cstats.drop_len += qdisc_pkt_len(skb); + rtnl_kfree_skbs(skb, skb); +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index 68e6acd0f130d9..607c580d75e4b6 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -357,7 +357,7 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt, + + /* Drop excess packets if new limit is lower */ + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = fq_pie_qdisc_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + len_dropped += qdisc_pkt_len(skb); + num_dropped += 1; +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index d26cd436cbe31b..83fc44f20e31cb 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -560,7 +560,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt, + qlen = sch->q.qlen; + prev_backlog = sch->qstats.backlog; + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = hhf_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + rtnl_kfree_skbs(skb, skb); + } +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index 2da6250ec34636..48c5ab8ec143c1 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -190,7 +190,7 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt, + /* Drop excess packets if new limit is lower */ + qlen = sch->q.qlen; + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, true); + + dropped += qdisc_pkt_len(skb); + qdisc_qstats_backlog_dec(sch, skb); +diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c +index fd73be940f4607..77a76634014a5a 100644 +--- a/net/sctp/sysctl.c ++++ b/net/sctp/sysctl.c +@@ -529,6 +529,8 @@ static int proc_sctp_do_auth(struct ctl_table *ctl, int write, + return ret; + } + ++static DEFINE_MUTEX(sctp_sysctl_mutex); ++ + static int proc_sctp_do_udp_port(struct ctl_table *ctl, int write, + void *buffer, size_t *lenp, loff_t *ppos) + { +@@ -553,6 +555,7 @@ static int proc_sctp_do_udp_port(struct ctl_table *ctl, int write, + if (new_value > max || new_value < min) + return -EINVAL; + ++ mutex_lock(&sctp_sysctl_mutex); + net->sctp.udp_port = new_value; + sctp_udp_sock_stop(net); + if (new_value) { +@@ -565,6 +568,7 @@ static int proc_sctp_do_udp_port(struct ctl_table *ctl, int write, + lock_sock(sk); + sctp_sk(sk)->udp_port = htons(net->sctp.udp_port); + release_sock(sk); ++ mutex_unlock(&sctp_sysctl_mutex); + } + + return ret; +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index 5df08d848b5c9c..1852fac3e72b76 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -395,7 +395,6 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) + return 0; + + shinfo = skb_shinfo(strp->anchor); +- shinfo->frag_list = NULL; + + /* If we don't know the length go max plus page for cipher overhead */ + need_spc = strp->stm.full_len ?: TLS_MAX_PAYLOAD_SIZE + PAGE_SIZE; +@@ -411,6 +410,8 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) + page, 0, 0); + } + ++ shinfo->frag_list = NULL; ++ + strp->copy_mode = 1; + strp->stm.offset = 0; + +diff --git a/samples/ftrace/sample-trace-array.c b/samples/ftrace/sample-trace-array.c +index d0ee9001c7b376..aaa8fa92e24d52 100644 +--- a/samples/ftrace/sample-trace-array.c ++++ b/samples/ftrace/sample-trace-array.c +@@ -112,7 +112,7 @@ static int __init sample_trace_array_init(void) + /* + * If context specific per-cpu buffers havent already been allocated. + */ +- trace_printk_init_buffers(); ++ trace_array_init_printk(tr); + + simple_tsk = kthread_run(simple_thread, NULL, "sample-instance"); + if (IS_ERR(simple_tsk)) { +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 6195fe9dda1799..49f6763c3250dd 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -736,15 +736,21 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, + */ + static int __deliver_to_subscribers(struct snd_seq_client *client, + struct snd_seq_event *event, +- struct snd_seq_client_port *src_port, +- int atomic, int hop) ++ int port, int atomic, int hop) + { ++ struct snd_seq_client_port *src_port; + struct snd_seq_subscribers *subs; + int err, result = 0, num_ev = 0; + union __snd_seq_event event_saved; + size_t saved_size; + struct snd_seq_port_subs_info *grp; + ++ if (port < 0) ++ return 0; ++ src_port = snd_seq_port_use_ptr(client, port); ++ if (!src_port) ++ return 0; ++ + /* save original event record */ + saved_size = snd_seq_event_packet_size(event); + memcpy(&event_saved, event, saved_size); +@@ -780,6 +786,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, + read_unlock(&grp->list_lock); + else + up_read(&grp->list_mutex); ++ snd_seq_port_unlock(src_port); + memcpy(event, &event_saved, saved_size); + return (result < 0) ? result : num_ev; + } +@@ -788,25 +795,32 @@ static int deliver_to_subscribers(struct snd_seq_client *client, + struct snd_seq_event *event, + int atomic, int hop) + { +- struct snd_seq_client_port *src_port; +- int ret = 0, ret2; +- +- src_port = snd_seq_port_use_ptr(client, event->source.port); +- if (src_port) { +- ret = __deliver_to_subscribers(client, event, src_port, atomic, hop); +- snd_seq_port_unlock(src_port); +- } +- +- if (client->ump_endpoint_port < 0 || +- event->source.port == client->ump_endpoint_port) +- return ret; ++ int ret; ++#if IS_ENABLED(CONFIG_SND_SEQ_UMP) ++ int ret2; ++#endif + +- src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port); +- if (!src_port) ++ ret = __deliver_to_subscribers(client, event, ++ event->source.port, atomic, hop); ++#if IS_ENABLED(CONFIG_SND_SEQ_UMP) ++ if (!snd_seq_client_is_ump(client) || client->ump_endpoint_port < 0) + return ret; +- ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop); +- snd_seq_port_unlock(src_port); +- return ret2 < 0 ? ret2 : ret; ++ /* If it's an event from EP port (and with a UMP group), ++ * deliver to subscribers of the corresponding UMP group port, too. ++ * Or, if it's from non-EP port, deliver to subscribers of EP port, too. ++ */ ++ if (event->source.port == client->ump_endpoint_port) ++ ret2 = __deliver_to_subscribers(client, event, ++ snd_seq_ump_group_port(event), ++ atomic, hop); ++ else ++ ret2 = __deliver_to_subscribers(client, event, ++ client->ump_endpoint_port, ++ atomic, hop); ++ if (ret2 < 0) ++ return ret2; ++#endif ++ return ret; + } + + /* deliver an event to the destination port(s). +diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c +index 4dd540cbb1cbbc..83a27362b7a066 100644 +--- a/sound/core/seq/seq_ump_convert.c ++++ b/sound/core/seq/seq_ump_convert.c +@@ -1284,3 +1284,21 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source, + else + return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop); + } ++ ++/* return the UMP group-port number of the event; ++ * return -1 if groupless or non-UMP event ++ */ ++int snd_seq_ump_group_port(const struct snd_seq_event *event) ++{ ++ const struct snd_seq_ump_event *ump_ev = ++ (const struct snd_seq_ump_event *)event; ++ unsigned char type; ++ ++ if (!snd_seq_ev_is_ump(event)) ++ return -1; ++ type = ump_message_type(ump_ev->ump[0]); ++ if (ump_is_groupless_msg(type)) ++ return -1; ++ /* group-port number starts from 1 */ ++ return ump_message_group(ump_ev->ump[0]) + 1; ++} +diff --git a/sound/core/seq/seq_ump_convert.h b/sound/core/seq/seq_ump_convert.h +index 6c146d8032804f..4abf0a7637d701 100644 +--- a/sound/core/seq/seq_ump_convert.h ++++ b/sound/core/seq/seq_ump_convert.h +@@ -18,5 +18,6 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop); ++int snd_seq_ump_group_port(const struct snd_seq_event *event); + + #endif /* __SEQ_UMP_CONVERT_H */ +diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c +index 4bc0f53c223b79..bc9203da35fb6f 100644 +--- a/sound/pci/es1968.c ++++ b/sound/pci/es1968.c +@@ -1569,7 +1569,7 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) + struct snd_pcm_runtime *runtime = substream->runtime; + struct es1968 *chip = snd_pcm_substream_chip(substream); + struct esschan *es; +- int apu1, apu2; ++ int err, apu1, apu2; + + apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE); + if (apu1 < 0) +@@ -1613,7 +1613,9 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) + runtime->hw = snd_es1968_capture; + runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = + calc_available_memory_size(chip) - 1024; /* keep MIXBUF size */ +- snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); ++ err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); ++ if (err < 0) ++ return err; + + spin_lock_irq(&chip->substream_lock); + list_add(&es->list, &chip->substream_list); +diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig +index b75fbb3236a7b9..f5fa09d740b4c9 100644 +--- a/sound/sh/Kconfig ++++ b/sound/sh/Kconfig +@@ -14,7 +14,7 @@ if SND_SUPERH + + config SND_AICA + tristate "Dreamcast Yamaha AICA sound" +- depends on SH_DREAMCAST ++ depends on SH_DREAMCAST && SH_DMA_API + select SND_PCM + select G2_DMA + help +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index d9d4c5922a50bb..0b8b20550ab381 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2140,6 +2140,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */ + QUIRK_FLAG_GET_SAMPLE_RATE), ++ DEVICE_FLG(0x0c45, 0x636b, /* Microdia JP001 USB Camera */ ++ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x0d8c, 0x0014, /* USB Audio Device */ + QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ +@@ -2148,6 +2150,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_FIXED_RATE), + DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */ + QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), ++ DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ ++ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), + DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ +diff --git a/tools/net/ynl/ethtool.py b/tools/net/ynl/ethtool.py +index 6c9f7e31250cdb..ffd8eb6d190483 100755 +--- a/tools/net/ynl/ethtool.py ++++ b/tools/net/ynl/ethtool.py +@@ -320,20 +320,37 @@ def main(): + return + + if args.show_time_stamping: +- tsinfo = dumpit(ynl, args, 'tsinfo-get') ++ req = { ++ 'header': { ++ 'flags': 'stats', ++ }, ++ } ++ ++ tsinfo = dumpit(ynl, args, 'tsinfo-get', req) + + print(f'Time stamping parameters for {args.device}:') + + print('Capabilities:') + [print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])] + +- print(f'PTP Hardware Clock: {tsinfo["phc-index"]}') ++ print(f'PTP Hardware Clock: {tsinfo.get("phc-index", "none")}') ++ ++ if 'tx-types' in tsinfo: ++ print('Hardware Transmit Timestamp Modes:') ++ [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] ++ else: ++ print('Hardware Transmit Timestamp Modes: none') ++ ++ if 'rx-filters' in tsinfo: ++ print('Hardware Receive Filter Modes:') ++ [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] ++ else: ++ print('Hardware Receive Filter Modes: none') + +- print('Hardware Transmit Timestamp Modes:') +- [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] ++ if 'stats' in tsinfo and tsinfo['stats']: ++ print('Statistics:') ++ [print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()] + +- print('Hardware Receive Filter Modes:') +- [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] + return + + print(f'Settings for {args.device}:') +diff --git a/tools/testing/selftests/exec/Makefile b/tools/testing/selftests/exec/Makefile +index a0b8688b083694..a705493c04bb73 100644 +--- a/tools/testing/selftests/exec/Makefile ++++ b/tools/testing/selftests/exec/Makefile +@@ -3,8 +3,13 @@ CFLAGS = -Wall + CFLAGS += -Wno-nonnull + CFLAGS += -D_GNU_SOURCE + ++ALIGNS := 0x1000 0x200000 0x1000000 ++ALIGN_PIES := $(patsubst %,load_address.%,$(ALIGNS)) ++ALIGN_STATIC_PIES := $(patsubst %,load_address.static.%,$(ALIGNS)) ++ALIGNMENT_TESTS := $(ALIGN_PIES) $(ALIGN_STATIC_PIES) ++ + TEST_PROGS := binfmt_script.py +-TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216 non-regular ++TEST_GEN_PROGS := execveat non-regular $(ALIGNMENT_TESTS) + TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir + # Makefile is a run-time dependency, since it's accessed by the execveat test + TEST_FILES := Makefile +@@ -28,9 +33,9 @@ $(OUTPUT)/execveat.symlink: $(OUTPUT)/execveat + $(OUTPUT)/execveat.denatured: $(OUTPUT)/execveat + cp $< $@ + chmod -x $@ +-$(OUTPUT)/load_address_4096: load_address.c +- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000 -pie -static $< -o $@ +-$(OUTPUT)/load_address_2097152: load_address.c +- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x200000 -pie -static $< -o $@ +-$(OUTPUT)/load_address_16777216: load_address.c +- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000000 -pie -static $< -o $@ ++$(OUTPUT)/load_address.0x%: load_address.c ++ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \ ++ -fPIE -pie $< -o $@ ++$(OUTPUT)/load_address.static.0x%: load_address.c ++ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \ ++ -fPIE -static-pie $< -o $@ +diff --git a/tools/testing/selftests/exec/load_address.c b/tools/testing/selftests/exec/load_address.c +index d487c2f6a61509..8257fddba8c8db 100644 +--- a/tools/testing/selftests/exec/load_address.c ++++ b/tools/testing/selftests/exec/load_address.c +@@ -5,10 +5,13 @@ + #include + #include + #include ++#include ++#include "../kselftest.h" + + struct Statistics { + unsigned long long load_address; + unsigned long long alignment; ++ bool interp; + }; + + int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data) +@@ -25,11 +28,20 @@ int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data) + stats->alignment = 0; + + for (i = 0; i < info->dlpi_phnum; i++) { ++ unsigned long long align; ++ ++ if (info->dlpi_phdr[i].p_type == PT_INTERP) { ++ stats->interp = true; ++ continue; ++ } ++ + if (info->dlpi_phdr[i].p_type != PT_LOAD) + continue; + +- if (info->dlpi_phdr[i].p_align > stats->alignment) +- stats->alignment = info->dlpi_phdr[i].p_align; ++ align = info->dlpi_phdr[i].p_align; ++ ++ if (align > stats->alignment) ++ stats->alignment = align; + } + + return 1; // Terminate dl_iterate_phdr. +@@ -37,32 +49,57 @@ int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data) + + int main(int argc, char **argv) + { +- struct Statistics extracted; +- unsigned long long misalign; ++ struct Statistics extracted = { }; ++ unsigned long long misalign, pow2; ++ bool interp_needed; ++ char buf[1024]; ++ FILE *maps; + int ret; + +- ret = dl_iterate_phdr(ExtractStatistics, &extracted); +- if (ret != 1) { +- fprintf(stderr, "FAILED\n"); +- return 1; +- } ++ ksft_print_header(); ++ ksft_set_plan(4); + +- if (extracted.alignment == 0) { +- fprintf(stderr, "No alignment found\n"); +- return 1; +- } else if (extracted.alignment & (extracted.alignment - 1)) { +- fprintf(stderr, "Alignment is not a power of 2\n"); +- return 1; ++ /* Dump maps file for debugging reference. */ ++ maps = fopen("/proc/self/maps", "r"); ++ if (!maps) ++ ksft_exit_fail_msg("FAILED: /proc/self/maps: %s\n", strerror(errno)); ++ while (fgets(buf, sizeof(buf), maps)) { ++ ksft_print_msg("%s", buf); + } ++ fclose(maps); ++ ++ /* Walk the program headers. */ ++ ret = dl_iterate_phdr(ExtractStatistics, &extracted); ++ if (ret != 1) ++ ksft_exit_fail_msg("FAILED: dl_iterate_phdr\n"); ++ ++ /* Report our findings. */ ++ ksft_print_msg("load_address=%#llx alignment=%#llx\n", ++ extracted.load_address, extracted.alignment); ++ ++ /* If we're named with ".static." we expect no INTERP. */ ++ interp_needed = strstr(argv[0], ".static.") == NULL; ++ ++ /* Were we built as expected? */ ++ ksft_test_result(interp_needed == extracted.interp, ++ "%s INTERP program header %s\n", ++ interp_needed ? "Wanted" : "Unwanted", ++ extracted.interp ? "seen" : "missing"); + ++ /* Did we find an alignment? */ ++ ksft_test_result(extracted.alignment != 0, ++ "Alignment%s found\n", extracted.alignment ? "" : " NOT"); ++ ++ /* Is the alignment sane? */ ++ pow2 = extracted.alignment & (extracted.alignment - 1); ++ ksft_test_result(pow2 == 0, ++ "Alignment is%s a power of 2: %#llx\n", ++ pow2 == 0 ? "" : " NOT", extracted.alignment); ++ ++ /* Is the load address aligned? */ + misalign = extracted.load_address & (extracted.alignment - 1); +- if (misalign) { +- printf("alignment = %llu, load_address = %llu\n", +- extracted.alignment, extracted.load_address); +- fprintf(stderr, "FAILED\n"); +- return 1; +- } ++ ksft_test_result(misalign == 0, "Load Address is %saligned (%#llx)\n", ++ misalign ? "MIS" : "", misalign); + +- fprintf(stderr, "PASS\n"); +- return 0; ++ ksft_finished(); + } +diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c +index 309b3750e57e13..38fec412206b9a 100644 +--- a/tools/testing/selftests/mm/compaction_test.c ++++ b/tools/testing/selftests/mm/compaction_test.c +@@ -89,6 +89,8 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size) + int compaction_index = 0; + char initial_nr_hugepages[20] = {0}; + char nr_hugepages[20] = {0}; ++ char target_nr_hugepages[24] = {0}; ++ int slen; + + /* We want to test with 80% of available memory. Else, OOM killer comes + in to play */ +@@ -119,11 +121,18 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size) + + lseek(fd, 0, SEEK_SET); + +- /* Request a large number of huge pages. The Kernel will allocate +- as much as it can */ +- if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { +- ksft_print_msg("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); ++ /* ++ * Request huge pages for about half of the free memory. The Kernel ++ * will allocate as much as it can, and we expect it will get at least 1/3 ++ */ ++ nr_hugepages_ul = mem_free / hugepage_size / 2; ++ snprintf(target_nr_hugepages, sizeof(target_nr_hugepages), ++ "%lu", nr_hugepages_ul); ++ ++ slen = strlen(target_nr_hugepages); ++ if (write(fd, target_nr_hugepages, slen) != slen) { ++ ksft_print_msg("Failed to write %lu to /proc/sys/vm/nr_hugepages: %s\n", ++ nr_hugepages_ul, strerror(errno)); + goto close_fd; + } + diff --git a/patch/kernel/archive/odroidxu4-6.6/patch-6.6.92-93.patch b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.92-93.patch new file mode 100644 index 000000000000..24359d6adb34 --- /dev/null +++ b/patch/kernel/archive/odroidxu4-6.6/patch-6.6.92-93.patch @@ -0,0 +1,20602 @@ +diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd +index 825e619250bf2e..f2ec42949a54d7 100644 +--- a/Documentation/ABI/stable/sysfs-driver-dma-idxd ++++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd +@@ -270,6 +270,12 @@ Description: Shows the operation capability bits displayed in bitmap format + correlates to the operations allowed. It's visible only + on platforms that support the capability. + ++What: /sys/bus/dsa/devices/wq./driver_name ++Date: Sept 8, 2023 ++KernelVersion: 6.7.0 ++Contact: dmaengine@vger.kernel.org ++Description: Name of driver to be bounded to the wq. ++ + What: /sys/bus/dsa/devices/engine./group_id + Date: Oct 25, 2019 + KernelVersion: 5.6.0 +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index f95734ceb82b86..315a817e338042 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -5978,6 +5978,8 @@ + + Selecting 'on' will also enable the mitigation + against user space to user space task attacks. ++ Selecting specific mitigation does not force enable ++ user mitigations. + + Selecting 'off' will disable both the kernel and + the user space protections. +diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst +index 84b43061c11be2..60434f2b028637 100644 +--- a/Documentation/driver-api/serial/driver.rst ++++ b/Documentation/driver-api/serial/driver.rst +@@ -103,4 +103,4 @@ Some helpers are provided in order to set/get modem control lines via GPIO. + .. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c + :identifiers: mctrl_gpio_init mctrl_gpio_free mctrl_gpio_to_gpiod + mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms +- mctrl_gpio_disable_ms ++ mctrl_gpio_disable_ms_sync mctrl_gpio_disable_ms_no_sync +diff --git a/Documentation/hwmon/dell-smm-hwmon.rst b/Documentation/hwmon/dell-smm-hwmon.rst +index d8f1d6859b964b..1c12fbba440bca 100644 +--- a/Documentation/hwmon/dell-smm-hwmon.rst ++++ b/Documentation/hwmon/dell-smm-hwmon.rst +@@ -32,12 +32,12 @@ Temperature sensors and fans can be queried and set via the standard + =============================== ======= ======================================= + Name Perm Description + =============================== ======= ======================================= +-fan[1-3]_input RO Fan speed in RPM. +-fan[1-3]_label RO Fan label. +-fan[1-3]_min RO Minimal Fan speed in RPM +-fan[1-3]_max RO Maximal Fan speed in RPM +-fan[1-3]_target RO Expected Fan speed in RPM +-pwm[1-3] RW Control the fan PWM duty-cycle. ++fan[1-4]_input RO Fan speed in RPM. ++fan[1-4]_label RO Fan label. ++fan[1-4]_min RO Minimal Fan speed in RPM ++fan[1-4]_max RO Maximal Fan speed in RPM ++fan[1-4]_target RO Expected Fan speed in RPM ++pwm[1-4] RW Control the fan PWM duty-cycle. + pwm1_enable WO Enable or disable automatic BIOS fan + control (not supported on all laptops, + see below for details). +@@ -93,7 +93,7 @@ Again, when you find new codes, we'd be happy to have your patches! + --------------------------- + + The driver also exports the fans as thermal cooling devices with +-``type`` set to ``dell-smm-fan[1-3]``. This allows for easy fan control ++``type`` set to ``dell-smm-fan[1-4]``. This allows for easy fan control + using one of the thermal governors. + + Module parameters +diff --git a/Makefile b/Makefile +index 51d975b3555195..c9a1e2286b3a79 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 92 ++SUBLEVEL = 93 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm/boot/dts/nvidia/tegra114.dtsi b/arch/arm/boot/dts/nvidia/tegra114.dtsi +index 86f14e2fd29f3a..6c057b50695140 100644 +--- a/arch/arm/boot/dts/nvidia/tegra114.dtsi ++++ b/arch/arm/boot/dts/nvidia/tegra114.dtsi +@@ -139,7 +139,7 @@ dsib: dsi@54400000 { + reg = <0x54400000 0x00040000>; + clocks = <&tegra_car TEGRA114_CLK_DSIB>, + <&tegra_car TEGRA114_CLK_DSIBLP>, +- <&tegra_car TEGRA114_CLK_PLL_D2_OUT0>; ++ <&tegra_car TEGRA114_CLK_PLL_D_OUT0>; + clock-names = "dsi", "lp", "parent"; + resets = <&tegra_car 82>; + reset-names = "dsi"; +diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c +index 22ecaf09d00f96..f635ad29511f6a 100644 +--- a/arch/arm/mach-at91/pm.c ++++ b/arch/arm/mach-at91/pm.c +@@ -538,11 +538,12 @@ extern u32 at91_pm_suspend_in_sram_sz; + + static int at91_suspend_finish(unsigned long val) + { +- unsigned char modified_gray_code[] = { +- 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0c, 0x0d, +- 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, 0x18, 0x19, 0x1a, 0x1b, +- 0x1e, 0x1f, 0x1c, 0x1d, 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, +- 0x10, 0x11, ++ /* SYNOPSYS workaround to fix a bug in the calibration logic */ ++ unsigned char modified_fix_code[] = { ++ 0x00, 0x01, 0x01, 0x06, 0x07, 0x0c, 0x06, 0x07, 0x0b, 0x18, ++ 0x0a, 0x0b, 0x0c, 0x0d, 0x0d, 0x0a, 0x13, 0x13, 0x12, 0x13, ++ 0x14, 0x15, 0x15, 0x12, 0x18, 0x19, 0x19, 0x1e, 0x1f, 0x14, ++ 0x1e, 0x1f, + }; + unsigned int tmp, index; + int i; +@@ -553,25 +554,25 @@ static int at91_suspend_finish(unsigned long val) + * restore the ZQ0SR0 with the value saved here. But the + * calibration is buggy and restoring some values from ZQ0SR0 + * is forbidden and risky thus we need to provide processed +- * values for these (modified gray code values). ++ * values for these. + */ + tmp = readl(soc_pm.data.ramc_phy + DDR3PHY_ZQ0SR0); + + /* Store pull-down output impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PDO_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] = modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] = modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDO_OFF; + + /* Store pull-up output impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PUO_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PUO_OFF; + + /* Store pull-down on-die termination impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PDODT_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDODT_OFF; + + /* Store pull-up on-die termination impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SRO_PUODT_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SRO_PUODT_OFF; + + /* + * The 1st 8 words of memory might get corrupted in the process +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +index 381d58cea092d9..c854c7e3105196 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +@@ -151,28 +151,12 @@ &pio { + vcc-pg-supply = <®_aldo1>; + }; + +-&r_ir { +- linux,rc-map-name = "rc-beelink-gs1"; +- status = "okay"; +-}; +- +-&r_pio { +- /* +- * FIXME: We can't add that supply for now since it would +- * create a circular dependency between pinctrl, the regulator +- * and the RSB Bus. +- * +- * vcc-pl-supply = <®_aldo1>; +- */ +- vcc-pm-supply = <®_aldo1>; +-}; +- +-&r_rsb { ++&r_i2c { + status = "okay"; + +- axp805: pmic@745 { ++ axp805: pmic@36 { + compatible = "x-powers,axp805", "x-powers,axp806"; +- reg = <0x745>; ++ reg = <0x36>; + interrupt-parent = <&r_intc>; + interrupts = ; + interrupt-controller; +@@ -290,6 +274,22 @@ sw { + }; + }; + ++&r_ir { ++ linux,rc-map-name = "rc-beelink-gs1"; ++ status = "okay"; ++}; ++ ++&r_pio { ++ /* ++ * PL0 and PL1 are used for PMIC I2C ++ * don't enable the pl-supply else ++ * it will fail at boot ++ * ++ * vcc-pl-supply = <®_aldo1>; ++ */ ++ vcc-pm-supply = <®_aldo1>; ++}; ++ + &spdif { + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx_pin>; +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +index 6fc65e8db22068..8c476e089185b5 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +@@ -175,16 +175,12 @@ &pio { + vcc-pg-supply = <®_vcc_wifi_io>; + }; + +-&r_ir { +- status = "okay"; +-}; +- +-&r_rsb { ++&r_i2c { + status = "okay"; + +- axp805: pmic@745 { ++ axp805: pmic@36 { + compatible = "x-powers,axp805", "x-powers,axp806"; +- reg = <0x745>; ++ reg = <0x36>; + interrupt-parent = <&r_intc>; + interrupts = ; + interrupt-controller; +@@ -295,6 +291,10 @@ sw { + }; + }; + ++&r_ir { ++ status = "okay"; ++}; ++ + &rtc { + clocks = <&ext_osc32k>; + }; +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi +index 92745128fcfebd..4ec4996592befb 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi +@@ -112,20 +112,12 @@ &pio { + vcc-pg-supply = <®_aldo1>; + }; + +-&r_ir { +- status = "okay"; +-}; +- +-&r_pio { +- vcc-pm-supply = <®_bldo3>; +-}; +- +-&r_rsb { ++&r_i2c { + status = "okay"; + +- axp805: pmic@745 { ++ axp805: pmic@36 { + compatible = "x-powers,axp805", "x-powers,axp806"; +- reg = <0x745>; ++ reg = <0x36>; + interrupt-parent = <&r_intc>; + interrupts = ; + interrupt-controller; +@@ -240,6 +232,14 @@ sw { + }; + }; + ++&r_ir { ++ status = "okay"; ++}; ++ ++&r_pio { ++ vcc-pm-supply = <®_bldo3>; ++}; ++ + &rtc { + clocks = <&ext_osc32k>; + }; +diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +index 3f79923376fb28..37244e8816d9e8 100644 +--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +@@ -26,6 +26,8 @@ memory@0 { + + leds { + compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi_quad_pins>; + + led-power1 { + label = "udpu:green:power"; +@@ -82,8 +84,6 @@ &sdhci0 { + + &spi0 { + status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&spi_quad_pins>; + + flash@0 { + compatible = "jedec,spi-nor"; +@@ -108,6 +108,10 @@ partition@180000 { + }; + }; + ++&spi_quad_pins { ++ function = "gpio"; ++}; ++ + &pinctrl_nb { + i2c2_recovery_pins: i2c2-recovery-pins { + groups = "i2c2"; +diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi +index b4a1108c2dd74f..0639f5ce1bd9e4 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi +@@ -1635,7 +1635,7 @@ vdd_1v8_dis: regulator-vdd-1v8-dis { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; +- gpio = <&exp1 14 GPIO_ACTIVE_HIGH>; ++ gpio = <&exp1 9 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_1v8>; + }; +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts +index bac611d735c589..2fa48972b2a91f 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts +@@ -102,6 +102,16 @@ pcie@14160000 { + }; + + pcie@141a0000 { ++ reg = <0x00 0x141a0000 0x0 0x00020000 /* appl registers (128K) */ ++ 0x00 0x3a000000 0x0 0x00040000 /* configuration space (256K) */ ++ 0x00 0x3a040000 0x0 0x00040000 /* iATU_DMA reg space (256K) */ ++ 0x00 0x3a080000 0x0 0x00040000 /* DBI reg space (256K) */ ++ 0x2e 0x20000000 0x0 0x10000000>; /* ECAM (256MB) */ ++ ++ ranges = <0x81000000 0x00 0x3a100000 0x00 0x3a100000 0x0 0x00100000 /* downstream I/O (1MB) */ ++ 0x82000000 0x00 0x40000000 0x2e 0x30000000 0x0 0x08000000 /* non-prefetchable memory (128MB) */ ++ 0xc3000000 0x28 0x00000000 0x28 0x00000000 0x6 0x20000000>; /* prefetchable memory (25088MB) */ ++ + status = "okay"; + vddio-pex-ctl-supply = <&vdd_1v8_ls>; + phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>, +diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi +index 8a72ad4afd0320..82e4fd5eb388ff 100644 +--- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi +@@ -231,6 +231,8 @@ cryptobam: dma-controller@704000 { + interrupts = ; + #dma-cells = <1>; + qcom,ee = <1>; ++ qcom,num-ees = <4>; ++ num-channels = <16>; + qcom,controlled-remotely; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi +index 2a4d950ac02bfe..5376c0a00fab65 100644 +--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi +@@ -442,7 +442,7 @@ cdsp_secure_heap: memory@80c00000 { + no-map; + }; + +- pil_camera_mem: mmeory@85200000 { ++ pil_camera_mem: memory@85200000 { + reg = <0x0 0x85200000 0x0 0x500000>; + no-map; + }; +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 3b4d7882300897..c1ed39cac8c5b7 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -4233,6 +4233,8 @@ cryptobam: dma-controller@1dc4000 { + interrupts = ; + #dma-cells = <1>; + qcom,ee = <0>; ++ qcom,num-ees = <4>; ++ num-channels = <16>; + qcom,controlled-remotely; + iommus = <&apps_smmu 0x584 0x11>, + <&apps_smmu 0x588 0x0>, +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index bc9a1fca2db3ae..c14c6f8583d548 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -1866,6 +1866,8 @@ cryptobam: dma-controller@1dc4000 { + interrupts = ; + #dma-cells = <1>; + qcom,ee = <0>; ++ qcom,num-ees = <4>; ++ num-channels = <20>; + qcom,controlled-remotely; + iommus = <&apps_smmu 0x480 0x0>, + <&apps_smmu 0x481 0x0>; +diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +index 5df5946687b348..2e92f4174b3cf0 100644 +--- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts ++++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +@@ -43,6 +43,17 @@ vusb_main: regulator-vusb-main5v0 { + regulator-boot-on; + }; + ++ vsys_5v0: regulator-vsys5v0 { ++ /* Output of LM61460 */ ++ compatible = "regulator-fixed"; ++ regulator-name = "vsys_5v0"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vusb_main>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ + vsys_3v3: regulator-vsys3v3 { + /* Output of LM5141 */ + compatible = "regulator-fixed"; +@@ -75,7 +86,7 @@ vdd_sd_dv: regulator-tlv71033 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; +- vin-supply = <&vsys_3v3>; ++ vin-supply = <&vsys_5v0>; + gpios = <&main_gpio0 49 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; +diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi +index ccaca29200bb93..995bd8ce9d43af 100644 +--- a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi ++++ b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi +@@ -10,39 +10,44 @@ + + #include + / { +- pss_ref_clk: pss_ref_clk { ++ pss_ref_clk: pss-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <33333333>; ++ clock-output-names = "pss_ref_clk"; + }; + +- video_clk: video_clk { ++ video_clk: video-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; ++ clock-output-names = "video_clk"; + }; + +- pss_alt_ref_clk: pss_alt_ref_clk { ++ pss_alt_ref_clk: pss-alt-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; ++ clock-output-names = "pss_alt_ref_clk"; + }; + +- gt_crx_ref_clk: gt_crx_ref_clk { ++ gt_crx_ref_clk: gt-crx-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <108000000>; ++ clock-output-names = "gt_crx_ref_clk"; + }; + +- aux_ref_clk: aux_ref_clk { ++ aux_ref_clk: aux-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; ++ clock-output-names = "aux_ref_clk"; + }; + }; + +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index 8a6b7feca3e428..d92a0203e5a93d 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -132,6 +132,7 @@ + #define FUJITSU_CPU_PART_A64FX 0x001 + + #define HISI_CPU_PART_TSV110 0xD01 ++#define HISI_CPU_PART_HIP09 0xD02 + + #define APPLE_CPU_PART_M1_ICESTORM 0x022 + #define APPLE_CPU_PART_M1_FIRESTORM 0x023 +@@ -208,6 +209,7 @@ + #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL) + #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX) + #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110) ++#define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09) + #define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) + #define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) + #define MIDR_APPLE_M1_ICESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO) +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index 07bdf5dd8ebef5..0212129b13d074 100644 +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -679,7 +679,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) + pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e)) + + #define pud_none(pud) (!pud_val(pud)) +-#define pud_bad(pud) (!pud_table(pud)) ++#define pud_bad(pud) ((pud_val(pud) & PUD_TYPE_MASK) != \ ++ PUD_TYPE_TABLE) + #define pud_present(pud) pte_present(pud_pte(pud)) + #define pud_leaf(pud) (pud_present(pud) && !pud_table(pud)) + #define pud_valid(pud) pte_valid(pud_pte(pud)) +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index 28c48bc9c09538..2c81e0efaf378e 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -904,6 +904,7 @@ static u8 spectre_bhb_loop_affected(void) + MIDR_ALL_VERSIONS(MIDR_CORTEX_A77), + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), + MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_GOLD), ++ MIDR_ALL_VERSIONS(MIDR_HISI_HIP09), + {}, + }; + static const struct midr_range spectre_bhb_k11_list[] = { +diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h +index db497a8167da29..e3212f44446fa9 100644 +--- a/arch/mips/include/asm/ftrace.h ++++ b/arch/mips/include/asm/ftrace.h +@@ -87,4 +87,20 @@ struct dyn_arch_ftrace { + #endif /* CONFIG_DYNAMIC_FTRACE */ + #endif /* __ASSEMBLY__ */ + #endif /* CONFIG_FUNCTION_TRACER */ ++ ++#ifdef CONFIG_FTRACE_SYSCALLS ++#ifndef __ASSEMBLY__ ++/* ++ * Some syscall entry functions on mips start with "__sys_" (fork and clone, ++ * for instance). We should also match the sys_ variant with those. ++ */ ++#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME ++static inline bool arch_syscall_match_sym_name(const char *sym, ++ const char *name) ++{ ++ return !strcmp(sym, name) || ++ (!strncmp(sym, "__sys_", 6) && !strcmp(sym + 6, name + 4)); ++} ++#endif /* __ASSEMBLY__ */ ++#endif /* CONFIG_FTRACE_SYSCALLS */ + #endif /* _ASM_MIPS_FTRACE_H */ +diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c +index 9bf60d7d44d362..a7bcf2b814c865 100644 +--- a/arch/mips/kernel/pm-cps.c ++++ b/arch/mips/kernel/pm-cps.c +@@ -56,10 +56,7 @@ static DEFINE_PER_CPU_ALIGNED(u32*, ready_count); + /* Indicates online CPUs coupled with the current CPU */ + static DEFINE_PER_CPU_ALIGNED(cpumask_t, online_coupled); + +-/* +- * Used to synchronize entry to deep idle states. Actually per-core rather +- * than per-CPU. +- */ ++/* Used to synchronize entry to deep idle states */ + static DEFINE_PER_CPU_ALIGNED(atomic_t, pm_barrier); + + /* Saved CPU state across the CPS_PM_POWER_GATED state */ +@@ -118,9 +115,10 @@ int cps_pm_enter_state(enum cps_pm_state state) + cps_nc_entry_fn entry; + struct core_boot_config *core_cfg; + struct vpe_boot_config *vpe_cfg; ++ atomic_t *barrier; + + /* Check that there is an entry function for this state */ +- entry = per_cpu(nc_asm_enter, core)[state]; ++ entry = per_cpu(nc_asm_enter, cpu)[state]; + if (!entry) + return -EINVAL; + +@@ -156,7 +154,7 @@ int cps_pm_enter_state(enum cps_pm_state state) + smp_mb__after_atomic(); + + /* Create a non-coherent mapping of the core ready_count */ +- core_ready_count = per_cpu(ready_count, core); ++ core_ready_count = per_cpu(ready_count, cpu); + nc_addr = kmap_noncoherent(virt_to_page(core_ready_count), + (unsigned long)core_ready_count); + nc_addr += ((unsigned long)core_ready_count & ~PAGE_MASK); +@@ -164,7 +162,8 @@ int cps_pm_enter_state(enum cps_pm_state state) + + /* Ensure ready_count is zero-initialised before the assembly runs */ + WRITE_ONCE(*nc_core_ready_count, 0); +- coupled_barrier(&per_cpu(pm_barrier, core), online); ++ barrier = &per_cpu(pm_barrier, cpumask_first(&cpu_sibling_map[cpu])); ++ coupled_barrier(barrier, online); + + /* Run the generated entry code */ + left = entry(online, nc_core_ready_count); +@@ -635,12 +634,14 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) + + static int cps_pm_online_cpu(unsigned int cpu) + { +- enum cps_pm_state state; +- unsigned core = cpu_core(&cpu_data[cpu]); ++ unsigned int sibling, core; + void *entry_fn, *core_rc; ++ enum cps_pm_state state; ++ ++ core = cpu_core(&cpu_data[cpu]); + + for (state = CPS_PM_NC_WAIT; state < CPS_PM_STATE_COUNT; state++) { +- if (per_cpu(nc_asm_enter, core)[state]) ++ if (per_cpu(nc_asm_enter, cpu)[state]) + continue; + if (!test_bit(state, state_support)) + continue; +@@ -652,16 +653,19 @@ static int cps_pm_online_cpu(unsigned int cpu) + clear_bit(state, state_support); + } + +- per_cpu(nc_asm_enter, core)[state] = entry_fn; ++ for_each_cpu(sibling, &cpu_sibling_map[cpu]) ++ per_cpu(nc_asm_enter, sibling)[state] = entry_fn; + } + +- if (!per_cpu(ready_count, core)) { ++ if (!per_cpu(ready_count, cpu)) { + core_rc = kmalloc(sizeof(u32), GFP_KERNEL); + if (!core_rc) { + pr_err("Failed allocate core %u ready_count\n", core); + return -ENOMEM; + } +- per_cpu(ready_count, core) = core_rc; ++ ++ for_each_cpu(sibling, &cpu_sibling_map[cpu]) ++ per_cpu(ready_count, sibling) = core_rc; + } + + return 0; +diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h +index da827d2d08666e..f2c4457c94c397 100644 +--- a/arch/powerpc/include/asm/mmzone.h ++++ b/arch/powerpc/include/asm/mmzone.h +@@ -35,6 +35,7 @@ extern cpumask_var_t node_to_cpumask_map[]; + #ifdef CONFIG_MEMORY_HOTPLUG + extern unsigned long max_pfn; + u64 memory_hotplug_max(void); ++u64 hot_add_drconf_memory_max(void); + #else + #define memory_hotplug_max() memblock_end_of_DRAM() + #endif +diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c +index a6090896f74979..ac669e58e20230 100644 +--- a/arch/powerpc/kernel/prom_init.c ++++ b/arch/powerpc/kernel/prom_init.c +@@ -2974,11 +2974,11 @@ static void __init fixup_device_tree_pmac(void) + char type[8]; + phandle node; + +- // Some pmacs are missing #size-cells on escc nodes ++ // Some pmacs are missing #size-cells on escc or i2s nodes + for (node = 0; prom_next_node(&node); ) { + type[0] = '\0'; + prom_getprop(node, "device_type", type, sizeof(type)); +- if (prom_strcmp(type, "escc")) ++ if (prom_strcmp(type, "escc") && prom_strcmp(type, "i2s")) + continue; + + if (prom_getproplen(node, "#size-cells") != PROM_ERROR) +diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c +index 28460e33408084..aff3b37e32d64e 100644 +--- a/arch/powerpc/mm/book3s64/radix_pgtable.c ++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c +@@ -912,7 +912,7 @@ int __meminit radix__vmemmap_create_mapping(unsigned long start, + return 0; + } + +- ++#ifdef CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP + bool vmemmap_can_optimize(struct vmem_altmap *altmap, struct dev_pagemap *pgmap) + { + if (radix_enabled()) +@@ -920,6 +920,7 @@ bool vmemmap_can_optimize(struct vmem_altmap *altmap, struct dev_pagemap *pgmap) + + return false; + } ++#endif + + int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node, + unsigned long addr, unsigned long next) +diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c +index f6c4ace3b22197..65a9df0b9e5a09 100644 +--- a/arch/powerpc/mm/numa.c ++++ b/arch/powerpc/mm/numa.c +@@ -1342,7 +1342,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr) + return nid; + } + +-static u64 hot_add_drconf_memory_max(void) ++u64 hot_add_drconf_memory_max(void) + { + struct device_node *memory = NULL; + struct device_node *dn = NULL; +diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c +index 10b946e9c6e756..4bb84dc4393fca 100644 +--- a/arch/powerpc/perf/core-book3s.c ++++ b/arch/powerpc/perf/core-book3s.c +@@ -2229,6 +2229,10 @@ static struct pmu power_pmu = { + #define PERF_SAMPLE_ADDR_TYPE (PERF_SAMPLE_ADDR | \ + PERF_SAMPLE_PHYS_ADDR | \ + PERF_SAMPLE_DATA_PAGE_SIZE) ++ ++#define SIER_TYPE_SHIFT 15 ++#define SIER_TYPE_MASK (0x7ull << SIER_TYPE_SHIFT) ++ + /* + * A counter has overflowed; update its count and record + * things if requested. Note that interrupts are hard-disabled +@@ -2297,6 +2301,22 @@ static void record_and_restart(struct perf_event *event, unsigned long val, + is_kernel_addr(mfspr(SPRN_SIAR))) + record = 0; + ++ /* ++ * SIER[46-48] presents instruction type of the sampled instruction. ++ * In ISA v3.0 and before values "0" and "7" are considered reserved. ++ * In ISA v3.1, value "7" has been used to indicate "larx/stcx". ++ * Drop the sample if "type" has reserved values for this field with a ++ * ISA version check. ++ */ ++ if (event->attr.sample_type & PERF_SAMPLE_DATA_SRC && ++ ppmu->get_mem_data_src) { ++ val = (regs->dar & SIER_TYPE_MASK) >> SIER_TYPE_SHIFT; ++ if (val == 0 || (val == 7 && !cpu_has_feature(CPU_FTR_ARCH_31))) { ++ record = 0; ++ atomic64_inc(&event->lost_samples); ++ } ++ } ++ + /* + * Finally record data if requested. + */ +diff --git a/arch/powerpc/perf/isa207-common.c b/arch/powerpc/perf/isa207-common.c +index 56301b2bc8ae87..031a2b63c171dc 100644 +--- a/arch/powerpc/perf/isa207-common.c ++++ b/arch/powerpc/perf/isa207-common.c +@@ -321,8 +321,10 @@ void isa207_get_mem_data_src(union perf_mem_data_src *dsrc, u32 flags, + + sier = mfspr(SPRN_SIER); + val = (sier & ISA207_SIER_TYPE_MASK) >> ISA207_SIER_TYPE_SHIFT; +- if (val != 1 && val != 2 && !(val == 7 && cpu_has_feature(CPU_FTR_ARCH_31))) ++ if (val != 1 && val != 2 && !(val == 7 && cpu_has_feature(CPU_FTR_ARCH_31))) { ++ dsrc->val = 0; + return; ++ } + + idx = (sier & ISA207_SIER_LDST_MASK) >> ISA207_SIER_LDST_SHIFT; + sub_idx = (sier & ISA207_SIER_DATA_SRC_MASK) >> ISA207_SIER_DATA_SRC_SHIFT; +diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c +index b1e6d275cda9eb..bf02f94a973dbd 100644 +--- a/arch/powerpc/platforms/pseries/iommu.c ++++ b/arch/powerpc/platforms/pseries/iommu.c +@@ -1183,17 +1183,13 @@ static LIST_HEAD(failed_ddw_pdn_list); + + static phys_addr_t ddw_memory_hotplug_max(void) + { +- resource_size_t max_addr = memory_hotplug_max(); +- struct device_node *memory; ++ resource_size_t max_addr; + +- for_each_node_by_type(memory, "memory") { +- struct resource res; +- +- if (of_address_to_resource(memory, 0, &res)) +- continue; +- +- max_addr = max_t(resource_size_t, max_addr, res.end + 1); +- } ++#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG) ++ max_addr = hot_add_drconf_memory_max(); ++#else ++ max_addr = memblock_end_of_DRAM(); ++#endif + + return max_addr; + } +@@ -1471,7 +1467,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) + window->direct = true; + + /* DDW maps the whole partition, so enable direct DMA mapping */ +- ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT, ++ ret = walk_system_ram_range(0, ddw_memory_hotplug_max() >> PAGE_SHIFT, + win64->value, tce_setrange_multi_pSeriesLP_walk); + if (ret) { + dev_info(&dev->dev, "failed to map DMA window for %pOF: %d\n", +@@ -1658,11 +1654,17 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, + struct memory_notify *arg = data; + int ret = 0; + ++ /* This notifier can get called when onlining persistent memory as well. ++ * TCEs are not pre-mapped for persistent memory. Persistent memory will ++ * always be above ddw_memory_hotplug_max() ++ */ ++ + switch (action) { + case MEM_GOING_ONLINE: + spin_lock(&dma_win_list_lock); + list_for_each_entry(window, &dma_win_list, list) { +- if (window->direct) { ++ if (window->direct && (arg->start_pfn << PAGE_SHIFT) < ++ ddw_memory_hotplug_max()) { + ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn, + arg->nr_pages, window->prop); + } +@@ -1674,7 +1676,8 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, + case MEM_OFFLINE: + spin_lock(&dma_win_list_lock); + list_for_each_entry(window, &dma_win_list, list) { +- if (window->direct) { ++ if (window->direct && (arg->start_pfn << PAGE_SHIFT) < ++ ddw_memory_hotplug_max()) { + ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn, + arg->nr_pages, window->prop); + } +diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h +index 4d1f58848129e8..dbb9d0d0f405e1 100644 +--- a/arch/riscv/include/asm/page.h ++++ b/arch/riscv/include/asm/page.h +@@ -26,12 +26,9 @@ + * When not using MMU this corresponds to the first free page in + * physical memory (aligned on a page boundary). + */ +-#ifdef CONFIG_64BIT + #ifdef CONFIG_MMU ++#ifdef CONFIG_64BIT + #define PAGE_OFFSET kernel_map.page_offset +-#else +-#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) +-#endif + /* + * By default, CONFIG_PAGE_OFFSET value corresponds to SV57 address space so + * define the PAGE_OFFSET value for SV48 and SV39. +@@ -41,6 +38,9 @@ + #else + #define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) + #endif /* CONFIG_64BIT */ ++#else ++#define PAGE_OFFSET ((unsigned long)phys_ram_base) ++#endif /* CONFIG_MMU */ + + #ifndef __ASSEMBLY__ + +@@ -97,11 +97,7 @@ typedef struct page *pgtable_t; + #define MIN_MEMBLOCK_ADDR 0 + #endif + +-#ifdef CONFIG_MMU + #define ARCH_PFN_OFFSET (PFN_DOWN((unsigned long)phys_ram_base)) +-#else +-#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) +-#endif /* CONFIG_MMU */ + + struct kernel_mapping { + unsigned long page_offset; +diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h +index f540b2625714d0..332a6bf72b1d54 100644 +--- a/arch/riscv/include/asm/pgtable.h ++++ b/arch/riscv/include/asm/pgtable.h +@@ -12,7 +12,7 @@ + #include + + #ifndef CONFIG_MMU +-#define KERNEL_LINK_ADDR PAGE_OFFSET ++#define KERNEL_LINK_ADDR _AC(CONFIG_PAGE_OFFSET, UL) + #define KERN_VIRT_SIZE (UL(-1)) + #else + +diff --git a/arch/s390/hypfs/hypfs_diag_fs.c b/arch/s390/hypfs/hypfs_diag_fs.c +index 00a6d370a28032..280266a74f378d 100644 +--- a/arch/s390/hypfs/hypfs_diag_fs.c ++++ b/arch/s390/hypfs/hypfs_diag_fs.c +@@ -208,6 +208,8 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info) + snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_get_info_type(), + cpu_info)); + cpu_dir = hypfs_mkdir(cpus_dir, buffer); ++ if (IS_ERR(cpu_dir)) ++ return PTR_ERR(cpu_dir); + rc = hypfs_create_u64(cpu_dir, "mgmtime", + cpu_info__acc_time(diag204_get_info_type(), cpu_info) - + cpu_info__lp_time(diag204_get_info_type(), cpu_info)); +diff --git a/arch/um/Makefile b/arch/um/Makefile +index 34957dcb88b9c3..744c5d0bdeb8fc 100644 +--- a/arch/um/Makefile ++++ b/arch/um/Makefile +@@ -151,5 +151,6 @@ MRPROPER_FILES += $(HOST_DIR)/include/generated + archclean: + @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ + -o -name '*.gcov' \) -type f -print | xargs rm -f ++ $(Q)$(MAKE) -f $(srctree)/Makefile ARCH=$(HEADER_ARCH) clean + + export HEADER_ARCH SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING DEV_NULL_PATH +diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c +index 38d5a71a579bcb..f6c766b2bdf5e4 100644 +--- a/arch/um/kernel/mem.c ++++ b/arch/um/kernel/mem.c +@@ -68,6 +68,7 @@ void __init mem_init(void) + map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); + memblock_free((void *)brk_end, uml_reserved - brk_end); + uml_reserved = brk_end; ++ min_low_pfn = PFN_UP(__pa(uml_reserved)); + + /* this will put all low memory onto the freelists */ + memblock_free_all(); +diff --git a/arch/x86/Makefile b/arch/x86/Makefile +index c83582b5a010de..6d593fb85a9e93 100644 +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -43,7 +43,7 @@ endif + + # How to compile the 16-bit code. Note we always compile for -march=i386; + # that way we can complain to the user if the CPU is insufficient. +-REALMODE_CFLAGS := -m16 -g -Os -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \ ++REALMODE_CFLAGS := -std=gnu11 -m16 -g -Os -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \ + -Wall -Wstrict-prototypes -march=i386 -mregparm=3 \ + -fno-strict-aliasing -fomit-frame-pointer -fno-pic \ + -mno-mmx -mno-sse $(call cc-option,-fcf-protection=none) +diff --git a/arch/x86/boot/genimage.sh b/arch/x86/boot/genimage.sh +index c9299aeb7333e6..3882ead513f742 100644 +--- a/arch/x86/boot/genimage.sh ++++ b/arch/x86/boot/genimage.sh +@@ -22,6 +22,7 @@ + # This script requires: + # bash + # syslinux ++# genisoimage + # mtools (for fdimage* and hdimage) + # edk2/OVMF (for hdimage) + # +@@ -251,7 +252,9 @@ geniso() { + cp "$isolinux" "$ldlinux" "$tmp_dir" + cp "$FBZIMAGE" "$tmp_dir"/linux + echo default linux "$KCMDLINE" > "$tmp_dir"/isolinux.cfg +- cp "${FDINITRDS[@]}" "$tmp_dir"/ ++ if [ ${#FDINITRDS[@]} -gt 0 ]; then ++ cp "${FDINITRDS[@]}" "$tmp_dir"/ ++ fi + genisoimage -J -r -appid 'LINUX_BOOT' -input-charset=utf-8 \ + -quiet -o "$FIMAGE" -b isolinux.bin \ + -c boot.cat -no-emul-boot -boot-load-size 4 \ +diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S +index 78fd2442b49dcd..ad292c0d971a3f 100644 +--- a/arch/x86/entry/entry.S ++++ b/arch/x86/entry/entry.S +@@ -59,7 +59,7 @@ EXPORT_SYMBOL_GPL(mds_verw_sel); + * entirely in the C code, and use an alias emitted by the linker script + * instead. + */ +-#ifdef CONFIG_STACKPROTECTOR ++#if defined(CONFIG_STACKPROTECTOR) && defined(CONFIG_SMP) + EXPORT_SYMBOL(__ref_stack_chk_guard); + #endif + #endif +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index f483874fa20f19..fac3d97111b098 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -272,7 +272,7 @@ static int perf_ibs_init(struct perf_event *event) + { + struct hw_perf_event *hwc = &event->hw; + struct perf_ibs *perf_ibs; +- u64 max_cnt, config; ++ u64 config; + int ret; + + perf_ibs = get_ibs_pmu(event->attr.type); +@@ -306,10 +306,19 @@ static int perf_ibs_init(struct perf_event *event) + if (!hwc->sample_period) + hwc->sample_period = 0x10; + } else { +- max_cnt = config & perf_ibs->cnt_mask; ++ u64 period = 0; ++ ++ if (perf_ibs == &perf_ibs_op) { ++ period = (config & IBS_OP_MAX_CNT) << 4; ++ if (ibs_caps & IBS_CAPS_OPCNTEXT) ++ period |= config & IBS_OP_MAX_CNT_EXT_MASK; ++ } else { ++ period = (config & IBS_FETCH_MAX_CNT) << 4; ++ } ++ + config &= ~perf_ibs->cnt_mask; +- event->attr.sample_period = max_cnt << 4; +- hwc->sample_period = event->attr.sample_period; ++ event->attr.sample_period = period; ++ hwc->sample_period = period; + } + + if (!hwc->sample_period) +@@ -1219,7 +1228,8 @@ static __init int perf_ibs_op_init(void) + if (ibs_caps & IBS_CAPS_OPCNTEXT) { + perf_ibs_op.max_period |= IBS_OP_MAX_CNT_EXT_MASK; + perf_ibs_op.config_mask |= IBS_OP_MAX_CNT_EXT_MASK; +- perf_ibs_op.cnt_mask |= IBS_OP_MAX_CNT_EXT_MASK; ++ perf_ibs_op.cnt_mask |= (IBS_OP_MAX_CNT_EXT_MASK | ++ IBS_OP_CUR_CNT_EXT_MASK); + } + + if (ibs_caps & IBS_CAPS_ZEN4) +diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h +index 806649c7f23dc6..9a0f29be1a9ea6 100644 +--- a/arch/x86/include/asm/bug.h ++++ b/arch/x86/include/asm/bug.h +@@ -22,8 +22,9 @@ + #define SECOND_BYTE_OPCODE_UD2 0x0b + + #define BUG_NONE 0xffff +-#define BUG_UD1 0xfffe +-#define BUG_UD2 0xfffd ++#define BUG_UD2 0xfffe ++#define BUG_UD1 0xfffd ++#define BUG_UD1_UBSAN 0xfffc + + #ifdef CONFIG_GENERIC_BUG + +diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h +index 1e59581d500ca9..b778ae6e67ee8c 100644 +--- a/arch/x86/include/asm/ibt.h ++++ b/arch/x86/include/asm/ibt.h +@@ -41,7 +41,7 @@ + _ASM_PTR fname "\n\t" \ + ".popsection\n\t" + +-static inline __attribute_const__ u32 gen_endbr(void) ++static __always_inline __attribute_const__ u32 gen_endbr(void) + { + u32 endbr; + +@@ -56,7 +56,7 @@ static inline __attribute_const__ u32 gen_endbr(void) + return endbr; + } + +-static inline __attribute_const__ u32 gen_endbr_poison(void) ++static __always_inline __attribute_const__ u32 gen_endbr_poison(void) + { + /* + * 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it +diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h +index 5c5f1e56c4048d..6f3d145670a957 100644 +--- a/arch/x86/include/asm/nmi.h ++++ b/arch/x86/include/asm/nmi.h +@@ -59,6 +59,8 @@ int __register_nmi_handler(unsigned int, struct nmiaction *); + + void unregister_nmi_handler(unsigned int, const char *); + ++void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler); ++ + void stop_nmi(void); + void restart_nmi(void); + void local_touch_nmi(void); +diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h +index 384e8a7db4827b..ba2a3935dc624d 100644 +--- a/arch/x86/include/asm/perf_event.h ++++ b/arch/x86/include/asm/perf_event.h +@@ -501,6 +501,7 @@ struct pebs_xmm { + */ + #define IBS_OP_CUR_CNT (0xFFF80ULL<<32) + #define IBS_OP_CUR_CNT_RAND (0x0007FULL<<32) ++#define IBS_OP_CUR_CNT_EXT_MASK (0x7FULL<<52) + #define IBS_OP_CNT_CTL (1ULL<<19) + #define IBS_OP_VAL (1ULL<<18) + #define IBS_OP_ENABLE (1ULL<<17) +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 07b45bbf6348de..e9c4bcb38f4586 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -1442,9 +1442,13 @@ static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd; + static enum spectre_v2_user_cmd __init + spectre_v2_parse_user_cmdline(void) + { ++ enum spectre_v2_user_cmd mode; + char arg[20]; + int ret, i; + ++ mode = IS_ENABLED(CONFIG_MITIGATION_SPECTRE_V2) ? ++ SPECTRE_V2_USER_CMD_AUTO : SPECTRE_V2_USER_CMD_NONE; ++ + switch (spectre_v2_cmd) { + case SPECTRE_V2_CMD_NONE: + return SPECTRE_V2_USER_CMD_NONE; +@@ -1457,7 +1461,7 @@ spectre_v2_parse_user_cmdline(void) + ret = cmdline_find_option(boot_command_line, "spectre_v2_user", + arg, sizeof(arg)); + if (ret < 0) +- return SPECTRE_V2_USER_CMD_AUTO; ++ return mode; + + for (i = 0; i < ARRAY_SIZE(v2_user_options); i++) { + if (match_option(arg, ret, v2_user_options[i].option)) { +@@ -1467,8 +1471,8 @@ spectre_v2_parse_user_cmdline(void) + } + } + +- pr_err("Unknown user space protection option (%s). Switching to AUTO select\n", arg); +- return SPECTRE_V2_USER_CMD_AUTO; ++ pr_err("Unknown user space protection option (%s). Switching to default\n", arg); ++ return mode; + } + + static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode) +diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c +index 6da2cfa23c2939..35fd5f1444fdb4 100644 +--- a/arch/x86/kernel/nmi.c ++++ b/arch/x86/kernel/nmi.c +@@ -39,8 +39,12 @@ + #define CREATE_TRACE_POINTS + #include + ++/* ++ * An emergency handler can be set in any context including NMI ++ */ + struct nmi_desc { + raw_spinlock_t lock; ++ nmi_handler_t emerg_handler; + struct list_head head; + }; + +@@ -131,9 +135,22 @@ static void nmi_check_duration(struct nmiaction *action, u64 duration) + static int nmi_handle(unsigned int type, struct pt_regs *regs) + { + struct nmi_desc *desc = nmi_to_desc(type); ++ nmi_handler_t ehandler; + struct nmiaction *a; + int handled=0; + ++ /* ++ * Call the emergency handler, if set ++ * ++ * In the case of crash_nmi_callback() emergency handler, it will ++ * return in the case of the crashing CPU to enable it to complete ++ * other necessary crashing actions ASAP. Other handlers in the ++ * linked list won't need to be run. ++ */ ++ ehandler = desc->emerg_handler; ++ if (ehandler) ++ return ehandler(type, regs); ++ + rcu_read_lock(); + + /* +@@ -223,6 +240,31 @@ void unregister_nmi_handler(unsigned int type, const char *name) + } + EXPORT_SYMBOL_GPL(unregister_nmi_handler); + ++/** ++ * set_emergency_nmi_handler - Set emergency handler ++ * @type: NMI type ++ * @handler: the emergency handler to be stored ++ * ++ * Set an emergency NMI handler which, if set, will preempt all the other ++ * handlers in the linked list. If a NULL handler is passed in, it will clear ++ * it. It is expected that concurrent calls to this function will not happen ++ * or the system is screwed beyond repair. ++ */ ++void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler) ++{ ++ struct nmi_desc *desc = nmi_to_desc(type); ++ ++ if (WARN_ON_ONCE(desc->emerg_handler == handler)) ++ return; ++ desc->emerg_handler = handler; ++ ++ /* ++ * Ensure the emergency handler is visible to other CPUs before ++ * function return ++ */ ++ smp_wmb(); ++} ++ + static void + pci_serr_error(unsigned char reason, struct pt_regs *regs) + { +diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c +index 830425e6d38e2f..456e61070a730b 100644 +--- a/arch/x86/kernel/reboot.c ++++ b/arch/x86/kernel/reboot.c +@@ -908,15 +908,11 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback) + shootdown_callback = callback; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); +- /* Would it be better to replace the trap vector here? */ +- if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, +- NMI_FLAG_FIRST, "crash")) +- return; /* Return what? */ ++ + /* +- * Ensure the new callback function is set before sending +- * out the NMI ++ * Set emergency handler to preempt other handlers. + */ +- wmb(); ++ set_emergency_nmi_handler(NMI_LOCAL, crash_nmi_callback); + + apic_send_IPI_allbutself(NMI_VECTOR); + +diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c +index d8d9bc5a9b3280..8718d58dd0fbea 100644 +--- a/arch/x86/kernel/traps.c ++++ b/arch/x86/kernel/traps.c +@@ -92,10 +92,17 @@ __always_inline int is_valid_bugaddr(unsigned long addr) + + /* + * Check for UD1 or UD2, accounting for Address Size Override Prefixes. +- * If it's a UD1, get the ModRM byte to pass along to UBSan. ++ * If it's a UD1, further decode to determine its use: ++ * ++ * UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax ++ * UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax ++ * static_call: 0f b9 cc ud1 %esp,%ecx ++ * ++ * Notably UBSAN uses EAX, static_call uses ECX. + */ +-__always_inline int decode_bug(unsigned long addr, u32 *imm) ++__always_inline int decode_bug(unsigned long addr, s32 *imm, int *len) + { ++ unsigned long start = addr; + u8 v; + + if (addr < TASK_SIZE_MAX) +@@ -108,24 +115,42 @@ __always_inline int decode_bug(unsigned long addr, u32 *imm) + return BUG_NONE; + + v = *(u8 *)(addr++); +- if (v == SECOND_BYTE_OPCODE_UD2) ++ if (v == SECOND_BYTE_OPCODE_UD2) { ++ *len = addr - start; + return BUG_UD2; ++ } + +- if (!IS_ENABLED(CONFIG_UBSAN_TRAP) || v != SECOND_BYTE_OPCODE_UD1) ++ if (v != SECOND_BYTE_OPCODE_UD1) + return BUG_NONE; + +- /* Retrieve the immediate (type value) for the UBSAN UD1 */ +- v = *(u8 *)(addr++); +- if (X86_MODRM_RM(v) == 4) +- addr++; +- + *imm = 0; +- if (X86_MODRM_MOD(v) == 1) +- *imm = *(u8 *)addr; +- else if (X86_MODRM_MOD(v) == 2) +- *imm = *(u32 *)addr; +- else +- WARN_ONCE(1, "Unexpected MODRM_MOD: %u\n", X86_MODRM_MOD(v)); ++ v = *(u8 *)(addr++); /* ModRM */ ++ ++ if (X86_MODRM_MOD(v) != 3 && X86_MODRM_RM(v) == 4) ++ addr++; /* SIB */ ++ ++ /* Decode immediate, if present */ ++ switch (X86_MODRM_MOD(v)) { ++ case 0: if (X86_MODRM_RM(v) == 5) ++ addr += 4; /* RIP + disp32 */ ++ break; ++ ++ case 1: *imm = *(s8 *)addr; ++ addr += 1; ++ break; ++ ++ case 2: *imm = *(s32 *)addr; ++ addr += 4; ++ break; ++ ++ case 3: break; ++ } ++ ++ /* record instruction length */ ++ *len = addr - start; ++ ++ if (X86_MODRM_REG(v) == 0) /* EAX */ ++ return BUG_UD1_UBSAN; + + return BUG_UD1; + } +@@ -256,10 +281,10 @@ static inline void handle_invalid_op(struct pt_regs *regs) + static noinstr bool handle_bug(struct pt_regs *regs) + { + bool handled = false; +- int ud_type; +- u32 imm; ++ int ud_type, ud_len; ++ s32 ud_imm; + +- ud_type = decode_bug(regs->ip, &imm); ++ ud_type = decode_bug(regs->ip, &ud_imm, &ud_len); + if (ud_type == BUG_NONE) + return handled; + +@@ -279,15 +304,28 @@ static noinstr bool handle_bug(struct pt_regs *regs) + */ + if (regs->flags & X86_EFLAGS_IF) + raw_local_irq_enable(); +- if (ud_type == BUG_UD2) { ++ ++ switch (ud_type) { ++ case BUG_UD2: + if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN || + handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) { +- regs->ip += LEN_UD2; ++ regs->ip += ud_len; + handled = true; + } +- } else if (IS_ENABLED(CONFIG_UBSAN_TRAP)) { +- pr_crit("%s at %pS\n", report_ubsan_failure(regs, imm), (void *)regs->ip); ++ break; ++ ++ case BUG_UD1_UBSAN: ++ if (IS_ENABLED(CONFIG_UBSAN_TRAP)) { ++ pr_crit("%s at %pS\n", ++ report_ubsan_failure(regs, ud_imm), ++ (void *)regs->ip); ++ } ++ break; ++ ++ default: ++ break; + } ++ + if (regs->flags & X86_EFLAGS_IF) + raw_local_irq_disable(); + instrumentation_end(); +diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c +index 71d29dd7ad761e..6cbb5974e4f9ea 100644 +--- a/arch/x86/mm/init.c ++++ b/arch/x86/mm/init.c +@@ -644,8 +644,13 @@ static void __init memory_map_top_down(unsigned long map_start, + */ + addr = memblock_phys_alloc_range(PMD_SIZE, PMD_SIZE, map_start, + map_end); +- memblock_phys_free(addr, PMD_SIZE); +- real_end = addr + PMD_SIZE; ++ if (!addr) { ++ pr_warn("Failed to release memory for alloc_low_pages()"); ++ real_end = max(map_start, ALIGN_DOWN(map_end, PMD_SIZE)); ++ } else { ++ memblock_phys_free(addr, PMD_SIZE); ++ real_end = addr + PMD_SIZE; ++ } + + /* step_size need to be small so pgt_buf from BRK could cover it */ + step_size = PMD_SIZE; +diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c +index aa69353da49f24..11eb93e13ce175 100644 +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -959,9 +959,18 @@ int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages, + ret = __add_pages(nid, start_pfn, nr_pages, params); + WARN_ON_ONCE(ret); + +- /* update max_pfn, max_low_pfn and high_memory */ +- update_end_of_memory_vars(start_pfn << PAGE_SHIFT, +- nr_pages << PAGE_SHIFT); ++ /* ++ * Special case: add_pages() is called by memremap_pages() for adding device ++ * private pages. Do not bump up max_pfn in the device private path, ++ * because max_pfn changes affect dma_addressing_limited(). ++ * ++ * dma_addressing_limited() returning true when max_pfn is the device's ++ * addressable memory can force device drivers to use bounce buffers ++ * and impact their performance negatively: ++ */ ++ if (!params->pgmap) ++ /* update max_pfn, max_low_pfn and high_memory */ ++ update_end_of_memory_vars(start_pfn << PAGE_SHIFT, nr_pages << PAGE_SHIFT); + + return ret; + } +diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c +index 230f1dee4f0954..e0b0ec0f824574 100644 +--- a/arch/x86/mm/kaslr.c ++++ b/arch/x86/mm/kaslr.c +@@ -109,8 +109,14 @@ void __init kernel_randomize_memory(void) + memory_tb = DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) + + CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING; + +- /* Adapt physical memory region size based on available memory */ +- if (memory_tb < kaslr_regions[0].size_tb) ++ /* ++ * Adapt physical memory region size based on available memory, ++ * except when CONFIG_PCI_P2PDMA is enabled. P2PDMA exposes the ++ * device BAR space assuming the direct map space is large enough ++ * for creating a ZONE_DEVICE mapping in the direct map corresponding ++ * to the physical BAR address. ++ */ ++ if (!IS_ENABLED(CONFIG_PCI_P2PDMA) && (memory_tb < kaslr_regions[0].size_tb)) + kaslr_regions[0].size_tb = memory_tb; + + /* +diff --git a/arch/x86/um/os-Linux/mcontext.c b/arch/x86/um/os-Linux/mcontext.c +index 49c3744cac371b..81b9d1f9f4e68b 100644 +--- a/arch/x86/um/os-Linux/mcontext.c ++++ b/arch/x86/um/os-Linux/mcontext.c +@@ -26,7 +26,6 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc) + COPY(RIP); + COPY2(EFLAGS, EFL); + COPY2(CS, CSGSFS); +- regs->gp[CS / sizeof(unsigned long)] &= 0xffff; +- regs->gp[CS / sizeof(unsigned long)] |= 3; ++ regs->gp[SS / sizeof(unsigned long)] = mc->gregs[REG_CSGSFS] >> 48; + #endif + } +diff --git a/crypto/ahash.c b/crypto/ahash.c +index 709ef094079913..6168f3532f552a 100644 +--- a/crypto/ahash.c ++++ b/crypto/ahash.c +@@ -427,6 +427,7 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) + hash->setkey = ahash_nosetkey; + + crypto_ahash_set_statesize(hash, alg->halg.statesize); ++ crypto_ahash_set_reqsize(hash, alg->reqsize); + + if (tfm->__crt_alg->cra_type != &crypto_ahash_type) + return crypto_init_shash_ops_async(tfm); +@@ -599,6 +600,9 @@ static int ahash_prepare_alg(struct ahash_alg *alg) + if (alg->halg.statesize == 0) + return -EINVAL; + ++ if (alg->reqsize && alg->reqsize < alg->halg.statesize) ++ return -EINVAL; ++ + err = hash_prepare_alg(&alg->halg); + if (err) + return err; +diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c +index e24c829d7a0154..5ab7441734b8e0 100644 +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -265,10 +265,6 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags, + goto out_free_state; + + err = crypto_ahash_import(&ctx2->req, state); +- if (err) { +- sock_orphan(sk2); +- sock_put(sk2); +- } + + out_free_state: + kfree_sensitive(state); +diff --git a/crypto/lzo-rle.c b/crypto/lzo-rle.c +index 0631d975bfac11..0abc2d87f04200 100644 +--- a/crypto/lzo-rle.c ++++ b/crypto/lzo-rle.c +@@ -55,7 +55,7 @@ static int __lzorle_compress(const u8 *src, unsigned int slen, + size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ + int err; + +- err = lzorle1x_1_compress(src, slen, dst, &tmp_len, ctx); ++ err = lzorle1x_1_compress_safe(src, slen, dst, &tmp_len, ctx); + + if (err != LZO_E_OK) + return -EINVAL; +diff --git a/crypto/lzo.c b/crypto/lzo.c +index ebda132dd22bf5..8338851c7406a3 100644 +--- a/crypto/lzo.c ++++ b/crypto/lzo.c +@@ -55,7 +55,7 @@ static int __lzo_compress(const u8 *src, unsigned int slen, + size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ + int err; + +- err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx); ++ err = lzo1x_1_compress_safe(src, slen, dst, &tmp_len, ctx); + + if (err != LZO_E_OK) + return -EINVAL; +diff --git a/crypto/skcipher.c b/crypto/skcipher.c +index 7b275716cf4e3a..acc879ed6031a9 100644 +--- a/crypto/skcipher.c ++++ b/crypto/skcipher.c +@@ -811,6 +811,7 @@ struct crypto_sync_skcipher *crypto_alloc_sync_skcipher( + + /* Only sync algorithms allowed. */ + mask |= CRYPTO_ALG_ASYNC | CRYPTO_ALG_SKCIPHER_REQSIZE_LARGE; ++ type &= ~(CRYPTO_ALG_ASYNC | CRYPTO_ALG_SKCIPHER_REQSIZE_LARGE); + + tfm = crypto_alloc_tfm(alg_name, &crypto_skcipher_type, type, mask); + +diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c +index b5de82e6eb4d56..e69bfb30b44e07 100644 +--- a/drivers/accel/qaic/qaic_drv.c ++++ b/drivers/accel/qaic/qaic_drv.c +@@ -400,7 +400,7 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev) + int bars; + int ret; + +- bars = pci_select_bars(pdev, IORESOURCE_MEM); ++ bars = pci_select_bars(pdev, IORESOURCE_MEM) & 0x3f; + + /* make sure the device has the expected BARs */ + if (bars != (BIT(0) | BIT(2) | BIT(4))) { +diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +index cee82b473dc509..648228831f5e87 100644 +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -438,7 +438,7 @@ config ACPI_SBS + the modules will be called sbs and sbshc. + + config ACPI_HED +- tristate "Hardware Error Device" ++ bool "Hardware Error Device" + help + This driver supports the Hardware Error Device (PNP0C33), + which is used to report some hardware errors notified via +diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c +index 01abf26764b00c..3f5a1840f57330 100644 +--- a/drivers/acpi/acpi_pnp.c ++++ b/drivers/acpi/acpi_pnp.c +@@ -355,8 +355,10 @@ static bool acpi_pnp_match(const char *idstr, const struct acpi_device_id **matc + * device represented by it. + */ + static const struct acpi_device_id acpi_nonpnp_device_ids[] = { ++ {"INT3F0D"}, + {"INTC1080"}, + {"INTC1081"}, ++ {"INTC1099"}, + {""}, + }; + +diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c +index 46c6f8c35b4368..2e01eaa8d8cd51 100644 +--- a/drivers/acpi/hed.c ++++ b/drivers/acpi/hed.c +@@ -80,7 +80,12 @@ static struct acpi_driver acpi_hed_driver = { + .remove = acpi_hed_remove, + }, + }; +-module_acpi_driver(acpi_hed_driver); ++ ++static int __init acpi_hed_driver_init(void) ++{ ++ return acpi_bus_register_driver(&acpi_hed_driver); ++} ++subsys_initcall(acpi_hed_driver_init); + + MODULE_AUTHOR("Huang Ying"); + MODULE_DESCRIPTION("ACPI Hardware Error Device Driver"); +diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c +index 6d309e4971b617..e243291a7e77c9 100644 +--- a/drivers/auxdisplay/charlcd.c ++++ b/drivers/auxdisplay/charlcd.c +@@ -594,18 +594,19 @@ static int charlcd_init(struct charlcd *lcd) + return 0; + } + +-struct charlcd *charlcd_alloc(void) ++struct charlcd *charlcd_alloc(unsigned int drvdata_size) + { + struct charlcd_priv *priv; + struct charlcd *lcd; + +- priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ priv = kzalloc(sizeof(*priv) + drvdata_size, GFP_KERNEL); + if (!priv) + return NULL; + + priv->esc_seq.len = -1; + + lcd = &priv->lcd; ++ lcd->drvdata = priv->drvdata; + + return lcd; + } +diff --git a/drivers/auxdisplay/charlcd.h b/drivers/auxdisplay/charlcd.h +index eed80063a6d20d..4bbf106b2dd8a2 100644 +--- a/drivers/auxdisplay/charlcd.h ++++ b/drivers/auxdisplay/charlcd.h +@@ -49,7 +49,7 @@ struct charlcd { + unsigned long y; + } addr; + +- void *drvdata; ++ void *drvdata; /* Set by charlcd_alloc() */ + }; + + /** +@@ -93,7 +93,8 @@ struct charlcd_ops { + }; + + void charlcd_backlight(struct charlcd *lcd, enum charlcd_onoff on); +-struct charlcd *charlcd_alloc(void); ++ ++struct charlcd *charlcd_alloc(unsigned int drvdata_size); + void charlcd_free(struct charlcd *lcd); + + int charlcd_register(struct charlcd *lcd); +diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c +index 8b690f59df27d6..ebaf0ff518f4c2 100644 +--- a/drivers/auxdisplay/hd44780.c ++++ b/drivers/auxdisplay/hd44780.c +@@ -226,7 +226,7 @@ static int hd44780_probe(struct platform_device *pdev) + if (!hdc) + return -ENOMEM; + +- lcd = charlcd_alloc(); ++ lcd = charlcd_alloc(0); + if (!lcd) + goto fail1; + +diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c +index 6422be0dfe20e6..0ecf6a9469f24c 100644 +--- a/drivers/auxdisplay/lcd2s.c ++++ b/drivers/auxdisplay/lcd2s.c +@@ -307,7 +307,7 @@ static int lcd2s_i2c_probe(struct i2c_client *i2c) + if (err < 0) + return err; + +- lcd = charlcd_alloc(); ++ lcd = charlcd_alloc(0); + if (!lcd) + return -ENOMEM; + +diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c +index eba04c0de7eb3f..0f3999b665e70f 100644 +--- a/drivers/auxdisplay/panel.c ++++ b/drivers/auxdisplay/panel.c +@@ -835,7 +835,7 @@ static void lcd_init(void) + if (!hdc) + return; + +- charlcd = charlcd_alloc(); ++ charlcd = charlcd_alloc(0); + if (!charlcd) { + kfree(hdc); + return; +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index d6195565ef7aeb..e0dd6988960883 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -3525,9 +3525,8 @@ static void btusb_coredump_qca(struct hci_dev *hdev) + static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + { + int ret = 0; ++ unsigned int skip = 0; + u8 pkt_type; +- u8 *sk_ptr; +- unsigned int sk_len; + u16 seqno; + u32 dump_size; + +@@ -3536,18 +3535,13 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + struct usb_device *udev = btdata->udev; + + pkt_type = hci_skb_pkt_type(skb); +- sk_ptr = skb->data; +- sk_len = skb->len; ++ skip = sizeof(struct hci_event_hdr); ++ if (pkt_type == HCI_ACLDATA_PKT) ++ skip += sizeof(struct hci_acl_hdr); + +- if (pkt_type == HCI_ACLDATA_PKT) { +- sk_ptr += HCI_ACL_HDR_SIZE; +- sk_len -= HCI_ACL_HDR_SIZE; +- } +- +- sk_ptr += HCI_EVENT_HDR_SIZE; +- sk_len -= HCI_EVENT_HDR_SIZE; ++ skb_pull(skb, skip); ++ dump_hdr = (struct qca_dump_hdr *)skb->data; + +- dump_hdr = (struct qca_dump_hdr *)sk_ptr; + seqno = le16_to_cpu(dump_hdr->seqno); + if (seqno == 0) { + set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags); +@@ -3567,16 +3561,15 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + + btdata->qca_dump.ram_dump_size = dump_size; + btdata->qca_dump.ram_dump_seqno = 0; +- sk_ptr += offsetof(struct qca_dump_hdr, data0); +- sk_len -= offsetof(struct qca_dump_hdr, data0); ++ ++ skb_pull(skb, offsetof(struct qca_dump_hdr, data0)); + + usb_disable_autosuspend(udev); + bt_dev_info(hdev, "%s memdump size(%u)\n", + (pkt_type == HCI_ACLDATA_PKT) ? "ACL" : "event", + dump_size); + } else { +- sk_ptr += offsetof(struct qca_dump_hdr, data); +- sk_len -= offsetof(struct qca_dump_hdr, data); ++ skb_pull(skb, offsetof(struct qca_dump_hdr, data)); + } + + if (!btdata->qca_dump.ram_dump_size) { +@@ -3596,7 +3589,6 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + return ret; + } + +- skb_pull(skb, skb->len - sk_len); + hci_devcd_append(hdev, skb); + btdata->qca_dump.ram_dump_seqno++; + if (seqno == QCA_LAST_SEQUENCE_NUM) { +@@ -3624,68 +3616,58 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + /* Return: true if the ACL packet is a dump packet, false otherwise. */ + static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- u8 *sk_ptr; +- unsigned int sk_len; +- + struct hci_event_hdr *event_hdr; + struct hci_acl_hdr *acl_hdr; + struct qca_dump_hdr *dump_hdr; ++ struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); ++ bool is_dump = false; + +- sk_ptr = skb->data; +- sk_len = skb->len; +- +- acl_hdr = hci_acl_hdr(skb); +- if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE) ++ if (!clone) + return false; + +- sk_ptr += HCI_ACL_HDR_SIZE; +- sk_len -= HCI_ACL_HDR_SIZE; +- event_hdr = (struct hci_event_hdr *)sk_ptr; +- +- if ((event_hdr->evt != HCI_VENDOR_PKT) || +- (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) +- return false; ++ acl_hdr = skb_pull_data(clone, sizeof(*acl_hdr)); ++ if (!acl_hdr || (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)) ++ goto out; + +- sk_ptr += HCI_EVENT_HDR_SIZE; +- sk_len -= HCI_EVENT_HDR_SIZE; ++ event_hdr = skb_pull_data(clone, sizeof(*event_hdr)); ++ if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT)) ++ goto out; + +- dump_hdr = (struct qca_dump_hdr *)sk_ptr; +- if ((sk_len < offsetof(struct qca_dump_hdr, data)) || +- (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || +- (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) +- return false; ++ dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr)); ++ if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ goto out; + +- return true; ++ is_dump = true; ++out: ++ consume_skb(clone); ++ return is_dump; + } + + /* Return: true if the event packet is a dump packet, false otherwise. */ + static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- u8 *sk_ptr; +- unsigned int sk_len; +- + struct hci_event_hdr *event_hdr; + struct qca_dump_hdr *dump_hdr; ++ struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); ++ bool is_dump = false; + +- sk_ptr = skb->data; +- sk_len = skb->len; +- +- event_hdr = hci_event_hdr(skb); +- +- if ((event_hdr->evt != HCI_VENDOR_PKT) +- || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) ++ if (!clone) + return false; + +- sk_ptr += HCI_EVENT_HDR_SIZE; +- sk_len -= HCI_EVENT_HDR_SIZE; ++ event_hdr = skb_pull_data(clone, sizeof(*event_hdr)); ++ if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT)) ++ goto out; + +- dump_hdr = (struct qca_dump_hdr *)sk_ptr; +- if ((sk_len < offsetof(struct qca_dump_hdr, data)) || +- (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || +- (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) +- return false; ++ dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr)); ++ if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ goto out; + +- return true; ++ is_dump = true; ++out: ++ consume_skb(clone); ++ return is_dump; + } + + static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb) +diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c +index 38c456540d1b98..337144570fafa2 100644 +--- a/drivers/clk/clk-s2mps11.c ++++ b/drivers/clk/clk-s2mps11.c +@@ -137,6 +137,8 @@ static int s2mps11_clk_probe(struct platform_device *pdev) + if (!clk_data) + return -ENOMEM; + ++ clk_data->num = S2MPS11_CLKS_NUM; ++ + switch (hwid) { + case S2MPS11X: + s2mps11_reg = S2MPS11_REG_RTC_CTRL; +@@ -186,7 +188,6 @@ static int s2mps11_clk_probe(struct platform_device *pdev) + clk_data->hws[i] = &s2mps11_clks[i].hw; + } + +- clk_data->num = S2MPS11_CLKS_NUM; + of_clk_add_hw_provider(s2mps11_clks->clk_np, of_clk_hw_onecell_get, + clk_data); + +diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c +index 747f5397692e5f..2a0804dd4b8462 100644 +--- a/drivers/clk/imx/clk-imx8mp.c ++++ b/drivers/clk/imx/clk-imx8mp.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -406,11 +407,151 @@ static const char * const imx8mp_clkout_sels[] = {"audio_pll1_out", "audio_pll2_ + static struct clk_hw **hws; + static struct clk_hw_onecell_data *clk_hw_data; + ++struct imx8mp_clock_constraints { ++ unsigned int clkid; ++ u32 maxrate; ++}; ++ ++/* ++ * Below tables are taken from IMX8MPCEC Rev. 2.1, 07/2023 ++ * Table 13. Maximum frequency of modules. ++ * Probable typos fixed are marked with a comment. ++ */ ++static const struct imx8mp_clock_constraints imx8mp_clock_common_constraints[] = { ++ { IMX8MP_CLK_A53_DIV, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_AXI, 266666667 }, /* Datasheet claims 266MHz */ ++ { IMX8MP_CLK_NAND_USDHC_BUS, 266666667 }, /* Datasheet claims 266MHz */ ++ { IMX8MP_CLK_MEDIA_APB, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_APB, 133333333 }, /* Datasheet claims 133MHz */ ++ { IMX8MP_CLK_ML_AXI, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_AHB, 133333333 }, ++ { IMX8MP_CLK_IPG_ROOT, 66666667 }, ++ { IMX8MP_CLK_AUDIO_AHB, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_DISP2_PIX, 170 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_DRAM_ALT, 666666667 }, ++ { IMX8MP_CLK_DRAM_APB, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_CAN1, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_CAN2, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_PCIE_AUX, 10 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_I2C5, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C6, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI1, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI2, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI3, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI5, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI6, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_ENET_QOS, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_QOS_TIMER, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_REF, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_TIMER, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_PHY_REF, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NAND, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_QSPI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_USDHC1, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_USDHC2, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_I2C1, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C2, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C3, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C4, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_UART1, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_UART2, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_UART3, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_UART4, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ECSPI1, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ECSPI2, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_PWM1, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_PWM2, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_PWM3, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_PWM4, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_GPT1, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT2, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT3, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT4, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT5, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT6, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_WDOG, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_IPP_DO_CLKO1, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_IPP_DO_CLKO2, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_REF_266M, 266 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_USDHC3, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_MIPI_PHY1_REF, 300 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_DISP1_PIX, 250 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_CAM2_PIX, 277 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_LDB, 595 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_MIPI_TEST_BYTE, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ECSPI3, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_PDM, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_SAI7, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_MAIN_AXI, 400 * HZ_PER_MHZ }, ++ { /* Sentinel */ } ++}; ++ ++static const struct imx8mp_clock_constraints imx8mp_clock_nominal_constraints[] = { ++ { IMX8MP_CLK_M7_CORE, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ML_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_SHADER_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU2D_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_AUDIO_AXI_SRC, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HSIO_AXI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_ISP, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_BUS, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_AXI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_AXI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AXI, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AHB, 300 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC_IO, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ML_AHB, 300 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G1, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G2, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_CAM1_PIX, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_VC8000E, 400 * HZ_PER_MHZ }, /* Datasheet claims 500MHz */ ++ { IMX8MP_CLK_DRAM_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GIC, 400 * HZ_PER_MHZ }, ++ { /* Sentinel */ } ++}; ++ ++static const struct imx8mp_clock_constraints imx8mp_clock_overdrive_constraints[] = { ++ { IMX8MP_CLK_M7_CORE, 800 * HZ_PER_MHZ}, ++ { IMX8MP_CLK_ML_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_SHADER_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU2D_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_AUDIO_AXI_SRC, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HSIO_AXI, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_ISP, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_BUS, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_AXI, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_AXI, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AXI, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AHB, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC_IO, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ML_AHB, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G1, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G2, 700 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_CAM1_PIX, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_VC8000E, 500 * HZ_PER_MHZ }, /* Datasheet claims 400MHz */ ++ { IMX8MP_CLK_DRAM_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GIC, 500 * HZ_PER_MHZ }, ++ { /* Sentinel */ } ++}; ++ ++static void imx8mp_clocks_apply_constraints(const struct imx8mp_clock_constraints constraints[]) ++{ ++ const struct imx8mp_clock_constraints *constr; ++ ++ for (constr = constraints; constr->clkid; constr++) ++ clk_hw_set_rate_range(hws[constr->clkid], 0, constr->maxrate); ++} ++ + static int imx8mp_clocks_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct device_node *np; + void __iomem *anatop_base, *ccm_base; ++ const char *opmode; + int err; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mp-anatop"); +@@ -715,6 +856,16 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + + imx_check_clk_hws(hws, IMX8MP_CLK_END); + ++ imx8mp_clocks_apply_constraints(imx8mp_clock_common_constraints); ++ ++ err = of_property_read_string(np, "fsl,operating-mode", &opmode); ++ if (!err) { ++ if (!strcmp(opmode, "nominal")) ++ imx8mp_clocks_apply_constraints(imx8mp_clock_nominal_constraints); ++ else if (!strcmp(opmode, "overdrive")) ++ imx8mp_clocks_apply_constraints(imx8mp_clock_overdrive_constraints); ++ } ++ + err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); + if (err < 0) { + dev_err(dev, "failed to register hws for i.MX8MP\n"); +diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig +index 1de1661037b1b1..95cbea8d380c37 100644 +--- a/drivers/clk/qcom/Kconfig ++++ b/drivers/clk/qcom/Kconfig +@@ -148,7 +148,7 @@ config IPQ_GCC_4019 + + config IPQ_GCC_5018 + tristate "IPQ5018 Global Clock Controller" +- depends on ARM64 || COMPILE_TEST ++ depends on ARM || ARM64 || COMPILE_TEST + help + Support for global clock controller on ipq5018 devices. + Say Y if you want to use peripheral devices such as UART, SPI, +diff --git a/drivers/clk/qcom/camcc-sm8250.c b/drivers/clk/qcom/camcc-sm8250.c +index 9b32c56a5bc5af..e29706d7828707 100644 +--- a/drivers/clk/qcom/camcc-sm8250.c ++++ b/drivers/clk/qcom/camcc-sm8250.c +@@ -411,7 +411,7 @@ static struct clk_rcg2 cam_cc_bps_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -433,7 +433,7 @@ static struct clk_rcg2 cam_cc_camnoc_axi_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -454,7 +454,7 @@ static struct clk_rcg2 cam_cc_cci_0_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -469,7 +469,7 @@ static struct clk_rcg2 cam_cc_cci_1_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -490,7 +490,7 @@ static struct clk_rcg2 cam_cc_cphy_rx_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -511,7 +511,7 @@ static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -526,7 +526,7 @@ static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -556,7 +556,7 @@ static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -571,7 +571,7 @@ static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -586,7 +586,7 @@ static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -611,7 +611,7 @@ static struct clk_rcg2 cam_cc_fast_ahb_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -634,7 +634,7 @@ static struct clk_rcg2 cam_cc_fd_core_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -649,7 +649,7 @@ static struct clk_rcg2 cam_cc_icp_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -673,7 +673,7 @@ static struct clk_rcg2 cam_cc_ife_0_clk_src = { + .parent_data = cam_cc_parent_data_2, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -710,7 +710,7 @@ static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -734,7 +734,7 @@ static struct clk_rcg2 cam_cc_ife_1_clk_src = { + .parent_data = cam_cc_parent_data_3, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -749,7 +749,7 @@ static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -771,7 +771,7 @@ static struct clk_rcg2 cam_cc_ife_lite_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -786,7 +786,7 @@ static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -810,7 +810,7 @@ static struct clk_rcg2 cam_cc_ipe_0_clk_src = { + .parent_data = cam_cc_parent_data_4, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -825,7 +825,7 @@ static struct clk_rcg2 cam_cc_jpeg_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -847,7 +847,7 @@ static struct clk_rcg2 cam_cc_mclk0_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -862,7 +862,7 @@ static struct clk_rcg2 cam_cc_mclk1_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -877,7 +877,7 @@ static struct clk_rcg2 cam_cc_mclk2_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -892,7 +892,7 @@ static struct clk_rcg2 cam_cc_mclk3_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -907,7 +907,7 @@ static struct clk_rcg2 cam_cc_mclk4_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -922,7 +922,7 @@ static struct clk_rcg2 cam_cc_mclk5_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -993,7 +993,7 @@ static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c +index 80aadafffacdb1..732ca46703ba30 100644 +--- a/drivers/clk/qcom/clk-alpha-pll.c ++++ b/drivers/clk/qcom/clk-alpha-pll.c +@@ -645,14 +645,19 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 alpha_width = pll_alpha_width(pll); + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) ++ return 0; + +- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); + if (ctl & PLL_ALPHA_EN) { +- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low); ++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low)) ++ return 0; + if (alpha_width > 32) { +- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), +- &high); ++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), ++ &high)) ++ return 0; + a = (u64)high << 32 | low; + } else { + a = low & GENMASK(alpha_width - 1, 0); +@@ -844,8 +849,11 @@ alpha_pll_huayra_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, alpha = 0, ctl, alpha_m, alpha_n; + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); +- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) ++ return 0; + + if (ctl & PLL_ALPHA_EN) { + regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &alpha); +@@ -1039,8 +1047,11 @@ clk_trion_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, frac, alpha_width = pll_alpha_width(pll); + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); +- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac)) ++ return 0; + + return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); + } +@@ -1098,7 +1109,8 @@ clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + u32 ctl; + +- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); ++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) ++ return 0; + + ctl >>= PLL_POST_DIV_SHIFT; + ctl &= PLL_POST_DIV_MASK(pll); +@@ -1314,8 +1326,11 @@ static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw, + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, frac, alpha_width = pll_alpha_width(pll); + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); +- regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac)) ++ return 0; + + return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); + } +@@ -1465,7 +1480,8 @@ clk_trion_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct regmap *regmap = pll->clkr.regmap; + u32 i, div = 1, val; + +- regmap_read(regmap, PLL_USER_CTL(pll), &val); ++ if (regmap_read(regmap, PLL_USER_CTL(pll), &val)) ++ return 0; + + val >>= pll->post_div_shift; + val &= PLL_POST_DIV_MASK(pll); +@@ -2339,9 +2355,12 @@ static unsigned long alpha_pll_lucid_evo_recalc_rate(struct clk_hw *hw, + struct regmap *regmap = pll->clkr.regmap; + u32 l, frac; + +- regmap_read(regmap, PLL_L_VAL(pll), &l); ++ if (regmap_read(regmap, PLL_L_VAL(pll), &l)) ++ return 0; + l &= LUCID_EVO_PLL_L_VAL_MASK; +- regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac); ++ ++ if (regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac)) ++ return 0; + + return alpha_pll_calc_rate(parent_rate, l, frac, pll_alpha_width(pll)); + } +@@ -2416,7 +2435,8 @@ static unsigned long clk_rivian_evo_pll_recalc_rate(struct clk_hw *hw, + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l; + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; + + return parent_rate * l; + } +diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c +index f95c3615ca7727..98f107e96317ec 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c ++++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c +@@ -412,19 +412,23 @@ static const struct clk_parent_data mmc0_mmc1_parents[] = { + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, + }; +-static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_mmc1_parents, 0x830, +- 0, 4, /* M */ +- 8, 2, /* P */ +- 24, 3, /* mux */ +- BIT(31), /* gate */ +- 0); +- +-static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc0_mmc1_parents, 0x834, +- 0, 4, /* M */ +- 8, 2, /* P */ +- 24, 3, /* mux */ +- BIT(31), /* gate */ +- 0); ++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", ++ mmc0_mmc1_parents, 0x830, ++ 0, 4, /* M */ ++ 8, 2, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 2, /* post-div */ ++ 0); ++ ++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", ++ mmc0_mmc1_parents, 0x834, ++ 0, 4, /* M */ ++ 8, 2, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 2, /* post-div */ ++ 0); + + static const struct clk_parent_data mmc2_parents[] = { + { .fw_name = "hosc" }, +@@ -433,12 +437,14 @@ static const struct clk_parent_data mmc2_parents[] = { + { .hw = &pll_periph0_800M_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, + }; +-static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x838, +- 0, 4, /* M */ +- 8, 2, /* P */ +- 24, 3, /* mux */ +- BIT(31), /* gate */ +- 0); ++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc2_parents, ++ 0x838, ++ 0, 4, /* M */ ++ 8, 2, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 2, /* post-div */ ++ 0); + + static SUNXI_CCU_GATE_HWS(bus_mmc0_clk, "bus-mmc0", psi_ahb_hws, + 0x84c, BIT(0), 0); +diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h +index 6e50f3728fb5f1..7d836a9fb3db34 100644 +--- a/drivers/clk/sunxi-ng/ccu_mp.h ++++ b/drivers/clk/sunxi-ng/ccu_mp.h +@@ -52,6 +52,28 @@ struct ccu_mp { + } \ + } + ++#define SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, \ ++ _reg, \ ++ _mshift, _mwidth, \ ++ _pshift, _pwidth, \ ++ _muxshift, _muxwidth, \ ++ _gate, _postdiv, _flags)\ ++ struct ccu_mp _struct = { \ ++ .enable = _gate, \ ++ .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ ++ .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \ ++ .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ ++ .fixed_post_div = _postdiv, \ ++ .common = { \ ++ .reg = _reg, \ ++ .features = CCU_FEATURE_FIXED_POSTDIV, \ ++ .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ ++ _parents, \ ++ &ccu_mp_ops, \ ++ _flags), \ ++ } \ ++ } ++ + #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ +diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c +index b3ae38f3672052..39c70b5ac44c96 100644 +--- a/drivers/clocksource/mips-gic-timer.c ++++ b/drivers/clocksource/mips-gic-timer.c +@@ -114,6 +114,9 @@ static void gic_update_frequency(void *data) + + static int gic_starting_cpu(unsigned int cpu) + { ++ /* Ensure the GIC counter is running */ ++ clear_gic_config(GIC_CONFIG_COUNTSTOP); ++ + gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device)); + return 0; + } +@@ -248,9 +251,6 @@ static int __init gic_clocksource_of_init(struct device_node *node) + pr_warn("Unable to register clock notifier\n"); + } + +- /* And finally start the counter */ +- clear_gic_config(GIC_CONFIG_COUNTSTOP); +- + /* + * It's safe to use the MIPS GIC timer as a sched clock source only if + * its ticks are stable, which is true on either the platforms with +diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c +index 09becf14653b58..c58c1defd74588 100644 +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -165,6 +165,7 @@ static const struct of_device_id blocklist[] __initconst = { + { .compatible = "qcom,sm8350", }, + { .compatible = "qcom,sm8450", }, + { .compatible = "qcom,sm8550", }, ++ { .compatible = "qcom,sm8650", }, + + { .compatible = "st,stih407", }, + { .compatible = "st,stih410", }, +diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c +index 7b8fcfa55038bc..4e5b6f9a56d1b2 100644 +--- a/drivers/cpufreq/tegra186-cpufreq.c ++++ b/drivers/cpufreq/tegra186-cpufreq.c +@@ -73,11 +73,18 @@ static int tegra186_cpufreq_init(struct cpufreq_policy *policy) + { + struct tegra186_cpufreq_data *data = cpufreq_get_driver_data(); + unsigned int cluster = data->cpus[policy->cpu].bpmp_cluster_id; ++ u32 cpu; + + policy->freq_table = data->clusters[cluster].table; + policy->cpuinfo.transition_latency = 300 * 1000; + policy->driver_data = NULL; + ++ /* set same policy for all cpus in a cluster */ ++ for (cpu = 0; cpu < ARRAY_SIZE(tegra186_cpus); cpu++) { ++ if (data->cpus[cpu].bpmp_cluster_id == cluster) ++ cpumask_set_cpu(cpu, policy->cpus); ++ } ++ + return 0; + } + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index b96e3da0fedd01..edd9a8fb9878d6 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -246,8 +246,19 @@ static unsigned int get_typical_interval(struct menu_device *data) + * This can deal with workloads that have long pauses interspersed + * with sporadic activity with a bunch of short pauses. + */ +- if ((divisor * 4) <= INTERVALS * 3) ++ if (divisor * 4 <= INTERVALS * 3) { ++ /* ++ * If there are sufficiently many data points still under ++ * consideration after the outliers have been eliminated, ++ * returning without a prediction would be a mistake because it ++ * is likely that the next interval will not exceed the current ++ * maximum, so return the latter in that case. ++ */ ++ if (divisor >= INTERVALS / 2) ++ return max; ++ + return UINT_MAX; ++ } + + thresh = max - 1; + goto again; +diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c +index 811ded72ce5fbd..798bb40fed68df 100644 +--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c ++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c +@@ -410,9 +410,10 @@ static int cpt_process_ccode(struct otx2_cptlfs_info *lfs, + break; + } + +- dev_err(&pdev->dev, +- "Request failed with software error code 0x%x\n", +- cpt_status->s.uc_compcode); ++ pr_debug("Request failed with software error code 0x%x: algo = %s driver = %s\n", ++ cpt_status->s.uc_compcode, ++ info->req->areq->tfm->__crt_alg->cra_name, ++ info->req->areq->tfm->__crt_alg->cra_driver_name); + otx2_cpt_dump_sg_list(pdev, info->req); + break; + } +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index cc9923ab686dcd..eccbcf67951fbe 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -58,7 +58,7 @@ static irqreturn_t fsl_edma3_tx_handler(int irq, void *dev_id) + + intr = edma_readl_chreg(fsl_chan, ch_int); + if (!intr) +- return IRQ_HANDLED; ++ return IRQ_NONE; + + edma_writel_chreg(fsl_chan, 1, ch_int); + +diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c +index c18633ad8455fa..7e3a67f9f0a654 100644 +--- a/drivers/dma/idxd/cdev.c ++++ b/drivers/dma/idxd/cdev.c +@@ -225,7 +225,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp) + struct idxd_wq *wq; + struct device *dev, *fdev; + int rc = 0; +- struct iommu_sva *sva; ++ struct iommu_sva *sva = NULL; + unsigned int pasid; + struct idxd_cdev *idxd_cdev; + +@@ -322,7 +322,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp) + if (device_user_pasid_enabled(idxd)) + idxd_xa_pasid_remove(ctx); + failed_get_pasid: +- if (device_user_pasid_enabled(idxd)) ++ if (device_user_pasid_enabled(idxd) && !IS_ERR_OR_NULL(sva)) + iommu_sva_unbind_device(sva); + failed: + mutex_unlock(&wq->wq_lock); +@@ -412,6 +412,9 @@ static int idxd_cdev_mmap(struct file *filp, struct vm_area_struct *vma) + if (!idxd->user_submission_safe && !capable(CAP_SYS_RAWIO)) + return -EPERM; + ++ if (current->mm != ctx->mm) ++ return -EPERM; ++ + rc = check_vma(wq, vma, __func__); + if (rc < 0) + return rc; +@@ -478,6 +481,9 @@ static ssize_t idxd_cdev_write(struct file *filp, const char __user *buf, size_t + ssize_t written = 0; + int i; + ++ if (current->mm != ctx->mm) ++ return -EPERM; ++ + for (i = 0; i < len/sizeof(struct dsa_hw_desc); i++) { + int rc = idxd_submit_user_descriptor(ctx, udesc + i); + +@@ -498,6 +504,9 @@ static __poll_t idxd_cdev_poll(struct file *filp, + struct idxd_device *idxd = wq->idxd; + __poll_t out = 0; + ++ if (current->mm != ctx->mm) ++ return POLLNVAL; ++ + poll_wait(filp, &wq->err_queue, wait); + spin_lock(&idxd->dev_lock); + if (idxd->sw_err.valid) +@@ -584,6 +593,7 @@ void idxd_wq_del_cdev(struct idxd_wq *wq) + + static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) + { ++ struct device *dev = &idxd_dev->conf_dev; + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + struct idxd_device *idxd = wq->idxd; + int rc; +@@ -611,6 +621,12 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) + + mutex_lock(&wq->wq_lock); + ++ if (!idxd_wq_driver_name_match(wq, dev)) { ++ idxd->cmd_status = IDXD_SCMD_WQ_NO_DRV_NAME; ++ rc = -ENODEV; ++ goto wq_err; ++ } ++ + wq->wq = create_workqueue(dev_name(wq_confdev(wq))); + if (!wq->wq) { + rc = -ENOMEM; +diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c +index 07623fb0f52fc2..47a01893cfdbf9 100644 +--- a/drivers/dma/idxd/dma.c ++++ b/drivers/dma/idxd/dma.c +@@ -306,6 +306,12 @@ static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev) + return -ENXIO; + + mutex_lock(&wq->wq_lock); ++ if (!idxd_wq_driver_name_match(wq, dev)) { ++ idxd->cmd_status = IDXD_SCMD_WQ_NO_DRV_NAME; ++ rc = -ENODEV; ++ goto err; ++ } ++ + wq->type = IDXD_WQT_KERNEL; + + rc = drv_enable_wq(wq); +diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h +index bea10c5cdb76bb..fcbb8caea89952 100644 +--- a/drivers/dma/idxd/idxd.h ++++ b/drivers/dma/idxd/idxd.h +@@ -159,6 +159,8 @@ struct idxd_cdev { + int minor; + }; + ++#define DRIVER_NAME_SIZE 128 ++ + #define IDXD_ALLOCATED_BATCH_SIZE 128U + #define WQ_NAME_SIZE 1024 + #define WQ_TYPE_SIZE 10 +@@ -227,6 +229,8 @@ struct idxd_wq { + /* Lock to protect upasid_xa access. */ + struct mutex uc_lock; + struct xarray upasid_xa; ++ ++ char driver_name[DRIVER_NAME_SIZE + 1]; + }; + + struct idxd_engine { +@@ -648,6 +652,11 @@ static inline void idxd_wqcfg_set_max_batch_shift(int idxd_type, union wqcfg *wq + wqcfg->max_batch_shift = max_batch_shift; + } + ++static inline int idxd_wq_driver_name_match(struct idxd_wq *wq, struct device *dev) ++{ ++ return (strncmp(wq->driver_name, dev->driver->name, strlen(dev->driver->name)) == 0); ++} ++ + int __must_check __idxd_driver_register(struct idxd_device_driver *idxd_drv, + struct module *module, const char *mod_name); + #define idxd_driver_register(driver) \ +diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c +index 1fd5a93045f79e..3a5ce477a81ad6 100644 +--- a/drivers/dma/idxd/sysfs.c ++++ b/drivers/dma/idxd/sysfs.c +@@ -1282,6 +1282,39 @@ static ssize_t wq_op_config_store(struct device *dev, struct device_attribute *a + static struct device_attribute dev_attr_wq_op_config = + __ATTR(op_config, 0644, wq_op_config_show, wq_op_config_store); + ++static ssize_t wq_driver_name_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct idxd_wq *wq = confdev_to_wq(dev); ++ ++ return sysfs_emit(buf, "%s\n", wq->driver_name); ++} ++ ++static ssize_t wq_driver_name_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct idxd_wq *wq = confdev_to_wq(dev); ++ char *input, *pos; ++ ++ if (wq->state != IDXD_WQ_DISABLED) ++ return -EPERM; ++ ++ if (strlen(buf) > DRIVER_NAME_SIZE || strlen(buf) == 0) ++ return -EINVAL; ++ ++ input = kstrndup(buf, count, GFP_KERNEL); ++ if (!input) ++ return -ENOMEM; ++ ++ pos = strim(input); ++ memset(wq->driver_name, 0, DRIVER_NAME_SIZE + 1); ++ sprintf(wq->driver_name, "%s", pos); ++ kfree(input); ++ return count; ++} ++ ++static struct device_attribute dev_attr_wq_driver_name = ++ __ATTR(driver_name, 0644, wq_driver_name_show, wq_driver_name_store); ++ + static struct attribute *idxd_wq_attributes[] = { + &dev_attr_wq_clients.attr, + &dev_attr_wq_state.attr, +@@ -1301,6 +1334,7 @@ static struct attribute *idxd_wq_attributes[] = { + &dev_attr_wq_occupancy.attr, + &dev_attr_wq_enqcmds_retries.attr, + &dev_attr_wq_op_config.attr, ++ &dev_attr_wq_driver_name.attr, + NULL, + }; + +diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c +index 56be8ef40f376b..e3635fba63b493 100644 +--- a/drivers/edac/ie31200_edac.c ++++ b/drivers/edac/ie31200_edac.c +@@ -405,10 +405,9 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) + int i, j, ret; + struct mem_ctl_info *mci = NULL; + struct edac_mc_layer layers[2]; +- struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL]; + void __iomem *window; + struct ie31200_priv *priv; +- u32 addr_decode, mad_offset; ++ u32 addr_decode[IE31200_CHANNELS], mad_offset; + + /* + * Kaby Lake, Coffee Lake seem to work like Skylake. Please re-visit +@@ -466,19 +465,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) + mad_offset = IE31200_MAD_DIMM_0_OFFSET; + } + +- /* populate DIMM info */ + for (i = 0; i < IE31200_CHANNELS; i++) { +- addr_decode = readl(window + mad_offset + ++ addr_decode[i] = readl(window + mad_offset + + (i * 4)); +- edac_dbg(0, "addr_decode: 0x%x\n", addr_decode); +- for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) { +- populate_dimm_info(&dimm_info[i][j], addr_decode, j, +- skl); +- edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n", +- dimm_info[i][j].size, +- dimm_info[i][j].dual_rank, +- dimm_info[i][j].x16_width); +- } ++ edac_dbg(0, "addr_decode: 0x%x\n", addr_decode[i]); + } + + /* +@@ -489,14 +479,22 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) + */ + for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) { + for (j = 0; j < IE31200_CHANNELS; j++) { ++ struct dimm_data dimm_info; + struct dimm_info *dimm; + unsigned long nr_pages; + +- nr_pages = IE31200_PAGES(dimm_info[j][i].size, skl); ++ populate_dimm_info(&dimm_info, addr_decode[j], i, ++ skl); ++ edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n", ++ dimm_info.size, ++ dimm_info.dual_rank, ++ dimm_info.x16_width); ++ ++ nr_pages = IE31200_PAGES(dimm_info.size, skl); + if (nr_pages == 0) + continue; + +- if (dimm_info[j][i].dual_rank) { ++ if (dimm_info.dual_rank) { + nr_pages = nr_pages / 2; + dimm = edac_get_dimm(mci, (i * 2) + 1, j, 0); + dimm->nr_pages = nr_pages; +diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c +index 7865438b36960d..d885e1381072ac 100644 +--- a/drivers/firmware/arm_ffa/bus.c ++++ b/drivers/firmware/arm_ffa/bus.c +@@ -191,6 +191,7 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, + dev = &ffa_dev->dev; + dev->bus = &ffa_bus_type; + dev->release = ffa_release_device; ++ dev->dma_mask = &dev->coherent_dma_mask; + dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); + + ffa_dev->id = id; +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 7c2db3f017651b..488f8345dd1b63 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -121,6 +121,14 @@ static int ffa_version_check(u32 *version) + return -EOPNOTSUPP; + } + ++ if (FFA_MAJOR_VERSION(ver.a0) > FFA_MAJOR_VERSION(FFA_DRIVER_VERSION)) { ++ pr_err("Incompatible v%d.%d! Latest supported v%d.%d\n", ++ FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0), ++ FFA_MAJOR_VERSION(FFA_DRIVER_VERSION), ++ FFA_MINOR_VERSION(FFA_DRIVER_VERSION)); ++ return -EINVAL; ++ } ++ + if (ver.a0 < FFA_MIN_VERSION) { + pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n", + FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0), +diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c +index 51eeaf14367dac..e1b949aedf9e08 100644 +--- a/drivers/firmware/arm_scmi/bus.c ++++ b/drivers/firmware/arm_scmi/bus.c +@@ -42,7 +42,7 @@ static atomic_t scmi_syspower_registered = ATOMIC_INIT(0); + * This helper let an SCMI driver request specific devices identified by the + * @id_table to be created for each active SCMI instance. + * +- * The requested device name MUST NOT be already existent for any protocol; ++ * The requested device name MUST NOT be already existent for this protocol; + * at first the freshly requested @id_table is annotated in the IDR table + * @scmi_requested_devices and then the requested device is advertised to any + * registered party via the @scmi_requested_devices_nh notification chain. +@@ -52,7 +52,6 @@ static atomic_t scmi_syspower_registered = ATOMIC_INIT(0); + static int scmi_protocol_device_request(const struct scmi_device_id *id_table) + { + int ret = 0; +- unsigned int id = 0; + struct list_head *head, *phead = NULL; + struct scmi_requested_dev *rdev; + +@@ -67,19 +66,13 @@ static int scmi_protocol_device_request(const struct scmi_device_id *id_table) + } + + /* +- * Search for the matching protocol rdev list and then search +- * of any existent equally named device...fails if any duplicate found. ++ * Find the matching protocol rdev list and then search of any ++ * existent equally named device...fails if any duplicate found. + */ + mutex_lock(&scmi_requested_devices_mtx); +- idr_for_each_entry(&scmi_requested_devices, head, id) { +- if (!phead) { +- /* A list found registered in the IDR is never empty */ +- rdev = list_first_entry(head, struct scmi_requested_dev, +- node); +- if (rdev->id_table->protocol_id == +- id_table->protocol_id) +- phead = head; +- } ++ phead = idr_find(&scmi_requested_devices, id_table->protocol_id); ++ if (phead) { ++ head = phead; + list_for_each_entry(rdev, head, node) { + if (!strcmp(rdev->id_table->name, id_table->name)) { + pr_err("Ignoring duplicate request [%d] %s\n", +diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c +index 4ffb9da537d82c..5295ff90482bc6 100644 +--- a/drivers/fpga/altera-cvp.c ++++ b/drivers/fpga/altera-cvp.c +@@ -52,7 +52,7 @@ + /* V2 Defines */ + #define VSE_CVP_TX_CREDITS 0x49 /* 8bit */ + +-#define V2_CREDIT_TIMEOUT_US 20000 ++#define V2_CREDIT_TIMEOUT_US 40000 + #define V2_CHECK_CREDIT_US 10 + #define V2_POLL_TIMEOUT_US 1000000 + #define V2_USER_TIMEOUT_US 500000 +diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c +index b882b26ab5007b..faadbe66b23e71 100644 +--- a/drivers/gpio/gpio-pca953x.c ++++ b/drivers/gpio/gpio-pca953x.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -519,12 +520,10 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) + struct pca953x_chip *chip = gpiochip_get_data(gc); + u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); + u8 bit = BIT(off % BANK_SZ); +- int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = regmap_write_bits(chip->regmap, dirreg, bit, bit); +- mutex_unlock(&chip->i2c_lock); +- return ret; ++ guard(mutex)(&chip->i2c_lock); ++ ++ return regmap_write_bits(chip->regmap, dirreg, bit, bit); + } + + static int pca953x_gpio_direction_output(struct gpio_chip *gc, +@@ -536,17 +535,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, + u8 bit = BIT(off % BANK_SZ); + int ret; + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); ++ + /* set output level */ + ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); + if (ret) +- goto exit; ++ return ret; + + /* then direction */ +- ret = regmap_write_bits(chip->regmap, dirreg, bit, 0); +-exit: +- mutex_unlock(&chip->i2c_lock); +- return ret; ++ return regmap_write_bits(chip->regmap, dirreg, bit, 0); + } + + static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) +@@ -557,9 +554,8 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) + u32 reg_val; + int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = regmap_read(chip->regmap, inreg, ®_val); +- mutex_unlock(&chip->i2c_lock); ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = regmap_read(chip->regmap, inreg, ®_val); + if (ret < 0) + return ret; + +@@ -572,9 +568,9 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) + u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); + u8 bit = BIT(off % BANK_SZ); + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); ++ + regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); +- mutex_unlock(&chip->i2c_lock); + } + + static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) +@@ -585,9 +581,8 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) + u32 reg_val; + int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = regmap_read(chip->regmap, dirreg, ®_val); +- mutex_unlock(&chip->i2c_lock); ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = regmap_read(chip->regmap, dirreg, ®_val); + if (ret < 0) + return ret; + +@@ -604,9 +599,8 @@ static int pca953x_gpio_get_multiple(struct gpio_chip *gc, + DECLARE_BITMAP(reg_val, MAX_LINE); + int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = pca953x_read_regs(chip, chip->regs->input, reg_val); +- mutex_unlock(&chip->i2c_lock); ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = pca953x_read_regs(chip, chip->regs->input, reg_val); + if (ret) + return ret; + +@@ -621,16 +615,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, + DECLARE_BITMAP(reg_val, MAX_LINE); + int ret; + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); ++ + ret = pca953x_read_regs(chip, chip->regs->output, reg_val); + if (ret) +- goto exit; ++ return; + + bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio); + + pca953x_write_regs(chip, chip->regs->output, reg_val); +-exit: +- mutex_unlock(&chip->i2c_lock); + } + + static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, +@@ -638,7 +631,6 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, + unsigned long config) + { + enum pin_config_param param = pinconf_to_config_param(config); +- + u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset); + u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset); + u8 bit = BIT(offset % BANK_SZ); +@@ -651,7 +643,7 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, + if (!(chip->driver_data & PCA_PCAL)) + return -ENOTSUPP; + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); + + /* Configure pull-up/pull-down */ + if (param == PIN_CONFIG_BIAS_PULL_UP) +@@ -661,17 +653,13 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, + else + ret = 0; + if (ret) +- goto exit; ++ return ret; + + /* Disable/Enable pull-up/pull-down */ + if (param == PIN_CONFIG_BIAS_DISABLE) +- ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0); ++ return regmap_write_bits(chip->regmap, pull_en_reg, bit, 0); + else +- ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit); +- +-exit: +- mutex_unlock(&chip->i2c_lock); +- return ret; ++ return regmap_write_bits(chip->regmap, pull_en_reg, bit, bit); + } + + static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset, +@@ -883,10 +871,8 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) + + bitmap_zero(pending, MAX_LINE); + +- mutex_lock(&chip->i2c_lock); +- ret = pca953x_irq_pending(chip, pending); +- mutex_unlock(&chip->i2c_lock); +- ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = pca953x_irq_pending(chip, pending); + if (ret) { + ret = 0; + +@@ -1168,9 +1154,9 @@ static int pca953x_probe(struct i2c_client *client) + } + + #ifdef CONFIG_PM_SLEEP +-static int pca953x_regcache_sync(struct device *dev) ++static int pca953x_regcache_sync(struct pca953x_chip *chip) + { +- struct pca953x_chip *chip = dev_get_drvdata(dev); ++ struct device *dev = &chip->client->dev; + int ret; + u8 regaddr; + +@@ -1217,13 +1203,38 @@ static int pca953x_regcache_sync(struct device *dev) + return 0; + } + ++static int pca953x_restore_context(struct pca953x_chip *chip) ++{ ++ int ret; ++ ++ guard(mutex)(&chip->i2c_lock); ++ ++ if (chip->client->irq > 0) ++ enable_irq(chip->client->irq); ++ regcache_cache_only(chip->regmap, false); ++ regcache_mark_dirty(chip->regmap); ++ ret = pca953x_regcache_sync(chip); ++ if (ret) ++ return ret; ++ ++ return regcache_sync(chip->regmap); ++} ++ ++static void pca953x_save_context(struct pca953x_chip *chip) ++{ ++ guard(mutex)(&chip->i2c_lock); ++ ++ /* Disable IRQ to prevent early triggering while regmap "cache only" is on */ ++ if (chip->client->irq > 0) ++ disable_irq(chip->client->irq); ++ regcache_cache_only(chip->regmap, true); ++} ++ + static int pca953x_suspend(struct device *dev) + { + struct pca953x_chip *chip = dev_get_drvdata(dev); + +- mutex_lock(&chip->i2c_lock); +- regcache_cache_only(chip->regmap, true); +- mutex_unlock(&chip->i2c_lock); ++ pca953x_save_context(chip); + + if (atomic_read(&chip->wakeup_path)) + device_set_wakeup_path(dev); +@@ -1246,17 +1257,7 @@ static int pca953x_resume(struct device *dev) + } + } + +- mutex_lock(&chip->i2c_lock); +- regcache_cache_only(chip->regmap, false); +- regcache_mark_dirty(chip->regmap); +- ret = pca953x_regcache_sync(dev); +- if (ret) { +- mutex_unlock(&chip->i2c_lock); +- return ret; +- } +- +- ret = regcache_sync(chip->regmap); +- mutex_unlock(&chip->i2c_lock); ++ ret = pca953x_restore_context(chip); + if (ret) { + dev_err(dev, "Failed to restore register map: %d\n", ret); + return ret; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +index be4cc4868a748e..493e18bcea069e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +@@ -43,6 +43,29 @@ + #include + #include + ++static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops; ++ ++/** ++ * dma_buf_attach_adev - Helper to get adev of an attachment ++ * ++ * @attach: attachment ++ * ++ * Returns: ++ * A struct amdgpu_device * if the attaching device is an amdgpu device or ++ * partition, NULL otherwise. ++ */ ++static struct amdgpu_device *dma_buf_attach_adev(struct dma_buf_attachment *attach) ++{ ++ if (attach->importer_ops == &amdgpu_dma_buf_attach_ops) { ++ struct drm_gem_object *obj = attach->importer_priv; ++ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); ++ ++ return amdgpu_ttm_adev(bo->tbo.bdev); ++ } ++ ++ return NULL; ++} ++ + /** + * amdgpu_dma_buf_attach - &dma_buf_ops.attach implementation + * +@@ -54,12 +77,14 @@ + static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attach) + { ++ struct amdgpu_device *attach_adev = dma_buf_attach_adev(attach); + struct drm_gem_object *obj = dmabuf->priv; + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + int r; + +- if (pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) ++ if (!amdgpu_dmabuf_is_xgmi_accessible(attach_adev, bo) && ++ pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) + attach->peer2peer = false; + + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); +@@ -482,6 +507,9 @@ bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev, + struct drm_gem_object *obj = &bo->tbo.base; + struct drm_gem_object *gobj; + ++ if (!adev) ++ return false; ++ + if (obj->import_attach) { + struct dma_buf *dma_buf = obj->import_attach->dmabuf; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +index 6a24e8ceb94493..ffa5e72a84ebcb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +@@ -43,7 +43,7 @@ + #include "amdgpu_securedisplay.h" + #include "amdgpu_atomfirmware.h" + +-#define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*3) ++#define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*16) + + static int psp_load_smu_fw(struct psp_context *psp); + static int psp_rap_terminate(struct psp_context *psp); +@@ -506,7 +506,6 @@ static int psp_sw_fini(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct psp_context *psp = &adev->psp; +- struct psp_gfx_cmd_resp *cmd = psp->cmd; + + psp_memory_training_fini(psp); + +@@ -516,8 +515,8 @@ static int psp_sw_fini(void *handle) + amdgpu_ucode_release(&psp->cap_fw); + amdgpu_ucode_release(&psp->toc_fw); + +- kfree(cmd); +- cmd = NULL; ++ kfree(psp->cmd); ++ psp->cmd = NULL; + + psp_free_shared_bufs(psp); + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +index 66c6bab75f8a58..0d3d00681edac5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +@@ -92,12 +92,12 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) + { + uint64_t value; + +- /* Program the AGP BAR */ +- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BASE, 0); +- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 24); +- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 24); +- + if (!amdgpu_sriov_vf(adev) || adev->asic_type <= CHIP_VEGA10) { ++ /* Program the AGP BAR */ ++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BASE, 0); ++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 24); ++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 24); ++ + /* Program the system aperture low logical page number. */ + WREG32_SOC15_RLC(GC, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, + min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c +index 9086f2fdfaf422..553f4f24f5adeb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c +@@ -172,6 +172,30 @@ static void mmhub_v1_7_init_tlb_regs(struct amdgpu_device *adev) + WREG32_SOC15(MMHUB, 0, regMC_VM_MX_L1_TLB_CNTL, tmp); + } + ++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */ ++static void mmhub_v1_7_init_snoop_override_regs(struct amdgpu_device *adev) ++{ ++ uint32_t tmp; ++ int i; ++ uint32_t distance = regDAGB1_WRCLI_GPU_SNOOP_OVERRIDE - ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE; ++ ++ for (i = 0; i < 5; i++) { /* DAGB instances */ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, i * distance); ++ tmp |= (1 << 15); /* SDMA client is BIT15 */ ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, i * distance, tmp); ++ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, i * distance); ++ tmp |= (1 << 15); ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, i * distance, tmp); ++ } ++ ++} ++ + static void mmhub_v1_7_init_cache_regs(struct amdgpu_device *adev) + { + uint32_t tmp; +@@ -337,6 +361,7 @@ static int mmhub_v1_7_gart_enable(struct amdgpu_device *adev) + mmhub_v1_7_init_system_aperture_regs(adev); + mmhub_v1_7_init_tlb_regs(adev); + mmhub_v1_7_init_cache_regs(adev); ++ mmhub_v1_7_init_snoop_override_regs(adev); + + mmhub_v1_7_enable_system_domain(adev); + mmhub_v1_7_disable_identity_aperture(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +index 3d8e579d5c4e8a..c7bdccff785b71 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +@@ -213,6 +213,32 @@ static void mmhub_v1_8_init_tlb_regs(struct amdgpu_device *adev) + } + } + ++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */ ++static void mmhub_v1_8_init_snoop_override_regs(struct amdgpu_device *adev) ++{ ++ uint32_t tmp, inst_mask; ++ int i, j; ++ uint32_t distance = regDAGB1_WRCLI_GPU_SNOOP_OVERRIDE - ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE; ++ ++ inst_mask = adev->aid_mask; ++ for_each_inst(i, inst_mask) { ++ for (j = 0; j < 5; j++) { /* DAGB instances */ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, j * distance); ++ tmp |= (1 << 15); /* SDMA client is BIT15 */ ++ WREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, j * distance, tmp); ++ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, j * distance); ++ tmp |= (1 << 15); ++ WREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, j * distance, tmp); ++ } ++ } ++} ++ + static void mmhub_v1_8_init_cache_regs(struct amdgpu_device *adev) + { + uint32_t tmp, inst_mask; +@@ -418,6 +444,7 @@ static int mmhub_v1_8_gart_enable(struct amdgpu_device *adev) + mmhub_v1_8_init_system_aperture_regs(adev); + mmhub_v1_8_init_tlb_regs(adev); + mmhub_v1_8_init_cache_regs(adev); ++ mmhub_v1_8_init_snoop_override_regs(adev); + + mmhub_v1_8_enable_system_domain(adev); + mmhub_v1_8_disable_identity_aperture(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c +index 5718e4d40e6665..9713cb59d1c14f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c +@@ -198,6 +198,36 @@ static void mmhub_v9_4_init_tlb_regs(struct amdgpu_device *adev, int hubid) + hubid * MMHUB_INSTANCE_REGISTER_OFFSET, tmp); + } + ++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */ ++static void mmhub_v9_4_init_snoop_override_regs(struct amdgpu_device *adev, int hubid) ++{ ++ uint32_t tmp; ++ int i; ++ uint32_t distance = mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE - ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE; ++ uint32_t huboffset = hubid * MMHUB_INSTANCE_REGISTER_OFFSET; ++ ++ for (i = 0; i < 5 - (2 * hubid); i++) { ++ /* DAGB instances 0 to 4 are in hub0 and 5 to 7 are in hub1 */ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, ++ huboffset + i * distance); ++ tmp |= (1 << 15); /* SDMA client is BIT15 */ ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, ++ huboffset + i * distance, tmp); ++ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, ++ huboffset + i * distance); ++ tmp |= (1 << 15); ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, ++ huboffset + i * distance, tmp); ++ } ++ ++} ++ + static void mmhub_v9_4_init_cache_regs(struct amdgpu_device *adev, int hubid) + { + uint32_t tmp; +@@ -392,6 +422,7 @@ static int mmhub_v9_4_gart_enable(struct amdgpu_device *adev) + if (!amdgpu_sriov_vf(adev)) + mmhub_v9_4_init_cache_regs(adev, i); + ++ mmhub_v9_4_init_snoop_override_regs(adev, i); + mmhub_v9_4_enable_system_domain(adev, i); + if (!amdgpu_sriov_vf(adev)) + mmhub_v9_4_disable_identity_aperture(adev, i); +diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c +index 7910c463ae3855..82709e692f4cc0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/nv.c ++++ b/drivers/gpu/drm/amd/amdgpu/nv.c +@@ -142,23 +142,23 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] = { + }; + + static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn0[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 1920, 1088, 3)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 1920, 1088, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 1920, 1088, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, + }; + + static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn1[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 1920, 1088, 3)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 1920, 1088, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 1920, 1088, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + }; + +diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c +index 4712ffc0a482c8..7819f5d584f597 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc21.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc21.c +@@ -117,23 +117,17 @@ static struct amdgpu_video_codecs sriov_vcn_4_0_0_video_codecs_encode_vcn1 = { + }; + + static struct amdgpu_video_codec_info sriov_vcn_4_0_0_video_codecs_decode_array_vcn0[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, + }; + + static struct amdgpu_video_codec_info sriov_vcn_4_0_0_video_codecs_decode_array_vcn1[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + }; + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index 4d9a406925e189..fd4a75073364c7 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -2147,14 +2147,6 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, + return retval; + } + +-/* +- * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to +- * stay in user mode. +- */ +-#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL +-/* APE1 limit is inclusive and 64K aligned. */ +-#define APE1_LIMIT_ALIGNMENT 0xFFFF +- + static bool set_cache_memory_policy(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, +@@ -2169,34 +2161,6 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, + + dqm_lock(dqm); + +- if (alternate_aperture_size == 0) { +- /* base > limit disables APE1 */ +- qpd->sh_mem_ape1_base = 1; +- qpd->sh_mem_ape1_limit = 0; +- } else { +- /* +- * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]}, +- * SH_MEM_APE1_BASE[31:0], 0x0000 } +- * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]}, +- * SH_MEM_APE1_LIMIT[31:0], 0xFFFF } +- * Verify that the base and size parameters can be +- * represented in this format and convert them. +- * Additionally restrict APE1 to user-mode addresses. +- */ +- +- uint64_t base = (uintptr_t)alternate_aperture_base; +- uint64_t limit = base + alternate_aperture_size - 1; +- +- if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 || +- (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) { +- retval = false; +- goto out; +- } +- +- qpd->sh_mem_ape1_base = base >> 16; +- qpd->sh_mem_ape1_limit = limit >> 16; +- } +- + retval = dqm->asic_ops.set_cache_memory_policy( + dqm, + qpd, +@@ -2205,6 +2169,9 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, + alternate_aperture_base, + alternate_aperture_size); + ++ if (retval) ++ goto out; ++ + if ((dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0)) + program_sh_mem_settings(dqm, qpd); + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +index d4d95c7f2e5d40..32bedef912b3b2 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +@@ -27,6 +27,14 @@ + #include "oss/oss_2_4_sh_mask.h" + #include "gca/gfx_7_2_sh_mask.h" + ++/* ++ * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to ++ * stay in user mode. ++ */ ++#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL ++/* APE1 limit is inclusive and 64K aligned. */ ++#define APE1_LIMIT_ALIGNMENT 0xFFFF ++ + static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, +@@ -84,6 +92,36 @@ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + { + uint32_t default_mtype; + uint32_t ape1_mtype; ++ unsigned int temp; ++ bool retval = true; ++ ++ if (alternate_aperture_size == 0) { ++ /* base > limit disables APE1 */ ++ qpd->sh_mem_ape1_base = 1; ++ qpd->sh_mem_ape1_limit = 0; ++ } else { ++ /* ++ * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]}, ++ * SH_MEM_APE1_BASE[31:0], 0x0000 } ++ * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]}, ++ * SH_MEM_APE1_LIMIT[31:0], 0xFFFF } ++ * Verify that the base and size parameters can be ++ * represented in this format and convert them. ++ * Additionally restrict APE1 to user-mode addresses. ++ */ ++ ++ uint64_t base = (uintptr_t)alternate_aperture_base; ++ uint64_t limit = base + alternate_aperture_size - 1; ++ ++ if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 || ++ (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) { ++ retval = false; ++ goto out; ++ } ++ ++ qpd->sh_mem_ape1_base = base >> 16; ++ qpd->sh_mem_ape1_limit = limit >> 16; ++ } + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_NONCACHED : +@@ -97,37 +135,22 @@ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) + | DEFAULT_MTYPE(default_mtype) + | APE1_MTYPE(ape1_mtype); +- +- return true; +-} +- +-static int update_qpd_cik(struct device_queue_manager *dqm, +- struct qcm_process_device *qpd) +-{ +- struct kfd_process_device *pdd; +- unsigned int temp; +- +- pdd = qpd_to_pdd(qpd); +- +- /* check if sh_mem_config register already configured */ +- if (qpd->sh_mem_config == 0) { +- qpd->sh_mem_config = +- ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) | +- DEFAULT_MTYPE(MTYPE_NONCACHED) | +- APE1_MTYPE(MTYPE_NONCACHED); +- qpd->sh_mem_ape1_limit = 0; +- qpd->sh_mem_ape1_base = 0; +- } +- + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ +- temp = get_sh_mem_bases_nybble_64(pdd); ++ temp = get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd)); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + + pr_debug("is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n", + qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases); + ++out: ++ return retval; ++} ++ ++static int update_qpd_cik(struct device_queue_manager *dqm, ++ struct qcm_process_device *qpd) ++{ + return 0; + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +index b291ee0fab9439..320518f418903d 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +@@ -27,6 +27,14 @@ + #include "gca/gfx_8_0_sh_mask.h" + #include "oss/oss_3_0_sh_mask.h" + ++/* ++ * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to ++ * stay in user mode. ++ */ ++#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL ++/* APE1 limit is inclusive and 64K aligned. */ ++#define APE1_LIMIT_ALIGNMENT 0xFFFF ++ + static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, +@@ -85,6 +93,36 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + { + uint32_t default_mtype; + uint32_t ape1_mtype; ++ unsigned int temp; ++ bool retval = true; ++ ++ if (alternate_aperture_size == 0) { ++ /* base > limit disables APE1 */ ++ qpd->sh_mem_ape1_base = 1; ++ qpd->sh_mem_ape1_limit = 0; ++ } else { ++ /* ++ * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]}, ++ * SH_MEM_APE1_BASE[31:0], 0x0000 } ++ * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]}, ++ * SH_MEM_APE1_LIMIT[31:0], 0xFFFF } ++ * Verify that the base and size parameters can be ++ * represented in this format and convert them. ++ * Additionally restrict APE1 to user-mode addresses. ++ */ ++ ++ uint64_t base = (uintptr_t)alternate_aperture_base; ++ uint64_t limit = base + alternate_aperture_size - 1; ++ ++ if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 || ++ (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) { ++ retval = false; ++ goto out; ++ } ++ ++ qpd->sh_mem_ape1_base = base >> 16; ++ qpd->sh_mem_ape1_limit = limit >> 16; ++ } + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_UC : +@@ -100,40 +138,21 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + default_mtype << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + ape1_mtype << SH_MEM_CONFIG__APE1_MTYPE__SHIFT; + +- return true; +-} +- +-static int update_qpd_vi(struct device_queue_manager *dqm, +- struct qcm_process_device *qpd) +-{ +- struct kfd_process_device *pdd; +- unsigned int temp; +- +- pdd = qpd_to_pdd(qpd); +- +- /* check if sh_mem_config register already configured */ +- if (qpd->sh_mem_config == 0) { +- qpd->sh_mem_config = +- SH_MEM_ALIGNMENT_MODE_UNALIGNED << +- SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | +- MTYPE_UC << +- SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | +- MTYPE_UC << +- SH_MEM_CONFIG__APE1_MTYPE__SHIFT; +- +- qpd->sh_mem_ape1_limit = 0; +- qpd->sh_mem_ape1_base = 0; +- } +- + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ +- temp = get_sh_mem_bases_nybble_64(pdd); ++ temp = get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd)); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + + pr_debug("sh_mem_bases nybble: 0x%X and register 0x%X\n", + temp, qpd->sh_mem_bases); ++out: ++ return retval; ++} + ++static int update_qpd_vi(struct device_queue_manager *dqm, ++ struct qcm_process_device *qpd) ++{ + return 0; + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index a6d08dee74f6ea..93740b8fc3f44b 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -812,6 +812,14 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) + return ERR_PTR(-EINVAL); + } + ++ /* If the process just called exec(3), it is possible that the ++ * cleanup of the kfd_process (following the release of the mm ++ * of the old process image) is still in the cleanup work queue. ++ * Make sure to drain any job before trying to recreate any ++ * resource for this process. ++ */ ++ flush_workqueue(kfd_process_wq); ++ + /* + * take kfd processes mutex before starting of process creation + * so there won't be a case where two threads of the same process +@@ -830,14 +838,6 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) + if (process) { + pr_debug("Process already found\n"); + } else { +- /* If the process just called exec(3), it is possible that the +- * cleanup of the kfd_process (following the release of the mm +- * of the old process image) is still in the cleanup work queue. +- * Make sure to drain any job before trying to recreate any +- * resource for this process. +- */ +- flush_workqueue(kfd_process_wq); +- + process = create_process(thread); + if (IS_ERR(process)) + goto out; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index bcf0dc05c76765..9189864c236a7e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -2896,11 +2896,6 @@ static int dm_resume(void *handle) + + return 0; + } +- +- /* leave display off for S4 sequence */ +- if (adev->in_s4) +- return 0; +- + /* Recreate dc_state - DC invalidates it when setting power state to S3. */ + dc_release_state(dm_state->context); + dm_state->context = dc_create_state(dm->dc); +@@ -7474,7 +7469,7 @@ static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap, + int i; + int result = -EIO; + +- if (!ddc_service->ddc_pin || !ddc_service->ddc_pin->hw_info.hw_supported) ++ if (!ddc_service->ddc_pin) + return result; + + cmd.payloads = kcalloc(num, sizeof(struct i2c_payload), GFP_KERNEL); +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +index d4d3f58a613f7a..327776eeb9f3ec 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +@@ -130,7 +130,7 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; + struct dc *dc = clk_mgr_base->ctx->dc; +- int display_count; ++ int display_count = 0; + bool update_dppclk = false; + bool update_dispclk = false; + bool dpp_clock_lowered = false; +@@ -194,8 +194,6 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. + if (new_clocks->dppclk_khz < MIN_DPP_DISP_CLK) + new_clocks->dppclk_khz = MIN_DPP_DISP_CLK; +- if (new_clocks->dispclk_khz < MIN_DPP_DISP_CLK) +- new_clocks->dispclk_khz = MIN_DPP_DISP_CLK; + + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { + if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) +@@ -204,15 +202,19 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + update_dppclk = true; + } + +- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { +- /* No need to apply the w/a if we haven't taken over from bios yet */ +- if (clk_mgr_base->clks.dispclk_khz) +- dcn315_disable_otg_wa(clk_mgr_base, context, true); ++ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) && ++ (new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) { ++ int requested_dispclk_khz = new_clocks->dispclk_khz; + ++ dcn315_disable_otg_wa(clk_mgr_base, context, true); ++ ++ /* Clamp the requested clock to PMFW based on their limit. */ ++ if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz) ++ requested_dispclk_khz = dc->debug.min_disp_clk_khz; ++ ++ dcn315_smu_set_dispclk(clk_mgr, requested_dispclk_khz); + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; +- dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); +- if (clk_mgr_base->clks.dispclk_khz) +- dcn315_disable_otg_wa(clk_mgr_base, context, false); ++ dcn315_disable_otg_wa(clk_mgr_base, context, false); + + update_dispclk = true; + } +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +index a13ead3d21e310..f95e5e767eb1a6 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +@@ -140,7 +140,7 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; + struct dc *dc = clk_mgr_base->ctx->dc; +- int display_count; ++ int display_count = 0; + bool update_dppclk = false; + bool update_dispclk = false; + bool dpp_clock_lowered = false; +@@ -201,8 +201,6 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, + // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. + if (new_clocks->dppclk_khz < 100000) + new_clocks->dppclk_khz = 100000; +- if (new_clocks->dispclk_khz < 100000) +- new_clocks->dispclk_khz = 100000; + + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { + if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) +@@ -211,11 +209,18 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, + update_dppclk = true; + } + +- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { ++ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) && ++ (new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) { ++ int requested_dispclk_khz = new_clocks->dispclk_khz; ++ + dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); + ++ /* Clamp the requested clock to PMFW based on their limit. */ ++ if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz) ++ requested_dispclk_khz = dc->debug.min_disp_clk_khz; ++ ++ dcn316_smu_set_dispclk(clk_mgr, requested_dispclk_khz); + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; +- dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); + dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); + + update_dispclk = true; +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index c2efe18ceacd07..640d010b52bec3 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -266,6 +266,7 @@ static bool create_links( + link->link_id.type = OBJECT_TYPE_CONNECTOR; + link->link_id.id = CONNECTOR_ID_VIRTUAL; + link->link_id.enum_id = ENUM_ID_1; ++ link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; + link->link_enc = kzalloc(sizeof(*link->link_enc), GFP_KERNEL); + + if (!link->link_enc) { +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +index 7b5c1498941dd6..d389eeb264a79e 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +@@ -1066,7 +1066,8 @@ void dce110_edp_backlight_control( + DC_LOG_DC("edp_receiver_ready_T9 skipped\n"); + } + +- if (!enable && link->dpcd_sink_ext_caps.bits.oled) { ++ if (!enable) { ++ /*follow oem panel config's requirement*/ + pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms; + msleep(pre_T11_delay); + } +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +index 50dc834046446a..4ce45f1bdac0fe 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +@@ -392,11 +392,6 @@ bool dpp3_get_optimal_number_of_taps( + int min_taps_y, min_taps_c; + enum lb_memory_config lb_config; + +- if (scl_data->viewport.width > scl_data->h_active && +- dpp->ctx->dc->debug.max_downscale_src_width != 0 && +- scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width) +- return false; +- + /* + * Set default taps if none are provided + * From programming guide: taps = min{ ceil(2*H_RATIO,1), 8} for downscaling +@@ -434,6 +429,12 @@ bool dpp3_get_optimal_number_of_taps( + else + scl_data->taps.h_taps_c = in_taps->h_taps_c; + ++ // Avoid null data in the scl data with this early return, proceed non-adaptive calcualtion first ++ if (scl_data->viewport.width > scl_data->h_active && ++ dpp->ctx->dc->debug.max_downscale_src_width != 0 && ++ scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width) ++ return false; ++ + /*Ensure we can support the requested number of vtaps*/ + min_taps_y = dc_fixpt_ceil(scl_data->ratios.vert); + min_taps_c = dc_fixpt_ceil(scl_data->ratios.vert_c); +diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +index 597fa0364a3a9b..d1601d61f05adc 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +@@ -1692,7 +1692,7 @@ static int dcn315_populate_dml_pipes_from_context( + pipes[pipe_cnt].dout.dsc_input_bpc = 0; + DC_FP_START(); + dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); +- if (pixel_rate_crb && !pipe->top_pipe && !pipe->prev_odm_pipe) { ++ if (pixel_rate_crb) { + int bpp = source_format_to_bpp(pipes[pipe_cnt].pipe.src.source_format); + /* Ceil to crb segment size */ + int approx_det_segs_required_for_pstate = dcn_get_approx_det_segs_required_for_pstate( +@@ -1749,28 +1749,26 @@ static int dcn315_populate_dml_pipes_from_context( + continue; + } + +- if (!pipe->top_pipe && !pipe->prev_odm_pipe) { +- bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc) +- || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); +- +- if (remaining_det_segs > MIN_RESERVED_DET_SEGS && crb_pipes != 0) +- pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes + +- (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0); +- if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) { +- /* Clamp to 2 pipe split max det segments */ +- remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS); +- pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS; +- } +- if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) { +- /* If we are splitting we must have an even number of segments */ +- remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2; +- pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2; +- } +- /* Convert segments into size for DML use */ +- pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB; +- +- crb_idx++; ++ bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc) ++ || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); ++ ++ if (remaining_det_segs > MIN_RESERVED_DET_SEGS && crb_pipes != 0) ++ pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes + ++ (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0); ++ if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) { ++ /* Clamp to 2 pipe split max det segments */ ++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS); ++ pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS; ++ } ++ if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) { ++ /* If we are splitting we must have an even number of segments */ ++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2; ++ pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2; + } ++ /* Convert segments into size for DML use */ ++ pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB; ++ ++ crb_idx++; + pipe_cnt++; + } + } +diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h +index eaad1260bfd180..4b284ce669ae52 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h +@@ -532,7 +532,7 @@ struct dc_state { + */ + struct bw_context bw_ctx; + +- struct block_sequence block_sequence[50]; ++ struct block_sequence block_sequence[100]; + unsigned int block_sequence_steps; + struct dc_dmub_cmd dc_dmub_cmd[10]; + unsigned int dmub_cmd_count; +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +index 4901e27f678bcf..9b470812d96a5f 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +@@ -145,6 +145,7 @@ void link_blank_dp_stream(struct dc_link *link, bool hw_init) + void link_set_all_streams_dpms_off_for_link(struct dc_link *link) + { + struct pipe_ctx *pipes[MAX_PIPES]; ++ struct dc_stream_state *streams[MAX_PIPES]; + struct dc_state *state = link->dc->current_state; + uint8_t count; + int i; +@@ -157,10 +158,18 @@ void link_set_all_streams_dpms_off_for_link(struct dc_link *link) + + link_get_master_pipes_with_dpms_on(link, state, &count, pipes); + ++ /* The subsequent call to dc_commit_updates_for_stream for a full update ++ * will release the current state and swap to a new state. Releasing the ++ * current state results in the stream pointers in the pipe_ctx structs ++ * to be zero'd. Hence, cache all streams prior to dc_commit_updates_for_stream. ++ */ ++ for (i = 0; i < count; i++) ++ streams[i] = pipes[i]->stream; ++ + for (i = 0; i < count; i++) { +- stream_update.stream = pipes[i]->stream; ++ stream_update.stream = streams[i]; + dc_commit_updates_for_stream(link->ctx->dc, NULL, 0, +- pipes[i]->stream, &stream_update, ++ streams[i], &stream_update, + state); + } + +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +index 3d589072fe307e..adf0ef8b70e4b1 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +@@ -239,21 +239,21 @@ static uint32_t intersect_frl_link_bw_support( + { + uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps; + +- // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode) +- if (hdmi_encoded_link_bw.bits.FRL_MODE) { +- if (hdmi_encoded_link_bw.bits.BW_48Gbps) +- supported_bw_in_kbps = 48000000; +- else if (hdmi_encoded_link_bw.bits.BW_40Gbps) +- supported_bw_in_kbps = 40000000; +- else if (hdmi_encoded_link_bw.bits.BW_32Gbps) +- supported_bw_in_kbps = 32000000; +- else if (hdmi_encoded_link_bw.bits.BW_24Gbps) +- supported_bw_in_kbps = 24000000; +- else if (hdmi_encoded_link_bw.bits.BW_18Gbps) +- supported_bw_in_kbps = 18000000; +- else if (hdmi_encoded_link_bw.bits.BW_9Gbps) +- supported_bw_in_kbps = 9000000; +- } ++ /* Skip checking FRL_MODE bit, as certain PCON will clear ++ * it despite supporting the link BW indicated in the other bits. ++ */ ++ if (hdmi_encoded_link_bw.bits.BW_48Gbps) ++ supported_bw_in_kbps = 48000000; ++ else if (hdmi_encoded_link_bw.bits.BW_40Gbps) ++ supported_bw_in_kbps = 40000000; ++ else if (hdmi_encoded_link_bw.bits.BW_32Gbps) ++ supported_bw_in_kbps = 32000000; ++ else if (hdmi_encoded_link_bw.bits.BW_24Gbps) ++ supported_bw_in_kbps = 24000000; ++ else if (hdmi_encoded_link_bw.bits.BW_18Gbps) ++ supported_bw_in_kbps = 18000000; ++ else if (hdmi_encoded_link_bw.bits.BW_9Gbps) ++ supported_bw_in_kbps = 9000000; + + return supported_bw_in_kbps; + } +@@ -920,6 +920,9 @@ bool link_decide_link_settings(struct dc_stream_state *stream, + * TODO: add MST specific link training routine + */ + decide_mst_link_settings(link, link_setting); ++ } else if (stream->signal == SIGNAL_TYPE_VIRTUAL) { ++ link_setting->lane_count = LANE_COUNT_FOUR; ++ link_setting->link_rate = LINK_RATE_HIGH3; + } else if (link->connector_signal == SIGNAL_TYPE_EDP) { + /* enable edp link optimization for DSC eDP case */ + if (stream->timing.flags.DSC) { +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c +index 9bde0c8bf914a6..f01a3df584552f 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c +@@ -74,7 +74,8 @@ void dp_disable_link_phy(struct dc_link *link, + struct dc *dc = link->ctx->dc; + + if (!link->wa_flags.dp_keep_receiver_powered && +- !link->skip_implict_edp_power_control) ++ !link->skip_implict_edp_power_control && ++ link->type != dc_connection_none) + dpcd_write_rx_power_ctrl(link, false); + + dc->hwss.disable_link_output(link, link_res, signal); +@@ -159,8 +160,9 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource + } else { + if (link->fec_state == dc_link_fec_ready) { + fec_config = 0; +- core_link_write_dpcd(link, DP_FEC_CONFIGURATION, +- &fec_config, sizeof(fec_config)); ++ if (link->type != dc_connection_none) ++ core_link_write_dpcd(link, DP_FEC_CONFIGURATION, ++ &fec_config, sizeof(fec_config)); + + link_enc->funcs->fec_set_ready(link_enc, false); + link->fec_state = dc_link_fec_not_ready; +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c +index 2b4c15b0b40708..52261e7c11c0b4 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c +@@ -36,7 +36,8 @@ + link->ctx->logger + + static int32_t get_cr_training_aux_rd_interval(struct dc_link *link, +- const struct dc_link_settings *link_settings) ++ const struct dc_link_settings *link_settings, ++ enum lttpr_mode lttpr_mode) + { + union training_aux_rd_interval training_rd_interval; + uint32_t wait_in_micro_secs = 100; +@@ -49,6 +50,8 @@ static int32_t get_cr_training_aux_rd_interval(struct dc_link *link, + DP_TRAINING_AUX_RD_INTERVAL, + (uint8_t *)&training_rd_interval, + sizeof(training_rd_interval)); ++ if (lttpr_mode != LTTPR_MODE_NON_TRANSPARENT) ++ wait_in_micro_secs = 400; + if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) + wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000; + } +@@ -110,7 +113,6 @@ void decide_8b_10b_training_settings( + */ + lt_settings->link_settings.link_spread = link->dp_ss_off ? + LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ; +- lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting); + lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting); + lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting); + lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting); +@@ -119,6 +121,7 @@ void decide_8b_10b_training_settings( + lt_settings->disallow_per_lane_settings = true; + lt_settings->always_match_dpcd_with_hw_lane_settings = true; + lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link); ++ lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting, lt_settings->lttpr_mode); + dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + } + +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +index 13104d000b9e09..d4d92da153ece2 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +@@ -662,6 +662,18 @@ bool edp_setup_psr(struct dc_link *link, + if (!link) + return false; + ++ //Clear PSR cfg ++ memset(&psr_configuration, 0, sizeof(psr_configuration)); ++ dm_helpers_dp_write_dpcd( ++ link->ctx, ++ link, ++ DP_PSR_EN_CFG, ++ &psr_configuration.raw, ++ sizeof(psr_configuration.raw)); ++ ++ if (link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED) ++ return false; ++ + dc = link->ctx->dc; + dmcu = dc->res_pool->dmcu; + psr = dc->res_pool->psr; +@@ -672,9 +684,6 @@ bool edp_setup_psr(struct dc_link *link, + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + +- +- memset(&psr_configuration, 0, sizeof(psr_configuration)); +- + psr_configuration.bits.ENABLE = 1; + psr_configuration.bits.CRC_VERIFICATION = 1; + psr_configuration.bits.FRAME_CAPTURE_INDICATION = +@@ -938,6 +947,16 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream + if (!link) + return false; + ++ //Clear Replay config ++ dm_helpers_dp_write_dpcd(link->ctx, link, ++ DP_SINK_PR_ENABLE_AND_CONFIGURATION, ++ (uint8_t *)&(replay_config.raw), sizeof(uint8_t)); ++ ++ if (!(link->replay_settings.config.replay_supported)) ++ return false; ++ ++ link->replay_settings.config.replay_error_status.raw = 0; ++ + dc = link->ctx->dc; + + replay = dc->res_pool->replay; +diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h +index c488d4a50cf46a..b2252deabc17a4 100644 +--- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h ++++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h +@@ -203,6 +203,10 @@ + #define mmDAGB0_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB0_WR_MISC_CREDIT 0x0058 + #define mmDAGB0_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE 0x005b ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x005c ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB0_WRCLI_ASK_PENDING 0x005d + #define mmDAGB0_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB0_WRCLI_GO_PENDING 0x005e +@@ -455,6 +459,10 @@ + #define mmDAGB1_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB1_WR_MISC_CREDIT 0x00d8 + #define mmDAGB1_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE 0x00db ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x00dc ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB1_WRCLI_ASK_PENDING 0x00dd + #define mmDAGB1_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB1_WRCLI_GO_PENDING 0x00de +@@ -707,6 +715,10 @@ + #define mmDAGB2_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB2_WR_MISC_CREDIT 0x0158 + #define mmDAGB2_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE 0x015b ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x015c ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB2_WRCLI_ASK_PENDING 0x015d + #define mmDAGB2_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB2_WRCLI_GO_PENDING 0x015e +@@ -959,6 +971,10 @@ + #define mmDAGB3_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB3_WR_MISC_CREDIT 0x01d8 + #define mmDAGB3_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE 0x01db ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x01dc ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB3_WRCLI_ASK_PENDING 0x01dd + #define mmDAGB3_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB3_WRCLI_GO_PENDING 0x01de +@@ -1211,6 +1227,10 @@ + #define mmDAGB4_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB4_WR_MISC_CREDIT 0x0258 + #define mmDAGB4_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE 0x025b ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x025c ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB4_WRCLI_ASK_PENDING 0x025d + #define mmDAGB4_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB4_WRCLI_GO_PENDING 0x025e +@@ -4793,6 +4813,10 @@ + #define mmDAGB5_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB5_WR_MISC_CREDIT 0x3058 + #define mmDAGB5_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE 0x305b ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x305c ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB5_WRCLI_ASK_PENDING 0x305d + #define mmDAGB5_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB5_WRCLI_GO_PENDING 0x305e +@@ -5045,6 +5069,10 @@ + #define mmDAGB6_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB6_WR_MISC_CREDIT 0x30d8 + #define mmDAGB6_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE 0x30db ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x30dc ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB6_WRCLI_ASK_PENDING 0x30dd + #define mmDAGB6_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB6_WRCLI_GO_PENDING 0x30de +@@ -5297,6 +5325,10 @@ + #define mmDAGB7_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB7_WR_MISC_CREDIT 0x3158 + #define mmDAGB7_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE 0x315b ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x315c ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB7_WRCLI_ASK_PENDING 0x315d + #define mmDAGB7_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB7_WRCLI_GO_PENDING 0x315e +diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h +index 2969fbf282b7d0..5069d2fd467f2b 100644 +--- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h ++++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h +@@ -1532,6 +1532,12 @@ + //DAGB0_WRCLI_DBUS_GO_PENDING + #define DAGB0_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB0_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB0_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB0_DAGB_DLY + #define DAGB0_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB0_DAGB_DLY__CLI__SHIFT 0x8 +@@ -3207,6 +3213,12 @@ + //DAGB1_WRCLI_DBUS_GO_PENDING + #define DAGB1_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB1_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB1_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB1_DAGB_DLY + #define DAGB1_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB1_DAGB_DLY__CLI__SHIFT 0x8 +@@ -4882,6 +4894,12 @@ + //DAGB2_WRCLI_DBUS_GO_PENDING + #define DAGB2_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB2_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB2_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB2_DAGB_DLY + #define DAGB2_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB2_DAGB_DLY__CLI__SHIFT 0x8 +@@ -6557,6 +6575,12 @@ + //DAGB3_WRCLI_DBUS_GO_PENDING + #define DAGB3_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB3_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB3_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB3_DAGB_DLY + #define DAGB3_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB3_DAGB_DLY__CLI__SHIFT 0x8 +@@ -8232,6 +8256,12 @@ + //DAGB4_WRCLI_DBUS_GO_PENDING + #define DAGB4_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB4_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB4_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB4_DAGB_DLY + #define DAGB4_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB4_DAGB_DLY__CLI__SHIFT 0x8 +@@ -28737,6 +28767,12 @@ + //DAGB5_WRCLI_DBUS_GO_PENDING + #define DAGB5_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB5_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB5_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB5_DAGB_DLY + #define DAGB5_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB5_DAGB_DLY__CLI__SHIFT 0x8 +@@ -30412,6 +30448,12 @@ + //DAGB6_WRCLI_DBUS_GO_PENDING + #define DAGB6_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB6_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB6_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB6_DAGB_DLY + #define DAGB6_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB6_DAGB_DLY__CLI__SHIFT 0x8 +@@ -32087,6 +32129,12 @@ + //DAGB7_WRCLI_DBUS_GO_PENDING + #define DAGB7_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB7_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB7_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB7_DAGB_DLY + #define DAGB7_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB7_DAGB_DLY__CLI__SHIFT 0x8 +diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c +index 3de0f457fff6ab..5f58da6ebaadb4 100644 +--- a/drivers/gpu/drm/ast/ast_mode.c ++++ b/drivers/gpu/drm/ast/ast_mode.c +@@ -132,7 +132,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + return false; + } + +- switch (mode->crtc_hdisplay) { ++ switch (mode->hdisplay) { + case 640: + vbios_mode->enh_table = &res_640x480[refresh_rate_index]; + break; +@@ -146,7 +146,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table = &res_1152x864[refresh_rate_index]; + break; + case 1280: +- if (mode->crtc_vdisplay == 800) ++ if (mode->vdisplay == 800) + vbios_mode->enh_table = &res_1280x800[refresh_rate_index]; + else + vbios_mode->enh_table = &res_1280x1024[refresh_rate_index]; +@@ -158,7 +158,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table = &res_1440x900[refresh_rate_index]; + break; + case 1600: +- if (mode->crtc_vdisplay == 900) ++ if (mode->vdisplay == 900) + vbios_mode->enh_table = &res_1600x900[refresh_rate_index]; + else + vbios_mode->enh_table = &res_1600x1200[refresh_rate_index]; +@@ -167,7 +167,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table = &res_1680x1050[refresh_rate_index]; + break; + case 1920: +- if (mode->crtc_vdisplay == 1080) ++ if (mode->vdisplay == 1080) + vbios_mode->enh_table = &res_1920x1080[refresh_rate_index]; + else + vbios_mode->enh_table = &res_1920x1200[refresh_rate_index]; +@@ -211,6 +211,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0; + vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0; + ++ adjusted_mode->crtc_hdisplay = vbios_mode->enh_table->hde; + adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht; + adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder; + adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder; +@@ -220,6 +221,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table->hfp + + vbios_mode->enh_table->hsync); + ++ adjusted_mode->crtc_vdisplay = vbios_mode->enh_table->vde; + adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt; + adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder; + adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder; +diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +index 8f786592143b6c..24e1e11acf6978 100644 +--- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c ++++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +@@ -244,7 +244,9 @@ static const struct hdmi_codec_pdata codec_data = { + .ops = &adv7511_codec_ops, + .max_i2s_channels = 2, + .i2s = 1, ++ .no_i2s_capture = 1, + .spdif = 1, ++ .no_spdif_capture = 1, + }; + + int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511) +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index f3681970887cc8..1aa59586c8f81a 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -573,6 +573,30 @@ mode_valid(struct drm_atomic_state *state) + return 0; + } + ++static int drm_atomic_check_valid_clones(struct drm_atomic_state *state, ++ struct drm_crtc *crtc) ++{ ++ struct drm_encoder *drm_enc; ++ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, ++ crtc); ++ ++ drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) { ++ if (!drm_enc->possible_clones) { ++ DRM_DEBUG("enc%d possible_clones is 0\n", drm_enc->base.id); ++ continue; ++ } ++ ++ if ((crtc_state->encoder_mask & drm_enc->possible_clones) != ++ crtc_state->encoder_mask) { ++ DRM_DEBUG("crtc%d failed valid clone check for mask 0x%x\n", ++ crtc->base.id, crtc_state->encoder_mask); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ + /** + * drm_atomic_helper_check_modeset - validate state object for modeset changes + * @dev: DRM device +@@ -744,6 +768,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret != 0) + return ret; ++ ++ ret = drm_atomic_check_valid_clones(state, crtc); ++ if (ret != 0) ++ return ret; + } + + /* +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index ad872c61aac0e3..c6e6e4766c8bf6 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -6471,6 +6471,7 @@ static void drm_reset_display_info(struct drm_connector *connector) + info->has_hdmi_infoframe = false; + info->rgb_quant_range_selectable = false; + memset(&info->hdmi, 0, sizeof(info->hdmi)); ++ memset(&connector->hdr_sink_metadata, 0, sizeof(connector->hdr_sink_metadata)); + + info->edid_hdmi_rgb444_dc_modes = 0; + info->edid_hdmi_ycbcr444_dc_modes = 0; +diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c +index 44a948b80ee14e..deb93f78ce3442 100644 +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -322,7 +322,7 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + return -ENOENT; + + /* Don't allow imported objects to be mapped */ +- if (obj->import_attach) { ++ if (drm_gem_is_imported(obj)) { + ret = -EINVAL; + goto out; + } +@@ -1155,7 +1155,7 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent, + drm_vma_node_start(&obj->vma_node)); + drm_printf_indent(p, indent, "size=%zu\n", obj->size); + drm_printf_indent(p, indent, "imported=%s\n", +- str_yes_no(obj->import_attach)); ++ str_yes_no(drm_gem_is_imported(obj))); + + if (obj->funcs->print_info) + obj->funcs->print_info(p, indent, obj); +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 54fc3f819577e3..6391afdf202e27 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -410,12 +410,13 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable) + + static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) + { +- mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); ++ if (dpi->conf->reg_h_fre_con) ++ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); + } + + static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi) + { +- if (dpi->conf->edge_sel_en) ++ if (dpi->conf->edge_sel_en && dpi->conf->reg_h_fre_con) + mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN); + } + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index 94fe2f3836a9a3..53b3b24d7d7c05 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -1923,6 +1923,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, "LQ140M1JW46"), + EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), + ++ EDP_PANEL_ENTRY('S', 'T', 'A', 0x0004, &delay_200_500_e200, "116KHD024006"), + EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"), + + { /* sentinal */ } +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +index d8f8c37c326c43..0193d10867dd2f 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +@@ -1290,10 +1290,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, + + rb_swap = vop2_win_rb_swap(fb->format->format); + vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap); +- if (!vop2_cluster_window(win)) { +- uv_swap = vop2_win_uv_swap(fb->format->format); +- vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); +- } ++ uv_swap = vop2_win_uv_swap(fb->format->format); ++ vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); + + if (fb->format->is_yuv) { + vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4)); +diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c +index ffbbe9d527d324..0e8ea990118844 100644 +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -226,11 +226,21 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ v3d->clk = devm_clk_get_optional(dev, NULL); ++ if (IS_ERR(v3d->clk)) ++ return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n"); ++ ++ ret = clk_prepare_enable(v3d->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't enable the V3D clock\n"); ++ return ret; ++ } ++ + mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); + mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); + ret = dma_set_mask_and_coherent(dev, mask); + if (ret) +- return ret; ++ goto clk_disable; + + v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); + +@@ -245,28 +255,29 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + ret = PTR_ERR(v3d->reset); + + if (ret == -EPROBE_DEFER) +- return ret; ++ goto clk_disable; + + v3d->reset = NULL; + ret = map_regs(v3d, &v3d->bridge_regs, "bridge"); + if (ret) { + dev_err(dev, + "Failed to get reset control or bridge regs\n"); +- return ret; ++ goto clk_disable; + } + } + + if (v3d->ver < 41) { + ret = map_regs(v3d, &v3d->gca_regs, "gca"); + if (ret) +- return ret; ++ goto clk_disable; + } + + v3d->mmu_scratch = dma_alloc_wc(dev, 4096, &v3d->mmu_scratch_paddr, + GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); + if (!v3d->mmu_scratch) { + dev_err(dev, "Failed to allocate MMU scratch page\n"); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto clk_disable; + } + + ret = v3d_gem_init(drm); +@@ -289,6 +300,8 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + v3d_gem_destroy(drm); + dma_free: + dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr); ++clk_disable: ++ clk_disable_unprepare(v3d->clk); + return ret; + } + +@@ -303,6 +316,8 @@ static void v3d_platform_drm_remove(struct platform_device *pdev) + + dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch, + v3d->mmu_scratch_paddr); ++ ++ clk_disable_unprepare(v3d->clk); + } + + static struct platform_driver v3d_platform_driver = { +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 8e721ec3faaff3..a8665d57094b22 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -41,6 +41,10 @@ + #define USB_VENDOR_ID_ACTIONSTAR 0x2101 + #define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011 + ++#define USB_VENDOR_ID_ADATA_XPG 0x125f ++#define USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE 0x7505 ++#define USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE 0x7506 ++ + #define USB_VENDOR_ID_ADS_TECH 0x06e1 + #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 5d7a418ccdbecf..73979643315bfd 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -27,6 +27,8 @@ + static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD), HID_QUIRK_BADPAD }, + { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR), HID_QUIRK_BADPAD }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016), HID_QUIRK_FULLSPEED_INTERVAL }, + { HID_USB_DEVICE(USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS), HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX), HID_QUIRK_NO_INIT_REPORTS }, +diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c +index c439ed2f16dbca..af6bc76dbf6493 100644 +--- a/drivers/hid/usbhid/usbkbd.c ++++ b/drivers/hid/usbhid/usbkbd.c +@@ -160,7 +160,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type, + return -1; + + spin_lock_irqsave(&kbd->leds_lock, flags); +- kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | ++ kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 4) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | + (!!test_bit(LED_NUML, dev->led)); + +diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c +index 44aaf9b9191d41..8d94ecc3cc468c 100644 +--- a/drivers/hwmon/dell-smm-hwmon.c ++++ b/drivers/hwmon/dell-smm-hwmon.c +@@ -67,7 +67,7 @@ + #define I8K_POWER_BATTERY 0x01 + + #define DELL_SMM_NO_TEMP 10 +-#define DELL_SMM_NO_FANS 3 ++#define DELL_SMM_NO_FANS 4 + + struct dell_smm_data { + struct mutex i8k_mutex; /* lock for sensors writes */ +@@ -940,11 +940,14 @@ static const struct hwmon_channel_info * const dell_smm_info[] = { + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | ++ HWMON_F_TARGET, ++ HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET + ), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, + HWMON_PWM_INPUT, ++ HWMON_PWM_INPUT, + HWMON_PWM_INPUT + ), + NULL +diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c +index d92c536be9af78..b779240328d59f 100644 +--- a/drivers/hwmon/gpio-fan.c ++++ b/drivers/hwmon/gpio-fan.c +@@ -393,7 +393,12 @@ static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev, + if (state >= fan_data->num_speed) + return -EINVAL; + ++ mutex_lock(&fan_data->lock); ++ + set_fan_speed(fan_data, state); ++ ++ mutex_unlock(&fan_data->lock); ++ + return 0; + } + +@@ -489,7 +494,11 @@ MODULE_DEVICE_TABLE(of, of_gpio_fan_match); + + static void gpio_fan_stop(void *data) + { ++ struct gpio_fan_data *fan_data = data; ++ ++ mutex_lock(&fan_data->lock); + set_fan_speed(data, 0); ++ mutex_unlock(&fan_data->lock); + } + + static int gpio_fan_probe(struct platform_device *pdev) +@@ -562,7 +571,9 @@ static int gpio_fan_suspend(struct device *dev) + + if (fan_data->gpios) { + fan_data->resume_speed = fan_data->speed_index; ++ mutex_lock(&fan_data->lock); + set_fan_speed(fan_data, 0); ++ mutex_unlock(&fan_data->lock); + } + + return 0; +@@ -572,8 +583,11 @@ static int gpio_fan_resume(struct device *dev) + { + struct gpio_fan_data *fan_data = dev_get_drvdata(dev); + +- if (fan_data->gpios) ++ if (fan_data->gpios) { ++ mutex_lock(&fan_data->lock); + set_fan_speed(fan_data, fan_data->resume_speed); ++ mutex_unlock(&fan_data->lock); ++ } + + return 0; + } +diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c +index 207084d55044a1..6768dbf3903906 100644 +--- a/drivers/hwmon/xgene-hwmon.c ++++ b/drivers/hwmon/xgene-hwmon.c +@@ -111,7 +111,7 @@ struct xgene_hwmon_dev { + + phys_addr_t comm_base_addr; + void *pcc_comm_addr; +- u64 usecs_lat; ++ unsigned int usecs_lat; + }; + + /* +diff --git a/drivers/hwtracing/intel_th/Kconfig b/drivers/hwtracing/intel_th/Kconfig +index 4b6359326ede99..4f7d2b6d79e294 100644 +--- a/drivers/hwtracing/intel_th/Kconfig ++++ b/drivers/hwtracing/intel_th/Kconfig +@@ -60,6 +60,7 @@ config INTEL_TH_STH + + config INTEL_TH_MSU + tristate "Intel(R) Trace Hub Memory Storage Unit" ++ depends on MMU + help + Memory Storage Unit (MSU) trace output device enables + storing STP traces to system memory. It supports single +diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c +index 9621efe0e95c4d..54629458fb710c 100644 +--- a/drivers/hwtracing/intel_th/msu.c ++++ b/drivers/hwtracing/intel_th/msu.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_X86 + #include +@@ -965,7 +966,6 @@ static void msc_buffer_contig_free(struct msc *msc) + for (off = 0; off < msc->nr_pages << PAGE_SHIFT; off += PAGE_SIZE) { + struct page *page = virt_to_page(msc->base + off); + +- page->mapping = NULL; + __free_page(page); + } + +@@ -1147,9 +1147,6 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win) + int i; + + for_each_sg(win->sgt->sgl, sg, win->nr_segs, i) { +- struct page *page = msc_sg_page(sg); +- +- page->mapping = NULL; + dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE, + sg_virt(sg), sg_dma_address(sg)); + } +@@ -1584,22 +1581,10 @@ static void msc_mmap_close(struct vm_area_struct *vma) + { + struct msc_iter *iter = vma->vm_file->private_data; + struct msc *msc = iter->msc; +- unsigned long pg; + + if (!atomic_dec_and_mutex_lock(&msc->mmap_count, &msc->buf_mutex)) + return; + +- /* drop page _refcounts */ +- for (pg = 0; pg < msc->nr_pages; pg++) { +- struct page *page = msc_buffer_get_page(msc, pg); +- +- if (WARN_ON_ONCE(!page)) +- continue; +- +- if (page->mapping) +- page->mapping = NULL; +- } +- + /* last mapping -- drop user_count */ + atomic_dec(&msc->user_count); + mutex_unlock(&msc->buf_mutex); +@@ -1609,16 +1594,14 @@ static vm_fault_t msc_mmap_fault(struct vm_fault *vmf) + { + struct msc_iter *iter = vmf->vma->vm_file->private_data; + struct msc *msc = iter->msc; ++ struct page *page; + +- vmf->page = msc_buffer_get_page(msc, vmf->pgoff); +- if (!vmf->page) ++ page = msc_buffer_get_page(msc, vmf->pgoff); ++ if (!page) + return VM_FAULT_SIGBUS; + +- get_page(vmf->page); +- vmf->page->mapping = vmf->vma->vm_file->f_mapping; +- vmf->page->index = vmf->pgoff; +- +- return 0; ++ get_page(page); ++ return vmf_insert_mixed(vmf->vma, vmf->address, page_to_pfn_t(page)); + } + + static const struct vm_operations_struct msc_mmap_ops = { +@@ -1659,7 +1642,7 @@ static int intel_th_msc_mmap(struct file *file, struct vm_area_struct *vma) + atomic_dec(&msc->user_count); + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +- vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY); ++ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY | VM_MIXEDMAP); + vma->vm_ops = &msc_mmap_ops; + return ret; + } +diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c +index ced2fb4aeda8d3..79e083aab08e0c 100644 +--- a/drivers/i2c/busses/i2c-designware-common.c ++++ b/drivers/i2c/busses/i2c-designware-common.c +@@ -669,6 +669,7 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) + + i2c_dw_release_lock(dev); + } ++EXPORT_SYMBOL_GPL(i2c_dw_disable); + + MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h +index 5eb130c1d67195..e93870a0f9a459 100644 +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -238,7 +238,6 @@ struct reset_control; + * @semaphore_idx: Index of table with semaphore type attached to the bus. It's + * -1 if there is no semaphore. + * @shared_with_punit: true if this bus is shared with the SoCs PUNIT +- * @disable: function to disable the controller + * @init: function to initialize the I2C hardware + * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing + * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE +@@ -295,7 +294,6 @@ struct dw_i2c_dev { + void (*release_lock)(void); + int semaphore_idx; + bool shared_with_punit; +- void (*disable)(struct dw_i2c_dev *dev); + int (*init)(struct dw_i2c_dev *dev); + int (*set_sda_hold_time)(struct dw_i2c_dev *dev); + int mode; +@@ -305,6 +303,7 @@ struct dw_i2c_dev { + #define ACCESS_INTR_MASK BIT(0) + #define ACCESS_NO_IRQ_SUSPEND BIT(1) + #define ARBITRATION_SEMAPHORE BIT(2) ++#define ACCESS_POLLING BIT(3) + + #define MODEL_MSCC_OCELOT BIT(8) + #define MODEL_BAIKAL_BT1 BIT(9) +@@ -339,7 +338,6 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); + int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev); + int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev); + u32 i2c_dw_func(struct i2c_adapter *adap); +-void i2c_dw_disable(struct dw_i2c_dev *dev); + + static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) + { +@@ -354,6 +352,7 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) + } + + void __i2c_dw_disable(struct dw_i2c_dev *dev); ++void i2c_dw_disable(struct dw_i2c_dev *dev); + + extern void i2c_dw_configure_master(struct dw_i2c_dev *dev); + extern int i2c_dw_probe_master(struct dw_i2c_dev *dev); +diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c +index 579c668cb78a6d..51f5491648c077 100644 +--- a/drivers/i2c/busses/i2c-designware-master.c ++++ b/drivers/i2c/busses/i2c-designware-master.c +@@ -991,31 +991,6 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) + return 0; + } + +-static int i2c_dw_poll_adap_quirk(struct dw_i2c_dev *dev) +-{ +- struct i2c_adapter *adap = &dev->adapter; +- int ret; +- +- pm_runtime_get_noresume(dev->dev); +- ret = i2c_add_numbered_adapter(adap); +- if (ret) +- dev_err(dev->dev, "Failed to add adapter: %d\n", ret); +- pm_runtime_put_noidle(dev->dev); +- +- return ret; +-} +- +-static bool i2c_dw_is_model_poll(struct dw_i2c_dev *dev) +-{ +- switch (dev->flags & MODEL_MASK) { +- case MODEL_AMD_NAVI_GPU: +- case MODEL_WANGXUN_SP: +- return true; +- default: +- return false; +- } +-} +- + int i2c_dw_probe_master(struct dw_i2c_dev *dev) + { + struct i2c_adapter *adap = &dev->adapter; +@@ -1026,7 +1001,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + init_completion(&dev->cmd_complete); + + dev->init = i2c_dw_init_master; +- dev->disable = i2c_dw_disable; + + ret = i2c_dw_init_regmap(dev); + if (ret) +@@ -1071,9 +1045,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + adap->dev.parent = dev->dev; + i2c_set_adapdata(adap, dev); + +- if (i2c_dw_is_model_poll(dev)) +- return i2c_dw_poll_adap_quirk(dev); +- + if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { + irq_flags = IRQF_NO_SUSPEND; + } else { +@@ -1087,12 +1058,14 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + regmap_write(dev->map, DW_IC_INTR_MASK, 0); + i2c_dw_release_lock(dev); + +- ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags, +- dev_name(dev->dev), dev); +- if (ret) { +- dev_err(dev->dev, "failure requesting irq %i: %d\n", +- dev->irq, ret); +- return ret; ++ if (!(dev->flags & ACCESS_POLLING)) { ++ ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, ++ irq_flags, dev_name(dev->dev), dev); ++ if (ret) { ++ dev_err(dev->dev, "failure requesting irq %i: %d\n", ++ dev->irq, ret); ++ return ret; ++ } + } + + ret = i2c_dw_init_recovery_info(dev); +diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c +index 61d7a27aa07018..b85f1e4ed13bc8 100644 +--- a/drivers/i2c/busses/i2c-designware-pcidrv.c ++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c +@@ -154,7 +154,7 @@ static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c) + { + struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev); + +- dev->flags |= MODEL_AMD_NAVI_GPU; ++ dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING; + dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; + return 0; + } +@@ -198,7 +198,7 @@ static int __maybe_unused i2c_dw_pci_runtime_suspend(struct device *dev) + { + struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + +- i_dev->disable(i_dev); ++ i2c_dw_disable(i_dev); + return 0; + } + +@@ -248,6 +248,7 @@ static const struct software_node dgpu_node = { + static int i2c_dw_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { ++ struct device *device = &pdev->dev; + struct dw_i2c_dev *dev; + struct i2c_adapter *adap; + int r; +@@ -256,25 +257,22 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + struct i2c_timings *t; + + if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) +- return dev_err_probe(&pdev->dev, -EINVAL, +- "Invalid driver data %ld\n", ++ return dev_err_probe(device, -EINVAL, "Invalid driver data %ld\n", + id->driver_data); + + controller = &dw_pci_controllers[id->driver_data]; + + r = pcim_enable_device(pdev); + if (r) +- return dev_err_probe(&pdev->dev, r, +- "Failed to enable I2C PCI device\n"); ++ return dev_err_probe(device, r, "Failed to enable I2C PCI device\n"); + + pci_set_master(pdev); + + r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); + if (r) +- return dev_err_probe(&pdev->dev, r, +- "I/O memory remapping failed\n"); ++ return dev_err_probe(device, r, "I/O memory remapping failed\n"); + +- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + +@@ -284,7 +282,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + + dev->get_clk_rate_khz = controller->get_clk_rate_khz; + dev->base = pcim_iomap_table(pdev)[0]; +- dev->dev = &pdev->dev; ++ dev->dev = device; + dev->irq = pci_irq_vector(pdev, 0); + dev->flags |= controller->flags; + +@@ -337,15 +335,17 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + + if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) { + dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, &dgpu_node); +- if (IS_ERR(dev->slave)) +- return dev_err_probe(dev->dev, PTR_ERR(dev->slave), ++ if (IS_ERR(dev->slave)) { ++ i2c_del_adapter(&dev->adapter); ++ return dev_err_probe(device, PTR_ERR(dev->slave), + "register UCSI failed\n"); ++ } + } + +- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); +- pm_runtime_use_autosuspend(&pdev->dev); +- pm_runtime_put_autosuspend(&pdev->dev); +- pm_runtime_allow(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(device, 1000); ++ pm_runtime_use_autosuspend(device); ++ pm_runtime_put_autosuspend(device); ++ pm_runtime_allow(device); + + return 0; + } +@@ -353,10 +353,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + static void i2c_dw_pci_remove(struct pci_dev *pdev) + { + struct dw_i2c_dev *dev = pci_get_drvdata(pdev); ++ struct device *device = &pdev->dev; ++ ++ i2c_dw_disable(dev); + +- dev->disable(dev); +- pm_runtime_forbid(&pdev->dev); +- pm_runtime_get_noresume(&pdev->dev); ++ pm_runtime_forbid(device); ++ pm_runtime_get_noresume(device); + + i2c_del_adapter(&dev->adapter); + devm_free_irq(&pdev->dev, dev->irq, dev); +diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c +index 855b698e99c080..f3245a68563095 100644 +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -275,6 +275,7 @@ static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) + + static int dw_i2c_plat_probe(struct platform_device *pdev) + { ++ struct device *device = &pdev->dev; + struct i2c_adapter *adap; + struct dw_i2c_dev *dev; + struct i2c_timings *t; +@@ -284,15 +285,15 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); ++ dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + +- dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); +- if (device_property_present(&pdev->dev, "wx,i2c-snps-model")) +- dev->flags = MODEL_WANGXUN_SP; ++ dev->flags = (uintptr_t)device_get_match_data(device); ++ if (device_property_present(device, "wx,i2c-snps-model")) ++ dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING; + +- dev->dev = &pdev->dev; ++ dev->dev = device; + dev->irq = irq; + platform_set_drvdata(pdev, dev); + +@@ -300,7 +301,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + if (ret) + return ret; + +- dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ dev->rst = devm_reset_control_get_optional_exclusive(device, NULL); + if (IS_ERR(dev->rst)) + return PTR_ERR(dev->rst); + +@@ -328,13 +329,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + i2c_dw_configure(dev); + + /* Optional interface clock */ +- dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk"); ++ dev->pclk = devm_clk_get_optional(device, "pclk"); + if (IS_ERR(dev->pclk)) { + ret = PTR_ERR(dev->pclk); + goto exit_reset; + } + +- dev->clk = devm_clk_get_optional(&pdev->dev, NULL); ++ dev->clk = devm_clk_get_optional(device, NULL); + if (IS_ERR(dev->clk)) { + ret = PTR_ERR(dev->clk); + goto exit_reset; +@@ -363,28 +364,24 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + adap->dev.of_node = pdev->dev.of_node; + adap->nr = -1; + +- if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { +- dev_pm_set_driver_flags(&pdev->dev, +- DPM_FLAG_SMART_PREPARE); +- } else { +- dev_pm_set_driver_flags(&pdev->dev, +- DPM_FLAG_SMART_PREPARE | +- DPM_FLAG_SMART_SUSPEND); +- } ++ if (dev->flags & ACCESS_NO_IRQ_SUSPEND) ++ dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE); ++ else ++ dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE | DPM_FLAG_SMART_SUSPEND); + +- device_enable_async_suspend(&pdev->dev); ++ device_enable_async_suspend(device); + + /* The code below assumes runtime PM to be disabled. */ +- WARN_ON(pm_runtime_enabled(&pdev->dev)); ++ WARN_ON(pm_runtime_enabled(device)); + +- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); +- pm_runtime_use_autosuspend(&pdev->dev); +- pm_runtime_set_active(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(device, 1000); ++ pm_runtime_use_autosuspend(device); ++ pm_runtime_set_active(device); + + if (dev->shared_with_punit) +- pm_runtime_get_noresume(&pdev->dev); ++ pm_runtime_get_noresume(device); + +- pm_runtime_enable(&pdev->dev); ++ pm_runtime_enable(device); + + ret = i2c_dw_probe(dev); + if (ret) +@@ -402,15 +399,16 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + static void dw_i2c_plat_remove(struct platform_device *pdev) + { + struct dw_i2c_dev *dev = platform_get_drvdata(pdev); ++ struct device *device = &pdev->dev; + +- pm_runtime_get_sync(&pdev->dev); ++ pm_runtime_get_sync(device); + + i2c_del_adapter(&dev->adapter); + +- dev->disable(dev); ++ i2c_dw_disable(dev); + +- pm_runtime_dont_use_autosuspend(&pdev->dev); +- pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(device); ++ pm_runtime_put_sync(device); + dw_i2c_plat_pm_cleanup(dev); + + i2c_dw_remove_lock_support(dev); +@@ -436,7 +434,7 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev) + if (i_dev->shared_with_punit) + return 0; + +- i_dev->disable(i_dev); ++ i2c_dw_disable(i_dev); + i2c_dw_prepare_clk(i_dev, false); + + return 0; +diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c +index 78e2c47e3d7da7..345b532a2b455d 100644 +--- a/drivers/i2c/busses/i2c-designware-slave.c ++++ b/drivers/i2c/busses/i2c-designware-slave.c +@@ -88,7 +88,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave) + struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter); + + regmap_write(dev->map, DW_IC_INTR_MASK, 0); +- dev->disable(dev); ++ i2c_dw_disable(dev); + synchronize_irq(dev->irq); + dev->slave = NULL; + pm_runtime_put(dev->dev); +@@ -235,7 +235,6 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) + int ret; + + dev->init = i2c_dw_init_slave; +- dev->disable = i2c_dw_disable; + + ret = i2c_dw_init_regmap(dev); + if (ret) +diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c +index 3bd406470940fb..affdd94f06aaf0 100644 +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -1504,7 +1504,10 @@ static int i2c_pxa_probe(struct platform_device *dev) + i2c->adap.name); + } + +- clk_prepare_enable(i2c->clk); ++ ret = clk_prepare_enable(i2c->clk); ++ if (ret) ++ return dev_err_probe(&dev->dev, ret, ++ "failed to enable clock\n"); + + if (i2c->use_pio) { + i2c->adap.algo = &i2c_pxa_pio_algorithm; +diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c +index 598102d16677a1..ee92a315f074fe 100644 +--- a/drivers/i2c/busses/i2c-qup.c ++++ b/drivers/i2c/busses/i2c-qup.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -150,6 +151,8 @@ + /* TAG length for DATA READ in RX FIFO */ + #define READ_RX_TAGS_LEN 2 + ++#define QUP_BUS_WIDTH 8 ++ + static unsigned int scl_freq; + module_param_named(scl_freq, scl_freq, uint, 0444); + MODULE_PARM_DESC(scl_freq, "SCL frequency override"); +@@ -227,6 +230,7 @@ struct qup_i2c_dev { + int irq; + struct clk *clk; + struct clk *pclk; ++ struct icc_path *icc_path; + struct i2c_adapter adap; + + int clk_ctl; +@@ -255,6 +259,10 @@ struct qup_i2c_dev { + /* To configure when bus is in run state */ + u32 config_run; + ++ /* bandwidth votes */ ++ u32 src_clk_freq; ++ u32 cur_bw_clk_freq; ++ + /* dma parameters */ + bool is_dma; + /* To check if the current transfer is using DMA */ +@@ -453,6 +461,23 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) + return ret; + } + ++static int qup_i2c_vote_bw(struct qup_i2c_dev *qup, u32 clk_freq) ++{ ++ u32 needed_peak_bw; ++ int ret; ++ ++ if (qup->cur_bw_clk_freq == clk_freq) ++ return 0; ++ ++ needed_peak_bw = Bps_to_icc(clk_freq * QUP_BUS_WIDTH); ++ ret = icc_set_bw(qup->icc_path, 0, needed_peak_bw); ++ if (ret) ++ return ret; ++ ++ qup->cur_bw_clk_freq = clk_freq; ++ return 0; ++} ++ + static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) + { + struct qup_i2c_block *blk = &qup->blk; +@@ -840,6 +865,10 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int ret = 0; + int idx = 0; + ++ ret = qup_i2c_vote_bw(qup, qup->src_clk_freq); ++ if (ret) ++ return ret; ++ + enable_irq(qup->irq); + ret = qup_i2c_req_dma(qup); + +@@ -1645,6 +1674,7 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) + config = readl(qup->base + QUP_CONFIG); + config |= QUP_CLOCK_AUTO_GATE; + writel(config, qup->base + QUP_CONFIG); ++ qup_i2c_vote_bw(qup, 0); + clk_disable_unprepare(qup->pclk); + } + +@@ -1745,6 +1775,11 @@ static int qup_i2c_probe(struct platform_device *pdev) + goto fail_dma; + } + qup->is_dma = true; ++ ++ qup->icc_path = devm_of_icc_get(&pdev->dev, NULL); ++ if (IS_ERR(qup->icc_path)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(qup->icc_path), ++ "failed to get interconnect path\n"); + } + + nodma: +@@ -1793,6 +1828,7 @@ static int qup_i2c_probe(struct platform_device *pdev) + qup_i2c_enable_clocks(qup); + src_clk_freq = clk_get_rate(qup->clk); + } ++ qup->src_clk_freq = src_clk_freq; + + /* + * Bootloaders might leave a pending interrupt on certain QUP's, +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index fa1f12a89158cf..d1630d47ef6fcf 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -503,6 +503,8 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) + queue_work(master->base.wq, &master->hj_work); + break; + case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: ++ svc_i3c_master_emit_stop(master); ++ break; + default: + break; + } +@@ -840,6 +842,8 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, + u32 reg; + int ret, i; + ++ svc_i3c_master_flush_fifo(master); ++ + while (true) { + /* Enter/proceed with DAA */ + writel(SVC_I3C_MCTRL_REQUEST_PROC_DAA | +diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c +index 07c571c7b69992..c5b68639476058 100644 +--- a/drivers/infiniband/core/umem.c ++++ b/drivers/infiniband/core/umem.c +@@ -80,9 +80,12 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem, + unsigned long pgsz_bitmap, + unsigned long virt) + { +- struct scatterlist *sg; ++ unsigned long curr_len = 0; ++ dma_addr_t curr_base = ~0; + unsigned long va, pgoff; ++ struct scatterlist *sg; + dma_addr_t mask; ++ dma_addr_t end; + int i; + + umem->iova = va = virt; +@@ -107,17 +110,30 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem, + pgoff = umem->address & ~PAGE_MASK; + + for_each_sgtable_dma_sg(&umem->sgt_append.sgt, sg, i) { +- /* Walk SGL and reduce max page size if VA/PA bits differ +- * for any address. ++ /* If the current entry is physically contiguous with the previous ++ * one, no need to take its start addresses into consideration. + */ +- mask |= (sg_dma_address(sg) + pgoff) ^ va; ++ if (check_add_overflow(curr_base, curr_len, &end) || ++ end != sg_dma_address(sg)) { ++ ++ curr_base = sg_dma_address(sg); ++ curr_len = 0; ++ ++ /* Reduce max page size if VA/PA bits differ */ ++ mask |= (curr_base + pgoff) ^ va; ++ ++ /* The alignment of any VA matching a discontinuity point ++ * in the physical memory sets the maximum possible page ++ * size as this must be a starting point of a new page that ++ * needs to be aligned. ++ */ ++ if (i != 0) ++ mask |= va; ++ } ++ ++ curr_len += sg_dma_len(sg); + va += sg_dma_len(sg) - pgoff; +- /* Except for the last entry, the ending iova alignment sets +- * the maximum possible page size as the low bits of the iova +- * must be zero when starting the next chunk. +- */ +- if (i != (umem->sgt_append.sgt.nents - 1)) +- mask |= va; ++ + pgoff = 0; + } + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index c6053e82ecf6f3..33e2fe0facd529 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -718,8 +718,8 @@ static int ib_uverbs_reg_mr(struct uverbs_attr_bundle *attrs) + goto err_free; + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_free; + } + +@@ -809,8 +809,8 @@ static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs) + if (cmd.flags & IB_MR_REREG_PD) { + new_pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, + attrs); +- if (!new_pd) { +- ret = -EINVAL; ++ if (IS_ERR(new_pd)) { ++ ret = PTR_ERR(new_pd); + goto put_uobjs; + } + } else { +@@ -919,8 +919,8 @@ static int ib_uverbs_alloc_mw(struct uverbs_attr_bundle *attrs) + return PTR_ERR(uobj); + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_free; + } + +@@ -1127,8 +1127,8 @@ static int ib_uverbs_resize_cq(struct uverbs_attr_bundle *attrs) + return ret; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + ret = cq->device->ops.resize_cq(cq, cmd.cqe, &attrs->driver_udata); + if (ret) +@@ -1189,8 +1189,8 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs) + return ret; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + /* we copy a struct ib_uverbs_poll_cq_resp to user space */ + header_ptr = attrs->ucore.outbuf; +@@ -1238,8 +1238,8 @@ static int ib_uverbs_req_notify_cq(struct uverbs_attr_bundle *attrs) + return ret; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + ib_req_notify_cq(cq, cmd.solicited_only ? + IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); +@@ -1321,8 +1321,8 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + ind_tbl = uobj_get_obj_read(rwq_ind_table, + UVERBS_OBJECT_RWQ_IND_TBL, + cmd->rwq_ind_tbl_handle, attrs); +- if (!ind_tbl) { +- ret = -EINVAL; ++ if (IS_ERR(ind_tbl)) { ++ ret = PTR_ERR(ind_tbl); + goto err_put; + } + +@@ -1360,8 +1360,10 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + if (cmd->is_srq) { + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, + cmd->srq_handle, attrs); +- if (!srq || srq->srq_type == IB_SRQT_XRC) { +- ret = -EINVAL; ++ if (IS_ERR(srq) || ++ srq->srq_type == IB_SRQT_XRC) { ++ ret = IS_ERR(srq) ? PTR_ERR(srq) : ++ -EINVAL; + goto err_put; + } + } +@@ -1371,23 +1373,29 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + rcq = uobj_get_obj_read( + cq, UVERBS_OBJECT_CQ, + cmd->recv_cq_handle, attrs); +- if (!rcq) { +- ret = -EINVAL; ++ if (IS_ERR(rcq)) { ++ ret = PTR_ERR(rcq); + goto err_put; + } + } + } + } + +- if (has_sq) ++ if (has_sq) { + scq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, + cmd->send_cq_handle, attrs); ++ if (IS_ERR(scq)) { ++ ret = PTR_ERR(scq); ++ goto err_put; ++ } ++ } ++ + if (!ind_tbl && cmd->qp_type != IB_QPT_XRC_INI) + rcq = rcq ?: scq; + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, + attrs); +- if (!pd || (!scq && has_sq)) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_put; + } + +@@ -1482,18 +1490,18 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + err_put: + if (!IS_ERR(xrcd_uobj)) + uobj_put_read(xrcd_uobj); +- if (pd) ++ if (!IS_ERR_OR_NULL(pd)) + uobj_put_obj_read(pd); +- if (scq) ++ if (!IS_ERR_OR_NULL(scq)) + rdma_lookup_put_uobject(&scq->uobject->uevent.uobject, + UVERBS_LOOKUP_READ); +- if (rcq && rcq != scq) ++ if (!IS_ERR_OR_NULL(rcq) && rcq != scq) + rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject, + UVERBS_LOOKUP_READ); +- if (srq) ++ if (!IS_ERR_OR_NULL(srq)) + rdma_lookup_put_uobject(&srq->uobject->uevent.uobject, + UVERBS_LOOKUP_READ); +- if (ind_tbl) ++ if (!IS_ERR_OR_NULL(ind_tbl)) + uobj_put_obj_read(ind_tbl); + + uobj_alloc_abort(&obj->uevent.uobject, attrs); +@@ -1655,8 +1663,8 @@ static int ib_uverbs_query_qp(struct uverbs_attr_bundle *attrs) + } + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -1761,8 +1769,8 @@ static int modify_qp(struct uverbs_attr_bundle *attrs, + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle, + attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -2027,8 +2035,8 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + return -ENOMEM; + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -2065,9 +2073,9 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + + ud->ah = uobj_get_obj_read(ah, UVERBS_OBJECT_AH, + user_wr->wr.ud.ah, attrs); +- if (!ud->ah) { ++ if (IS_ERR(ud->ah)) { ++ ret = PTR_ERR(ud->ah); + kfree(ud); +- ret = -EINVAL; + goto out_put; + } + ud->remote_qpn = user_wr->wr.ud.remote_qpn; +@@ -2304,8 +2312,8 @@ static int ib_uverbs_post_recv(struct uverbs_attr_bundle *attrs) + return PTR_ERR(wr); + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -2355,8 +2363,8 @@ static int ib_uverbs_post_srq_recv(struct uverbs_attr_bundle *attrs) + return PTR_ERR(wr); + + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs); +- if (!srq) { +- ret = -EINVAL; ++ if (IS_ERR(srq)) { ++ ret = PTR_ERR(srq); + goto out; + } + +@@ -2412,8 +2420,8 @@ static int ib_uverbs_create_ah(struct uverbs_attr_bundle *attrs) + } + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err; + } + +@@ -2482,8 +2490,8 @@ static int ib_uverbs_attach_mcast(struct uverbs_attr_bundle *attrs) + return ret; + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) +- return -EINVAL; ++ if (IS_ERR(qp)) ++ return PTR_ERR(qp); + + obj = qp->uobject; + +@@ -2532,8 +2540,8 @@ static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs) + return ret; + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) +- return -EINVAL; ++ if (IS_ERR(qp)) ++ return PTR_ERR(qp); + + obj = qp->uobject; + mutex_lock(&obj->mcast_lock); +@@ -2667,8 +2675,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs, + UVERBS_OBJECT_FLOW_ACTION, + kern_spec->action.handle, + attrs); +- if (!ib_spec->action.act) +- return -EINVAL; ++ if (IS_ERR(ib_spec->action.act)) ++ return PTR_ERR(ib_spec->action.act); + ib_spec->action.size = + sizeof(struct ib_flow_spec_action_handle); + flow_resources_add(uflow_res, +@@ -2685,8 +2693,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs, + UVERBS_OBJECT_COUNTERS, + kern_spec->flow_count.handle, + attrs); +- if (!ib_spec->flow_count.counters) +- return -EINVAL; ++ if (IS_ERR(ib_spec->flow_count.counters)) ++ return PTR_ERR(ib_spec->flow_count.counters); + ib_spec->flow_count.size = + sizeof(struct ib_flow_spec_action_count); + flow_resources_add(uflow_res, +@@ -2904,14 +2912,14 @@ static int ib_uverbs_ex_create_wq(struct uverbs_attr_bundle *attrs) + return PTR_ERR(obj); + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- err = -EINVAL; ++ if (IS_ERR(pd)) { ++ err = PTR_ERR(pd); + goto err_uobj; + } + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) { +- err = -EINVAL; ++ if (IS_ERR(cq)) { ++ err = PTR_ERR(cq); + goto err_put_pd; + } + +@@ -3012,8 +3020,8 @@ static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs) + return -EINVAL; + + wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, attrs); +- if (!wq) +- return -EINVAL; ++ if (IS_ERR(wq)) ++ return PTR_ERR(wq); + + if (cmd.attr_mask & IB_WQ_FLAGS) { + wq_attr.flags = cmd.flags; +@@ -3096,8 +3104,8 @@ static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs) + num_read_wqs++) { + wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, + wqs_handles[num_read_wqs], attrs); +- if (!wq) { +- err = -EINVAL; ++ if (IS_ERR(wq)) { ++ err = PTR_ERR(wq); + goto put_wqs; + } + +@@ -3252,8 +3260,8 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs) + } + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- err = -EINVAL; ++ if (IS_ERR(qp)) { ++ err = PTR_ERR(qp); + goto err_uobj; + } + +@@ -3399,15 +3407,15 @@ static int __uverbs_create_xsrq(struct uverbs_attr_bundle *attrs, + if (ib_srq_has_cq(cmd->srq_type)) { + attr.ext.cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, + cmd->cq_handle, attrs); +- if (!attr.ext.cq) { +- ret = -EINVAL; ++ if (IS_ERR(attr.ext.cq)) { ++ ret = PTR_ERR(attr.ext.cq); + goto err_put_xrcd; + } + } + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_put_cq; + } + +@@ -3514,8 +3522,8 @@ static int ib_uverbs_modify_srq(struct uverbs_attr_bundle *attrs) + return ret; + + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs); +- if (!srq) +- return -EINVAL; ++ if (IS_ERR(srq)) ++ return PTR_ERR(srq); + + attr.max_wr = cmd.max_wr; + attr.srq_limit = cmd.srq_limit; +@@ -3542,8 +3550,8 @@ static int ib_uverbs_query_srq(struct uverbs_attr_bundle *attrs) + return ret; + + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs); +- if (!srq) +- return -EINVAL; ++ if (IS_ERR(srq)) ++ return PTR_ERR(srq); + + ret = ib_query_srq(srq, &attr); + +@@ -3668,8 +3676,8 @@ static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs) + return -EOPNOTSUPP; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + ret = rdma_set_cq_moderation(cq, cmd.attr.cq_count, cmd.attr.cq_period); + +diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c +index ba05de0380e96e..6567d437512808 100644 +--- a/drivers/infiniband/core/verbs.c ++++ b/drivers/infiniband/core/verbs.c +@@ -3029,22 +3029,23 @@ EXPORT_SYMBOL(__rdma_block_iter_start); + bool __rdma_block_iter_next(struct ib_block_iter *biter) + { + unsigned int block_offset; +- unsigned int sg_delta; ++ unsigned int delta; + + if (!biter->__sg_nents || !biter->__sg) + return false; + + biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; + block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); +- sg_delta = BIT_ULL(biter->__pg_bit) - block_offset; ++ delta = BIT_ULL(biter->__pg_bit) - block_offset; + +- if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) { +- biter->__sg_advance += sg_delta; +- } else { ++ while (biter->__sg_nents && biter->__sg && ++ sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) { ++ delta -= sg_dma_len(biter->__sg) - biter->__sg_advance; + biter->__sg_advance = 0; + biter->__sg = sg_next(biter->__sg); + biter->__sg_nents--; + } ++ biter->__sg_advance += delta; + + return true; + } +diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c +index c65321964131cf..e6fed973ea7411 100644 +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -289,6 +289,8 @@ static const struct xpad_device { + { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, + { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, + { 0x10f5, 0x7005, "Turtle Beach Recon Controller", 0, XTYPE_XBOXONE }, ++ { 0x10f5, 0x7008, "Turtle Beach Recon Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, ++ { 0x10f5, 0x7073, "Turtle Beach Stealth Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 }, + { 0x11ff, 0x0511, "PXN V900", 0, XTYPE_XBOX360 }, + { 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 }, +@@ -353,6 +355,7 @@ static const struct xpad_device { + { 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 }, + { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, + { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE }, ++ { 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, +diff --git a/drivers/iommu/amd/io_pgtable_v2.c b/drivers/iommu/amd/io_pgtable_v2.c +index cbf0c46015125a..6c0777a3c57b79 100644 +--- a/drivers/iommu/amd/io_pgtable_v2.c ++++ b/drivers/iommu/amd/io_pgtable_v2.c +@@ -259,7 +259,7 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova, + pte = v2_alloc_pte(pdom->nid, pdom->iop.pgd, + iova, map_size, gfp, &updated); + if (!pte) { +- ret = -EINVAL; ++ ret = -ENOMEM; + goto out; + } + +diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c +index 2da969fc899004..3f7fcf1801a97a 100644 +--- a/drivers/iommu/dma-iommu.c ++++ b/drivers/iommu/dma-iommu.c +@@ -1716,7 +1716,7 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr) + static DEFINE_MUTEX(msi_prepare_lock); /* see below */ + + if (!domain || !domain->iova_cookie) { +- desc->iommu_cookie = NULL; ++ msi_desc_set_iommu_msi_iova(desc, 0, 0); + return 0; + } + +@@ -1728,11 +1728,12 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr) + mutex_lock(&msi_prepare_lock); + msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain); + mutex_unlock(&msi_prepare_lock); +- +- msi_desc_set_iommu_cookie(desc, msi_page); +- + if (!msi_page) + return -ENOMEM; ++ ++ msi_desc_set_iommu_msi_iova( ++ desc, msi_page->iova, ++ ilog2(cookie_msi_granule(domain->iova_cookie))); + return 0; + } + +@@ -1743,18 +1744,15 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr) + */ + void iommu_dma_compose_msi_msg(struct msi_desc *desc, struct msi_msg *msg) + { +- struct device *dev = msi_desc_to_dev(desc); +- const struct iommu_domain *domain = iommu_get_domain_for_dev(dev); +- const struct iommu_dma_msi_page *msi_page; ++#ifdef CONFIG_IRQ_MSI_IOMMU ++ if (desc->iommu_msi_shift) { ++ u64 msi_iova = desc->iommu_msi_iova << desc->iommu_msi_shift; + +- msi_page = msi_desc_get_iommu_cookie(desc); +- +- if (!domain || !domain->iova_cookie || WARN_ON(!msi_page)) +- return; +- +- msg->address_hi = upper_32_bits(msi_page->iova); +- msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1; +- msg->address_lo += lower_32_bits(msi_page->iova); ++ msg->address_hi = upper_32_bits(msi_iova); ++ msg->address_lo = lower_32_bits(msi_iova) | ++ (msg->address_lo & ((1 << desc->iommu_msi_shift) - 1)); ++ } ++#endif + } + + static int iommu_dma_init(void) +diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c +index e1a81e0109e8a5..c0aa34b1d0e2dc 100644 +--- a/drivers/leds/rgb/leds-pwm-multicolor.c ++++ b/drivers/leds/rgb/leds-pwm-multicolor.c +@@ -135,8 +135,11 @@ static int led_pwm_mc_probe(struct platform_device *pdev) + + /* init the multicolor's LED class device */ + cdev = &priv->mc_cdev.led_cdev; +- fwnode_property_read_u32(mcnode, "max-brightness", ++ ret = fwnode_property_read_u32(mcnode, "max-brightness", + &cdev->max_brightness); ++ if (ret) ++ goto release_mcnode; ++ + cdev->flags = LED_CORE_SUSPENDRESUME; + cdev->brightness_set_blocking = led_pwm_mc_set; + +diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c +index 79719fc8a08fb4..f8912fa60c4988 100644 +--- a/drivers/leds/trigger/ledtrig-netdev.c ++++ b/drivers/leds/trigger/ledtrig-netdev.c +@@ -54,6 +54,7 @@ struct led_netdev_data { + unsigned int last_activity; + + unsigned long mode; ++ unsigned long blink_delay; + int link_speed; + u8 duplex; + +@@ -69,6 +70,10 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) + /* Already validated, hw control is possible with the requested mode */ + if (trigger_data->hw_control) { + led_cdev->hw_control_set(led_cdev, trigger_data->mode); ++ if (led_cdev->blink_set) { ++ led_cdev->blink_set(led_cdev, &trigger_data->blink_delay, ++ &trigger_data->blink_delay); ++ } + + return; + } +@@ -386,10 +391,11 @@ static ssize_t interval_store(struct device *dev, + size_t size) + { + struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); ++ struct led_classdev *led_cdev = trigger_data->led_cdev; + unsigned long value; + int ret; + +- if (trigger_data->hw_control) ++ if (trigger_data->hw_control && !led_cdev->blink_set) + return -EINVAL; + + ret = kstrtoul(buf, 0, &value); +@@ -398,9 +404,13 @@ static ssize_t interval_store(struct device *dev, + + /* impose some basic bounds on the timer interval */ + if (value >= 5 && value <= 10000) { +- cancel_delayed_work_sync(&trigger_data->work); ++ if (trigger_data->hw_control) { ++ trigger_data->blink_delay = value; ++ } else { ++ cancel_delayed_work_sync(&trigger_data->work); + +- atomic_set(&trigger_data->interval, msecs_to_jiffies(value)); ++ atomic_set(&trigger_data->interval, msecs_to_jiffies(value)); ++ } + set_baseline_state(trigger_data); /* resets timer */ + } + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index ebff3baf304515..f13d705f7861af 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -415,11 +415,12 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) + + mutex_lock(&con_mutex); + +- if (of_parse_phandle_with_args(dev->of_node, "mboxes", +- "#mbox-cells", index, &spec)) { ++ ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", ++ index, &spec); ++ if (ret) { + dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__); + mutex_unlock(&con_mutex); +- return ERR_PTR(-ENODEV); ++ return ERR_PTR(ret); + } + + chan = ERR_PTR(-EPROBE_DEFER); +diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c +index f8215a8f656a46..49254d99a8ad68 100644 +--- a/drivers/mailbox/pcc.c ++++ b/drivers/mailbox/pcc.c +@@ -419,8 +419,12 @@ int pcc_mbox_ioremap(struct mbox_chan *chan) + return -1; + pchan_info = chan->con_priv; + pcc_mbox_chan = &pchan_info->chan; +- pcc_mbox_chan->shmem = ioremap(pcc_mbox_chan->shmem_base_addr, +- pcc_mbox_chan->shmem_size); ++ ++ pcc_mbox_chan->shmem = acpi_os_ioremap(pcc_mbox_chan->shmem_base_addr, ++ pcc_mbox_chan->shmem_size); ++ if (!pcc_mbox_chan->shmem) ++ return -ENXIO; ++ + return 0; + } + EXPORT_SYMBOL_GPL(pcc_mbox_ioremap); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index c5851c9f7ec041..0d002d50329da9 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2903,6 +2903,27 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + return to_cblock(size); + } + ++static bool can_resume(struct cache *cache) ++{ ++ /* ++ * Disallow retrying the resume operation for devices that failed the ++ * first resume attempt, as the failure leaves the policy object partially ++ * initialized. Retrying could trigger BUG_ON when loading cache mappings ++ * into the incomplete policy object. ++ */ ++ if (cache->sized && !cache->loaded_mappings) { ++ if (get_cache_mode(cache) != CM_WRITE) ++ DMERR("%s: unable to resume a failed-loaded cache, please check metadata.", ++ cache_device_name(cache)); ++ else ++ DMERR("%s: unable to resume cache due to missing proper cache table reload", ++ cache_device_name(cache)); ++ return false; ++ } ++ ++ return true; ++} ++ + static bool can_resize(struct cache *cache, dm_cblock_t new_size) + { + if (from_cblock(new_size) > from_cblock(cache->cache_size)) { +@@ -2951,6 +2972,9 @@ static int cache_preresume(struct dm_target *ti) + struct cache *cache = ti->private; + dm_cblock_t csize = get_cache_dev_size(cache); + ++ if (!can_resume(cache)) ++ return -EINVAL; ++ + /* + * Check to see if the cache has resized. + */ +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 7a33da2dd64b12..bf2ade89c8c2dc 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -669,6 +669,10 @@ int dm_table_add_target(struct dm_table *t, const char *type, + DMERR("%s: zero-length target", dm_device_name(t->md)); + return -EINVAL; + } ++ if (start + len < start || start + len > LLONG_MAX >> SECTOR_SHIFT) { ++ DMERR("%s: too large device", dm_device_name(t->md)); ++ return -EINVAL; ++ } + + ti->type = dm_get_target_type(type); + if (!ti->type) { +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index 5dd0a42463a2b8..9ea868bd0d1293 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1536,14 +1536,18 @@ static void __send_empty_flush(struct clone_info *ci) + { + struct dm_table *t = ci->map; + struct bio flush_bio; ++ blk_opf_t opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC; ++ ++ if ((ci->io->orig_bio->bi_opf & (REQ_IDLE | REQ_SYNC)) == ++ (REQ_IDLE | REQ_SYNC)) ++ opf |= REQ_IDLE; + + /* + * Use an on-stack bio for this, it's safe since we don't + * need to reference it after submit. It's just used as + * the basis for the clone(s). + */ +- bio_init(&flush_bio, ci->io->md->disk->part0, NULL, 0, +- REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC); ++ bio_init(&flush_bio, ci->io->md->disk->part0, NULL, 0, opf); + + ci->bio = &flush_bio; + ci->sector_count = 0; +diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c +index 99ba925e8ec8e6..114ac0c263fb2b 100644 +--- a/drivers/media/i2c/adv7180.c ++++ b/drivers/media/i2c/adv7180.c +@@ -194,6 +194,7 @@ struct adv7180_state; + #define ADV7180_FLAG_V2 BIT(1) + #define ADV7180_FLAG_MIPI_CSI2 BIT(2) + #define ADV7180_FLAG_I2P BIT(3) ++#define ADV7180_FLAG_TEST_PATTERN BIT(4) + + struct adv7180_chip_info { + unsigned int flags; +@@ -673,11 +674,15 @@ static int adv7180_init_controls(struct adv7180_state *state) + ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); + v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); + +- v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops, +- V4L2_CID_TEST_PATTERN, +- ARRAY_SIZE(test_pattern_menu) - 1, +- 0, ARRAY_SIZE(test_pattern_menu) - 1, +- test_pattern_menu); ++ if (state->chip_info->flags & ADV7180_FLAG_TEST_PATTERN) { ++ v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, ++ &adv7180_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ ARRAY_SIZE(test_pattern_menu) - 1, ++ 0, ++ ARRAY_SIZE(test_pattern_menu) - 1, ++ test_pattern_menu); ++ } + + state->sd.ctrl_handler = &state->ctrl_hdl; + if (state->ctrl_hdl.error) { +@@ -1209,7 +1214,7 @@ static const struct adv7180_chip_info adv7182_info = { + }; + + static const struct adv7180_chip_info adv7280_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1223,7 +1228,8 @@ static const struct adv7180_chip_info adv7280_info = { + }; + + static const struct adv7180_chip_info adv7280_m_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1244,7 +1250,8 @@ static const struct adv7180_chip_info adv7280_m_info = { + }; + + static const struct adv7180_chip_info adv7281_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN7) | +@@ -1259,7 +1266,8 @@ static const struct adv7180_chip_info adv7281_info = { + }; + + static const struct adv7180_chip_info adv7281_m_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1279,7 +1287,8 @@ static const struct adv7180_chip_info adv7281_m_info = { + }; + + static const struct adv7180_chip_info adv7281_ma_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1304,7 +1313,7 @@ static const struct adv7180_chip_info adv7281_ma_info = { + }; + + static const struct adv7180_chip_info adv7282_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN7) | +@@ -1319,7 +1328,8 @@ static const struct adv7180_chip_info adv7282_info = { + }; + + static const struct adv7180_chip_info adv7282_m_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c +index a14e571dc62bc5..a3d5a8a7c660b0 100644 +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -77,7 +77,7 @@ + #define IMX219_VTS_30FPS_640x480 0x06e3 + #define IMX219_VTS_MAX 0xffff + +-#define IMX219_VBLANK_MIN 4 ++#define IMX219_VBLANK_MIN 32 + + /*Frame Length Line*/ + #define IMX219_FLL_MIN 0x08a6 +diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c +index 566f5eaddd572e..b12a6bd42102e9 100644 +--- a/drivers/media/i2c/tc358746.c ++++ b/drivers/media/i2c/tc358746.c +@@ -460,24 +460,20 @@ static int tc358746_apply_misc_config(struct tc358746 *tc358746) + return err; + } + +-/* Use MHz as base so the div needs no u64 */ +-static u32 tc358746_cfg_to_cnt(unsigned int cfg_val, +- unsigned int clk_mhz, +- unsigned int time_base) ++static u32 tc358746_cfg_to_cnt(unsigned long cfg_val, unsigned long clk_hz, ++ unsigned long long time_base) + { +- return DIV_ROUND_UP(cfg_val * clk_mhz, time_base); ++ return div64_u64((u64)cfg_val * clk_hz + time_base - 1, time_base); + } + +-static u32 tc358746_ps_to_cnt(unsigned int cfg_val, +- unsigned int clk_mhz) ++static u32 tc358746_ps_to_cnt(unsigned long cfg_val, unsigned long clk_hz) + { +- return tc358746_cfg_to_cnt(cfg_val, clk_mhz, USEC_PER_SEC); ++ return tc358746_cfg_to_cnt(cfg_val, clk_hz, PSEC_PER_SEC); + } + +-static u32 tc358746_us_to_cnt(unsigned int cfg_val, +- unsigned int clk_mhz) ++static u32 tc358746_us_to_cnt(unsigned long cfg_val, unsigned long clk_hz) + { +- return tc358746_cfg_to_cnt(cfg_val, clk_mhz, 1); ++ return tc358746_cfg_to_cnt(cfg_val, clk_hz, USEC_PER_SEC); + } + + static int tc358746_apply_dphy_config(struct tc358746 *tc358746) +@@ -492,7 +488,6 @@ static int tc358746_apply_dphy_config(struct tc358746 *tc358746) + + /* The hs_byte_clk is also called SYSCLK in the excel sheet */ + hs_byte_clk = cfg->hs_clk_rate / 8; +- hs_byte_clk /= HZ_PER_MHZ; + hf_clk = hs_byte_clk / 2; + + val = tc358746_us_to_cnt(cfg->init, hf_clk) - 1; +diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c +index 6360314f04a636..b90e2e690f3aa1 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid.c ++++ b/drivers/media/platform/qcom/camss/camss-csid.c +@@ -239,11 +239,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) + int ret; + + if (enable) { +- ret = v4l2_ctrl_handler_setup(&csid->ctrls); +- if (ret < 0) { +- dev_err(csid->camss->dev, +- "could not sync v4l2 controls: %d\n", ret); +- return ret; ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) { ++ ret = v4l2_ctrl_handler_setup(&csid->ctrls); ++ if (ret < 0) { ++ dev_err(csid->camss->dev, ++ "could not sync v4l2 controls: %d\n", ret); ++ return ret; ++ } + } + + if (!csid->testgen.enabled && +@@ -318,7 +320,8 @@ static void csid_try_format(struct csid_device *csid, + break; + + case MSM_CSID_PAD_SRC: +- if (csid->testgen_mode->cur.val == 0) { ++ if (csid->testgen.nmodes == CSID_PAYLOAD_MODE_DISABLED || ++ csid->testgen_mode->cur.val == 0) { + /* Test generator is disabled, */ + /* keep pad formats in sync */ + u32 code = fmt->code; +@@ -368,7 +371,8 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, + + code->code = csid->formats[code->index].code; + } else { +- if (csid->testgen_mode->cur.val == 0) { ++ if (csid->testgen.nmodes == CSID_PAYLOAD_MODE_DISABLED || ++ csid->testgen_mode->cur.val == 0) { + struct v4l2_mbus_framefmt *sink_fmt; + + sink_fmt = __csid_get_format(csid, sd_state, +@@ -750,7 +754,8 @@ static int csid_link_setup(struct media_entity *entity, + + /* If test generator is enabled */ + /* do not allow a link from CSIPHY to CSID */ +- if (csid->testgen_mode->cur.val != 0) ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED && ++ csid->testgen_mode->cur.val != 0) + return -EBUSY; + + sd = media_entity_to_v4l2_subdev(remote->entity); +@@ -843,24 +848,27 @@ int msm_csid_register_entity(struct csid_device *csid, + MSM_CSID_NAME, csid->id); + v4l2_set_subdevdata(sd, csid); + +- ret = v4l2_ctrl_handler_init(&csid->ctrls, 1); +- if (ret < 0) { +- dev_err(dev, "Failed to init ctrl handler: %d\n", ret); +- return ret; +- } ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) { ++ ret = v4l2_ctrl_handler_init(&csid->ctrls, 1); ++ if (ret < 0) { ++ dev_err(dev, "Failed to init ctrl handler: %d\n", ret); ++ return ret; ++ } + +- csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls, +- &csid_ctrl_ops, V4L2_CID_TEST_PATTERN, +- csid->testgen.nmodes, 0, 0, +- csid->testgen.modes); ++ csid->testgen_mode = ++ v4l2_ctrl_new_std_menu_items(&csid->ctrls, ++ &csid_ctrl_ops, V4L2_CID_TEST_PATTERN, ++ csid->testgen.nmodes, 0, 0, ++ csid->testgen.modes); + +- if (csid->ctrls.error) { +- dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error); +- ret = csid->ctrls.error; +- goto free_ctrl; +- } ++ if (csid->ctrls.error) { ++ dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error); ++ ret = csid->ctrls.error; ++ goto free_ctrl; ++ } + +- csid->subdev.ctrl_handler = &csid->ctrls; ++ csid->subdev.ctrl_handler = &csid->ctrls; ++ } + + ret = csid_init_formats(sd, NULL); + if (ret < 0) { +@@ -891,7 +899,8 @@ int msm_csid_register_entity(struct csid_device *csid, + media_cleanup: + media_entity_cleanup(&sd->entity); + free_ctrl: +- v4l2_ctrl_handler_free(&csid->ctrls); ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) ++ v4l2_ctrl_handler_free(&csid->ctrls); + + return ret; + } +@@ -904,5 +913,6 @@ void msm_csid_unregister_entity(struct csid_device *csid) + { + v4l2_device_unregister_subdev(&csid->subdev); + media_entity_cleanup(&csid->subdev.entity); +- v4l2_ctrl_handler_free(&csid->ctrls); ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) ++ v4l2_ctrl_handler_free(&csid->ctrls); + } +diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +index 5dc1f908b49bd6..9aa484126a0dd6 100644 +--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c ++++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +@@ -806,13 +806,12 @@ static int c8sectpfe_probe(struct platform_device *pdev) + } + tsin->i2c_adapter = + of_find_i2c_adapter_by_node(i2c_bus); ++ of_node_put(i2c_bus); + if (!tsin->i2c_adapter) { + dev_err(&pdev->dev, "No i2c adapter found\n"); +- of_node_put(i2c_bus); + ret = -ENODEV; + goto err_node_put; + } +- of_node_put(i2c_bus); + + /* Acquire reset GPIO and activate it */ + tsin->rst_gpio = devm_fwnode_gpiod_get(dev, +diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c +index 42048727d7ff35..b8cdffc9a1e9e9 100644 +--- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c +@@ -765,9 +765,14 @@ static int vivid_thread_vid_cap(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "Video Capture Thread End\n"); + return 0; +diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-out.c b/drivers/media/test-drivers/vivid/vivid-kthread-out.c +index fac6208b51da84..015a7b166a1e61 100644 +--- a/drivers/media/test-drivers/vivid/vivid-kthread-out.c ++++ b/drivers/media/test-drivers/vivid/vivid-kthread-out.c +@@ -235,9 +235,14 @@ static int vivid_thread_vid_out(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "Video Output Thread End\n"); + return 0; +diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c +index fa711ee36a3fbc..c862689786b69c 100644 +--- a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c ++++ b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c +@@ -135,9 +135,14 @@ static int vivid_thread_touch_cap(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "Touch Capture Thread End\n"); + return 0; +diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +index a81f26b769883f..1dd59c710dae74 100644 +--- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +@@ -206,9 +206,14 @@ static int vivid_thread_sdr_cap(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "SDR Capture Thread End\n"); + return 0; +diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c +index c5e21785fafe28..02343e88cc618c 100644 +--- a/drivers/media/usb/cx231xx/cx231xx-417.c ++++ b/drivers/media/usb/cx231xx/cx231xx-417.c +@@ -1722,6 +1722,8 @@ static void cx231xx_video_dev_init( + vfd->lock = &dev->lock; + vfd->release = video_device_release_empty; + vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl; ++ vfd->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_CAPTURE; + video_set_drvdata(vfd, dev); + if (dev->tuner_type == TUNER_ABSENT) { + v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); +diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c +index 028c4a5049af97..5926a9dfb0b1f8 100644 +--- a/drivers/media/usb/uvc/uvc_ctrl.c ++++ b/drivers/media/usb/uvc/uvc_ctrl.c +@@ -815,6 +815,25 @@ static inline void uvc_clear_bit(u8 *data, int bit) + data[bit >> 3] &= ~(1 << (bit & 7)); + } + ++static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val) ++{ ++ unsigned int i; ++ ++ for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { ++ u32 menu_value; ++ ++ if (!test_bit(i, &mapping->menu_mask)) ++ continue; ++ ++ menu_value = uvc_mapping_get_menu_value(mapping, i); ++ ++ if (menu_value == val) ++ return i; ++ } ++ ++ return val; ++} ++ + /* + * Extract the bit string specified by mapping->offset and mapping->size + * from the little-endian data stored at 'data' and return the result as +@@ -849,6 +868,16 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, + if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) + value |= -(value & (1 << (mapping->size - 1))); + ++ /* If it is a menu, convert from uvc to v4l2. */ ++ if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) ++ return value; ++ ++ switch (query) { ++ case UVC_GET_CUR: ++ case UVC_GET_DEF: ++ return uvc_menu_to_v4l2_menu(mapping, value); ++ } ++ + return value; + } + +@@ -1013,32 +1042,6 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, + return 0; + } + +-static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, +- const u8 *data) +-{ +- s32 value = mapping->get(mapping, UVC_GET_CUR, data); +- +- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { +- unsigned int i; +- +- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { +- u32 menu_value; +- +- if (!test_bit(i, &mapping->menu_mask)) +- continue; +- +- menu_value = uvc_mapping_get_menu_value(mapping, i); +- +- if (menu_value == value) { +- value = i; +- break; +- } +- } +- } +- +- return value; +-} +- + static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain, + struct uvc_control *ctrl) + { +@@ -1089,8 +1092,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, + if (ret < 0) + return ret; + +- *value = __uvc_ctrl_get_value(mapping, +- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); ++ *value = mapping->get(mapping, UVC_GET_CUR, ++ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + + return 0; + } +@@ -1240,7 +1243,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, + { + struct uvc_control_mapping *master_map = NULL; + struct uvc_control *master_ctrl = NULL; +- unsigned int i; + + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); + v4l2_ctrl->id = mapping->id; +@@ -1283,21 +1285,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, + v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1; + v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1; + v4l2_ctrl->step = 1; +- +- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { +- u32 menu_value; +- +- if (!test_bit(i, &mapping->menu_mask)) +- continue; +- +- menu_value = uvc_mapping_get_menu_value(mapping, i); +- +- if (menu_value == v4l2_ctrl->default_value) { +- v4l2_ctrl->default_value = i; +- break; +- } +- } +- + return 0; + + case V4L2_CTRL_TYPE_BOOLEAN: +@@ -1580,7 +1567,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain, + uvc_ctrl_set_handle(handle, ctrl, NULL); + + list_for_each_entry(mapping, &ctrl->info.mappings, list) { +- s32 value = __uvc_ctrl_get_value(mapping, data); ++ s32 value = mapping->get(mapping, UVC_GET_CUR, data); + + /* + * handle may be NULL here if the device sends auto-update +diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c +index 7bcd706281daf3..cb7d9fb589fca9 100644 +--- a/drivers/media/usb/uvc/uvc_v4l2.c ++++ b/drivers/media/usb/uvc/uvc_v4l2.c +@@ -106,6 +106,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain, + struct uvc_control_mapping *map; + int ret; + ++ if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) { ++ uvc_dbg(chain->dev, CONTROL, ++ "Unsupported UVC data type %u\n", xmap->data_type); ++ return -EINVAL; ++ } ++ + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (map == NULL) + return -ENOMEM; +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index 5f115438d07228..cb3ad72a3e54a6 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -351,6 +351,8 @@ static int call_enum_dv_timings(struct v4l2_subdev *sd, + static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_config *config) + { ++ memset(config, 0, sizeof(*config)); ++ + return check_pad(sd, pad) ? : + sd->ops->pad->get_mbus_config(sd, pad, config); + } +diff --git a/drivers/mfd/tps65219.c b/drivers/mfd/tps65219.c +index 0e0c42e4fdfc75..72a5f51fe32a52 100644 +--- a/drivers/mfd/tps65219.c ++++ b/drivers/mfd/tps65219.c +@@ -228,7 +228,6 @@ static struct regmap_irq_chip tps65219_irq_chip = { + static int tps65219_probe(struct i2c_client *client) + { + struct tps65219 *tps; +- unsigned int chipid; + bool pwr_button; + int ret; + +@@ -253,12 +252,6 @@ static int tps65219_probe(struct i2c_client *client) + if (ret) + return ret; + +- ret = regmap_read(tps->regmap, TPS65219_REG_TI_DEV_ID, &chipid); +- if (ret) { +- dev_err(tps->dev, "Failed to read device ID: %d\n", ret); +- return ret; +- } +- + ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, + tps65219_cells, ARRAY_SIZE(tps65219_cells), + NULL, 0, regmap_irq_get_domain(tps->irq_data)); +diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c +index 698408e8bad035..381a61adf06eee 100644 +--- a/drivers/mmc/host/dw_mmc-exynos.c ++++ b/drivers/mmc/host/dw_mmc-exynos.c +@@ -28,6 +28,8 @@ enum dw_mci_exynos_type { + DW_MCI_TYPE_EXYNOS5420_SMU, + DW_MCI_TYPE_EXYNOS7, + DW_MCI_TYPE_EXYNOS7_SMU, ++ DW_MCI_TYPE_EXYNOS7870, ++ DW_MCI_TYPE_EXYNOS7870_SMU, + DW_MCI_TYPE_ARTPEC8, + }; + +@@ -70,6 +72,12 @@ static struct dw_mci_exynos_compatible { + }, { + .compatible = "samsung,exynos7-dw-mshc-smu", + .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, ++ }, { ++ .compatible = "samsung,exynos7870-dw-mshc", ++ .ctrl_type = DW_MCI_TYPE_EXYNOS7870, ++ }, { ++ .compatible = "samsung,exynos7870-dw-mshc-smu", ++ .ctrl_type = DW_MCI_TYPE_EXYNOS7870_SMU, + }, { + .compatible = "axis,artpec8-dw-mshc", + .ctrl_type = DW_MCI_TYPE_ARTPEC8, +@@ -86,6 +94,8 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) + return EXYNOS4210_FIXED_CIU_CLK_DIV; + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; + else +@@ -101,7 +111,8 @@ static void dw_mci_exynos_config_smu(struct dw_mci *host) + * set for non-ecryption mode at this time. + */ + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || +- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) { + mci_writel(host, MPSBEGIN0, 0); + mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX); + mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT | +@@ -127,6 +138,12 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); + } + ++ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) { ++ /* Quirk needed for certain Exynos SoCs */ ++ host->quirks |= DW_MMC_QUIRK_FIFO64_32; ++ } ++ + if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) { + /* Quirk needed for the ARTPEC-8 SoC */ + host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT; +@@ -144,6 +161,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -153,6 +172,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -223,6 +244,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -231,6 +254,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) + if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -410,6 +435,8 @@ static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); + else +@@ -423,6 +450,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -430,6 +459,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -444,6 +475,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -454,6 +487,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -633,6 +668,10 @@ static const struct of_device_id dw_mci_exynos_match[] = { + .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc-smu", + .data = &exynos_drv_data, }, ++ { .compatible = "samsung,exynos7870-dw-mshc", ++ .data = &exynos_drv_data, }, ++ { .compatible = "samsung,exynos7870-dw-mshc-smu", ++ .data = &exynos_drv_data, }, + { .compatible = "axis,artpec8-dw-mshc", + .data = &artpec_drv_data, }, + {}, +diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c +index 6b351810a301c9..dbfe0a5324eaf0 100644 +--- a/drivers/mmc/host/sdhci-pci-core.c ++++ b/drivers/mmc/host/sdhci-pci-core.c +@@ -608,8 +608,12 @@ static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, + + sdhci_set_power(host, mode, vdd); + +- if (mode == MMC_POWER_OFF) ++ if (mode == MMC_POWER_OFF) { ++ if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD || ++ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BYT_SD) ++ usleep_range(15000, 17500); + return; ++ } + + /* + * Bus power might not enable after D3 -> D0 transition due to the +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index 9796a3cb3ca62c..f32429ff905ff6 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -2035,10 +2035,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) + + host->mmc->actual_clock = 0; + +- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); ++ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); ++ if (clk & SDHCI_CLOCK_CARD_EN) ++ sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, ++ SDHCI_CLOCK_CONTROL); + +- if (clock == 0) ++ if (clock == 0) { ++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + return; ++ } + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + sdhci_enable_clk(host, clk); +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 7eb62fe55947fe..56c241246d1af4 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -2469,7 +2469,7 @@ static int __bond_release_one(struct net_device *bond_dev, + + RCU_INIT_POINTER(bond->current_arp_slave, NULL); + +- if (!all && (!bond->params.fail_over_mac || ++ if (!all && (bond->params.fail_over_mac != BOND_FOM_ACTIVE || + BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) { + if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) && + bond_has_slaves(bond)) +diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c +index 7f405bcf11c23e..603680792f1ff6 100644 +--- a/drivers/net/can/c_can/c_can_platform.c ++++ b/drivers/net/can/c_can/c_can_platform.c +@@ -333,7 +333,7 @@ static int c_can_plat_probe(struct platform_device *pdev) + /* Check if we need custom RAMINIT via syscon. Mostly for TI + * platforms. Only supported with DT boot. + */ +- if (np && of_property_read_bool(np, "syscon-raminit")) { ++ if (np && of_property_present(np, "syscon-raminit")) { + u32 id; + struct c_can_raminit *raminit = &priv->raminit_sys; + +diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c +index c490b4ba065ba4..73b448cd00f29f 100644 +--- a/drivers/net/can/kvaser_pciefd.c ++++ b/drivers/net/can/kvaser_pciefd.c +@@ -1137,7 +1137,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, + skb = alloc_canfd_skb(priv->dev, &cf); + if (!skb) { + priv->dev->stats.rx_dropped++; +- return -ENOMEM; ++ return 0; + } + + cf->len = can_fd_dlc2len(dlc); +@@ -1149,7 +1149,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, + skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf); + if (!skb) { + priv->dev->stats.rx_dropped++; +- return -ENOMEM; ++ return 0; + } + can_frame_set_cc_len((struct can_frame *)cf, dlc, priv->ctrlmode); + } +@@ -1167,7 +1167,9 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, + priv->dev->stats.rx_packets++; + kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp); + +- return netif_rx(skb); ++ netif_rx(skb); ++ ++ return 0; + } + + static void kvaser_pciefd_change_state(struct kvaser_pciefd_can *can, +@@ -1580,24 +1582,28 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf) + return res; + } + +-static u32 kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) ++static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) + { ++ void __iomem *srb_cmd_reg = KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG; + u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG); + +- if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) ++ iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG); ++ ++ if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) { + kvaser_pciefd_read_buffer(pcie, 0); ++ iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, srb_cmd_reg); /* Rearm buffer */ ++ } + +- if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) ++ if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) { + kvaser_pciefd_read_buffer(pcie, 1); ++ iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1, srb_cmd_reg); /* Rearm buffer */ ++ } + + if (irq & KVASER_PCIEFD_SRB_IRQ_DOF0 || + irq & KVASER_PCIEFD_SRB_IRQ_DOF1 || + irq & KVASER_PCIEFD_SRB_IRQ_DUF0 || + irq & KVASER_PCIEFD_SRB_IRQ_DUF1) + dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq); +- +- iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG); +- return irq; + } + + static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) +@@ -1625,29 +1631,22 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) + struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev; + const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask; + u32 pci_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie)); +- u32 srb_irq = 0; +- u32 srb_release = 0; + int i; + + if (!(pci_irq & irq_mask->all)) + return IRQ_NONE; + ++ iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); ++ + if (pci_irq & irq_mask->kcan_rx0) +- srb_irq = kvaser_pciefd_receive_irq(pcie); ++ kvaser_pciefd_receive_irq(pcie); + + for (i = 0; i < pcie->nr_channels; i++) { + if (pci_irq & irq_mask->kcan_tx[i]) + kvaser_pciefd_transmit_irq(pcie->can[i]); + } + +- if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD0) +- srb_release |= KVASER_PCIEFD_SRB_CMD_RDB0; +- +- if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD1) +- srb_release |= KVASER_PCIEFD_SRB_CMD_RDB1; +- +- if (srb_release) +- iowrite32(srb_release, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG); ++ iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); + + return IRQ_HANDLED; + } +@@ -1667,13 +1666,22 @@ static void kvaser_pciefd_teardown_can_ctrls(struct kvaser_pciefd *pcie) + } + } + ++static void kvaser_pciefd_disable_irq_srcs(struct kvaser_pciefd *pcie) ++{ ++ unsigned int i; ++ ++ /* Masking PCI_IRQ is insufficient as running ISR will unmask it */ ++ iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG); ++ for (i = 0; i < pcie->nr_channels; ++i) ++ iowrite32(0, pcie->can[i]->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); ++} ++ + static int kvaser_pciefd_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { + int err; + struct kvaser_pciefd *pcie; + const struct kvaser_pciefd_irq_mask *irq_mask; +- void __iomem *irq_en_base; + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) +@@ -1726,8 +1734,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, + KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG); + + /* Enable PCI interrupts */ +- irq_en_base = KVASER_PCIEFD_PCI_IEN_ADDR(pcie); +- iowrite32(irq_mask->all, irq_en_base); ++ iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); + /* Ready the DMA buffers */ + iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, + KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG); +@@ -1741,8 +1748,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, + return 0; + + err_free_irq: +- /* Disable PCI interrupts */ +- iowrite32(0, irq_en_base); ++ kvaser_pciefd_disable_irq_srcs(pcie); + free_irq(pcie->pci->irq, pcie); + + err_teardown_can_ctrls: +@@ -1762,35 +1768,25 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, + return err; + } + +-static void kvaser_pciefd_remove_all_ctrls(struct kvaser_pciefd *pcie) +-{ +- int i; +- +- for (i = 0; i < pcie->nr_channels; i++) { +- struct kvaser_pciefd_can *can = pcie->can[i]; +- +- if (can) { +- iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); +- unregister_candev(can->can.dev); +- del_timer(&can->bec_poll_timer); +- kvaser_pciefd_pwm_stop(can); +- free_candev(can->can.dev); +- } +- } +-} +- + static void kvaser_pciefd_remove(struct pci_dev *pdev) + { + struct kvaser_pciefd *pcie = pci_get_drvdata(pdev); ++ unsigned int i; + +- kvaser_pciefd_remove_all_ctrls(pcie); ++ for (i = 0; i < pcie->nr_channels; ++i) { ++ struct kvaser_pciefd_can *can = pcie->can[i]; + +- /* Disable interrupts */ +- iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG); +- iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); ++ unregister_candev(can->can.dev); ++ del_timer(&can->bec_poll_timer); ++ kvaser_pciefd_pwm_stop(can); ++ } + ++ kvaser_pciefd_disable_irq_srcs(pcie); + free_irq(pcie->pci->irq, pcie); + ++ for (i = 0; i < pcie->nr_channels; ++i) ++ free_candev(pcie->can[i]->can.dev); ++ + pci_iounmap(pdev, pcie->reg_base); + pci_release_regions(pdev); + pci_disable_device(pdev); +diff --git a/drivers/net/can/slcan/slcan-core.c b/drivers/net/can/slcan/slcan-core.c +index 24c6622d36bd85..58ff2ec1d9757e 100644 +--- a/drivers/net/can/slcan/slcan-core.c ++++ b/drivers/net/can/slcan/slcan-core.c +@@ -71,12 +71,21 @@ MODULE_AUTHOR("Dario Binacchi "); + #define SLCAN_CMD_LEN 1 + #define SLCAN_SFF_ID_LEN 3 + #define SLCAN_EFF_ID_LEN 8 ++#define SLCAN_DATA_LENGTH_LEN 1 ++#define SLCAN_ERROR_LEN 1 + #define SLCAN_STATE_LEN 1 + #define SLCAN_STATE_BE_RXCNT_LEN 3 + #define SLCAN_STATE_BE_TXCNT_LEN 3 +-#define SLCAN_STATE_FRAME_LEN (1 + SLCAN_CMD_LEN + \ +- SLCAN_STATE_BE_RXCNT_LEN + \ +- SLCAN_STATE_BE_TXCNT_LEN) ++#define SLCAN_STATE_MSG_LEN (SLCAN_CMD_LEN + \ ++ SLCAN_STATE_LEN + \ ++ SLCAN_STATE_BE_RXCNT_LEN + \ ++ SLCAN_STATE_BE_TXCNT_LEN) ++#define SLCAN_ERROR_MSG_LEN_MIN (SLCAN_CMD_LEN + \ ++ SLCAN_ERROR_LEN + \ ++ SLCAN_DATA_LENGTH_LEN) ++#define SLCAN_FRAME_MSG_LEN_MIN (SLCAN_CMD_LEN + \ ++ SLCAN_SFF_ID_LEN + \ ++ SLCAN_DATA_LENGTH_LEN) + struct slcan { + struct can_priv can; + +@@ -176,6 +185,9 @@ static void slcan_bump_frame(struct slcan *sl) + u32 tmpid; + char *cmd = sl->rbuff; + ++ if (sl->rcount < SLCAN_FRAME_MSG_LEN_MIN) ++ return; ++ + skb = alloc_can_skb(sl->dev, &cf); + if (unlikely(!skb)) { + sl->dev->stats.rx_dropped++; +@@ -281,7 +293,7 @@ static void slcan_bump_state(struct slcan *sl) + return; + } + +- if (state == sl->can.state || sl->rcount < SLCAN_STATE_FRAME_LEN) ++ if (state == sl->can.state || sl->rcount != SLCAN_STATE_MSG_LEN) + return; + + cmd += SLCAN_STATE_BE_RXCNT_LEN + SLCAN_CMD_LEN + 1; +@@ -328,6 +340,9 @@ static void slcan_bump_err(struct slcan *sl) + bool rx_errors = false, tx_errors = false, rx_over_errors = false; + int i, len; + ++ if (sl->rcount < SLCAN_ERROR_MSG_LEN_MIN) ++ return; ++ + /* get len from sanitized ASCII value */ + len = cmd[1]; + if (len >= '0' && len < '9') +@@ -456,8 +471,7 @@ static void slcan_bump(struct slcan *sl) + static void slcan_unesc(struct slcan *sl, unsigned char s) + { + if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */ +- if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && +- sl->rcount > 4) ++ if (!test_and_clear_bit(SLF_ERROR, &sl->flags)) + slcan_bump(sl); + + sl->rcount = 0; +diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c +index b3fa867c8ccd91..c2ef55cff6b3ec 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.c ++++ b/drivers/net/ethernet/amd/pds_core/core.c +@@ -413,10 +413,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init) + if (err) + return err; + +- /* Scale the descriptor ring length based on number of CPUs and VFs */ +- numdescs = max_t(int, PDSC_ADMINQ_MIN_LENGTH, num_online_cpus()); +- numdescs += 2 * pci_sriov_get_totalvfs(pdsc->pdev); +- numdescs = roundup_pow_of_two(numdescs); ++ numdescs = PDSC_ADMINQ_MAX_LENGTH; + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_ADMINQ, 0, "adminq", + PDS_CORE_QCQ_F_CORE | PDS_CORE_QCQ_F_INTR, + numdescs, +diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h +index 61ee607ee48ace..42137140850314 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.h ++++ b/drivers/net/ethernet/amd/pds_core/core.h +@@ -16,7 +16,7 @@ + + #define PDSC_WATCHDOG_SECS 5 + #define PDSC_QUEUE_NAME_MAX_SZ 16 +-#define PDSC_ADMINQ_MIN_LENGTH 16 /* must be a power of two */ ++#define PDSC_ADMINQ_MAX_LENGTH 16 /* must be a power of two */ + #define PDSC_NOTIFYQ_LENGTH 64 /* must be a power of two */ + #define PDSC_TEARDOWN_RECOVERY false + #define PDSC_TEARDOWN_REMOVING true +diff --git a/drivers/net/ethernet/apm/xgene-v2/main.c b/drivers/net/ethernet/apm/xgene-v2/main.c +index 379d19d18dbed0..5808e3c73a8f43 100644 +--- a/drivers/net/ethernet/apm/xgene-v2/main.c ++++ b/drivers/net/ethernet/apm/xgene-v2/main.c +@@ -9,8 +9,6 @@ + + #include "main.h" + +-static const struct acpi_device_id xge_acpi_match[]; +- + static int xge_get_resources(struct xge_pdata *pdata) + { + struct platform_device *pdev; +@@ -733,7 +731,7 @@ MODULE_DEVICE_TABLE(acpi, xge_acpi_match); + static struct platform_driver xge_driver = { + .driver = { + .name = "xgene-enet-v2", +- .acpi_match_table = ACPI_PTR(xge_acpi_match), ++ .acpi_match_table = xge_acpi_match, + }, + .probe = xge_probe, + .remove = xge_remove, +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c +index 8feb7d4226bb58..0c09d82dbf00d4 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc.c +@@ -1572,6 +1572,16 @@ static void enetc_xdp_drop(struct enetc_bdr *rx_ring, int rx_ring_first, + } + } + ++static void enetc_bulk_flip_buff(struct enetc_bdr *rx_ring, int rx_ring_first, ++ int rx_ring_last) ++{ ++ while (rx_ring_first != rx_ring_last) { ++ enetc_flip_rx_buff(rx_ring, ++ &rx_ring->rx_swbd[rx_ring_first]); ++ enetc_bdr_idx_inc(rx_ring, &rx_ring_first); ++ } ++} ++ + static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring, + struct napi_struct *napi, int work_limit, + struct bpf_prog *prog) +@@ -1687,11 +1697,7 @@ static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring, + enetc_xdp_drop(rx_ring, orig_i, i); + rx_ring->stats.xdp_redirect_failures++; + } else { +- while (orig_i != i) { +- enetc_flip_rx_buff(rx_ring, +- &rx_ring->rx_swbd[orig_i]); +- enetc_bdr_idx_inc(rx_ring, &orig_i); +- } ++ enetc_bulk_flip_buff(rx_ring, orig_i, i); + xdp_redirect_frm_cnt++; + rx_ring->stats.xdp_redirect++; + } +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 7261838a09db63..291c88a76a27f4 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -1079,6 +1079,29 @@ static void fec_enet_enable_ring(struct net_device *ndev) + } + } + ++/* 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. ++ */ ++static void fec_ctrl_reset(struct fec_enet_private *fep, bool allow_wol) ++{ ++ u32 val; ++ ++ if (!allow_wol || !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { ++ 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(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL); ++ udelay(10); ++ } ++ } else { ++ val = readl(fep->hwp + FEC_ECNTRL); ++ val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); ++ writel(val, fep->hwp + FEC_ECNTRL); ++ } ++} ++ + /* + * This function is called to start or restart the FEC during a link + * change, transmit timeout, or to reconfigure the FEC. The network +@@ -1095,17 +1118,7 @@ fec_restart(struct net_device *ndev) + if (fep->bufdesc_ex) + fec_ptp_save_state(fep); + +- /* 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->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); +- } ++ fec_ctrl_reset(fep, false); + + /* + * enet-mac reset will reset mac address registers too, +@@ -1359,22 +1372,7 @@ fec_stop(struct net_device *ndev) + if (fep->bufdesc_ex) + fec_ptp_save_state(fep); + +- /* 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(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL); +- udelay(10); +- } +- } else { +- val = readl(fep->hwp + FEC_ECNTRL); +- val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); +- writel(val, fep->hwp + FEC_ECNTRL); +- } ++ fec_ctrl_reset(fep, true); + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + +diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c +index 39b5f24be7e4fc..dd58b2372dc0c7 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c ++++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c +@@ -3329,8 +3329,7 @@ static u32 ice_get_combined_cnt(struct ice_vsi *vsi) + ice_for_each_q_vector(vsi, q_idx) { + struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; + +- if (q_vector->rx.rx_ring && q_vector->tx.tx_ring) +- combined++; ++ combined += min(q_vector->num_ring_tx, q_vector->num_ring_rx); + } + + return combined; +diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c +index ad82ff7d199570..09f9c7ba52795b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_irq.c ++++ b/drivers/net/ethernet/intel/ice/ice_irq.c +@@ -45,7 +45,7 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index) + /** + * ice_get_irq_res - get an interrupt resource + * @pf: board private structure +- * @dyn_only: force entry to be dynamically allocated ++ * @dyn_allowed: allow entry to be dynamically allocated + * + * Allocate new irq entry in the free slot of the tracker. Since xarray + * is used, always allocate new entry at the lowest possible index. Set +@@ -53,11 +53,12 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index) + * + * Returns allocated irq entry or NULL on failure. + */ +-static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only) ++static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, ++ bool dyn_allowed) + { +- struct xa_limit limit = { .max = pf->irq_tracker.num_entries, ++ struct xa_limit limit = { .max = pf->irq_tracker.num_entries - 1, + .min = 0 }; +- unsigned int num_static = pf->irq_tracker.num_static; ++ unsigned int num_static = pf->irq_tracker.num_static - 1; + struct ice_irq_entry *entry; + unsigned int index; + int ret; +@@ -66,9 +67,9 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only) + if (!entry) + return NULL; + +- /* skip preallocated entries if the caller says so */ +- if (dyn_only) +- limit.min = num_static; ++ /* only already allocated if the caller says so */ ++ if (!dyn_allowed) ++ limit.max = num_static; + + ret = xa_alloc(&pf->irq_tracker.entries, &index, entry, limit, + GFP_KERNEL); +@@ -78,7 +79,7 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only) + entry = NULL; + } else { + entry->index = index; +- entry->dynamic = index >= num_static; ++ entry->dynamic = index > num_static; + } + + return entry; +@@ -272,7 +273,7 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) + /** + * ice_alloc_irq - Allocate new interrupt vector + * @pf: board private structure +- * @dyn_only: force dynamic allocation of the interrupt ++ * @dyn_allowed: allow dynamic allocation of the interrupt + * + * Allocate new interrupt vector for a given owner id. + * return struct msi_map with interrupt details and track +@@ -285,20 +286,20 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) + * interrupt will be allocated with pci_msix_alloc_irq_at. + * + * Some callers may only support dynamically allocated interrupts. +- * This is indicated with dyn_only flag. ++ * This is indicated with dyn_allowed flag. + * + * On failure, return map with negative .index. The caller + * is expected to check returned map index. + * + */ +-struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_only) ++struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_allowed) + { + int sriov_base_vector = pf->sriov_base_vector; + struct msi_map map = { .index = -ENOENT }; + struct device *dev = ice_pf_to_dev(pf); + struct ice_irq_entry *entry; + +- entry = ice_get_irq_res(pf, dyn_only); ++ entry = ice_get_irq_res(pf, dyn_allowed); + if (!entry) + return map; + +diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c +index 4e675c7c199fa1..4db0b770420e65 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lag.c ++++ b/drivers/net/ethernet/intel/ice/ice_lag.c +@@ -1229,12 +1229,18 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) + */ + if (!primary_lag) { + lag->primary = true; ++ if (!ice_is_switchdev_running(lag->pf)) ++ return; ++ + /* Configure primary's SWID to be shared */ + ice_lag_primary_swid(lag, true); + primary_lag = lag; + } else { + u16 swid; + ++ if (!ice_is_switchdev_running(primary_lag->pf)) ++ return; ++ + swid = primary_lag->pf->hw.port_info->sw_id; + ice_lag_set_swid(swid, lag, true); + ice_lag_add_prune_list(primary_lag, lag->pf); +diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c +index 1fc4805353eb58..a6a290514e5484 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_lib.c +@@ -587,6 +587,8 @@ ice_vsi_alloc_def(struct ice_vsi *vsi, struct ice_channel *ch) + return -ENOMEM; + } + ++ vsi->irq_dyn_alloc = pci_msix_can_alloc_dyn(vsi->back->pdev); ++ + switch (vsi->type) { + case ICE_VSI_SWITCHDEV_CTRL: + /* Setup eswitch MSIX irq handler for VSI */ +diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c +index e709b10a29761b..1edcf930318315 100644 +--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c ++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c +@@ -3769,7 +3769,6 @@ static int ice_vc_repr_add_mac(struct ice_vf *vf, u8 *msg) + } + + ice_vfhw_mac_add(vf, &al->list[i]); +- vf->num_mac++; + break; + } + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +index 339be6950c0395..6302990e9a5ff8 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +@@ -66,8 +66,18 @@ static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool en); + /* Supported devices */ + static const struct pci_device_id cgx_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, +- { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM) }, +- { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN10K_A) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF10K_A) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF10K_B) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN10K_B) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN20KA) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF20KA) }, + { 0, } /* end of table */ + }; + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index a607c7294b0c59..9fbc071ef29b0c 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -30,6 +30,8 @@ + #define PCI_SUBSYS_DEVID_CNF10K_A 0xBA00 + #define PCI_SUBSYS_DEVID_CNF10K_B 0xBC00 + #define PCI_SUBSYS_DEVID_CN10K_B 0xBD00 ++#define PCI_SUBSYS_DEVID_CN20KA 0xC220 ++#define PCI_SUBSYS_DEVID_CNF20KA 0xC320 + + /* PCI BAR nos */ + #define PCI_AF_REG_BAR_NUM 0 +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +index 0e74c5a2231e63..1e4cd4f7d0cfd4 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +@@ -13,19 +13,26 @@ + /* RVU LMTST */ + #define LMT_TBL_OP_READ 0 + #define LMT_TBL_OP_WRITE 1 +-#define LMT_MAP_TABLE_SIZE (128 * 1024) + #define LMT_MAPTBL_ENTRY_SIZE 16 ++#define LMT_MAX_VFS 256 ++ ++#define LMT_MAP_ENTRY_ENA BIT_ULL(20) ++#define LMT_MAP_ENTRY_LINES GENMASK_ULL(18, 16) + + /* Function to perform operations (read/write) on lmtst map table */ + static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val, + int lmt_tbl_op) + { + void __iomem *lmt_map_base; +- u64 tbl_base; ++ u64 tbl_base, cfg; ++ int pfs, vfs; + + tbl_base = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_MAP_BASE); ++ cfg = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CFG); ++ vfs = 1 << (cfg & 0xF); ++ pfs = 1 << ((cfg >> 4) & 0x7); + +- lmt_map_base = ioremap_wc(tbl_base, LMT_MAP_TABLE_SIZE); ++ lmt_map_base = ioremap_wc(tbl_base, pfs * vfs * LMT_MAPTBL_ENTRY_SIZE); + if (!lmt_map_base) { + dev_err(rvu->dev, "Failed to setup lmt map table mapping!!\n"); + return -ENOMEM; +@@ -35,6 +42,13 @@ static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val, + *val = readq(lmt_map_base + index); + } else { + writeq((*val), (lmt_map_base + index)); ++ ++ cfg = FIELD_PREP(LMT_MAP_ENTRY_ENA, 0x1); ++ /* 2048 LMTLINES */ ++ cfg |= FIELD_PREP(LMT_MAP_ENTRY_LINES, 0x6); ++ ++ writeq(cfg, (lmt_map_base + (index + 8))); ++ + /* Flushing the AP interceptor cache to make APR_LMT_MAP_ENTRY_S + * changes effective. Write 1 for flush and read is being used as a + * barrier and sets up a data dependency. Write to 0 after a write +@@ -52,7 +66,7 @@ static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val, + #define LMT_MAP_TBL_W1_OFF 8 + static u32 rvu_get_lmtst_tbl_index(struct rvu *rvu, u16 pcifunc) + { +- return ((rvu_get_pf(pcifunc) * rvu->hw->total_vfs) + ++ return ((rvu_get_pf(pcifunc) * LMT_MAX_VFS) + + (pcifunc & RVU_PFVF_FUNC_MASK)) * LMT_MAPTBL_ENTRY_SIZE; + } + +@@ -69,7 +83,7 @@ static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc, + + mutex_lock(&rvu->rsrc_lock); + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_REQ, iova); +- pf = rvu_get_pf(pcifunc) & 0x1F; ++ pf = rvu_get_pf(pcifunc) & RVU_PFVF_PF_MASK; + val = BIT_ULL(63) | BIT_ULL(14) | BIT_ULL(13) | pf << 8 | + ((pcifunc & RVU_PFVF_FUNC_MASK) & 0xFF); + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TXN_REQ, val); +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +index feca86e429df20..56dab11833b533 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +@@ -580,6 +580,7 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + u64 lmt_addr, val, tbl_base; + int pf, vf, num_vfs, hw_vfs; + void __iomem *lmt_map_base; ++ int apr_pfs, apr_vfs; + int buf_size = 10240; + size_t off = 0; + int index = 0; +@@ -595,8 +596,12 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + return -ENOMEM; + + tbl_base = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_MAP_BASE); ++ val = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CFG); ++ apr_vfs = 1 << (val & 0xF); ++ apr_pfs = 1 << ((val >> 4) & 0x7); + +- lmt_map_base = ioremap_wc(tbl_base, 128 * 1024); ++ lmt_map_base = ioremap_wc(tbl_base, apr_pfs * apr_vfs * ++ LMT_MAPTBL_ENTRY_SIZE); + if (!lmt_map_base) { + dev_err(rvu->dev, "Failed to setup lmt map table mapping!!\n"); + kfree(buf); +@@ -618,7 +623,7 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + off += scnprintf(&buf[off], buf_size - 1 - off, "PF%d \t\t\t", + pf); + +- index = pf * rvu->hw->total_vfs * LMT_MAPTBL_ENTRY_SIZE; ++ index = pf * apr_vfs * LMT_MAPTBL_ENTRY_SIZE; + off += scnprintf(&buf[off], buf_size - 1 - off, " 0x%llx\t\t", + (tbl_base + index)); + lmt_addr = readq(lmt_map_base + index); +@@ -631,7 +636,7 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + /* Reading num of VFs per PF */ + rvu_get_pf_numvfs(rvu, pf, &num_vfs, &hw_vfs); + for (vf = 0; vf < num_vfs; vf++) { +- index = (pf * rvu->hw->total_vfs * 16) + ++ index = (pf * apr_vfs * LMT_MAPTBL_ENTRY_SIZE) + + ((vf + 1) * LMT_MAPTBL_ENTRY_SIZE); + off += scnprintf(&buf[off], buf_size - 1 - off, + "PF%d:VF%d \t\t", pf, vf); +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +index 47adccf7a77765..1999918ca500fa 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +@@ -988,6 +988,7 @@ static int otx2_cq_init(struct otx2_nic *pfvf, u16 qidx) + int err, pool_id, non_xdp_queues; + struct nix_aq_enq_req *aq; + struct otx2_cq_queue *cq; ++ struct otx2_pool *pool; + + cq = &qset->cq[qidx]; + cq->cq_idx = qidx; +@@ -996,8 +997,13 @@ static int otx2_cq_init(struct otx2_nic *pfvf, u16 qidx) + cq->cq_type = CQ_RX; + cq->cint_idx = qidx; + cq->cqe_cnt = qset->rqe_cnt; +- if (pfvf->xdp_prog) ++ if (pfvf->xdp_prog) { ++ pool = &qset->pool[qidx]; + xdp_rxq_info_reg(&cq->xdp_rxq, pfvf->netdev, qidx, 0); ++ xdp_rxq_info_reg_mem_model(&cq->xdp_rxq, ++ MEM_TYPE_PAGE_POOL, ++ pool->page_pool); ++ } + } else if (qidx < non_xdp_queues) { + cq->cq_type = CQ_TX; + cq->cint_idx = qidx - pfvf->hw.rx_queues; +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +index a4efbeb1620841..889fd26843e608 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -34,8 +34,10 @@ struct mtk_flow_data { + u16 vlan_in; + + struct { +- u16 id; +- __be16 proto; ++ struct { ++ u16 id; ++ __be16 proto; ++ } vlans[2]; + u8 num; + } vlan; + struct { +@@ -330,18 +332,19 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f, + case FLOW_ACTION_CSUM: + break; + case FLOW_ACTION_VLAN_PUSH: +- if (data.vlan.num == 1 || ++ if (data.vlan.num + data.pppoe.num == 2 || + act->vlan.proto != htons(ETH_P_8021Q)) + return -EOPNOTSUPP; + +- data.vlan.id = act->vlan.vid; +- data.vlan.proto = act->vlan.proto; ++ data.vlan.vlans[data.vlan.num].id = act->vlan.vid; ++ data.vlan.vlans[data.vlan.num].proto = act->vlan.proto; + data.vlan.num++; + break; + case FLOW_ACTION_VLAN_POP: + break; + case FLOW_ACTION_PPPOE_PUSH: +- if (data.pppoe.num == 1) ++ if (data.pppoe.num == 1 || ++ data.vlan.num == 2) + return -EOPNOTSUPP; + + data.pppoe.sid = act->pppoe.sid; +@@ -431,12 +434,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f, + if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) + foe.bridge.vlan = data.vlan_in; + +- if (data.vlan.num == 1) { +- if (data.vlan.proto != htons(ETH_P_8021Q)) +- return -EOPNOTSUPP; ++ for (i = 0; i < data.vlan.num; i++) ++ mtk_foe_entry_set_vlan(eth, &foe, data.vlan.vlans[i].id); + +- mtk_foe_entry_set_vlan(eth, &foe, data.vlan.id); +- } + if (data.pppoe.num == 1) + mtk_foe_entry_set_pppoe(eth, &foe, data.pppoe.sid); + +diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c +index b330020dc0d674..f2bded847e61d1 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/alloc.c ++++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c +@@ -682,9 +682,9 @@ static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device) + } + + static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, +- struct mlx4_db *db, int order) ++ struct mlx4_db *db, unsigned int order) + { +- int o; ++ unsigned int o; + int i; + + for (o = order; o <= 1; ++o) { +@@ -712,7 +712,7 @@ static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, + return 0; + } + +-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order) ++int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, unsigned int order) + { + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_db_pgdir *pgdir; +diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c +index 65cb63f6c46587..61a0fd8424a2c5 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c +@@ -450,6 +450,8 @@ int mlx4_en_process_tx_cq(struct net_device *dev, + + if (unlikely(!priv->port_up)) + return 0; ++ if (unlikely(!napi_budget) && cq->type == TX_XDP) ++ return 0; + + netdev_txq_bql_complete_prefetchw(ring->tx_queue); + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h +index 20a6bc1a234f4e..9cf33ae48c216f 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h +@@ -93,8 +93,6 @@ struct page_pool; + #define MLX5_MPWRQ_DEF_LOG_STRIDE_SZ(mdev) \ + MLX5_MPWRQ_LOG_STRIDE_SZ(mdev, order_base_2(MLX5E_RX_MAX_HEAD)) + +-#define MLX5_MPWRQ_MAX_LOG_WQE_SZ 18 +- + /* Keep in sync with mlx5e_mpwrq_log_wqe_sz. + * These are theoretical maximums, which can be further restricted by + * capabilities. These values are used for static resource allocations and +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +index 775010e94cb7c6..dcd5db907f1028 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +@@ -9,6 +9,9 @@ + #include + #include + ++#define MLX5_MPWRQ_MAX_LOG_WQE_SZ 18 ++#define MLX5_REP_MPWRQ_MAX_LOG_WQE_SZ 17 ++ + static u8 mlx5e_mpwrq_min_page_shift(struct mlx5_core_dev *mdev) + { + u8 min_page_shift = MLX5_CAP_GEN_2(mdev, log_min_mkey_entity_size); +@@ -102,18 +105,22 @@ u8 mlx5e_mpwrq_log_wqe_sz(struct mlx5_core_dev *mdev, u8 page_shift, + enum mlx5e_mpwrq_umr_mode umr_mode) + { + u8 umr_entry_size = mlx5e_mpwrq_umr_entry_size(umr_mode); +- u8 max_pages_per_wqe, max_log_mpwqe_size; ++ u8 max_pages_per_wqe, max_log_wqe_size_calc; ++ u8 max_log_wqe_size_cap; + u16 max_wqe_size; + + /* Keep in sync with MLX5_MPWRQ_MAX_PAGES_PER_WQE. */ + max_wqe_size = mlx5e_get_max_sq_aligned_wqebbs(mdev) * MLX5_SEND_WQE_BB; + max_pages_per_wqe = ALIGN_DOWN(max_wqe_size - sizeof(struct mlx5e_umr_wqe), + MLX5_UMR_FLEX_ALIGNMENT) / umr_entry_size; +- max_log_mpwqe_size = ilog2(max_pages_per_wqe) + page_shift; ++ max_log_wqe_size_calc = ilog2(max_pages_per_wqe) + page_shift; ++ ++ WARN_ON_ONCE(max_log_wqe_size_calc < MLX5E_ORDER2_MAX_PACKET_MTU); + +- WARN_ON_ONCE(max_log_mpwqe_size < MLX5E_ORDER2_MAX_PACKET_MTU); ++ max_log_wqe_size_cap = mlx5_core_is_ecpf(mdev) ? ++ MLX5_REP_MPWRQ_MAX_LOG_WQE_SZ : MLX5_MPWRQ_MAX_LOG_WQE_SZ; + +- return min_t(u8, max_log_mpwqe_size, MLX5_MPWRQ_MAX_LOG_WQE_SZ); ++ return min_t(u8, max_log_wqe_size_calc, max_log_wqe_size_cap); + } + + u8 mlx5e_mpwrq_pages_per_wqe(struct mlx5_core_dev *mdev, u8 page_shift, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index d9dc7280302eb7..5c6f01abdcb91d 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -3627,8 +3627,11 @@ static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv, + /* MQPRIO is another toplevel qdisc that can't be attached + * simultaneously with the offloaded HTB. + */ +- if (WARN_ON(mlx5e_selq_is_htb_enabled(&priv->selq))) +- return -EINVAL; ++ if (mlx5e_selq_is_htb_enabled(&priv->selq)) { ++ NL_SET_ERR_MSG_MOD(mqprio->extack, ++ "MQPRIO cannot be configured when HTB offload is enabled."); ++ return -EOPNOTSUPP; ++ } + + switch (mqprio->mode) { + case TC_MQPRIO_MODE_DCB: +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +index 751d3ffcd2f6ce..851c499faa7954 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +@@ -63,6 +63,7 @@ + #define MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE \ + max(0x7, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE) + #define MLX5E_REP_PARAMS_DEF_NUM_CHANNELS 1 ++#define MLX5E_REP_PARAMS_DEF_LOG_RQ_SIZE 0x8 + + static const char mlx5e_rep_driver_name[] = "mlx5e_rep"; + +@@ -798,6 +799,8 @@ static void mlx5e_build_rep_params(struct net_device *netdev) + + /* RQ */ + mlx5e_build_rq_params(mdev, params); ++ if (!mlx5e_is_uplink_rep(priv) && mlx5_core_is_ecpf(mdev)) ++ params->log_rq_mtu_frames = MLX5E_REP_PARAMS_DEF_LOG_RQ_SIZE; + + /* If netdev is already registered (e.g. move from nic profile to uplink, + * RTNL lock must be held before triggering netdev notifiers. +@@ -829,6 +832,8 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev, + netdev->ethtool_ops = &mlx5e_rep_ethtool_ops; + + netdev->watchdog_timeo = 15 * HZ; ++ if (mlx5_core_is_ecpf(mdev)) ++ netdev->tx_queue_len = 1 << MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE; + + #if IS_ENABLED(CONFIG_MLX5_CLS_ACT) + netdev->hw_features |= NETIF_F_HW_TC; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +index 08a75654f5f188..c170503b3aace1 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +@@ -165,6 +165,9 @@ mlx5e_test_loopback_validate(struct sk_buff *skb, + struct udphdr *udph; + struct iphdr *iph; + ++ if (skb_linearize(skb)) ++ goto out; ++ + /* We are only going to peek, no need to clone the SKB */ + if (MLX5E_TEST_PKT_SIZE - ETH_HLEN > skb_headlen(skb)) + goto out; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c +index 8587cd572da536..bdb825aa872688 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c +@@ -96,7 +96,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw) + if (!flow_group_in) + return -ENOMEM; + +- ft_attr.max_fte = POOL_NEXT_SIZE; ++ ft_attr.max_fte = MLX5_FS_MAX_POOL_SIZE; + ft_attr.prio = LEGACY_FDB_PRIO; + fdb = mlx5_create_flow_table(root_ns, &ft_attr); + if (IS_ERR(fdb)) { +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c +index 3ec892d51f57d2..e7143d32b22119 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/events.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c +@@ -163,11 +163,16 @@ static int temp_warn(struct notifier_block *nb, unsigned long type, void *data) + u64 value_msb; + + value_lsb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_lsb); ++ /* bit 1-63 are not supported for NICs, ++ * hence read only bit 0 (asic) from lsb. ++ */ ++ value_lsb &= 0x1; + value_msb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_msb); + +- mlx5_core_warn(events->dev, +- "High temperature on sensors with bit set %llx %llx", +- value_msb, value_lsb); ++ if (net_ratelimit()) ++ mlx5_core_warn(events->dev, ++ "High temperature on sensors with bit set %llx %llx", ++ value_msb, value_lsb); + + return NOTIFY_OK; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c +index c14590acc77260..f6abfd00d7e68c 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c +@@ -50,10 +50,12 @@ mlx5_ft_pool_get_avail_sz(struct mlx5_core_dev *dev, enum fs_flow_table_type tab + int i, found_i = -1; + + for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--) { +- if (dev->priv.ft_pool->ft_left[i] && FT_POOLS[i] >= desired_size && ++ if (dev->priv.ft_pool->ft_left[i] && ++ (FT_POOLS[i] >= desired_size || ++ desired_size == MLX5_FS_MAX_POOL_SIZE) && + FT_POOLS[i] <= max_ft_size) { + found_i = i; +- if (desired_size != POOL_NEXT_SIZE) ++ if (desired_size != MLX5_FS_MAX_POOL_SIZE) + break; + } + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h +index 25f4274b372b56..173e312db7204f 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h +@@ -7,8 +7,6 @@ + #include + #include "fs_core.h" + +-#define POOL_NEXT_SIZE 0 +- + int mlx5_ft_pool_init(struct mlx5_core_dev *dev); + void mlx5_ft_pool_destroy(struct mlx5_core_dev *dev); + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c +index d798834c4e755d..3ac8043f76dacc 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c +@@ -833,6 +833,7 @@ static void poll_health(struct timer_list *t) + health->prev = count; + if (health->miss_counter == MAX_MISSES) { + mlx5_core_err(dev, "device's health compromised - reached miss count\n"); ++ health->synd = ioread8(&h->synd); + print_health_info(dev); + queue_work(health->wq, &health->report_work); + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c +index 711d14dea2485f..d313cb7f0ed88c 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c +@@ -161,7 +161,8 @@ mlx5_chains_create_table(struct mlx5_fs_chains *chains, + ft_attr.flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | + MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); + +- sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? FT_TBL_SZ : POOL_NEXT_SIZE; ++ sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? ++ FT_TBL_SZ : MLX5_FS_MAX_POOL_SIZE; + ft_attr.max_fte = sz; + + /* We use chains_default_ft(chains) as the table's next_ft till +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 5d2ceff72784f2..f971d60484f065 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -3259,6 +3259,7 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, + struct pci_dev *pdev) + { + struct lan743x_tx *tx; ++ u32 sgmii_ctl; + int index; + int ret; + +@@ -3271,6 +3272,15 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, + spin_lock_init(&adapter->eth_syslock_spinlock); + mutex_init(&adapter->sgmii_rw_lock); + pci11x1x_set_rfe_rd_fifo_threshold(adapter); ++ sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); ++ if (adapter->is_sgmii_en) { ++ sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_; ++ sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_; ++ } else { ++ sgmii_ctl &= ~SGMII_CTL_SGMII_ENABLE_; ++ sgmii_ctl |= SGMII_CTL_SGMII_POWER_DN_; ++ } ++ lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + } else { + adapter->max_tx_channels = LAN743X_MAX_TX_CHANNELS; + adapter->used_tx_channels = LAN743X_USED_TX_CHANNELS; +@@ -3319,7 +3329,6 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, + + static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) + { +- u32 sgmii_ctl; + int ret; + + adapter->mdiobus = devm_mdiobus_alloc(&adapter->pdev->dev); +@@ -3331,10 +3340,6 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) + adapter->mdiobus->priv = (void *)adapter; + if (adapter->is_pci11x1x) { + if (adapter->is_sgmii_en) { +- sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); +- sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_; +- sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_; +- lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + netif_dbg(adapter, drv, adapter->netdev, + "SGMII operation\n"); + adapter->mdiobus->read = lan743x_mdiobus_read_c22; +@@ -3345,10 +3350,6 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) + netif_dbg(adapter, drv, adapter->netdev, + "lan743x-mdiobus-c45\n"); + } else { +- sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); +- sgmii_ctl &= ~SGMII_CTL_SGMII_ENABLE_; +- sgmii_ctl |= SGMII_CTL_SGMII_POWER_DN_; +- lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + netif_dbg(adapter, drv, adapter->netdev, + "RGMII operation\n"); + // Only C22 support when RGMII I/F +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index ae014e21eb6056..9ed965d61e3554 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -1036,7 +1036,7 @@ static u32 mana_gd_write_client_oob(const struct gdma_wqe_request *wqe_req, + header->inline_oob_size_div4 = client_oob_size / sizeof(u32); + + if (oob_in_sgl) { +- WARN_ON_ONCE(!pad_data || wqe_req->num_sge < 2); ++ WARN_ON_ONCE(wqe_req->num_sge < 2); + + header->client_oob_in_sgl = 1; + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 7e5258b2c4290b..5af932a5e70c44 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5125,6 +5125,7 @@ static int r8169_mdio_register(struct rtl8169_private *tp) + new_bus->priv = tp; + new_bus->parent = &pdev->dev; + new_bus->irq[0] = PHY_MAC_INTERRUPT; ++ new_bus->phy_mask = GENMASK(31, 1); + snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x-%x", + pci_domain_nr(pdev->bus), pci_dev_id(pdev)); + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +index 63998d65fef8eb..9377b05bfc71e1 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +@@ -966,7 +966,7 @@ static int sun8i_dwmac_set_syscon(struct device *dev, + /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY + * address. No need to mask it again. + */ +- reg |= 1 << H3_EPHY_ADDR_SHIFT; ++ reg |= ret << H3_EPHY_ADDR_SHIFT; + } else { + /* For SoCs without internal PHY the PHY selection bit should be + * set to 0 (external PHY). +diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +index 9c8376b2718916..c379a958380ce0 100644 +--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c ++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +@@ -2095,7 +2095,7 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) + port->slave.mac_addr); + if (!is_valid_ether_addr(port->slave.mac_addr)) { + eth_random_addr(port->slave.mac_addr); +- dev_err(dev, "Use random MAC address\n"); ++ dev_info(dev, "Use random MAC address\n"); + } + } + } +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index 9061dca97fcbfd..1c1d4806c119b8 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -1416,6 +1416,7 @@ static int cpsw_create_ports(struct cpsw_common *cpsw) + ndev->netdev_ops = &cpsw_netdev_ops; + ndev->ethtool_ops = &cpsw_ethtool_ops; + SET_NETDEV_DEV(ndev, dev); ++ ndev->dev.of_node = slave_data->slave_node; + + if (!napi_ndev) { + /* CPSW Host port CPDMA interface is shared between +diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c +index 0a0ad3d77557f9..587643a371de3c 100644 +--- a/drivers/net/ieee802154/ca8210.c ++++ b/drivers/net/ieee802154/ca8210.c +@@ -1446,8 +1446,7 @@ static u8 mcps_data_request( + command.pdata.data_req.src_addr_mode = src_addr_mode; + command.pdata.data_req.dst.mode = dst_address_mode; + if (dst_address_mode != MAC_MODE_NO_ADDR) { +- command.pdata.data_req.dst.pan_id[0] = LS_BYTE(dst_pan_id); +- command.pdata.data_req.dst.pan_id[1] = MS_BYTE(dst_pan_id); ++ put_unaligned_le16(dst_pan_id, command.pdata.data_req.dst.pan_id); + if (dst_address_mode == MAC_MODE_SHORT_ADDR) { + command.pdata.data_req.dst.address[0] = LS_BYTE( + dst_addr->short_address +@@ -1795,12 +1794,12 @@ static int ca8210_skb_rx( + } + hdr.source.mode = data_ind[0]; + dev_dbg(&priv->spi->dev, "srcAddrMode: %#03x\n", hdr.source.mode); +- hdr.source.pan_id = *(u16 *)&data_ind[1]; ++ hdr.source.pan_id = cpu_to_le16(get_unaligned_le16(&data_ind[1])); + dev_dbg(&priv->spi->dev, "srcPanId: %#06x\n", hdr.source.pan_id); + memcpy(&hdr.source.extended_addr, &data_ind[3], 8); + hdr.dest.mode = data_ind[11]; + dev_dbg(&priv->spi->dev, "dstAddrMode: %#03x\n", hdr.dest.mode); +- hdr.dest.pan_id = *(u16 *)&data_ind[12]; ++ hdr.dest.pan_id = cpu_to_le16(get_unaligned_le16(&data_ind[12])); + dev_dbg(&priv->spi->dev, "dstPanId: %#06x\n", hdr.dest.pan_id); + memcpy(&hdr.dest.extended_addr, &data_ind[14], 8); + +@@ -1927,7 +1926,7 @@ static int ca8210_skb_tx( + status = mcps_data_request( + header.source.mode, + header.dest.mode, +- header.dest.pan_id, ++ le16_to_cpu(header.dest.pan_id), + (union macaddr *)&header.dest.extended_addr, + skb->len - mac_len, + &skb->data[mac_len], +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index b5f012619e42da..800e8b9eb4532b 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1718,7 +1718,7 @@ bool phylink_expects_phy(struct phylink *pl) + { + if (pl->cfg_link_an_mode == MLO_AN_FIXED || + (pl->cfg_link_an_mode == MLO_AN_INBAND && +- phy_interface_mode_is_8023z(pl->link_config.interface))) ++ phy_interface_mode_is_8023z(pl->link_interface))) + return false; + return true; + } +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index bbcefcc7ef8f06..1e85cfe524e875 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -10032,6 +10032,7 @@ static const struct usb_device_id rtl8152_table[] = { + { USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) }, + { USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) }, + { USB_DEVICE(VENDOR_ID_DLINK, 0xb301) }, ++ { USB_DEVICE(VENDOR_ID_DELL, 0xb097) }, + { USB_DEVICE(VENDOR_ID_ASUS, 0x1976) }, + {} + }; +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index 64db3e98a1b664..2ed879a0abc6ce 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -227,9 +227,9 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, + be32_to_cpu(fdb->vni))) + goto nla_put_failure; + +- ci.ndm_used = jiffies_to_clock_t(now - fdb->used); ++ ci.ndm_used = jiffies_to_clock_t(now - READ_ONCE(fdb->used)); + ci.ndm_confirmed = 0; +- ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated); ++ ci.ndm_updated = jiffies_to_clock_t(now - READ_ONCE(fdb->updated)); + ci.ndm_refcnt = 0; + + if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) +@@ -435,8 +435,8 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, + struct vxlan_fdb *f; + + f = __vxlan_find_mac(vxlan, mac, vni); +- if (f && f->used != jiffies) +- f->used = jiffies; ++ if (f && READ_ONCE(f->used) != jiffies) ++ WRITE_ONCE(f->used, jiffies); + + return f; + } +@@ -1010,12 +1010,12 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, + !(f->flags & NTF_VXLAN_ADDED_BY_USER)) { + if (f->state != state) { + f->state = state; +- f->updated = jiffies; ++ WRITE_ONCE(f->updated, jiffies); + notify = 1; + } + if (f->flags != fdb_flags) { + f->flags = fdb_flags; +- f->updated = jiffies; ++ WRITE_ONCE(f->updated, jiffies); + notify = 1; + } + } +@@ -1049,7 +1049,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, + } + + if (ndm_flags & NTF_USE) +- f->used = jiffies; ++ WRITE_ONCE(f->used, jiffies); + + if (notify) { + if (rd == NULL) +@@ -1478,7 +1478,7 @@ static bool vxlan_snoop(struct net_device *dev, + src_mac, &rdst->remote_ip.sa, &src_ip->sa); + + rdst->remote_ip = *src_ip; +- f->updated = jiffies; ++ WRITE_ONCE(f->updated, jiffies); + vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL); + } else { + u32 hash_index = fdb_head_index(vxlan, src_mac, vni); +@@ -2920,7 +2920,7 @@ static void vxlan_cleanup(struct timer_list *t) + if (f->flags & NTF_EXT_LEARNED) + continue; + +- timeout = f->used + vxlan->cfg.age_interval * HZ; ++ timeout = READ_ONCE(f->used) + vxlan->cfg.age_interval * HZ; + if (time_before_eq(timeout, jiffies)) { + netdev_dbg(vxlan->dev, + "garbage collect %pM\n", +@@ -4240,6 +4240,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + struct netlink_ext_ack *extack) + { + struct vxlan_dev *vxlan = netdev_priv(dev); ++ bool rem_ip_changed, change_igmp; + struct net_device *lowerdev; + struct vxlan_config conf; + struct vxlan_rdst *dst; +@@ -4263,8 +4264,13 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + if (err) + return err; + ++ rem_ip_changed = !vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip); ++ change_igmp = vxlan->dev->flags & IFF_UP && ++ (rem_ip_changed || ++ dst->remote_ifindex != conf.remote_ifindex); ++ + /* handle default dst entry */ +- if (!vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip)) { ++ if (rem_ip_changed) { + u32 hash_index = fdb_head_index(vxlan, all_zeros_mac, conf.vni); + + spin_lock_bh(&vxlan->hash_lock[hash_index]); +@@ -4308,6 +4314,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + } + } + ++ if (change_igmp && vxlan_addr_multicast(&dst->remote_ip)) ++ err = vxlan_multicast_leave(vxlan); ++ + if (conf.age_interval != vxlan->cfg.age_interval) + mod_timer(&vxlan->age_timer, jiffies); + +@@ -4315,7 +4324,12 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + if (lowerdev && lowerdev != dst->remote_dev) + dst->remote_dev = lowerdev; + vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true); +- return 0; ++ ++ if (!err && change_igmp && ++ vxlan_addr_multicast(&dst->remote_ip)) ++ err = vxlan_multicast_join(vxlan); ++ ++ return err; + } + + static void vxlan_dellink(struct net_device *dev, struct list_head *head) +diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h +index 33f4706af880d1..18dfd7aab610c9 100644 +--- a/drivers/net/wireless/ath/ath12k/core.h ++++ b/drivers/net/wireless/ath/ath12k/core.h +@@ -125,6 +125,7 @@ struct ath12k_ext_irq_grp { + u32 num_irq; + u32 grp_id; + u64 timestamp; ++ bool napi_enabled; + struct napi_struct napi; + struct net_device napi_ndev; + }; +diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c +index e025e4d0e7678f..474e0d4d406ea1 100644 +--- a/drivers/net/wireless/ath/ath12k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath12k/dp_tx.c +@@ -118,7 +118,7 @@ static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab, void *cmd, + le32_encode_bits(ti->data_len, + HAL_TX_MSDU_EXT_INFO1_BUF_LEN); + +- tcl_ext_cmd->info1 = le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) | ++ tcl_ext_cmd->info1 |= le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) | + le32_encode_bits(ti->encap_type, + HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) | + le32_encode_bits(ti->encrypt_type, +@@ -422,13 +422,13 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, + + switch (wbm_status) { + case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK: +- case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: +- case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: + ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK); + ts.ack_rssi = le32_get_bits(status_desc->info2, + HTT_TX_WBM_COMP_INFO2_ACK_RSSI); + ath12k_dp_tx_htt_tx_complete_buf(ab, msdu, tx_ring, &ts); + break; ++ case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: ++ case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: + case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ: + case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT: + ath12k_dp_tx_free_txbuf(ab, msdu, mac_id, tx_ring); +diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h +index 6c17adc6d60b56..1bb840c2bef577 100644 +--- a/drivers/net/wireless/ath/ath12k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath12k/hal_desc.h +@@ -2918,7 +2918,7 @@ struct hal_mon_buf_ring { + + #define HAL_MON_DEST_COOKIE_BUF_ID GENMASK(17, 0) + +-#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(15, 0) ++#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(11, 0) + #define HAL_MON_DEST_INFO0_FLUSH_DETECTED BIT(16) + #define HAL_MON_DEST_INFO0_END_OF_PPDU BIT(17) + #define HAL_MON_DEST_INFO0_INITIATOR BIT(18) +diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c +index 041a9602f0e15f..5fd80f90ecafed 100644 +--- a/drivers/net/wireless/ath/ath12k/pci.c ++++ b/drivers/net/wireless/ath/ath12k/pci.c +@@ -442,8 +442,11 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab) + + ath12k_pci_ext_grp_disable(irq_grp); + +- napi_synchronize(&irq_grp->napi); +- napi_disable(&irq_grp->napi); ++ if (irq_grp->napi_enabled) { ++ napi_synchronize(&irq_grp->napi); ++ napi_disable(&irq_grp->napi); ++ irq_grp->napi_enabled = false; ++ } + } + } + +@@ -976,7 +979,11 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab) + for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + +- napi_enable(&irq_grp->napi); ++ if (!irq_grp->napi_enabled) { ++ napi_enable(&irq_grp->napi); ++ irq_grp->napi_enabled = true; ++ } ++ + ath12k_pci_ext_grp_enable(irq_grp); + } + } +diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c +index c977dfbae0a464..d87d5980325e8f 100644 +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -2115,8 +2115,8 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar, + arg->dwell_time_active = 50; + arg->dwell_time_active_2g = 0; + arg->dwell_time_passive = 150; +- arg->dwell_time_active_6g = 40; +- arg->dwell_time_passive_6g = 30; ++ arg->dwell_time_active_6g = 70; ++ arg->dwell_time_passive_6g = 70; + arg->min_rest_time = 50; + arg->max_rest_time = 500; + arg->repeat_probe_time = 0; +diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c +index 4f00400c7ffb83..58386906598a73 100644 +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -691,7 +691,9 @@ static int ath9k_of_init(struct ath_softc *sc) + ah->ah_flags |= AH_NO_EEP_SWAP; + } + +- of_get_mac_address(np, common->macaddr); ++ ret = of_get_mac_address(np, common->macaddr); ++ if (ret == -EPROBE_DEFER) ++ return ret; + + return 0; + } +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +index a97ed7cbe4d140..d588e4cd808d8e 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + /* +- * Copyright (C) 2018-2024 Intel Corporation ++ * Copyright (C) 2018-2025 Intel Corporation + */ + #include + #include "iwl-drv.h" +@@ -1382,15 +1382,15 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + switch (tp_id) { + case IWL_FW_INI_TIME_POINT_EARLY: + iwl_dbg_tlv_init_cfg(fwrt); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_update_drams(fwrt); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + case IWL_FW_INI_TIME_POINT_AFTER_ALIVE: + iwl_dbg_tlv_apply_buffers(fwrt); + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + case IWL_FW_INI_TIME_POINT_PERIODIC: + iwl_dbg_tlv_set_periodic_trigs(fwrt); +@@ -1400,14 +1400,14 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + case IWL_FW_INI_TIME_POINT_MISSED_BEACONS: + case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, + iwl_dbg_tlv_check_fw_pkt); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + default: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + } + } +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +index 4a2de79f2e864b..c01a9a6f06a4d0 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +@@ -580,6 +580,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { + IWL_DEV_INFO(0x7A70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), + IWL_DEV_INFO(0x7AF0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), + IWL_DEV_INFO(0x7AF0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), ++ IWL_DEV_INFO(0x7F70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), ++ IWL_DEV_INFO(0x7F70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), + + IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name), + IWL_DEV_INFO(0x7E40, 0x1691, iwl_cfg_ma, iwl_ax411_killer_1690s_name), +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index 8b620d4fed4390..df0ea638370b56 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -439,6 +439,7 @@ struct mt76_hw_cap { + #define MT_DRV_RX_DMA_HDR BIT(3) + #define MT_DRV_HW_MGMT_TXQ BIT(4) + #define MT_DRV_AMSDU_OFFLOAD BIT(5) ++#define MT_DRV_IGNORE_TXS_FAILED BIT(6) + + struct mt76_driver_ops { + u32 drv_flags; +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +index 87bfa441a93743..4979012d5abfa0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +@@ -280,6 +280,9 @@ enum tx_mgnt_type { + #define MT_TXFREE_INFO_COUNT GENMASK(27, 24) + #define MT_TXFREE_INFO_STAT GENMASK(29, 28) + ++#define MT_TXS_HDR_SIZE 4 /* Unit: DW */ ++#define MT_TXS_SIZE 12 /* Unit: DW */ ++ + #define MT_TXS0_BW GENMASK(31, 29) + #define MT_TXS0_TID GENMASK(28, 26) + #define MT_TXS0_AMPDU BIT(25) +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +index 9277ff38b7a228..57ae362dad50b7 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +@@ -152,7 +152,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x02_txwi), + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | +- MT_DRV_SW_RX_AIRTIME, ++ MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +index 0422c332354a13..520fd46227a7b8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +@@ -210,7 +210,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) + { + static const struct mt76_driver_ops drv_ops = { +- .drv_flags = MT_DRV_SW_RX_AIRTIME, ++ .drv_flags = MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02u_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +index df85ebc6e1df07..7e2475b3c278e0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +@@ -22,7 +22,8 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x02_txwi), + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | +- MT_DRV_SW_RX_AIRTIME, ++ MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +index d8043099921966..70d3895762b4cd 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +@@ -29,7 +29,8 @@ static int mt76x2u_probe(struct usb_interface *intf, + const struct usb_device_id *id) + { + static const struct mt76_driver_ops drv_ops = { +- .drv_flags = MT_DRV_SW_RX_AIRTIME, ++ .drv_flags = MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02u_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 73d46ec1181ae8..35d9673ec0d8fc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1354,7 +1354,7 @@ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len) + mt7996_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: +- for (rxd += 4; rxd + 8 <= end; rxd += 8) ++ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE) + mt7996_mac_add_txs(dev, rxd); + return false; + case PKT_TYPE_RX_FW_MONITOR: +@@ -1391,7 +1391,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + mt7996_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_TXS: +- for (rxd += 4; rxd + 8 <= end; rxd += 8) ++ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE) + mt7996_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; +diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c +index 1809b03292c3d9..47cdccdbed6aaf 100644 +--- a/drivers/net/wireless/mediatek/mt76/tx.c ++++ b/drivers/net/wireless/mediatek/mt76/tx.c +@@ -100,7 +100,8 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, + return; + + /* Tx status can be unreliable. if it fails, mark the frame as ACKed */ +- if (flags & MT_TX_CB_TXS_FAILED) { ++ if (flags & MT_TX_CB_TXS_FAILED && ++ (dev->drv->drv_flags & MT_DRV_IGNORE_TXS_FAILED)) { + info->status.rates[0].count = 0; + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; +diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +index 6e47dde9389092..05e77d2bda3738 100644 +--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c ++++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +@@ -900,9 +900,10 @@ rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len) + return len; + + write_error: +- dev_info(&udev->dev, +- "%s: Failed to write block at addr: %04x size: %04x\n", +- __func__, addr, blocksize); ++ if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE) ++ dev_info(&udev->dev, ++ "%s: Failed to write block at addr: %04x size: %04x\n", ++ __func__, addr, blocksize); + return -EAGAIN; + } + +@@ -4073,8 +4074,14 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) + */ + rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, fops->trxff_boundary); + +- ret = rtl8xxxu_download_firmware(priv); +- dev_dbg(dev, "%s: download_firmware %i\n", __func__, ret); ++ for (int retry = 5; retry >= 0 ; retry--) { ++ ret = rtl8xxxu_download_firmware(priv); ++ dev_dbg(dev, "%s: download_firmware %i\n", __func__, ret); ++ if (ret != -EAGAIN) ++ break; ++ if (retry) ++ dev_dbg(dev, "%s: retry firmware download\n", __func__); ++ } + if (ret) + goto exit; + ret = rtl8xxxu_start_firmware(priv); +diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c +index 0c1c1ff31085cf..929182424b8b87 100644 +--- a/drivers/net/wireless/realtek/rtw88/mac.c ++++ b/drivers/net/wireless/realtek/rtw88/mac.c +@@ -783,7 +783,8 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev, + if (!check_firmware_size(data, size)) + return -EINVAL; + +- if (!ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp)) ++ if (rtwdev->chip->ltecoex_addr && ++ !ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp)) + return -EBUSY; + + wlan_cpu_enable(rtwdev, false); +@@ -801,7 +802,8 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev, + + wlan_cpu_enable(rtwdev, true); + +- if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) { ++ if (rtwdev->chip->ltecoex_addr && ++ !ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) { + ret = -EBUSY; + goto dlfw_fail; + } +diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c +index b90ea6c88b15d9..0d0b5123b5fe28 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.c ++++ b/drivers/net/wireless/realtek/rtw88/main.c +@@ -1544,6 +1544,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, + { + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; ++ int i; + + ht_cap->ht_supported = true; + ht_cap->cap = 0; +@@ -1563,25 +1564,20 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ampdu_density = chip->ampdu_density; + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +- if (efuse->hw_cap.nss > 1) { +- ht_cap->mcs.rx_mask[0] = 0xFF; +- ht_cap->mcs.rx_mask[1] = 0xFF; +- ht_cap->mcs.rx_mask[4] = 0x01; +- ht_cap->mcs.rx_highest = cpu_to_le16(300); +- } else { +- ht_cap->mcs.rx_mask[0] = 0xFF; +- ht_cap->mcs.rx_mask[1] = 0x00; +- ht_cap->mcs.rx_mask[4] = 0x01; +- ht_cap->mcs.rx_highest = cpu_to_le16(150); +- } ++ ++ for (i = 0; i < efuse->hw_cap.nss; i++) ++ ht_cap->mcs.rx_mask[i] = 0xFF; ++ ht_cap->mcs.rx_mask[4] = 0x01; ++ ht_cap->mcs.rx_highest = cpu_to_le16(150 * efuse->hw_cap.nss); + } + + static void rtw_init_vht_cap(struct rtw_dev *rtwdev, + struct ieee80211_sta_vht_cap *vht_cap) + { + struct rtw_efuse *efuse = &rtwdev->efuse; +- u16 mcs_map; ++ u16 mcs_map = 0; + __le16 highest; ++ int i; + + if (efuse->hw_cap.ptcl != EFUSE_HW_CAP_IGNORE && + efuse->hw_cap.ptcl != EFUSE_HW_CAP_PTCL_VHT) +@@ -1604,21 +1600,15 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev, + if (rtw_chip_has_rx_ldpc(rtwdev)) + vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; + +- mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; +- if (efuse->hw_cap.nss > 1) { +- highest = cpu_to_le16(780); +- mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2; +- } else { +- highest = cpu_to_le16(390); +- mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << 2; ++ for (i = 0; i < 8; i++) { ++ if (i < efuse->hw_cap.nss) ++ mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2); ++ else ++ mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2); + } + ++ highest = cpu_to_le16(390 * efuse->hw_cap.nss); ++ + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.rx_highest = highest; +diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h +index 7c6c11d50ff30f..0e76bc07bddef3 100644 +--- a/drivers/net/wireless/realtek/rtw88/reg.h ++++ b/drivers/net/wireless/realtek/rtw88/reg.h +@@ -108,6 +108,7 @@ + #define BIT_SHIFT_ROM_PGE 16 + #define BIT_FW_INIT_RDY BIT(15) + #define BIT_FW_DW_RDY BIT(14) ++#define BIT_CPU_CLK_SEL (BIT(12) | BIT(13)) + #define BIT_RPWM_TOGGLE BIT(7) + #define BIT_RAM_DL_SEL BIT(7) /* legacy only */ + #define BIT_DMEM_CHKSUM_OK BIT(6) +@@ -125,7 +126,7 @@ + BIT_CHECK_SUM_OK) + #define FW_READY_LEGACY (BIT_MCUFWDL_RDY | BIT_FWDL_CHK_RPT | \ + BIT_WINTINI_RDY | BIT_RAM_DL_SEL) +-#define FW_READY_MASK 0xffff ++#define FW_READY_MASK (0xffff & ~BIT_CPU_CLK_SEL) + + #define REG_MCU_TST_CFG 0x84 + #define VAL_FW_TRIGGER 0x1 +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c +index 3017a9760da8dc..99318a82b43f4b 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c +@@ -975,11 +975,11 @@ static void rtw8822b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, + } + + static void +-rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) ++rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, ++ u8 rs, u32 *phy_pwr_idx) + { + struct rtw_hal *hal = &rtwdev->hal; + static const u32 offset_txagc[2] = {0x1d00, 0x1d80}; +- static u32 phy_pwr_idx; + u8 rate, rate_idx, pwr_index, shift; + int j; + +@@ -987,12 +987,12 @@ rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) + rate = rtw_rate_section[rs][j]; + pwr_index = hal->tx_pwr_tbl[path][rate]; + shift = rate & 0x3; +- phy_pwr_idx |= ((u32)pwr_index << (shift * 8)); ++ *phy_pwr_idx |= ((u32)pwr_index << (shift * 8)); + if (shift == 0x3) { + rate_idx = rate & 0xfc; + rtw_write32(rtwdev, offset_txagc[path] + rate_idx, +- phy_pwr_idx); +- phy_pwr_idx = 0; ++ *phy_pwr_idx); ++ *phy_pwr_idx = 0; + } + } + } +@@ -1000,11 +1000,13 @@ rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) + static void rtw8822b_set_tx_power_index(struct rtw_dev *rtwdev) + { + struct rtw_hal *hal = &rtwdev->hal; ++ u32 phy_pwr_idx = 0; + int rs, path; + + for (path = 0; path < hal->rf_path_num; path++) { + for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) +- rtw8822b_set_tx_power_index_by_rate(rtwdev, path, rs); ++ rtw8822b_set_tx_power_index_by_rate(rtwdev, path, rs, ++ &phy_pwr_idx); + } + } + +diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c +index e222d3c01a77ec..66819f69440550 100644 +--- a/drivers/net/wireless/realtek/rtw88/util.c ++++ b/drivers/net/wireless/realtek/rtw88/util.c +@@ -101,7 +101,8 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss) + *nss = 4; + *mcs = rate - DESC_RATEVHT4SS_MCS0; + } else if (rate >= DESC_RATEMCS0 && +- rate <= DESC_RATEMCS15) { ++ rate <= DESC_RATEMCS31) { ++ *nss = 0; + *mcs = rate - DESC_RATEMCS0; + } + } +diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c +index a8e2efae6e5260..89b0a7970508e2 100644 +--- a/drivers/net/wireless/realtek/rtw89/fw.c ++++ b/drivers/net/wireless/realtek/rtw89/fw.c +@@ -755,7 +755,6 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); +- ret = -1; + goto fail; + } + +@@ -816,7 +815,6 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev, + ret = rtw89_h2c_tx(rtwdev, skb, true); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); +- ret = -1; + goto fail; + } + +diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c +index 9e2328db186560..91f0895d9f5404 100644 +--- a/drivers/net/wireless/realtek/rtw89/regd.c ++++ b/drivers/net/wireless/realtek/rtw89/regd.c +@@ -451,6 +451,7 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct rtw89_dev *rtwdev = hw->priv; + ++ wiphy_lock(wiphy); + mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); + +@@ -468,6 +469,7 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request + + exit: + mutex_unlock(&rtwdev->mutex); ++ wiphy_unlock(wiphy); + } + + static void __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) +diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c +index 01b17b8f4ff9dc..45165cf3e824e6 100644 +--- a/drivers/net/wireless/realtek/rtw89/ser.c ++++ b/drivers/net/wireless/realtek/rtw89/ser.c +@@ -156,9 +156,11 @@ static void ser_state_run(struct rtw89_ser *ser, u8 evt) + rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s receive %s\n", + ser_st_name(ser), ser_ev_name(ser, evt)); + ++ wiphy_lock(rtwdev->hw->wiphy); + mutex_lock(&rtwdev->mutex); + rtw89_leave_lps(rtwdev); + mutex_unlock(&rtwdev->mutex); ++ wiphy_unlock(rtwdev->hw->wiphy); + + ser->st_tbl[ser->state].st_func(ser, evt); + } +@@ -676,9 +678,11 @@ static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt) + + switch (evt) { + case SER_EV_STATE_IN: ++ wiphy_lock(rtwdev->hw->wiphy); + mutex_lock(&rtwdev->mutex); + ser_l2_reset_st_pre_hdl(ser); + mutex_unlock(&rtwdev->mutex); ++ wiphy_unlock(rtwdev->hw->wiphy); + + ieee80211_restart_hw(rtwdev->hw); + ser_set_alarm(ser, SER_RECFG_TIMEOUT, SER_EV_L2_RECFG_TIMEOUT); +diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c +index 082253a3a95607..04f4a049599a1a 100644 +--- a/drivers/nvdimm/label.c ++++ b/drivers/nvdimm/label.c +@@ -442,7 +442,8 @@ int nd_label_data_init(struct nvdimm_drvdata *ndd) + if (ndd->data) + return 0; + +- if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0) { ++ if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0 || ++ ndd->nsarea.config_size == 0) { + dev_dbg(ndd->dev, "failed to init config data area: (%u:%u)\n", + ndd->nsarea.max_xfer, ndd->nsarea.config_size); + return -ENXIO; +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 1e5c8220e365ca..97ab91a479d112 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3429,6 +3429,9 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1217, 0x8760), /* O2 Micro 64GB Steam Deck */ + .driver_data = NVME_QUIRK_DMAPOOL_ALIGN_512, }, ++ { PCI_DEVICE(0x126f, 0x1001), /* Silicon Motion generic */ ++ .driver_data = NVME_QUIRK_NO_DEEPEST_PS | ++ NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x126f, 0x2262), /* Silicon Motion generic */ + .driver_data = NVME_QUIRK_NO_DEEPEST_PS | + NVME_QUIRK_BOGUS_NID, }, +@@ -3452,6 +3455,9 @@ static const struct pci_device_id nvme_id_table[] = { + NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x15b7, 0x5008), /* Sandisk SN530 */ + .driver_data = NVME_QUIRK_BROKEN_MSI }, ++ { PCI_DEVICE(0x15b7, 0x5009), /* Sandisk SN550 */ ++ .driver_data = NVME_QUIRK_BROKEN_MSI | ++ NVME_QUIRK_NO_DEEPEST_PS }, + { PCI_DEVICE(0x1987, 0x5012), /* Phison E12 */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1987, 0x5016), /* Phison E16 */ +@@ -3535,6 +3541,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(0x1e49, 0x0041), /* ZHITAI TiPro7000 NVMe SSD */ + .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, ++ { PCI_DEVICE(0x025e, 0xf1ac), /* SOLIDIGM P44 pro SSDPFKKW020X7 */ ++ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(0xc0a9, 0x540a), /* Crucial P2 */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1d97, 0x2263), /* Lexar NM610 */ +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index a0af659a4c4a21..6a539c3b8b530e 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -1456,6 +1456,9 @@ static void nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue) + { + struct socket *sock = queue->sock; + ++ if (!queue->state_change) ++ return; ++ + write_lock_bh(&sock->sk->sk_callback_lock); + sock->sk->sk_data_ready = queue->data_ready; + sock->sk->sk_state_change = queue->state_change; +diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c +index 3ea94bc26e8003..dd00cc09ae5ec5 100644 +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -456,9 +456,11 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, + cell->nbits = info->nbits; + cell->np = info->np; + +- if (cell->nbits) ++ if (cell->nbits) { + cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, + BITS_PER_BYTE); ++ cell->raw_len = ALIGN(cell->bytes, nvmem->word_size); ++ } + + if (!IS_ALIGNED(cell->offset, nvmem->stride)) { + dev_err(&nvmem->dev, +@@ -467,6 +469,18 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, + return -EINVAL; + } + ++ if (!IS_ALIGNED(cell->raw_len, nvmem->word_size)) { ++ dev_err(&nvmem->dev, ++ "cell %s raw len %zd unaligned to nvmem word size %d\n", ++ cell->name ?: "", cell->raw_len, ++ nvmem->word_size); ++ ++ if (info->raw_len) ++ return -EINVAL; ++ ++ cell->raw_len = ALIGN(cell->raw_len, nvmem->word_size); ++ } ++ + return 0; + } + +diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c +index 6c554040c6e67d..7b0621fdbc82e2 100644 +--- a/drivers/nvmem/qfprom.c ++++ b/drivers/nvmem/qfprom.c +@@ -321,19 +321,32 @@ static int qfprom_reg_read(void *context, + unsigned int reg, void *_val, size_t bytes) + { + struct qfprom_priv *priv = context; +- u8 *val = _val; +- int i = 0, words = bytes; ++ u32 *val = _val; + void __iomem *base = priv->qfpcorrected; ++ int words = DIV_ROUND_UP(bytes, sizeof(u32)); ++ int i; + + if (read_raw_data && priv->qfpraw) + base = priv->qfpraw; + +- while (words--) +- *val++ = readb(base + reg + i++); ++ for (i = 0; i < words; i++) ++ *val++ = readl(base + reg + i * sizeof(u32)); + + return 0; + } + ++/* Align reads to word boundary */ ++static void qfprom_fixup_dt_cell_info(struct nvmem_device *nvmem, ++ struct nvmem_cell_info *cell) ++{ ++ unsigned int byte_offset = cell->offset % sizeof(u32); ++ ++ cell->bit_offset += byte_offset * BITS_PER_BYTE; ++ cell->offset -= byte_offset; ++ if (byte_offset && !cell->nbits) ++ cell->nbits = cell->bytes * BITS_PER_BYTE; ++} ++ + static void qfprom_runtime_disable(void *data) + { + pm_runtime_disable(data); +@@ -358,10 +371,11 @@ static int qfprom_probe(struct platform_device *pdev) + struct nvmem_config econfig = { + .name = "qfprom", + .add_legacy_fixed_of_cells = true, +- .stride = 1, +- .word_size = 1, ++ .stride = 4, ++ .word_size = 4, + .id = NVMEM_DEVID_AUTO, + .reg_read = qfprom_reg_read, ++ .fixup_dt_cell_info = qfprom_fixup_dt_cell_info, + }; + struct device *dev = &pdev->dev; + struct resource *res; +diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c +index 7107d68a2f8c75..c6684ab14e742e 100644 +--- a/drivers/nvmem/rockchip-otp.c ++++ b/drivers/nvmem/rockchip-otp.c +@@ -59,7 +59,6 @@ + #define RK3588_OTPC_AUTO_EN 0x08 + #define RK3588_OTPC_INT_ST 0x84 + #define RK3588_OTPC_DOUT0 0x20 +-#define RK3588_NO_SECURE_OFFSET 0x300 + #define RK3588_NBYTES 4 + #define RK3588_BURST_NUM 1 + #define RK3588_BURST_SHIFT 8 +@@ -69,6 +68,7 @@ + + struct rockchip_data { + int size; ++ int read_offset; + const char * const *clks; + int num_clks; + nvmem_reg_read_t reg_read; +@@ -196,7 +196,7 @@ static int rk3588_otp_read(void *context, unsigned int offset, + addr_start = round_down(offset, RK3588_NBYTES) / RK3588_NBYTES; + addr_end = round_up(offset + bytes, RK3588_NBYTES) / RK3588_NBYTES; + addr_len = addr_end - addr_start; +- addr_start += RK3588_NO_SECURE_OFFSET; ++ addr_start += otp->data->read_offset / RK3588_NBYTES; + + buf = kzalloc(array_size(addr_len, RK3588_NBYTES), GFP_KERNEL); + if (!buf) +@@ -273,12 +273,21 @@ static const struct rockchip_data px30_data = { + .reg_read = px30_otp_read, + }; + ++static const struct rockchip_data rk3576_data = { ++ .size = 0x100, ++ .read_offset = 0x700, ++ .clks = px30_otp_clocks, ++ .num_clks = ARRAY_SIZE(px30_otp_clocks), ++ .reg_read = rk3588_otp_read, ++}; ++ + static const char * const rk3588_otp_clocks[] = { + "otp", "apb_pclk", "phy", "arb", + }; + + static const struct rockchip_data rk3588_data = { + .size = 0x400, ++ .read_offset = 0xc00, + .clks = rk3588_otp_clocks, + .num_clks = ARRAY_SIZE(rk3588_otp_clocks), + .reg_read = rk3588_otp_read, +@@ -293,6 +302,10 @@ static const struct of_device_id rockchip_otp_match[] = { + .compatible = "rockchip,rk3308-otp", + .data = &px30_data, + }, ++ { ++ .compatible = "rockchip,rk3576-otp", ++ .data = &rk3576_data, ++ }, + { + .compatible = "rockchip,rk3588-otp", + .data = &rk3588_data, +diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig +index e9ae66cc4189b1..a3927daebeb024 100644 +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -180,6 +180,12 @@ config PCI_P2PDMA + P2P DMA transactions must be between devices behind the same root + port. + ++ Enabling this option will reduce the entropy of x86 KASLR memory ++ regions. For example - on a 46 bit system, the entropy goes down ++ from 16 bits to 15 bits. The actual reduction in entropy depends ++ on the physical address bits, on processor features, kernel config ++ (5 level page table) and physical memory present on the system. ++ + If unsure, say N. + + config PCI_LABEL +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index f2e5feba552678..26ad643fb42484 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -281,7 +281,7 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr, + u32 index; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + +- for (index = 0; index < pci->num_ob_windows; index++) { ++ for_each_set_bit(index, ep->ob_window_map, pci->num_ob_windows) { + if (ep->outbound_addr[index] != addr) + continue; + *atu_index = index; +diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c +index 940af934ce1bb8..9bcf4c68058eb3 100644 +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -284,8 +284,8 @@ static int brcm_pcie_encode_ibar_size(u64 size) + if (log2_in >= 12 && log2_in <= 15) + /* Covers 4KB to 32KB (inclusive) */ + return (log2_in - 12) + 0x1c; +- else if (log2_in >= 16 && log2_in <= 35) +- /* Covers 64KB to 32GB, (inclusive) */ ++ else if (log2_in >= 16 && log2_in <= 36) ++ /* Covers 64KB to 64GB, (inclusive) */ + return log2_in - 15; + /* Something is awry so disable */ + return 0; +@@ -1632,3 +1632,4 @@ module_platform_driver(brcm_pcie_driver); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Broadcom STB PCIe RC driver"); + MODULE_AUTHOR("Broadcom"); ++MODULE_SOFTDEP("pre: irq_bcm2712_mip"); +diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c +index dfa222e02c4da9..ad82feff0405ee 100644 +--- a/drivers/pci/controller/vmd.c ++++ b/drivers/pci/controller/vmd.c +@@ -17,6 +17,8 @@ + #include + #include + ++#include ++ + #include + + #define VMD_CFGBAR 0 +@@ -981,6 +983,24 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) + struct vmd_dev *vmd; + int err; + ++ if (xen_domain()) { ++ /* ++ * Xen doesn't have knowledge about devices in the VMD bus ++ * because the config space of devices behind the VMD bridge is ++ * not known to Xen, and hence Xen cannot discover or configure ++ * them in any way. ++ * ++ * Bypass of MSI remapping won't work in that case as direct ++ * write by Linux to the MSI entries won't result in functional ++ * interrupts, as Xen is the entity that manages the host ++ * interrupt controller and must configure interrupts. However ++ * multiplexing of interrupts by the VMD bridge will work under ++ * Xen, so force the usage of that mode which must always be ++ * supported by VMD bridges. ++ */ ++ features &= ~VMD_FEAT_CAN_BYPASS_MSI_REMAP; ++ } ++ + if (resource_size(&dev->resource[VMD_CFGBAR]) < (1 << 20)) + return -ENOMEM; + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index fba402f4f6330d..3f40be417856e0 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -802,11 +802,9 @@ static resource_size_t calculate_iosize(resource_size_t size, + size = (size & 0xff) + ((size & ~0xffUL) << 2); + #endif + size = size + size1; +- if (size < old_size) +- size = old_size; + +- size = ALIGN(max(size, add_size) + children_add_size, align); +- return size; ++ size = max(size, add_size) + children_add_size; ++ return ALIGN(max(size, old_size), align); + } + + static resource_size_t calculate_memsize(resource_size_t size, +diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c +index 7bd1733d797703..77aa37de59880f 100644 +--- a/drivers/perf/arm-cmn.c ++++ b/drivers/perf/arm-cmn.c +@@ -684,8 +684,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj, + + if ((chan == 5 && cmn->rsp_vc_num < 2) || + (chan == 6 && cmn->dat_vc_num < 2) || +- (chan == 7 && cmn->snp_vc_num < 2) || +- (chan == 8 && cmn->req_vc_num < 2)) ++ (chan == 7 && cmn->req_vc_num < 2) || ++ (chan == 8 && cmn->snp_vc_num < 2)) + return 0; + } + +@@ -841,8 +841,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj, + _CMN_EVENT_XP(pub_##_name, (_event) | (4 << 5)), \ + _CMN_EVENT_XP(rsp2_##_name, (_event) | (5 << 5)), \ + _CMN_EVENT_XP(dat2_##_name, (_event) | (6 << 5)), \ +- _CMN_EVENT_XP(snp2_##_name, (_event) | (7 << 5)), \ +- _CMN_EVENT_XP(req2_##_name, (_event) | (8 << 5)) ++ _CMN_EVENT_XP(req2_##_name, (_event) | (7 << 5)), \ ++ _CMN_EVENT_XP(snp2_##_name, (_event) | (8 << 5)) + + #define CMN_EVENT_XP_DAT(_name, _event) \ + _CMN_EVENT_XP_PORT(dat_##_name, (_event) | (3 << 5)), \ +@@ -2443,6 +2443,7 @@ static int arm_cmn_probe(struct platform_device *pdev) + + cmn->dev = &pdev->dev; + cmn->part = (unsigned long)device_get_match_data(cmn->dev); ++ cmn->cpu = cpumask_local_spread(0, dev_to_node(cmn->dev)); + platform_set_drvdata(pdev, cmn); + + if (cmn->part == PART_CMN600 && has_acpi_companion(cmn->dev)) { +@@ -2470,7 +2471,6 @@ static int arm_cmn_probe(struct platform_device *pdev) + if (err) + return err; + +- cmn->cpu = cpumask_local_spread(0, dev_to_node(cmn->dev)); + cmn->pmu = (struct pmu) { + .module = THIS_MODULE, + .attr_groups = arm_cmn_attr_groups, +diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c +index 0e8f54168cb641..0858e6096453ef 100644 +--- a/drivers/perf/arm_pmuv3.c ++++ b/drivers/perf/arm_pmuv3.c +@@ -751,10 +751,10 @@ static void armv8pmu_start(struct arm_pmu *cpu_pmu) + else + armv8pmu_disable_user_access(); + ++ kvm_vcpu_pmu_resync_el0(); ++ + /* Enable all counters */ + armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E); +- +- kvm_vcpu_pmu_resync_el0(); + } + + static void armv8pmu_stop(struct arm_pmu *cpu_pmu) +diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c +index a892e1d7e2d024..9417372a015547 100644 +--- a/drivers/phy/phy-core.c ++++ b/drivers/phy/phy-core.c +@@ -400,13 +400,14 @@ EXPORT_SYMBOL_GPL(phy_power_off); + + int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode) + { +- int ret; ++ int ret = 0; + +- if (!phy || !phy->ops->set_mode) ++ if (!phy) + return 0; + + mutex_lock(&phy->mutex); +- ret = phy->ops->set_mode(phy, mode, submode); ++ if (phy->ops->set_mode) ++ ret = phy->ops->set_mode(phy, mode, submode); + if (!ret) + phy->attrs.mode = mode; + mutex_unlock(&phy->mutex); +diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +index aa578be2bcb6df..9a6391361a0bed 100644 +--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c ++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +@@ -9,6 +9,7 @@ + * Copyright (C) 2014 Cogent Embedded, Inc. + */ + ++#include + #include + #include + #include +@@ -19,12 +20,14 @@ + #include + #include + #include ++#include + #include + #include + #include + + /******* USB2.0 Host registers (original offset is +0x200) *******/ + #define USB2_INT_ENABLE 0x000 ++#define USB2_AHB_BUS_CTR 0x008 + #define USB2_USBCTR 0x00c + #define USB2_SPD_RSM_TIMSET 0x10c + #define USB2_OC_TIMSET 0x110 +@@ -40,6 +43,10 @@ + #define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) /* For EHCI */ + #define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) /* For OHCI */ + ++/* AHB_BUS_CTR */ ++#define USB2_AHB_BUS_CTR_MBL_MASK GENMASK(1, 0) ++#define USB2_AHB_BUS_CTR_MBL_INCR4 2 ++ + /* USBCTR */ + #define USB2_USBCTR_DIRPD BIT(2) + #define USB2_USBCTR_PLL_RST BIT(1) +@@ -110,10 +117,10 @@ struct rcar_gen3_chan { + struct extcon_dev *extcon; + struct rcar_gen3_phy rphys[NUM_OF_PHYS]; + struct regulator *vbus; ++ struct reset_control *rstc; + struct work_struct work; +- struct mutex lock; /* protects rphys[...].powered */ ++ spinlock_t lock; /* protects access to hardware and driver data structure. */ + enum usb_dr_mode dr_mode; +- int irq; + u32 obint_enable_bits; + bool extcon_host; + bool is_otg_channel; +@@ -124,6 +131,7 @@ struct rcar_gen3_chan { + struct rcar_gen3_phy_drv_data { + const struct phy_ops *phy_usb2_ops; + bool no_adp_ctrl; ++ bool init_bus; + }; + + /* +@@ -338,6 +346,8 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, + bool is_b_device; + enum phy_mode cur_mode, new_mode; + ++ guard(spinlock_irqsave)(&ch->lock); ++ + if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) + return -EIO; + +@@ -405,7 +415,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + } +- msleep(20); ++ mdelay(20); + + writel(0xffffffff, usb2_base + USB2_OBINTSTA); + writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN); +@@ -417,16 +427,27 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) + { + struct rcar_gen3_chan *ch = _ch; + void __iomem *usb2_base = ch->base; +- u32 status = readl(usb2_base + USB2_OBINTSTA); ++ struct device *dev = ch->dev; + irqreturn_t ret = IRQ_NONE; ++ u32 status; ++ ++ pm_runtime_get_noresume(dev); ++ ++ if (pm_runtime_suspended(dev)) ++ goto rpm_put; + +- if (status & ch->obint_enable_bits) { +- dev_vdbg(ch->dev, "%s: %08x\n", __func__, status); +- writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); +- rcar_gen3_device_recognition(ch); +- ret = IRQ_HANDLED; ++ scoped_guard(spinlock, &ch->lock) { ++ status = readl(usb2_base + USB2_OBINTSTA); ++ if (status & ch->obint_enable_bits) { ++ dev_vdbg(dev, "%s: %08x\n", __func__, status); ++ writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); ++ rcar_gen3_device_recognition(ch); ++ ret = IRQ_HANDLED; ++ } + } + ++rpm_put: ++ pm_runtime_put_noidle(dev); + return ret; + } + +@@ -436,17 +457,8 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) + struct rcar_gen3_chan *channel = rphy->ch; + void __iomem *usb2_base = channel->base; + u32 val; +- int ret; + +- if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) { +- INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); +- ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq, +- IRQF_SHARED, dev_name(channel->dev), channel); +- if (ret < 0) { +- dev_err(channel->dev, "No irq handler (%d)\n", channel->irq); +- return ret; +- } +- } ++ guard(spinlock_irqsave)(&channel->lock); + + /* Initialize USB2 part */ + val = readl(usb2_base + USB2_INT_ENABLE); +@@ -474,6 +486,8 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) + void __iomem *usb2_base = channel->base; + u32 val; + ++ guard(spinlock_irqsave)(&channel->lock); ++ + rphy->initialized = false; + + val = readl(usb2_base + USB2_INT_ENABLE); +@@ -482,9 +496,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) + val &= ~USB2_INT_ENABLE_UCOM_INTEN; + writel(val, usb2_base + USB2_INT_ENABLE); + +- if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel)) +- free_irq(channel->irq, channel); +- + return 0; + } + +@@ -496,16 +507,17 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) + u32 val; + int ret = 0; + +- mutex_lock(&channel->lock); +- if (!rcar_gen3_are_all_rphys_power_off(channel)) +- goto out; +- + if (channel->vbus) { + ret = regulator_enable(channel->vbus); + if (ret) +- goto out; ++ return ret; + } + ++ guard(spinlock_irqsave)(&channel->lock); ++ ++ if (!rcar_gen3_are_all_rphys_power_off(channel)) ++ goto out; ++ + val = readl(usb2_base + USB2_USBCTR); + val |= USB2_USBCTR_PLL_RST; + writel(val, usb2_base + USB2_USBCTR); +@@ -515,7 +527,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) + out: + /* The powered flag should be set for any other phys anyway */ + rphy->powered = true; +- mutex_unlock(&channel->lock); + + return 0; + } +@@ -526,18 +537,20 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p) + struct rcar_gen3_chan *channel = rphy->ch; + int ret = 0; + +- mutex_lock(&channel->lock); +- rphy->powered = false; ++ scoped_guard(spinlock_irqsave, &channel->lock) { ++ rphy->powered = false; + +- if (!rcar_gen3_are_all_rphys_power_off(channel)) +- goto out; ++ if (rcar_gen3_are_all_rphys_power_off(channel)) { ++ u32 val = readl(channel->base + USB2_USBCTR); ++ ++ val |= USB2_USBCTR_PLL_RST; ++ writel(val, channel->base + USB2_USBCTR); ++ } ++ } + + if (channel->vbus) + ret = regulator_disable(channel->vbus); + +-out: +- mutex_unlock(&channel->lock); +- + return ret; + } + +@@ -645,13 +658,42 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) + return candidate; + } + ++static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) ++{ ++ struct device *dev = channel->dev; ++ int ret; ++ u32 val; ++ ++ channel->rstc = devm_reset_control_array_get_shared(dev); ++ if (IS_ERR(channel->rstc)) ++ return PTR_ERR(channel->rstc); ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret) ++ return ret; ++ ++ ret = reset_control_deassert(channel->rstc); ++ if (ret) ++ goto rpm_put; ++ ++ val = readl(channel->base + USB2_AHB_BUS_CTR); ++ val &= ~USB2_AHB_BUS_CTR_MBL_MASK; ++ val |= USB2_AHB_BUS_CTR_MBL_INCR4; ++ writel(val, channel->base + USB2_AHB_BUS_CTR); ++ ++rpm_put: ++ pm_runtime_put(dev); ++ ++ return ret; ++} ++ + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + { + const struct rcar_gen3_phy_drv_data *phy_data; + struct device *dev = &pdev->dev; + struct rcar_gen3_chan *channel; + struct phy_provider *provider; +- int ret = 0, i; ++ int ret = 0, i, irq; + + if (!dev->of_node) { + dev_err(dev, "This driver needs device tree\n"); +@@ -667,8 +709,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + return PTR_ERR(channel->base); + + channel->obint_enable_bits = USB2_OBINT_BITS; +- /* get irq number here and request_irq for OTG in phy_init */ +- channel->irq = platform_get_irq_optional(pdev, 0); + channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); + if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { + channel->is_otg_channel = true; +@@ -698,11 +738,20 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + goto error; + } + ++ platform_set_drvdata(pdev, channel); ++ channel->dev = dev; ++ ++ if (phy_data->init_bus) { ++ ret = rcar_gen3_phy_usb2_init_bus(channel); ++ if (ret) ++ goto error; ++ } ++ + channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl; + if (phy_data->no_adp_ctrl) + channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; + +- mutex_init(&channel->lock); ++ spin_lock_init(&channel->lock); + for (i = 0; i < NUM_OF_PHYS; i++) { + channel->rphys[i].phy = devm_phy_create(dev, NULL, + phy_data->phy_usb2_ops); +@@ -725,8 +774,19 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + channel->vbus = NULL; + } + +- platform_set_drvdata(pdev, channel); +- channel->dev = dev; ++ irq = platform_get_irq_optional(pdev, 0); ++ if (irq < 0 && irq != -ENXIO) { ++ ret = irq; ++ goto error; ++ } else if (irq > 0) { ++ INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); ++ ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, ++ IRQF_SHARED, dev_name(dev), channel); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request irq (%d)\n", irq); ++ goto error; ++ } ++ } + + provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate); + if (IS_ERR(provider)) { +@@ -754,6 +814,7 @@ static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev) + if (channel->is_otg_channel) + device_remove_file(&pdev->dev, &dev_attr_role); + ++ reset_control_assert(channel->rstc); + pm_runtime_disable(&pdev->dev); + }; + +diff --git a/drivers/phy/starfive/phy-jh7110-usb.c b/drivers/phy/starfive/phy-jh7110-usb.c +index 633912f8a05d04..bf52b41110db8e 100644 +--- a/drivers/phy/starfive/phy-jh7110-usb.c ++++ b/drivers/phy/starfive/phy-jh7110-usb.c +@@ -16,6 +16,8 @@ + #include + + #define USB_125M_CLK_RATE 125000000 ++#define USB_CLK_MODE_OFF 0x0 ++#define USB_CLK_MODE_RX_NORMAL_PWR BIT(1) + #define USB_LS_KEEPALIVE_OFF 0x4 + #define USB_LS_KEEPALIVE_ENABLE BIT(4) + +@@ -68,6 +70,7 @@ static int jh7110_usb2_phy_init(struct phy *_phy) + { + struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); + int ret; ++ unsigned int val; + + ret = clk_set_rate(phy->usb_125m_clk, USB_125M_CLK_RATE); + if (ret) +@@ -77,6 +80,10 @@ static int jh7110_usb2_phy_init(struct phy *_phy) + if (ret) + return ret; + ++ val = readl(phy->regs + USB_CLK_MODE_OFF); ++ val |= USB_CLK_MODE_RX_NORMAL_PWR; ++ writel(val, phy->regs + USB_CLK_MODE_OFF); ++ + return 0; + } + +diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +index cf6efa9c0364a1..a039b490cdb8e6 100644 +--- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +@@ -72,7 +72,7 @@ static enum bcm281xx_pin_type hdmi_pin = BCM281XX_PIN_TYPE_HDMI; + struct bcm281xx_pin_function { + const char *name; + const char * const *groups; +- const unsigned ngroups; ++ const unsigned int ngroups; + }; + + /* +@@ -84,10 +84,10 @@ struct bcm281xx_pinctrl_data { + + /* List of all pins */ + const struct pinctrl_pin_desc *pins; +- const unsigned npins; ++ const unsigned int npins; + + const struct bcm281xx_pin_function *functions; +- const unsigned nfunctions; ++ const unsigned int nfunctions; + + struct regmap *regmap; + }; +@@ -941,7 +941,7 @@ static struct bcm281xx_pinctrl_data bcm281xx_pinctrl = { + }; + + static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, +- unsigned pin) ++ unsigned int pin) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -985,7 +985,7 @@ static int bcm281xx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) + } + + static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, +- unsigned group) ++ unsigned int group) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -993,9 +993,9 @@ static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, +- unsigned group, ++ unsigned int group, + const unsigned **pins, +- unsigned *num_pins) ++ unsigned int *num_pins) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -1007,7 +1007,7 @@ static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + + static void bcm281xx_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, +- unsigned offset) ++ unsigned int offset) + { + seq_printf(s, " %s", dev_name(pctldev->dev)); + } +@@ -1029,7 +1029,7 @@ static int bcm281xx_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev) + } + + static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, +- unsigned function) ++ unsigned int function) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -1037,9 +1037,9 @@ static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, +- unsigned function, ++ unsigned int function, + const char * const **groups, +- unsigned * const num_groups) ++ unsigned int * const num_groups) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -1050,8 +1050,8 @@ static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, +- unsigned function, +- unsigned group) ++ unsigned int function, ++ unsigned int group) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + const struct bcm281xx_pin_function *f = &pdata->functions[function]; +@@ -1082,7 +1082,7 @@ static const struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = { + }; + + static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *config) + { + return -ENOTSUPP; +@@ -1091,9 +1091,9 @@ static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, + + /* Goes through the configs and update register val/mask */ + static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs, ++ unsigned int num_configs, + u32 *val, + u32 *mask) + { +@@ -1207,9 +1207,9 @@ static const u16 bcm281xx_pullup_map[] = { + + /* Goes through the configs and update register val/mask */ + static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs, ++ unsigned int num_configs, + u32 *val, + u32 *mask) + { +@@ -1277,9 +1277,9 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, + + /* Goes through the configs and update register val/mask */ + static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs, ++ unsigned int num_configs, + u32 *val, + u32 *mask) + { +@@ -1321,9 +1321,9 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs) ++ unsigned int num_configs) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + enum bcm281xx_pin_type pin_type; +diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c +index 5ee746cb81f591..6520b88db1105b 100644 +--- a/drivers/pinctrl/devicetree.c ++++ b/drivers/pinctrl/devicetree.c +@@ -143,10 +143,14 @@ static int dt_to_map_one_config(struct pinctrl *p, + pctldev = get_pinctrl_dev_from_of_node(np_pctldev); + if (pctldev) + break; +- /* Do not defer probing of hogs (circular loop) */ ++ /* ++ * Do not defer probing of hogs (circular loop) ++ * ++ * Return 1 to let the caller catch the case. ++ */ + if (np_pctldev == p->dev->of_node) { + of_node_put(np_pctldev); +- return -ENODEV; ++ return 1; + } + } + of_node_put(np_pctldev); +@@ -265,6 +269,8 @@ int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev) + ret = dt_to_map_one_config(p, pctldev, statename, + np_config); + of_node_put(np_config); ++ if (ret == 1) ++ continue; + if (ret < 0) + goto err; + } +diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c +index 524424ee6c4e71..5cc00fdc48d840 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson.c ++++ b/drivers/pinctrl/meson/pinctrl-meson.c +@@ -486,7 +486,7 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + if (meson_pinconf_get_pull(pc, pin) == param) +- arg = 1; ++ arg = 60000; + else + return -EINVAL; + break; +diff --git a/drivers/pinctrl/qcom/pinctrl-apq8064.c b/drivers/pinctrl/qcom/pinctrl-apq8064.c +index 20c3b902504451..a18df416229993 100644 +--- a/drivers/pinctrl/qcom/pinctrl-apq8064.c ++++ b/drivers/pinctrl/qcom/pinctrl-apq8064.c +@@ -629,7 +629,7 @@ static struct platform_driver apq8064_pinctrl_driver = { + .of_match_table = apq8064_pinctrl_of_match, + }, + .probe = apq8064_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init apq8064_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-apq8084.c b/drivers/pinctrl/qcom/pinctrl-apq8084.c +index 3fc0a40762b631..afada80e52a235 100644 +--- a/drivers/pinctrl/qcom/pinctrl-apq8084.c ++++ b/drivers/pinctrl/qcom/pinctrl-apq8084.c +@@ -1207,7 +1207,7 @@ static struct platform_driver apq8084_pinctrl_driver = { + .of_match_table = apq8084_pinctrl_of_match, + }, + .probe = apq8084_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init apq8084_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c +index 1f7944dd829d1b..cb13576ad6cfb4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c +@@ -710,7 +710,7 @@ static struct platform_driver ipq4019_pinctrl_driver = { + .of_match_table = ipq4019_pinctrl_of_match, + }, + .probe = ipq4019_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq4019_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c +index e2951f81c3eeb3..68f65b57003e91 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c +@@ -754,7 +754,7 @@ static struct platform_driver ipq5018_pinctrl_driver = { + .of_match_table = ipq5018_pinctrl_of_match, + }, + .probe = ipq5018_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq5018_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5332.c b/drivers/pinctrl/qcom/pinctrl-ipq5332.c +index 625f8014051f6a..88217511897088 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq5332.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq5332.c +@@ -834,7 +834,7 @@ static struct platform_driver ipq5332_pinctrl_driver = { + .of_match_table = ipq5332_pinctrl_of_match, + }, + .probe = ipq5332_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq5332_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq6018.c b/drivers/pinctrl/qcom/pinctrl-ipq6018.c +index 0ad08647dbcdf0..ac330d8712b5cb 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq6018.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq6018.c +@@ -1080,7 +1080,7 @@ static struct platform_driver ipq6018_pinctrl_driver = { + .of_match_table = ipq6018_pinctrl_of_match, + }, + .probe = ipq6018_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq6018_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c +index e2bb94e86aef6e..e10e1bc4c91131 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c +@@ -631,7 +631,7 @@ static struct platform_driver ipq8064_pinctrl_driver = { + .of_match_table = ipq8064_pinctrl_of_match, + }, + .probe = ipq8064_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq8064_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8074.c b/drivers/pinctrl/qcom/pinctrl-ipq8074.c +index 337f3a1c92c192..fee32c1d1d3e9a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq8074.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq8074.c +@@ -1041,7 +1041,7 @@ static struct platform_driver ipq8074_pinctrl_driver = { + .of_match_table = ipq8074_pinctrl_of_match, + }, + .probe = ipq8074_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq8074_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq9574.c b/drivers/pinctrl/qcom/pinctrl-ipq9574.c +index e2491617b2364a..20ab59cb621bc3 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq9574.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq9574.c +@@ -799,7 +799,7 @@ static struct platform_driver ipq9574_pinctrl_driver = { + .of_match_table = ipq9574_pinctrl_of_match, + }, + .probe = ipq9574_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq9574_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9607.c b/drivers/pinctrl/qcom/pinctrl-mdm9607.c +index e7cd3ef1cf3e81..415d24e16267d0 100644 +--- a/drivers/pinctrl/qcom/pinctrl-mdm9607.c ++++ b/drivers/pinctrl/qcom/pinctrl-mdm9607.c +@@ -1059,7 +1059,7 @@ static struct platform_driver mdm9607_pinctrl_driver = { + .of_match_table = mdm9607_pinctrl_of_match, + }, + .probe = mdm9607_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init mdm9607_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9615.c b/drivers/pinctrl/qcom/pinctrl-mdm9615.c +index 0a2ae383d3d57b..3f2eafea0b2467 100644 +--- a/drivers/pinctrl/qcom/pinctrl-mdm9615.c ++++ b/drivers/pinctrl/qcom/pinctrl-mdm9615.c +@@ -446,7 +446,7 @@ static struct platform_driver mdm9615_pinctrl_driver = { + .of_match_table = mdm9615_pinctrl_of_match, + }, + .probe = mdm9615_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init mdm9615_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c +index b252fc22f64e6b..ed70767ca0f0c9 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -43,7 +43,6 @@ + * @pctrl: pinctrl handle. + * @chip: gpiochip handle. + * @desc: pin controller descriptor +- * @restart_nb: restart notifier block. + * @irq: parent irq for the TLMM irq_chip. + * @intr_target_use_scm: route irq to application cpu using scm calls + * @lock: Spinlock to protect register resources as well +@@ -63,7 +62,6 @@ struct msm_pinctrl { + struct pinctrl_dev *pctrl; + struct gpio_chip chip; + struct pinctrl_desc desc; +- struct notifier_block restart_nb; + + int irq; + +@@ -1424,10 +1422,9 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) + return 0; + } + +-static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, +- void *data) ++static int msm_ps_hold_restart(struct sys_off_data *data) + { +- struct msm_pinctrl *pctrl = container_of(nb, struct msm_pinctrl, restart_nb); ++ struct msm_pinctrl *pctrl = data->cb_data; + + writel(0, pctrl->regs[0] + PS_HOLD_OFFSET); + mdelay(1000); +@@ -1438,7 +1435,11 @@ static struct msm_pinctrl *poweroff_pctrl; + + static void msm_ps_hold_poweroff(void) + { +- msm_ps_hold_restart(&poweroff_pctrl->restart_nb, 0, NULL); ++ struct sys_off_data data = { ++ .cb_data = poweroff_pctrl, ++ }; ++ ++ msm_ps_hold_restart(&data); + } + + static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) +@@ -1448,9 +1449,11 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) + + for (i = 0; i < pctrl->soc->nfunctions; i++) + if (!strcmp(func[i].name, "ps_hold")) { +- pctrl->restart_nb.notifier_call = msm_ps_hold_restart; +- pctrl->restart_nb.priority = 128; +- if (register_restart_handler(&pctrl->restart_nb)) ++ if (devm_register_sys_off_handler(pctrl->dev, ++ SYS_OFF_MODE_RESTART, ++ 128, ++ msm_ps_hold_restart, ++ pctrl)) + dev_err(pctrl->dev, + "failed to setup restart handler.\n"); + poweroff_pctrl = pctrl; +@@ -1547,15 +1550,11 @@ int msm_pinctrl_probe(struct platform_device *pdev, + } + EXPORT_SYMBOL(msm_pinctrl_probe); + +-int msm_pinctrl_remove(struct platform_device *pdev) ++void msm_pinctrl_remove(struct platform_device *pdev) + { + struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); + + gpiochip_remove(&pctrl->chip); +- +- unregister_restart_handler(&pctrl->restart_nb); +- +- return 0; + } + EXPORT_SYMBOL(msm_pinctrl_remove); + +diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h +index 1d2f2e904da190..4968d08a384da9 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm.h ++++ b/drivers/pinctrl/qcom/pinctrl-msm.h +@@ -166,6 +166,6 @@ extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops; + + int msm_pinctrl_probe(struct platform_device *pdev, + const struct msm_pinctrl_soc_data *soc_data); +-int msm_pinctrl_remove(struct platform_device *pdev); ++void msm_pinctrl_remove(struct platform_device *pdev); + + #endif +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8226.c b/drivers/pinctrl/qcom/pinctrl-msm8226.c +index 994619840a706c..90b4004e7faf18 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8226.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8226.c +@@ -638,7 +638,7 @@ static struct platform_driver msm8226_pinctrl_driver = { + .of_match_table = msm8226_pinctrl_of_match, + }, + .probe = msm8226_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8226_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8660.c b/drivers/pinctrl/qcom/pinctrl-msm8660.c +index 999a5f867eb508..dba6d531b4a146 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8660.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8660.c +@@ -981,7 +981,7 @@ static struct platform_driver msm8660_pinctrl_driver = { + .of_match_table = msm8660_pinctrl_of_match, + }, + .probe = msm8660_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8660_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8909.c b/drivers/pinctrl/qcom/pinctrl-msm8909.c +index 756856d20d6b5f..14b17ba9f9061a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8909.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8909.c +@@ -929,7 +929,7 @@ static struct platform_driver msm8909_pinctrl_driver = { + .of_match_table = msm8909_pinctrl_of_match, + }, + .probe = msm8909_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8909_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8916.c b/drivers/pinctrl/qcom/pinctrl-msm8916.c +index cea5c54f92fec1..184dcf8422735b 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8916.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8916.c +@@ -969,7 +969,7 @@ static struct platform_driver msm8916_pinctrl_driver = { + .of_match_table = msm8916_pinctrl_of_match, + }, + .probe = msm8916_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8916_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8953.c b/drivers/pinctrl/qcom/pinctrl-msm8953.c +index 998351bdfee136..c2253821ae8d36 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8953.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8953.c +@@ -1816,7 +1816,7 @@ static struct platform_driver msm8953_pinctrl_driver = { + .of_match_table = msm8953_pinctrl_of_match, + }, + .probe = msm8953_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8953_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8960.c b/drivers/pinctrl/qcom/pinctrl-msm8960.c +index ebe230b3b437cc..6b9148d226e9b8 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8960.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8960.c +@@ -1246,7 +1246,7 @@ static struct platform_driver msm8960_pinctrl_driver = { + .of_match_table = msm8960_pinctrl_of_match, + }, + .probe = msm8960_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8960_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8976.c b/drivers/pinctrl/qcom/pinctrl-msm8976.c +index c30d80e4e98ca6..9a951888e8a1b1 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8976.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8976.c +@@ -1096,7 +1096,7 @@ static struct platform_driver msm8976_pinctrl_driver = { + .of_match_table = msm8976_pinctrl_of_match, + }, + .probe = msm8976_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8976_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8994.c b/drivers/pinctrl/qcom/pinctrl-msm8994.c +index b1a6759ab4a5e7..1ed1dd32d6c795 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8994.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8994.c +@@ -1343,7 +1343,7 @@ static struct platform_driver msm8994_pinctrl_driver = { + .of_match_table = msm8994_pinctrl_of_match, + }, + .probe = msm8994_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8994_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8996.c b/drivers/pinctrl/qcom/pinctrl-msm8996.c +index 46cc0b49dbab52..5f0e7f78fd5178 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8996.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8996.c +@@ -1906,7 +1906,7 @@ static struct platform_driver msm8996_pinctrl_driver = { + .of_match_table = msm8996_pinctrl_of_match, + }, + .probe = msm8996_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8996_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c +index b7cbf32b3125a9..4aaf45e54f3a79 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8998.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c +@@ -1535,7 +1535,7 @@ static struct platform_driver msm8998_pinctrl_driver = { + .of_match_table = msm8998_pinctrl_of_match, + }, + .probe = msm8998_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8998_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8x74.c b/drivers/pinctrl/qcom/pinctrl-msm8x74.c +index d5fe62992849c9..58b4f6f31ae6ae 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8x74.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8x74.c +@@ -1071,7 +1071,7 @@ static struct platform_driver msm8x74_pinctrl_driver = { + .of_match_table = msm8x74_pinctrl_of_match, + }, + .probe = msm8x74_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8x74_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qcm2290.c b/drivers/pinctrl/qcom/pinctrl-qcm2290.c +index ba699eac9ee8b2..f5c1c427b44e91 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qcm2290.c ++++ b/drivers/pinctrl/qcom/pinctrl-qcm2290.c +@@ -1113,7 +1113,7 @@ static struct platform_driver qcm2290_pinctrl_driver = { + .of_match_table = qcm2290_pinctrl_of_match, + }, + .probe = qcm2290_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qcm2290_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c +index ae7224012f8aa0..9a875b7dc9989c 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qcs404.c ++++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c +@@ -1644,7 +1644,7 @@ static struct platform_driver qcs404_pinctrl_driver = { + .of_match_table = qcs404_pinctrl_of_match, + }, + .probe = qcs404_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qcs404_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c +index b5808fcfb13cde..4d2f6f495163bc 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c ++++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c +@@ -145,7 +145,7 @@ static struct platform_driver qdf2xxx_pinctrl_driver = { + .acpi_match_table = qdf2xxx_acpi_ids, + }, + .probe = qdf2xxx_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qdf2xxx_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qdu1000.c b/drivers/pinctrl/qcom/pinctrl-qdu1000.c +index 47bc529ef550d2..da4f940bc8d4e8 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qdu1000.c ++++ b/drivers/pinctrl/qcom/pinctrl-qdu1000.c +@@ -1248,7 +1248,7 @@ static struct platform_driver qdu1000_tlmm_driver = { + .of_match_table = qdu1000_tlmm_of_match, + }, + .probe = qdu1000_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qdu1000_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c +index 8fdea25d8d67e1..5459c0c681a23f 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sa8775p.c ++++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c +@@ -1530,7 +1530,7 @@ static struct platform_driver sa8775p_pinctrl_driver = { + .of_match_table = sa8775p_pinctrl_of_match, + }, + .probe = sa8775p_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sa8775p_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc7180.c b/drivers/pinctrl/qcom/pinctrl-sc7180.c +index 6eb0c73791c0bc..c27aaa599b917a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc7180.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc7180.c +@@ -1159,7 +1159,7 @@ static struct platform_driver sc7180_pinctrl_driver = { + .of_match_table = sc7180_pinctrl_of_match, + }, + .probe = sc7180_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc7180_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c +index 0c10eeb60b55e7..c2db663e396eb4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc7280.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c +@@ -1505,7 +1505,7 @@ static struct platform_driver sc7280_pinctrl_driver = { + .of_match_table = sc7280_pinctrl_of_match, + }, + .probe = sc7280_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc7280_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc8180x.c b/drivers/pinctrl/qcom/pinctrl-sc8180x.c +index d6a79ad41a40a8..cfa7c8be9770c9 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc8180x.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc8180x.c +@@ -1720,7 +1720,7 @@ static struct platform_driver sc8180x_pinctrl_driver = { + .acpi_match_table = sc8180x_pinctrl_acpi_match, + }, + .probe = sc8180x_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc8180x_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c +index 96f4fb5a5d297f..4b1c49697698de 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c +@@ -1926,7 +1926,7 @@ static struct platform_driver sc8280xp_pinctrl_driver = { + .of_match_table = sc8280xp_pinctrl_of_match, + }, + .probe = sc8280xp_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc8280xp_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c +index c2e0d5c034acf6..b0c29a24b09b5a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdm660.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c +@@ -1428,7 +1428,7 @@ static struct platform_driver sdm660_pinctrl_driver = { + .of_match_table = sdm660_pinctrl_of_match, + }, + .probe = sdm660_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdm660_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c +index cc3cce077de4e6..1e694a966953ac 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdm670.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c +@@ -1318,7 +1318,7 @@ static struct platform_driver sdm670_pinctrl_driver = { + .of_match_table = sdm670_pinctrl_of_match, + }, + .probe = sdm670_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdm670_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c +index cc05c415ed1551..3f3265e0018d66 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c +@@ -1351,7 +1351,7 @@ static struct platform_driver sdm845_pinctrl_driver = { + .acpi_match_table = ACPI_PTR(sdm845_pinctrl_acpi_match), + }, + .probe = sdm845_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdm845_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdx55.c b/drivers/pinctrl/qcom/pinctrl-sdx55.c +index 8826db9d21d04c..c88b8bfcacb6a7 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdx55.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdx55.c +@@ -990,7 +990,7 @@ static struct platform_driver sdx55_pinctrl_driver = { + .of_match_table = sdx55_pinctrl_of_match, + }, + .probe = sdx55_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdx55_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdx65.c b/drivers/pinctrl/qcom/pinctrl-sdx65.c +index f6f319c997fc7a..bd44ec0fcab43c 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdx65.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdx65.c +@@ -939,7 +939,7 @@ static struct platform_driver sdx65_pinctrl_driver = { + .of_match_table = sdx65_pinctrl_of_match, + }, + .probe = sdx65_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdx65_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdx75.c b/drivers/pinctrl/qcom/pinctrl-sdx75.c +index 3cfe8c7f04df81..396f6fc779a2e5 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdx75.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdx75.c +@@ -1124,7 +1124,7 @@ static struct platform_driver sdx75_pinctrl_driver = { + .of_match_table = sdx75_pinctrl_of_match, + }, + .probe = sdx75_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdx75_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115.c b/drivers/pinctrl/qcom/pinctrl-sm6115.c +index 2a06025f488584..87057089b2b649 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6115.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6115.c +@@ -895,7 +895,7 @@ static struct platform_driver sm6115_tlmm_driver = { + .of_match_table = sm6115_tlmm_of_match, + }, + .probe = sm6115_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6115_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6125.c b/drivers/pinctrl/qcom/pinctrl-sm6125.c +index d5e2b896954c22..e07339ba72bcac 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6125.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6125.c +@@ -1249,7 +1249,7 @@ static struct platform_driver sm6125_tlmm_driver = { + .of_match_table = sm6125_tlmm_of_match, + }, + .probe = sm6125_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6125_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350.c b/drivers/pinctrl/qcom/pinctrl-sm6350.c +index f3828c07b13450..4aeb1ba43ee3d4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6350.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6350.c +@@ -1373,7 +1373,7 @@ static struct platform_driver sm6350_tlmm_driver = { + .of_match_table = sm6350_tlmm_of_match, + }, + .probe = sm6350_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6350_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6375.c b/drivers/pinctrl/qcom/pinctrl-sm6375.c +index c82c8516932ea2..d86630d7125c2a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6375.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6375.c +@@ -1516,7 +1516,7 @@ static struct platform_driver sm6375_tlmm_driver = { + .of_match_table = sm6375_tlmm_of_match, + }, + .probe = sm6375_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6375_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c +index edb5984cd35190..b9f067de8ef0e4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm7150.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c +@@ -1254,7 +1254,7 @@ static struct platform_driver sm7150_tlmm_driver = { + .of_match_table = sm7150_tlmm_of_match, + }, + .probe = sm7150_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm7150_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c +index 01aea9c70b7a78..f8f5bee74f1dc0 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8150.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c +@@ -1542,7 +1542,7 @@ static struct platform_driver sm8150_pinctrl_driver = { + .of_match_table = sm8150_pinctrl_of_match, + }, + .probe = sm8150_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8150_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c +index e9961a49ff9811..54fda77bf2968c 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c +@@ -1351,7 +1351,7 @@ static struct platform_driver sm8250_pinctrl_driver = { + .of_match_table = sm8250_pinctrl_of_match, + }, + .probe = sm8250_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8250_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8350.c b/drivers/pinctrl/qcom/pinctrl-sm8350.c +index 9c69458bd91091..ac7f2820f2cbfb 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8350.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8350.c +@@ -1642,7 +1642,7 @@ static struct platform_driver sm8350_tlmm_driver = { + .of_match_table = sm8350_tlmm_of_match, + }, + .probe = sm8350_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8350_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450.c b/drivers/pinctrl/qcom/pinctrl-sm8450.c +index d11bb1ee9e3d8d..61728671169527 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8450.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8450.c +@@ -1677,7 +1677,7 @@ static struct platform_driver sm8450_tlmm_driver = { + .of_match_table = sm8450_tlmm_of_match, + }, + .probe = sm8450_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8450_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c +index 3c847d9cb5d93b..9184e0183755da 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8550.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c +@@ -1762,7 +1762,7 @@ static struct platform_driver sm8550_tlmm_driver = { + .of_match_table = sm8550_tlmm_of_match, + }, + .probe = sm8550_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8550_tlmm_init(void) +diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c +index 7c12a3470642c3..637b89ebe0e455 100644 +--- a/drivers/pinctrl/tegra/pinctrl-tegra.c ++++ b/drivers/pinctrl/tegra/pinctrl-tegra.c +@@ -280,8 +280,8 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev, + return 0; + } + +-static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, +- unsigned int offset) ++static int tegra_pinctrl_get_group_index(struct pinctrl_dev *pctldev, ++ unsigned int offset) + { + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + unsigned int group, num_pins, j; +@@ -294,12 +294,35 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev * + continue; + for (j = 0; j < num_pins; j++) { + if (offset == pins[j]) +- return &pmx->soc->groups[group]; ++ return group; + } + } + +- dev_err(pctldev->dev, "Pingroup not found for pin %u\n", offset); +- return NULL; ++ return -EINVAL; ++} ++ ++static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, ++ unsigned int offset, ++ int group_index) ++{ ++ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); ++ ++ if (group_index < 0 || group_index >= pmx->soc->ngroups) ++ return NULL; ++ ++ return &pmx->soc->groups[group_index]; ++} ++ ++static struct tegra_pingroup_config *tegra_pinctrl_get_group_config(struct pinctrl_dev *pctldev, ++ unsigned int offset, ++ int group_index) ++{ ++ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); ++ ++ if (group_index < 0) ++ return NULL; ++ ++ return &pmx->pingroup_configs[group_index]; + } + + static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, +@@ -308,12 +331,15 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + { + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tegra_pingroup *group; ++ struct tegra_pingroup_config *config; ++ int group_index; + u32 value; + + if (!pmx->soc->sfsel_in_mux) + return 0; + +- group = tegra_pinctrl_get_group(pctldev, offset); ++ group_index = tegra_pinctrl_get_group_index(pctldev, offset); ++ group = tegra_pinctrl_get_group(pctldev, offset, group_index); + + if (!group) + return -EINVAL; +@@ -321,7 +347,11 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + if (group->mux_reg < 0 || group->sfsel_bit < 0) + return -EINVAL; + ++ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); ++ if (!config) ++ return -EINVAL; + value = pmx_readl(pmx, group->mux_bank, group->mux_reg); ++ config->is_sfsel = (value & BIT(group->sfsel_bit)) != 0; + value &= ~BIT(group->sfsel_bit); + pmx_writel(pmx, value, group->mux_bank, group->mux_reg); + +@@ -334,12 +364,15 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, + { + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tegra_pingroup *group; ++ struct tegra_pingroup_config *config; ++ int group_index; + u32 value; + + if (!pmx->soc->sfsel_in_mux) + return; + +- group = tegra_pinctrl_get_group(pctldev, offset); ++ group_index = tegra_pinctrl_get_group_index(pctldev, offset); ++ group = tegra_pinctrl_get_group(pctldev, offset, group_index); + + if (!group) + return; +@@ -347,8 +380,12 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, + if (group->mux_reg < 0 || group->sfsel_bit < 0) + return; + ++ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); ++ if (!config) ++ return; + value = pmx_readl(pmx, group->mux_bank, group->mux_reg); +- value |= BIT(group->sfsel_bit); ++ if (config->is_sfsel) ++ value |= BIT(group->sfsel_bit); + pmx_writel(pmx, value, group->mux_bank, group->mux_reg); + } + +@@ -785,6 +822,12 @@ int tegra_pinctrl_probe(struct platform_device *pdev, + pmx->dev = &pdev->dev; + pmx->soc = soc_data; + ++ pmx->pingroup_configs = devm_kcalloc(&pdev->dev, ++ pmx->soc->ngroups, sizeof(*pmx->pingroup_configs), ++ GFP_KERNEL); ++ if (!pmx->pingroup_configs) ++ return -ENOMEM; ++ + /* + * Each mux group will appear in 4 functions' list of groups. + * This over-allocates slightly, since not all groups are mux groups. +diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h +index b3289bdf727d82..b97136685f7a88 100644 +--- a/drivers/pinctrl/tegra/pinctrl-tegra.h ++++ b/drivers/pinctrl/tegra/pinctrl-tegra.h +@@ -8,6 +8,10 @@ + #ifndef __PINMUX_TEGRA_H__ + #define __PINMUX_TEGRA_H__ + ++struct tegra_pingroup_config { ++ bool is_sfsel; ++}; ++ + struct tegra_pmx { + struct device *dev; + struct pinctrl_dev *pctl; +@@ -21,6 +25,8 @@ struct tegra_pmx { + int nbanks; + void __iomem **regs; + u32 *backup_regs; ++ /* Array of size soc->ngroups */ ++ struct tegra_pingroup_config *pingroup_configs; + }; + + enum tegra_pinconf_param { +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c +index 230e6ee966366a..d8f1bf5e58a0f4 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c +@@ -45,7 +45,7 @@ static ssize_t current_password_store(struct kobject *kobj, + int length; + + length = strlen(buf); +- if (buf[length-1] == '\n') ++ if (length && buf[length - 1] == '\n') + length--; + + /* firmware does verifiation of min/max password length, +diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c +index 085e044e888e4e..d7ef4f046d99b5 100644 +--- a/drivers/platform/x86/fujitsu-laptop.c ++++ b/drivers/platform/x86/fujitsu-laptop.c +@@ -17,13 +17,13 @@ + /* + * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional + * features made available on a range of Fujitsu laptops including the +- * P2xxx/P5xxx/S6xxx/S7xxx series. ++ * P2xxx/P5xxx/S2xxx/S6xxx/S7xxx series. + * + * This driver implements a vendor-specific backlight control interface for + * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu + * laptops. + * +- * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and ++ * This driver has been tested on a Fujitsu Lifebook S2110, S6410, S7020 and + * P8010. It should work on most P-series and S-series Lifebooks, but + * YMMV. + * +@@ -102,7 +102,11 @@ + #define KEY2_CODE 0x411 + #define KEY3_CODE 0x412 + #define KEY4_CODE 0x413 +-#define KEY5_CODE 0x420 ++#define KEY5_CODE 0x414 ++#define KEY6_CODE 0x415 ++#define KEY7_CODE 0x416 ++#define KEY8_CODE 0x417 ++#define KEY9_CODE 0x420 + + /* Hotkey ringbuffer limits */ + #define MAX_HOTKEY_RINGBUFFER_SIZE 100 +@@ -450,7 +454,7 @@ static const struct key_entry keymap_default[] = { + { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, + { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, + { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, +- { KE_KEY, KEY5_CODE, { KEY_RFKILL } }, ++ { KE_KEY, KEY9_CODE, { KEY_RFKILL } }, + /* Soft keys read from status flags */ + { KE_KEY, FLAG_RFKILL, { KEY_RFKILL } }, + { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } }, +@@ -474,6 +478,18 @@ static const struct key_entry keymap_p8010[] = { + { KE_END, 0 } + }; + ++static const struct key_entry keymap_s2110[] = { ++ { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, /* "A" */ ++ { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, /* "B" */ ++ { KE_KEY, KEY3_CODE, { KEY_WWW } }, /* "Internet" */ ++ { KE_KEY, KEY4_CODE, { KEY_EMAIL } }, /* "E-mail" */ ++ { KE_KEY, KEY5_CODE, { KEY_STOPCD } }, ++ { KE_KEY, KEY6_CODE, { KEY_PLAYPAUSE } }, ++ { KE_KEY, KEY7_CODE, { KEY_PREVIOUSSONG } }, ++ { KE_KEY, KEY8_CODE, { KEY_NEXTSONG } }, ++ { KE_END, 0 } ++}; ++ + static const struct key_entry *keymap = keymap_default; + + static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id) +@@ -511,6 +527,15 @@ static const struct dmi_system_id fujitsu_laptop_dmi_table[] = { + }, + .driver_data = (void *)keymap_p8010 + }, ++ { ++ .callback = fujitsu_laptop_dmi_keymap_override, ++ .ident = "Fujitsu LifeBook S2110", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S2110"), ++ }, ++ .driver_data = (void *)keymap_s2110 ++ }, + {} + }; + +diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c +index cde5f845cf2557..8de0d3232e48c5 100644 +--- a/drivers/platform/x86/thinkpad_acpi.c ++++ b/drivers/platform/x86/thinkpad_acpi.c +@@ -212,6 +212,7 @@ enum tpacpi_hkey_event_t { + /* Thermal events */ + TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */ + TP_HKEY_EV_ALARM_BAT_XHOT = 0x6012, /* battery critically hot */ ++ TP_HKEY_EV_ALARM_BAT_LIM_CHANGE = 0x6013, /* battery charge limit changed*/ + TP_HKEY_EV_ALARM_SENSOR_HOT = 0x6021, /* sensor too hot */ + TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ + TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* windows; thermal table changed */ +@@ -3942,6 +3943,10 @@ static bool hotkey_notify_6xxx(const u32 hkey, + pr_alert("THERMAL EMERGENCY: battery is extremely hot!\n"); + /* recommended action: immediate sleep/hibernate */ + break; ++ case TP_HKEY_EV_ALARM_BAT_LIM_CHANGE: ++ pr_debug("Battery Info: battery charge threshold changed\n"); ++ /* User changed charging threshold. No action needed */ ++ return true; + case TP_HKEY_EV_ALARM_SENSOR_HOT: + pr_crit("THERMAL ALARM: a sensor reports something is too hot!\n"); + /* recommended action: warn user through gui, that */ +@@ -11315,6 +11320,8 @@ static int __must_check __init get_thinkpad_model_data( + tp->vendor = PCI_VENDOR_ID_IBM; + else if (dmi_name_in_vendors("LENOVO")) + tp->vendor = PCI_VENDOR_ID_LENOVO; ++ else if (dmi_name_in_vendors("NEC")) ++ tp->vendor = PCI_VENDOR_ID_LENOVO; + else + return 0; + +diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c +index 13fce2b134f60a..84d68c805cac85 100644 +--- a/drivers/pmdomain/imx/gpcv2.c ++++ b/drivers/pmdomain/imx/gpcv2.c +@@ -1350,7 +1350,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) + } + + if (IS_ENABLED(CONFIG_LOCKDEP) && +- of_property_read_bool(domain->dev->of_node, "power-domains")) ++ of_property_present(domain->dev->of_node, "power-domains")) + lockdep_set_subclass(&domain->genpd.mlock, 1); + + ret = of_genpd_add_provider_simple(domain->dev->of_node, +diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c +index 40f7dba42b5ad7..404cbe32711e73 100644 +--- a/drivers/regulator/ad5398.c ++++ b/drivers/regulator/ad5398.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #define AD5398_CURRENT_EN_MASK 0x8000 + +@@ -221,15 +222,20 @@ static int ad5398_probe(struct i2c_client *client) + const struct ad5398_current_data_format *df = + (struct ad5398_current_data_format *)id->driver_data; + +- if (!init_data) +- return -EINVAL; +- + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + config.dev = &client->dev; ++ if (client->dev.of_node) ++ init_data = of_get_regulator_init_data(&client->dev, ++ client->dev.of_node, ++ &ad5398_reg); ++ if (!init_data) ++ return -EINVAL; ++ + config.init_data = init_data; ++ config.of_node = client->dev.of_node; + config.driver_data = chip; + + chip->client = client; +diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c +index 90de22c81da976..37174b544113f8 100644 +--- a/drivers/remoteproc/qcom_wcnss.c ++++ b/drivers/remoteproc/qcom_wcnss.c +@@ -117,10 +117,10 @@ static const struct wcnss_data pronto_v1_data = { + .pmu_offset = 0x1004, + .spare_offset = 0x1088, + +- .pd_names = { "mx", "cx" }, ++ .pd_names = { "cx", "mx" }, + .vregs = (struct wcnss_vreg_info[]) { +- { "vddmx", 950000, 1150000, 0 }, + { "vddcx", .super_turbo = true}, ++ { "vddmx", 950000, 1150000, 0 }, + { "vddpx", 1800000, 1800000, 0 }, + }, + .num_pd_vregs = 2, +@@ -131,10 +131,10 @@ static const struct wcnss_data pronto_v2_data = { + .pmu_offset = 0x1004, + .spare_offset = 0x1088, + +- .pd_names = { "mx", "cx" }, ++ .pd_names = { "cx", "mx" }, + .vregs = (struct wcnss_vreg_info[]) { +- { "vddmx", 1287500, 1287500, 0 }, + { "vddcx", .super_turbo = true }, ++ { "vddmx", 1287500, 1287500, 0 }, + { "vddpx", 1800000, 1800000, 0 }, + }, + .num_pd_vregs = 2, +@@ -397,8 +397,17 @@ static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev) + static int wcnss_init_pds(struct qcom_wcnss *wcnss, + const char * const pd_names[WCNSS_MAX_PDS]) + { ++ struct device *dev = wcnss->dev; + int i, ret; + ++ /* Handle single power domain */ ++ if (dev->pm_domain) { ++ wcnss->pds[0] = dev; ++ wcnss->num_pds = 1; ++ pm_runtime_enable(dev); ++ return 0; ++ } ++ + for (i = 0; i < WCNSS_MAX_PDS; i++) { + if (!pd_names[i]) + break; +@@ -418,8 +427,15 @@ static int wcnss_init_pds(struct qcom_wcnss *wcnss, + + static void wcnss_release_pds(struct qcom_wcnss *wcnss) + { ++ struct device *dev = wcnss->dev; + int i; + ++ /* Handle single power domain */ ++ if (wcnss->num_pds == 1 && dev->pm_domain) { ++ pm_runtime_disable(dev); ++ return; ++ } ++ + for (i = 0; i < wcnss->num_pds; i++) + dev_pm_domain_detach(wcnss->pds[i], false); + } +@@ -437,10 +453,14 @@ static int wcnss_init_regulators(struct qcom_wcnss *wcnss, + * the regulators for the power domains. For old device trees we need to + * reserve extra space to manage them through the regulator interface. + */ +- if (wcnss->num_pds) +- info += num_pd_vregs; +- else ++ if (wcnss->num_pds) { ++ info += wcnss->num_pds; ++ /* Handle single power domain case */ ++ if (wcnss->num_pds < num_pd_vregs) ++ num_vregs += num_pd_vregs - wcnss->num_pds; ++ } else { + num_vregs += num_pd_vregs; ++ } + + bulk = devm_kcalloc(wcnss->dev, + num_vregs, sizeof(struct regulator_bulk_data), +diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c +index 506b7d1c239701..0c78451960926d 100644 +--- a/drivers/rtc/rtc-ds1307.c ++++ b/drivers/rtc/rtc-ds1307.c +@@ -1802,10 +1802,8 @@ static int ds1307_probe(struct i2c_client *client) + * For some variants, be sure alarms can trigger when we're + * running on Vbackup (BBSQI/BBSQW) + */ +- if (want_irq || ds1307_can_wakeup_device) { ++ if (want_irq || ds1307_can_wakeup_device) + regs[0] |= DS1337_BIT_INTCN | chip->bbsqi_bit; +- regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); +- } + + regmap_write(ds1307->regmap, DS1337_REG_CONTROL, + regs[0]); +diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c +index 35b2e36b426a0d..cb01038a2e27fe 100644 +--- a/drivers/rtc/rtc-rv3032.c ++++ b/drivers/rtc/rtc-rv3032.c +@@ -69,7 +69,7 @@ + #define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5) + #define RV3032_CLKOUT2_OS BIT(7) + +-#define RV3032_CTRL1_EERD BIT(3) ++#define RV3032_CTRL1_EERD BIT(2) + #define RV3032_CTRL1_WADA BIT(5) + + #define RV3032_CTRL2_STOP BIT(0) +diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c +index d6ea2fd4c2a02b..d4151f519e8b22 100644 +--- a/drivers/s390/crypto/vfio_ap_ops.c ++++ b/drivers/s390/crypto/vfio_ap_ops.c +@@ -834,48 +834,66 @@ static void vfio_ap_mdev_remove(struct mdev_device *mdev) + vfio_put_device(&matrix_mdev->vdev); + } + +-#define MDEV_SHARING_ERR "Userspace may not re-assign queue %02lx.%04lx " \ +- "already assigned to %s" ++#define MDEV_SHARING_ERR "Userspace may not assign queue %02lx.%04lx to mdev: already assigned to %s" + +-static void vfio_ap_mdev_log_sharing_err(struct ap_matrix_mdev *matrix_mdev, +- unsigned long *apm, +- unsigned long *aqm) ++#define MDEV_IN_USE_ERR "Can not reserve queue %02lx.%04lx for host driver: in use by mdev" ++ ++static void vfio_ap_mdev_log_sharing_err(struct ap_matrix_mdev *assignee, ++ struct ap_matrix_mdev *assigned_to, ++ unsigned long *apm, unsigned long *aqm) + { + unsigned long apid, apqi; +- const struct device *dev = mdev_dev(matrix_mdev->mdev); +- const char *mdev_name = dev_name(dev); + +- for_each_set_bit_inv(apid, apm, AP_DEVICES) ++ for_each_set_bit_inv(apid, apm, AP_DEVICES) { ++ for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) { ++ dev_warn(mdev_dev(assignee->mdev), MDEV_SHARING_ERR, ++ apid, apqi, dev_name(mdev_dev(assigned_to->mdev))); ++ } ++ } ++} ++ ++static void vfio_ap_mdev_log_in_use_err(struct ap_matrix_mdev *assignee, ++ unsigned long *apm, unsigned long *aqm) ++{ ++ unsigned long apid, apqi; ++ ++ for_each_set_bit_inv(apid, apm, AP_DEVICES) { + for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) +- dev_warn(dev, MDEV_SHARING_ERR, apid, apqi, mdev_name); ++ dev_warn(mdev_dev(assignee->mdev), MDEV_IN_USE_ERR, apid, apqi); ++ } + } + + /** + * vfio_ap_mdev_verify_no_sharing - verify APQNs are not shared by matrix mdevs + * ++ * @assignee: the matrix mdev to which @mdev_apm and @mdev_aqm are being ++ * assigned; or, NULL if this function was called by the AP bus ++ * driver in_use callback to verify none of the APQNs being reserved ++ * for the host device driver are in use by a vfio_ap mediated device + * @mdev_apm: mask indicating the APIDs of the APQNs to be verified + * @mdev_aqm: mask indicating the APQIs of the APQNs to be verified + * +- * Verifies that each APQN derived from the Cartesian product of a bitmap of +- * AP adapter IDs and AP queue indexes is not configured for any matrix +- * mediated device. AP queue sharing is not allowed. ++ * Verifies that each APQN derived from the Cartesian product of APIDs ++ * represented by the bits set in @mdev_apm and the APQIs of the bits set in ++ * @mdev_aqm is not assigned to a mediated device other than the mdev to which ++ * the APQN is being assigned (@assignee). AP queue sharing is not allowed. + * + * Return: 0 if the APQNs are not shared; otherwise return -EADDRINUSE. + */ +-static int vfio_ap_mdev_verify_no_sharing(unsigned long *mdev_apm, ++static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *assignee, ++ unsigned long *mdev_apm, + unsigned long *mdev_aqm) + { +- struct ap_matrix_mdev *matrix_mdev; ++ struct ap_matrix_mdev *assigned_to; + DECLARE_BITMAP(apm, AP_DEVICES); + DECLARE_BITMAP(aqm, AP_DOMAINS); + +- list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) { ++ list_for_each_entry(assigned_to, &matrix_dev->mdev_list, node) { + /* +- * If the input apm and aqm are fields of the matrix_mdev +- * object, then move on to the next matrix_mdev. ++ * If the mdev to which the mdev_apm and mdev_aqm is being ++ * assigned is the same as the mdev being verified + */ +- if (mdev_apm == matrix_mdev->matrix.apm && +- mdev_aqm == matrix_mdev->matrix.aqm) ++ if (assignee == assigned_to) + continue; + + memset(apm, 0, sizeof(apm)); +@@ -885,15 +903,16 @@ static int vfio_ap_mdev_verify_no_sharing(unsigned long *mdev_apm, + * We work on full longs, as we can only exclude the leftover + * bits in non-inverse order. The leftover is all zeros. + */ +- if (!bitmap_and(apm, mdev_apm, matrix_mdev->matrix.apm, +- AP_DEVICES)) ++ if (!bitmap_and(apm, mdev_apm, assigned_to->matrix.apm, AP_DEVICES)) + continue; + +- if (!bitmap_and(aqm, mdev_aqm, matrix_mdev->matrix.aqm, +- AP_DOMAINS)) ++ if (!bitmap_and(aqm, mdev_aqm, assigned_to->matrix.aqm, AP_DOMAINS)) + continue; + +- vfio_ap_mdev_log_sharing_err(matrix_mdev, apm, aqm); ++ if (assignee) ++ vfio_ap_mdev_log_sharing_err(assignee, assigned_to, apm, aqm); ++ else ++ vfio_ap_mdev_log_in_use_err(assigned_to, apm, aqm); + + return -EADDRINUSE; + } +@@ -922,7 +941,8 @@ static int vfio_ap_mdev_validate_masks(struct ap_matrix_mdev *matrix_mdev) + matrix_mdev->matrix.aqm)) + return -EADDRNOTAVAIL; + +- return vfio_ap_mdev_verify_no_sharing(matrix_mdev->matrix.apm, ++ return vfio_ap_mdev_verify_no_sharing(matrix_mdev, ++ matrix_mdev->matrix.apm, + matrix_mdev->matrix.aqm); + } + +@@ -2271,7 +2291,7 @@ int vfio_ap_mdev_resource_in_use(unsigned long *apm, unsigned long *aqm) + + mutex_lock(&matrix_dev->guests_lock); + mutex_lock(&matrix_dev->mdevs_lock); +- ret = vfio_ap_mdev_verify_no_sharing(apm, aqm); ++ ret = vfio_ap_mdev_verify_no_sharing(NULL, apm, aqm); + mutex_unlock(&matrix_dev->mdevs_lock); + mutex_unlock(&matrix_dev->guests_lock); + +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 0ad8a10002ce36..5c9bc8af3c2df8 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -5646,6 +5646,7 @@ static struct lpfc_nodelist * + __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) + { + struct lpfc_nodelist *ndlp; ++ struct lpfc_nodelist *np = NULL; + uint32_t data1; + + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { +@@ -5660,14 +5661,20 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) + ndlp, ndlp->nlp_DID, + ndlp->nlp_flag, data1, ndlp->nlp_rpi, + ndlp->active_rrqs_xri_bitmap); +- return ndlp; ++ ++ /* Check for new or potentially stale node */ ++ if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) ++ return ndlp; ++ np = ndlp; + } + } + +- /* FIND node did NOT FOUND */ +- lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, +- "0932 FIND node did x%x NOT FOUND.\n", did); +- return NULL; ++ if (!np) ++ /* FIND node did NOT FOUND */ ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, ++ "0932 FIND node did x%x NOT FOUND.\n", did); ++ ++ return np; + } + + struct lpfc_nodelist * +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index 424b39a8155cb9..7c8e0e1d36da9b 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -13180,6 +13180,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) + eqhdl = lpfc_get_eq_hdl(0); + rc = pci_irq_vector(phba->pcidev, 0); + if (rc < 0) { ++ free_irq(phba->pcidev->irq, phba); + pci_free_irq_vectors(phba->pcidev); + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0496 MSI pci_irq_vec failed (%d)\n", rc); +@@ -13260,6 +13261,7 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) + eqhdl = lpfc_get_eq_hdl(0); + retval = pci_irq_vector(phba->pcidev, 0); + if (retval < 0) { ++ free_irq(phba->pcidev->irq, phba); + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0502 INTR pci_irq_vec failed (%d)\n", + retval); +diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c +index 0d148c39ebcc98..60714a6c26375e 100644 +--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c ++++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c +@@ -174,6 +174,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, + char *desc = NULL; + u16 event; + ++ if (!(mrioc->logging_level & MPI3_DEBUG_EVENT)) ++ return; ++ + event = event_reply->event; + + switch (event) { +diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c +index e289f18fc76437..daef90ee431f52 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c +@@ -679,6 +679,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, + size_t data_in_sz = 0; + long ret; + u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE; ++ int tm_ret; + + issue_reset = 0; + +@@ -1120,18 +1121,25 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device( + pcie_device->device_info)))) +- mpt3sas_scsih_issue_locked_tm(ioc, ++ tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, + le16_to_cpu(mpi_request->FunctionDependent1), + 0, 0, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, + 0, pcie_device->reset_timeout, + MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE); + else +- mpt3sas_scsih_issue_locked_tm(ioc, ++ tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, + le16_to_cpu(mpi_request->FunctionDependent1), + 0, 0, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, + 0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET); ++ ++ if (tm_ret != SUCCESS) { ++ ioc_info(ioc, ++ "target reset failed, issue hard reset: handle (0x%04x)\n", ++ le16_to_cpu(mpi_request->FunctionDependent1)); ++ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); ++ } + } else + mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); + } +diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c +index 900322bad4f3be..f9ab45c4bb40d5 100644 +--- a/drivers/scsi/st.c ++++ b/drivers/scsi/st.c +@@ -953,7 +953,6 @@ static void reset_state(struct scsi_tape *STp) + STp->partition = find_partition(STp); + if (STp->partition < 0) + STp->partition = 0; +- STp->new_partition = STp->partition; + } + } + +@@ -2895,7 +2894,6 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon + timeout = STp->long_timeout * 8; + + DEBC_printk(STp, "Erasing tape.\n"); +- fileno = blkno = at_sm = 0; + break; + case MTSETBLK: /* Set block length */ + case MTSETDENSITY: /* Set tape density */ +@@ -2928,14 +2926,17 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon + if (cmd_in == MTSETDENSITY) { + (STp->buffer)->b_data[4] = arg; + STp->density_changed = 1; /* At least we tried ;-) */ ++ STp->changed_density = arg; + } else if (cmd_in == SET_DENS_AND_BLK) + (STp->buffer)->b_data[4] = arg >> 24; + else + (STp->buffer)->b_data[4] = STp->density; + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { + ltmp = arg & MT_ST_BLKSIZE_MASK; +- if (cmd_in == MTSETBLK) ++ if (cmd_in == MTSETBLK) { + STp->blksize_changed = 1; /* At least we tried ;-) */ ++ STp->changed_blksize = arg; ++ } + } else + ltmp = STp->block_size; + (STp->buffer)->b_data[9] = (ltmp >> 16); +@@ -3082,7 +3083,9 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon + cmd_in == MTSETDRVBUFFER || + cmd_in == SET_DENS_AND_BLK) { + if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST && +- !(STp->use_pf & PF_TESTED)) { ++ cmdstatp->sense_hdr.asc == 0x24 && ++ (STp->device)->scsi_level <= SCSI_2 && ++ !(STp->use_pf & PF_TESTED)) { + /* Try the other possible state of Page Format if not + already tried */ + STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; +@@ -3634,9 +3637,25 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) + retval = (-EIO); + goto out; + } +- reset_state(STp); ++ reset_state(STp); /* Clears pos_unknown */ + /* remove this when the midlevel properly clears was_reset */ + STp->device->was_reset = 0; ++ ++ /* Fix the device settings after reset, ignore errors */ ++ if (mtc.mt_op == MTREW || mtc.mt_op == MTSEEK || ++ mtc.mt_op == MTEOM) { ++ if (STp->can_partitions) { ++ /* STp->new_partition contains the ++ * latest partition set ++ */ ++ STp->partition = 0; ++ switch_partition(STp); ++ } ++ if (STp->density_changed) ++ st_int_ioctl(STp, MTSETDENSITY, STp->changed_density); ++ if (STp->blksize_changed) ++ st_int_ioctl(STp, MTSETBLK, STp->changed_blksize); ++ } + } + + if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && +diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h +index 1aaaf5369a40fc..6d31b894ee84cc 100644 +--- a/drivers/scsi/st.h ++++ b/drivers/scsi/st.h +@@ -165,6 +165,7 @@ struct scsi_tape { + unsigned char compression_changed; + unsigned char drv_buffer; + unsigned char density; ++ unsigned char changed_density; + unsigned char door_locked; + unsigned char autorew_dev; /* auto-rewind device */ + unsigned char rew_at_close; /* rewind necessary at close */ +@@ -172,6 +173,7 @@ struct scsi_tape { + unsigned char cleaning_req; /* cleaning requested? */ + unsigned char first_tur; /* first TEST UNIT READY */ + int block_size; ++ int changed_blksize; + int min_block; + int max_block; + int recover_count; /* From tape opening */ +diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h +index 24bd619ec5e487..1da1dfd9cb199c 100644 +--- a/drivers/soc/apple/rtkit-internal.h ++++ b/drivers/soc/apple/rtkit-internal.h +@@ -48,6 +48,7 @@ struct apple_rtkit { + + struct apple_rtkit_shmem ioreport_buffer; + struct apple_rtkit_shmem crashlog_buffer; ++ struct apple_rtkit_shmem oslog_buffer; + + struct apple_rtkit_shmem syslog_buffer; + char *syslog_msg_buffer; +diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c +index d9f19dc99da5e8..2c37216f423d20 100644 +--- a/drivers/soc/apple/rtkit.c ++++ b/drivers/soc/apple/rtkit.c +@@ -66,8 +66,9 @@ enum { + #define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24) + + #define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56) +-#define APPLE_RTKIT_OSLOG_INIT 1 +-#define APPLE_RTKIT_OSLOG_ACK 3 ++#define APPLE_RTKIT_OSLOG_BUFFER_REQUEST 1 ++#define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36) ++#define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0) + + #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 + #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 +@@ -256,15 +257,21 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, + struct apple_rtkit_shmem *buffer, + u8 ep, u64 msg) + { +- size_t n_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg); + u64 reply; + int err; + ++ /* The different size vs. IOVA shifts look odd but are indeed correct this way */ ++ if (ep == APPLE_RTKIT_EP_OSLOG) { ++ buffer->size = FIELD_GET(APPLE_RTKIT_OSLOG_SIZE, msg); ++ buffer->iova = FIELD_GET(APPLE_RTKIT_OSLOG_IOVA, msg) << 12; ++ } else { ++ buffer->size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg) << 12; ++ buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); ++ } ++ + buffer->buffer = NULL; + buffer->iomem = NULL; + buffer->is_mapped = false; +- buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); +- buffer->size = n_4kpages << 12; + + dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n", + buffer->size, &buffer->iova); +@@ -289,11 +296,21 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, + } + + if (!buffer->is_mapped) { +- reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, +- APPLE_RTKIT_BUFFER_REQUEST); +- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, n_4kpages); +- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, +- buffer->iova); ++ /* oslog uses different fields and needs a shifted IOVA instead of size */ ++ if (ep == APPLE_RTKIT_EP_OSLOG) { ++ reply = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, ++ APPLE_RTKIT_OSLOG_BUFFER_REQUEST); ++ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_SIZE, buffer->size); ++ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_IOVA, ++ buffer->iova >> 12); ++ } else { ++ reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, ++ APPLE_RTKIT_BUFFER_REQUEST); ++ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, ++ buffer->size >> 12); ++ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, ++ buffer->iova); ++ } + apple_rtkit_send_message(rtk, ep, reply, NULL, false); + } + +@@ -487,25 +504,18 @@ static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg) + } + } + +-static void apple_rtkit_oslog_rx_init(struct apple_rtkit *rtk, u64 msg) +-{ +- u64 ack; +- +- dev_dbg(rtk->dev, "RTKit: oslog init: msg: 0x%llx\n", msg); +- ack = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_ACK); +- apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_OSLOG, ack, NULL, false); +-} +- + static void apple_rtkit_oslog_rx(struct apple_rtkit *rtk, u64 msg) + { + u8 type = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg); + + switch (type) { +- case APPLE_RTKIT_OSLOG_INIT: +- apple_rtkit_oslog_rx_init(rtk, msg); ++ case APPLE_RTKIT_OSLOG_BUFFER_REQUEST: ++ apple_rtkit_common_rx_get_buffer(rtk, &rtk->oslog_buffer, ++ APPLE_RTKIT_EP_OSLOG, msg); + break; + default: +- dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", msg); ++ dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", ++ msg); + } + } + +@@ -744,7 +754,7 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, + rtk->mbox_cl.rx_callback = &apple_rtkit_rx; + rtk->mbox_cl.tx_done = &apple_rtkit_tx_done; + +- rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM, ++ rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_HIGHPRI | WQ_MEM_RECLAIM, + dev_name(rtk->dev)); + if (!rtk->wq) { + ret = -ENOMEM; +@@ -787,6 +797,7 @@ int apple_rtkit_reinit(struct apple_rtkit *rtk) + + apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); + apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); ++ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer); + apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); + + kfree(rtk->syslog_msg_buffer); +@@ -967,6 +978,7 @@ void apple_rtkit_free(struct apple_rtkit *rtk) + + apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); + apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); ++ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer); + apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); + + kfree(rtk->syslog_msg_buffer); +diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c +index 6ea9b8c7d335c0..7a3bdef5a7c0da 100644 +--- a/drivers/soc/ti/k3-socinfo.c ++++ b/drivers/soc/ti/k3-socinfo.c +@@ -63,6 +63,12 @@ k3_chipinfo_partno_to_names(unsigned int partno, + return -EINVAL; + } + ++static const struct regmap_config k3_chipinfo_regmap_cfg = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++}; ++ + static int k3_chipinfo_probe(struct platform_device *pdev) + { + struct device_node *node = pdev->dev.of_node; +@@ -70,13 +76,18 @@ static int k3_chipinfo_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct soc_device *soc_dev; + struct regmap *regmap; ++ void __iomem *base; + u32 partno_id; + u32 variant; + u32 jtag_id; + u32 mfg; + int ret; + +- regmap = device_node_to_regmap(node); ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ regmap = regmap_init_mmio(dev, base, &k3_chipinfo_regmap_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + +diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c +index 79173ab540a6bf..31b203ebbae0ca 100644 +--- a/drivers/soundwire/amd_manager.c ++++ b/drivers/soundwire/amd_manager.c +@@ -1138,6 +1138,7 @@ static int __maybe_unused amd_suspend(struct device *dev) + amd_sdw_wake_enable(amd_manager, false); + return amd_sdw_clock_stop(amd_manager); + } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) { ++ amd_sdw_wake_enable(amd_manager, false); + /* + * As per hardware programming sequence on AMD platforms, + * clock stop should be invoked first before powering-off +@@ -1165,6 +1166,7 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev) + amd_sdw_wake_enable(amd_manager, true); + return amd_sdw_clock_stop(amd_manager); + } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) { ++ amd_sdw_wake_enable(amd_manager, true); + ret = amd_sdw_clock_stop(amd_manager); + if (ret) + return ret; +diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c +index e7553c38be59d6..767942f19adb6a 100644 +--- a/drivers/soundwire/bus.c ++++ b/drivers/soundwire/bus.c +@@ -121,6 +121,10 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, + set_bit(SDW_GROUP13_DEV_NUM, bus->assigned); + set_bit(SDW_MASTER_DEV_NUM, bus->assigned); + ++ ret = sdw_irq_create(bus, fwnode); ++ if (ret) ++ return ret; ++ + /* + * SDW is an enumerable bus, but devices can be powered off. So, + * they won't be able to report as present. +@@ -137,6 +141,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, + + if (ret < 0) { + dev_err(bus->dev, "Finding slaves failed:%d\n", ret); ++ sdw_irq_delete(bus); + return ret; + } + +@@ -155,10 +160,6 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, + bus->params.curr_bank = SDW_BANK0; + bus->params.next_bank = SDW_BANK1; + +- ret = sdw_irq_create(bus, fwnode); +- if (ret) +- return ret; +- + return 0; + } + EXPORT_SYMBOL(sdw_bus_master_add); +diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c +index bcb0de864d34db..7dd94369abb47c 100644 +--- a/drivers/spi/spi-fsl-dspi.c ++++ b/drivers/spi/spi-fsl-dspi.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0+ + // + // Copyright 2013 Freescale Semiconductor, Inc. +-// Copyright 2020 NXP ++// Copyright 2020-2025 NXP + // + // Freescale DSPI driver + // This file contains a driver for the Freescale DSPI +@@ -62,6 +62,7 @@ + #define SPI_SR_TFIWF BIT(18) + #define SPI_SR_RFDF BIT(17) + #define SPI_SR_CMDFFF BIT(16) ++#define SPI_SR_TXRXS BIT(30) + #define SPI_SR_CLEAR (SPI_SR_TCFQF | \ + SPI_SR_TFUF | SPI_SR_TFFF | \ + SPI_SR_CMDTCF | SPI_SR_SPEF | \ +@@ -926,9 +927,20 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + struct spi_transfer *transfer; + bool cs = false; + int status = 0; ++ u32 val = 0; ++ bool cs_change = false; + + message->actual_length = 0; + ++ /* Put DSPI in running mode if halted. */ ++ regmap_read(dspi->regmap, SPI_MCR, &val); ++ if (val & SPI_MCR_HALT) { ++ regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_HALT, 0); ++ while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 && ++ !(val & SPI_SR_TXRXS)) ++ ; ++ } ++ + list_for_each_entry(transfer, &message->transfers, transfer_list) { + dspi->cur_transfer = transfer; + dspi->cur_msg = message; +@@ -958,6 +970,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + dspi->tx_cmd |= SPI_PUSHR_CMD_CONT; + } + ++ cs_change = transfer->cs_change; + dspi->tx = transfer->tx_buf; + dspi->rx = transfer->rx_buf; + dspi->len = transfer->len; +@@ -967,6 +980,8 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); + ++ regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); ++ + spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, + dspi->progress, !dspi->irq); + +@@ -993,6 +1008,15 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + dspi_deassert_cs(spi, &cs); + } + ++ if (status || !cs_change) { ++ /* Put DSPI in stop mode */ ++ regmap_update_bits(dspi->regmap, SPI_MCR, ++ SPI_MCR_HALT, SPI_MCR_HALT); ++ while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 && ++ val & SPI_SR_TXRXS) ++ ; ++ } ++ + message->status = status; + spi_finalize_current_message(ctlr); + +@@ -1163,6 +1187,20 @@ static int dspi_resume(struct device *dev) + + static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); + ++static const struct regmap_range dspi_yes_ranges[] = { ++ regmap_reg_range(SPI_MCR, SPI_MCR), ++ regmap_reg_range(SPI_TCR, SPI_CTAR(3)), ++ regmap_reg_range(SPI_SR, SPI_TXFR3), ++ regmap_reg_range(SPI_RXFR0, SPI_RXFR3), ++ regmap_reg_range(SPI_CTARE(0), SPI_CTARE(3)), ++ regmap_reg_range(SPI_SREX, SPI_SREX), ++}; ++ ++static const struct regmap_access_table dspi_access_table = { ++ .yes_ranges = dspi_yes_ranges, ++ .n_yes_ranges = ARRAY_SIZE(dspi_yes_ranges), ++}; ++ + static const struct regmap_range dspi_volatile_ranges[] = { + regmap_reg_range(SPI_MCR, SPI_TCR), + regmap_reg_range(SPI_SR, SPI_SR), +@@ -1180,6 +1218,8 @@ static const struct regmap_config dspi_regmap_config = { + .reg_stride = 4, + .max_register = 0x88, + .volatile_table = &dspi_volatile_table, ++ .rd_table = &dspi_access_table, ++ .wr_table = &dspi_access_table, + }; + + static const struct regmap_range dspi_xspi_volatile_ranges[] = { +@@ -1201,6 +1241,8 @@ static const struct regmap_config dspi_xspi_regmap_config[] = { + .reg_stride = 4, + .max_register = 0x13c, + .volatile_table = &dspi_xspi_volatile_table, ++ .rd_table = &dspi_access_table, ++ .wr_table = &dspi_access_table, + }, + { + .name = "pushr", +@@ -1223,6 +1265,8 @@ static int dspi_init(struct fsl_dspi *dspi) + if (!spi_controller_is_target(dspi->ctlr)) + mcr |= SPI_MCR_HOST; + ++ mcr |= SPI_MCR_HALT; ++ + regmap_write(dspi->regmap, SPI_MCR, mcr); + regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index 1f374cf4d6f65c..1615f935c8f03f 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -542,7 +542,7 @@ static int rockchip_spi_config(struct rockchip_spi *rs, + cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; + if (spi->mode & SPI_LSB_FIRST) + cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; +- if (spi->mode & SPI_CS_HIGH) ++ if ((spi->mode & SPI_CS_HIGH) && !(spi_get_csgpiod(spi, 0))) + cr0 |= BIT(spi_get_chipselect(spi, 0)) << CR0_SOI_OFFSET; + + if (xfer->rx_buf && xfer->tx_buf) +diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c +index b8947265d329e4..5b2cb225a41983 100644 +--- a/drivers/spi/spi-sun4i.c ++++ b/drivers/spi/spi-sun4i.c +@@ -263,6 +263,9 @@ static int sun4i_spi_transfer_one(struct spi_master *master, + else + reg |= SUN4I_CTL_DHB; + ++ /* Now that the settings are correct, enable the interface */ ++ reg |= SUN4I_CTL_ENABLE; ++ + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); + + /* Ensure that we have a parent clock fast enough */ +@@ -403,7 +406,7 @@ static int sun4i_spi_runtime_resume(struct device *dev) + } + + sun4i_spi_write(sspi, SUN4I_CTL_REG, +- SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP); ++ SUN4I_CTL_MASTER | SUN4I_CTL_TP); + + return 0; + +diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c +index 3503e6c0a5c983..b5deb4fe3b8324 100644 +--- a/drivers/spi/spi-zynqmp-gqspi.c ++++ b/drivers/spi/spi-zynqmp-gqspi.c +@@ -799,7 +799,6 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi) + static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) + { + struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_id; +- irqreturn_t ret = IRQ_NONE; + u32 status, mask, dma_status = 0; + + status = zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST); +@@ -814,27 +813,24 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) + dma_status); + } + +- if (mask & GQSPI_ISR_TXNOT_FULL_MASK) { ++ if (!mask && !dma_status) ++ return IRQ_NONE; ++ ++ if (mask & GQSPI_ISR_TXNOT_FULL_MASK) + zynqmp_qspi_filltxfifo(xqspi, GQSPI_TX_FIFO_FILL); +- ret = IRQ_HANDLED; +- } + +- if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK) { ++ if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK) + zynqmp_process_dma_irq(xqspi); +- ret = IRQ_HANDLED; +- } else if (!(mask & GQSPI_IER_RXEMPTY_MASK) && +- (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) { ++ else if (!(mask & GQSPI_IER_RXEMPTY_MASK) && ++ (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) + zynqmp_qspi_readrxfifo(xqspi, GQSPI_RX_FIFO_FILL); +- ret = IRQ_HANDLED; +- } + + if (xqspi->bytes_to_receive == 0 && xqspi->bytes_to_transfer == 0 && + ((status & GQSPI_IRQ_MASK) == GQSPI_IRQ_MASK)) { + zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK); + complete(&xqspi->data_completion); +- ret = IRQ_HANDLED; + } +- return ret; ++ return IRQ_HANDLED; + } + + /** +diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c +index b516c2893420bc..b756d4cfecfe93 100644 +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -4323,8 +4323,8 @@ int iscsit_close_connection( + spin_unlock(&iscsit_global->ts_bitmap_lock); + + iscsit_stop_timers_for_cmds(conn); +- iscsit_stop_nopin_response_timer(conn); + iscsit_stop_nopin_timer(conn); ++ iscsit_stop_nopin_response_timer(conn); + + if (conn->conn_transport->iscsit_wait_conn) + conn->conn_transport->iscsit_wait_conn(conn); +diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c +index f110f932ba0543..675f774be1d30e 100644 +--- a/drivers/target/target_core_spc.c ++++ b/drivers/target/target_core_spc.c +@@ -2151,8 +2151,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) + if (descr->serv_action_valid) + return TCM_INVALID_CDB_FIELD; + +- if (!descr->enabled || descr->enabled(descr, cmd)) ++ if (!descr->enabled || descr->enabled(descr, cmd)) { + *opcode = descr; ++ return TCM_NO_SENSE; ++ } + break; + case 0x2: + /* +@@ -2166,8 +2168,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) + if (descr->serv_action_valid && + descr->service_action == requested_sa) { + if (!descr->enabled || descr->enabled(descr, +- cmd)) ++ cmd)) { + *opcode = descr; ++ return TCM_NO_SENSE; ++ } + } else if (!descr->serv_action_valid) + return TCM_INVALID_CDB_FIELD; + break; +@@ -2180,13 +2184,15 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) + */ + if (descr->service_action == requested_sa) + if (!descr->enabled || descr->enabled(descr, +- cmd)) ++ cmd)) { + *opcode = descr; ++ return TCM_NO_SENSE; ++ } + break; + } + } + +- return 0; ++ return TCM_NO_SENSE; + } + + static sense_reason_t +diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c +index 61c3d450ee605a..2e06b26be4ef69 100644 +--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c ++++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c +@@ -331,6 +331,7 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) + tj_max = intel_tcc_get_tjmax(cpu); + if (tj_max < 0) + return tj_max; ++ tj_max *= 1000; + + zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL); + if (!zonedev) +diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c +index 404f01cca4dab5..ff8657afb31d3c 100644 +--- a/drivers/thermal/qoriq_thermal.c ++++ b/drivers/thermal/qoriq_thermal.c +@@ -18,6 +18,7 @@ + #define SITES_MAX 16 + #define TMR_DISABLE 0x0 + #define TMR_ME 0x80000000 ++#define TMR_CMD BIT(29) + #define TMR_ALPF 0x0c000000 + #define TMR_ALPF_V2 0x03000000 + #define TMTMIR_DEFAULT 0x0000000f +@@ -356,6 +357,12 @@ static int __maybe_unused qoriq_tmu_suspend(struct device *dev) + if (ret) + return ret; + ++ if (data->ver > TMU_VER1) { ++ ret = regmap_set_bits(data->regmap, REGS_TMR, TMR_CMD); ++ if (ret) ++ return ret; ++ } ++ + clk_disable_unprepare(data->clk); + + return 0; +@@ -370,6 +377,12 @@ static int __maybe_unused qoriq_tmu_resume(struct device *dev) + if (ret) + return ret; + ++ if (data->ver > TMU_VER1) { ++ ret = regmap_clear_bits(data->regmap, REGS_TMR, TMR_CMD); ++ if (ret) ++ return ret; ++ } ++ + /* Enable monitoring */ + return regmap_update_bits(data->regmap, REGS_TMR, TMR_ME, TMR_ME); + } +diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c +index 2ee8c5ebca7c3c..43146c0685dfa7 100644 +--- a/drivers/thunderbolt/retimer.c ++++ b/drivers/thunderbolt/retimer.c +@@ -89,9 +89,11 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt) + if (ret) + goto err_nvm; + +- ret = tb_nvm_add_non_active(nvm, nvm_write); +- if (ret) +- goto err_nvm; ++ if (!rt->no_nvm_upgrade) { ++ ret = tb_nvm_add_non_active(nvm, nvm_write); ++ if (ret) ++ goto err_nvm; ++ } + + rt->nvm = nvm; + return 0; +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index c2778300e15100..d5ad6cae6b652b 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -1676,7 +1676,7 @@ static void serial8250_disable_ms(struct uart_port *port) + if (up->bugs & UART_BUG_NOMSR) + return; + +- mctrl_gpio_disable_ms(up->gpios); ++ mctrl_gpio_disable_ms_no_sync(up->gpios); + + up->ier &= ~UART_IER_MSI; + serial_port_out(port, UART_IER, up->ier); +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index bcca5627afaca8..85559d9b35d830 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -698,7 +698,7 @@ static void atmel_disable_ms(struct uart_port *port) + + atmel_port->ms_irq_enabled = false; + +- mctrl_gpio_disable_ms(atmel_port->gpios); ++ mctrl_gpio_disable_ms_no_sync(atmel_port->gpios); + + if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) + idr |= ATMEL_US_CTSIC; +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index 349d4849ba5e3b..04809b781f45be 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1597,7 +1597,7 @@ static void imx_uart_shutdown(struct uart_port *port) + imx_uart_dma_exit(sport); + } + +- mctrl_gpio_disable_ms(sport->gpios); ++ mctrl_gpio_disable_ms_sync(sport->gpios); + + spin_lock_irqsave(&sport->port.lock, flags); + ucr2 = imx_uart_readl(sport, UCR2); +diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c +index 7d5aaa8d422b19..d5fb293dd5a93c 100644 +--- a/drivers/tty/serial/serial_mctrl_gpio.c ++++ b/drivers/tty/serial/serial_mctrl_gpio.c +@@ -322,11 +322,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) + } + EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms); + +-/** +- * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines +- * @gpios: gpios to disable +- */ +-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) ++static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync) + { + enum mctrl_gpio_idx i; + +@@ -342,10 +338,34 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) + if (!gpios->irq[i]) + continue; + +- disable_irq(gpios->irq[i]); ++ if (sync) ++ disable_irq(gpios->irq[i]); ++ else ++ disable_irq_nosync(gpios->irq[i]); + } + } +-EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); ++ ++/** ++ * mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms ++ * lines, and wait for any pending IRQ to be processed ++ * @gpios: gpios to disable ++ */ ++void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios) ++{ ++ mctrl_gpio_disable_ms(gpios, true); ++} ++EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync); ++ ++/** ++ * mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the ++ * ms lines, and return immediately ++ * @gpios: gpios to disable ++ */ ++void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios) ++{ ++ mctrl_gpio_disable_ms(gpios, false); ++} ++EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync); + + void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) + { +diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h +index fc76910fb105a3..79e97838ebe567 100644 +--- a/drivers/tty/serial/serial_mctrl_gpio.h ++++ b/drivers/tty/serial/serial_mctrl_gpio.h +@@ -87,9 +87,16 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios); + void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); + + /* +- * Disable gpio interrupts to report status line changes. ++ * Disable gpio interrupts to report status line changes, and block until ++ * any corresponding IRQ is processed + */ +-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios); ++void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios); ++ ++/* ++ * Disable gpio interrupts to report status line changes, and return ++ * immediately ++ */ ++void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios); + + /* + * Enable gpio wakeup interrupts to enable wake up source. +@@ -148,7 +155,11 @@ static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) + { + } + +-static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) ++static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios) ++{ ++} ++ ++static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios) + { + } + +diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c +index 4350a69d97d7ac..61d8f50676b1bd 100644 +--- a/drivers/tty/serial/sh-sci.c ++++ b/drivers/tty/serial/sh-sci.c +@@ -104,6 +104,20 @@ struct plat_sci_reg { + u8 offset, size; + }; + ++struct sci_suspend_regs { ++ u16 scdl; ++ u16 sccks; ++ u16 scsmr; ++ u16 scscr; ++ u16 scfcr; ++ u16 scsptr; ++ u16 hssrr; ++ u16 scpcr; ++ u16 scpdr; ++ u8 scbrr; ++ u8 semr; ++}; ++ + struct sci_port_params { + const struct plat_sci_reg regs[SCIx_NR_REGS]; + unsigned int fifosize; +@@ -134,6 +148,8 @@ struct sci_port { + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + ++ struct reset_control *rstc; ++ + #ifdef CONFIG_SERIAL_SH_SCI_DMA + struct dma_chan *chan_tx_saved; + struct dma_chan *chan_rx_saved; +@@ -153,6 +169,7 @@ struct sci_port { + int rx_trigger; + struct timer_list rx_fifo_timer; + int rx_fifo_timeout; ++ struct sci_suspend_regs suspend_regs; + u16 hscif_tot; + + bool has_rtscts; +@@ -2237,7 +2254,7 @@ static void sci_shutdown(struct uart_port *port) + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + s->autorts = false; +- mctrl_gpio_disable_ms(to_sci_port(port)->gpios); ++ mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios); + + spin_lock_irqsave(&port->lock, flags); + sci_stop_rx(port); +@@ -3325,6 +3342,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, + } + + sp = &sci_ports[id]; ++ sp->rstc = rstc; + *dev_id = id; + + p->type = SCI_OF_TYPE(data); +@@ -3473,13 +3491,77 @@ static int sci_probe(struct platform_device *dev) + return 0; + } + ++static void sci_console_save(struct sci_port *s) ++{ ++ struct sci_suspend_regs *regs = &s->suspend_regs; ++ struct uart_port *port = &s->port; ++ ++ if (sci_getreg(port, SCDL)->size) ++ regs->scdl = sci_serial_in(port, SCDL); ++ if (sci_getreg(port, SCCKS)->size) ++ regs->sccks = sci_serial_in(port, SCCKS); ++ if (sci_getreg(port, SCSMR)->size) ++ regs->scsmr = sci_serial_in(port, SCSMR); ++ if (sci_getreg(port, SCSCR)->size) ++ regs->scscr = sci_serial_in(port, SCSCR); ++ if (sci_getreg(port, SCFCR)->size) ++ regs->scfcr = sci_serial_in(port, SCFCR); ++ if (sci_getreg(port, SCSPTR)->size) ++ regs->scsptr = sci_serial_in(port, SCSPTR); ++ if (sci_getreg(port, SCBRR)->size) ++ regs->scbrr = sci_serial_in(port, SCBRR); ++ if (sci_getreg(port, HSSRR)->size) ++ regs->hssrr = sci_serial_in(port, HSSRR); ++ if (sci_getreg(port, SCPCR)->size) ++ regs->scpcr = sci_serial_in(port, SCPCR); ++ if (sci_getreg(port, SCPDR)->size) ++ regs->scpdr = sci_serial_in(port, SCPDR); ++ if (sci_getreg(port, SEMR)->size) ++ regs->semr = sci_serial_in(port, SEMR); ++} ++ ++static void sci_console_restore(struct sci_port *s) ++{ ++ struct sci_suspend_regs *regs = &s->suspend_regs; ++ struct uart_port *port = &s->port; ++ ++ if (sci_getreg(port, SCDL)->size) ++ sci_serial_out(port, SCDL, regs->scdl); ++ if (sci_getreg(port, SCCKS)->size) ++ sci_serial_out(port, SCCKS, regs->sccks); ++ if (sci_getreg(port, SCSMR)->size) ++ sci_serial_out(port, SCSMR, regs->scsmr); ++ if (sci_getreg(port, SCSCR)->size) ++ sci_serial_out(port, SCSCR, regs->scscr); ++ if (sci_getreg(port, SCFCR)->size) ++ sci_serial_out(port, SCFCR, regs->scfcr); ++ if (sci_getreg(port, SCSPTR)->size) ++ sci_serial_out(port, SCSPTR, regs->scsptr); ++ if (sci_getreg(port, SCBRR)->size) ++ sci_serial_out(port, SCBRR, regs->scbrr); ++ if (sci_getreg(port, HSSRR)->size) ++ sci_serial_out(port, HSSRR, regs->hssrr); ++ if (sci_getreg(port, SCPCR)->size) ++ sci_serial_out(port, SCPCR, regs->scpcr); ++ if (sci_getreg(port, SCPDR)->size) ++ sci_serial_out(port, SCPDR, regs->scpdr); ++ if (sci_getreg(port, SEMR)->size) ++ sci_serial_out(port, SEMR, regs->semr); ++} ++ + static __maybe_unused int sci_suspend(struct device *dev) + { + struct sci_port *sport = dev_get_drvdata(dev); + +- if (sport) ++ if (sport) { + uart_suspend_port(&sci_uart_driver, &sport->port); + ++ if (!console_suspend_enabled && uart_console(&sport->port)) ++ sci_console_save(sport); ++ else ++ return reset_control_assert(sport->rstc); ++ } ++ + return 0; + } + +@@ -3487,8 +3569,18 @@ static __maybe_unused int sci_resume(struct device *dev) + { + struct sci_port *sport = dev_get_drvdata(dev); + +- if (sport) ++ if (sport) { ++ if (!console_suspend_enabled && uart_console(&sport->port)) { ++ sci_console_restore(sport); ++ } else { ++ int ret = reset_control_deassert(sport->rstc); ++ ++ if (ret) ++ return ret; ++ } ++ + uart_resume_port(&sci_uart_driver, &sport->port); ++ } + + return 0; + } +diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c +index 9ef90bb30a47eb..b58422ae156c93 100644 +--- a/drivers/tty/serial/stm32-usart.c ++++ b/drivers/tty/serial/stm32-usart.c +@@ -952,7 +952,7 @@ static void stm32_usart_enable_ms(struct uart_port *port) + + static void stm32_usart_disable_ms(struct uart_port *port) + { +- mctrl_gpio_disable_ms(to_stm32_port(port)->gpios); ++ mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios); + } + + /* Transmit stop */ +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index cb5611cbf45474..2346a1fc72b56e 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -257,6 +257,7 @@ static const struct ufs_dev_quirk ufs_fixups[] = { + .model = UFS_ANY_MODEL, + .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM | + UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE | ++ UFS_DEVICE_QUIRK_PA_HIBER8TIME | + UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS }, + { .wmanufacturerid = UFS_VENDOR_SKHYNIX, + .model = UFS_ANY_MODEL, +@@ -8459,6 +8460,31 @@ static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba) + return ret; + } + ++/** ++ * ufshcd_quirk_override_pa_h8time - Ensures proper adjustment of PA_HIBERN8TIME. ++ * @hba: per-adapter instance ++ * ++ * Some UFS devices require specific adjustments to the PA_HIBERN8TIME parameter ++ * to ensure proper hibernation timing. This function retrieves the current ++ * PA_HIBERN8TIME value and increments it by 100us. ++ */ ++static void ufshcd_quirk_override_pa_h8time(struct ufs_hba *hba) ++{ ++ u32 pa_h8time; ++ int ret; ++ ++ ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_HIBERN8TIME), &pa_h8time); ++ if (ret) { ++ dev_err(hba->dev, "Failed to get PA_HIBERN8TIME: %d\n", ret); ++ return; ++ } ++ ++ /* Increment by 1 to increase hibernation time by 100 µs */ ++ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), pa_h8time + 1); ++ if (ret) ++ dev_err(hba->dev, "Failed updating PA_HIBERN8TIME: %d\n", ret); ++} ++ + static void ufshcd_tune_unipro_params(struct ufs_hba *hba) + { + if (ufshcd_is_unipro_pa_params_tuning_req(hba)) { +@@ -8474,6 +8500,9 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) + + if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) + ufshcd_quirk_tune_host_pa_tactivate(hba); ++ ++ if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_HIBER8TIME) ++ ufshcd_quirk_override_pa_h8time(hba); + } + + static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 5a53280fa2edfd..44352df58c9e4e 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1180,7 +1180,14 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, + */ + switch (GET_EP_CTX_STATE(ep_ctx)) { + case EP_STATE_HALTED: +- xhci_dbg(xhci, "Stop ep completion raced with stall, reset ep\n"); ++ xhci_dbg(xhci, "Stop ep completion raced with stall\n"); ++ /* ++ * If the halt happened before Stop Endpoint failed, its transfer event ++ * should have already been handled and Reset Endpoint should be pending. ++ */ ++ if (ep->ep_state & EP_HALTED) ++ goto reset_done; ++ + if (ep->ep_state & EP_HAS_STREAMS) { + reset_type = EP_SOFT_RESET; + } else { +@@ -1191,8 +1198,11 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, + } + /* reset ep, reset handler cleans up cancelled tds */ + err = xhci_handle_halted_endpoint(xhci, ep, td, reset_type); ++ xhci_dbg(xhci, "Stop ep completion resetting ep, status %d\n", err); + if (err) + break; ++reset_done: ++ /* Reset EP handler will clean up cancelled TDs */ + ep->ep_state &= ~EP_STOP_CMD_PENDING; + return; + case EP_STATE_STOPPED: +diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c +index b56aae3f7be378..9b8b70ffde5a0a 100644 +--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c ++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c +@@ -3420,6 +3420,9 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, + ndev->mvdev.max_vqs = max_vqs; + mvdev = &ndev->mvdev; + mvdev->mdev = mdev; ++ /* cpu_to_mlx5vdpa16() below depends on this flag */ ++ mvdev->actual_features = ++ (device_features & BIT_ULL(VIRTIO_F_VERSION_1)); + + ndev->vqs = kcalloc(max_vqs, sizeof(*ndev->vqs), GFP_KERNEL); + ndev->event_cbs = kcalloc(max_vqs + 1, sizeof(*ndev->event_cbs), GFP_KERNEL); +diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c +index a2ad4f7c716bf3..d9eb8733a324b7 100644 +--- a/drivers/vfio/pci/vfio_pci_config.c ++++ b/drivers/vfio/pci/vfio_pci_config.c +@@ -1813,7 +1813,8 @@ int vfio_config_init(struct vfio_pci_core_device *vdev) + cpu_to_le16(PCI_COMMAND_MEMORY); + } + +- if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx) ++ if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx || ++ vdev->pdev->irq == IRQ_NOTCONNECTED) + vconfig[PCI_INTERRUPT_PIN] = 0; + + ret = vfio_cap_init(vdev); +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index a8f259bc2f4d0c..fa168b43423954 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -731,15 +731,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_finish_enable); + static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_type) + { + if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) { +- u8 pin; +- +- if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || +- vdev->nointx || vdev->pdev->is_virtfn) +- return 0; +- +- pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin); +- +- return pin ? 1 : 0; ++ return vdev->vconfig[PCI_INTERRUPT_PIN] ? 1 : 0; + } else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) { + u8 pos; + u16 flags; +diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c +index 620134041b4881..c4322faca2bd5b 100644 +--- a/drivers/vfio/pci/vfio_pci_intrs.c ++++ b/drivers/vfio/pci/vfio_pci_intrs.c +@@ -269,7 +269,7 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev, + if (!is_irq_none(vdev)) + return -EINVAL; + +- if (!pdev->irq) ++ if (!pdev->irq || pdev->irq == IRQ_NOTCONNECTED) + return -ENODEV; + + name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-intx(%s)", pci_name(pdev)); +diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c +index 8d8a22504d71fc..66235151115740 100644 +--- a/drivers/vhost/scsi.c ++++ b/drivers/vhost/scsi.c +@@ -560,6 +560,9 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) + int ret; + + llnode = llist_del_all(&svq->completion_list); ++ ++ mutex_lock(&svq->vq.mutex); ++ + llist_for_each_entry_safe(cmd, t, llnode, tvc_completion_list) { + se_cmd = &cmd->tvc_se_cmd; + +@@ -593,6 +596,8 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) + vhost_scsi_release_cmd_res(se_cmd); + } + ++ mutex_unlock(&svq->vq.mutex); ++ + if (signal) + vhost_signal(&svq->vs->dev, &svq->vq); + } +@@ -746,7 +751,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + size_t len = iov_iter_count(iter); + unsigned int nbytes = 0; + struct page *page; +- int i; ++ int i, ret; + + if (cmd->tvc_data_direction == DMA_FROM_DEVICE) { + cmd->saved_iter_addr = dup_iter(&cmd->saved_iter, iter, +@@ -759,6 +764,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + page = alloc_page(GFP_KERNEL); + if (!page) { + i--; ++ ret = -ENOMEM; + goto err; + } + +@@ -766,8 +772,10 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + sg_set_page(&sg[i], page, nbytes, 0); + + if (cmd->tvc_data_direction == DMA_TO_DEVICE && +- copy_page_from_iter(page, 0, nbytes, iter) != nbytes) ++ copy_page_from_iter(page, 0, nbytes, iter) != nbytes) { ++ ret = -EFAULT; + goto err; ++ } + + len -= nbytes; + } +@@ -782,7 +790,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + for (; i >= 0; i--) + __free_page(sg_page(&sg[i])); + kfree(cmd->saved_iter_addr); +- return -ENOMEM; ++ return ret; + } + + static int +@@ -1221,9 +1229,9 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) + " %d\n", cmd, exp_data_len, prot_bytes, data_direction); + + if (data_direction != DMA_NONE) { +- if (unlikely(vhost_scsi_mapal(cmd, prot_bytes, +- &prot_iter, exp_data_len, +- &data_iter))) { ++ ret = vhost_scsi_mapal(cmd, prot_bytes, &prot_iter, ++ exp_data_len, &data_iter); ++ if (unlikely(ret)) { + vq_err(vq, "Failed to map iov to sgl\n"); + vhost_scsi_release_cmd_res(&cmd->tvc_se_cmd); + goto err; +@@ -1301,8 +1309,11 @@ static void vhost_scsi_tmf_resp_work(struct vhost_work *work) + resp_code = VIRTIO_SCSI_S_FUNCTION_REJECTED; + } + ++ mutex_lock(&tmf->svq->vq.mutex); + vhost_scsi_send_tmf_resp(tmf->vhost, &tmf->svq->vq, tmf->in_iovs, + tmf->vq_desc, &tmf->resp_iov, resp_code); ++ mutex_unlock(&tmf->svq->vq.mutex); ++ + vhost_scsi_release_tmf_res(tmf); + } + +diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c +index 8587c9da067003..42e681a78136ab 100644 +--- a/drivers/video/fbdev/core/bitblit.c ++++ b/drivers/video/fbdev/core/bitblit.c +@@ -59,12 +59,11 @@ static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + struct fb_fillrect region; + +- region.color = attr_bgcol_ec(bgshift, vc, info); ++ region.color = bg; + region.dx = sx * vc->vc_font.width; + region.dy = sy * vc->vc_font.height; + region.width = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 405d587450ef84..7a6f9a3cb3ba34 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -1240,7 +1240,7 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_ops *ops = info->fbcon_par; +- ++ int fg, bg; + struct fbcon_display *p = &fb_display[vc->vc_num]; + u_int y_break; + +@@ -1261,16 +1261,18 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + fbcon_clear_margins(vc, 0); + } + ++ fg = get_color(vc, info, vc->vc_video_erase_char, 1); ++ bg = get_color(vc, info, vc->vc_video_erase_char, 0); + /* Split blits that cross physical y_wrap boundary */ + + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; +- ops->clear(vc, info, real_y(p, sy), sx, b, width); ++ ops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); + ops->clear(vc, info, real_y(p, sy + b), sx, height - b, +- width); ++ width, fg, bg); + } else +- ops->clear(vc, info, real_y(p, sy), sx, height, width); ++ ops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); + } + + static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, +diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h +index 0eaf54a2115167..25691d4b027bfc 100644 +--- a/drivers/video/fbdev/core/fbcon.h ++++ b/drivers/video/fbdev/core/fbcon.h +@@ -55,7 +55,7 @@ struct fbcon_ops { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); + void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width); ++ int sx, int height, int width, int fb, int bg); + void (*putcs)(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg); +@@ -116,42 +116,6 @@ static inline int mono_col(const struct fb_info *info) + return (~(0xfff << max_len)) & 0xff; + } + +-static inline int attr_col_ec(int shift, struct vc_data *vc, +- struct fb_info *info, int is_fg) +-{ +- int is_mono01; +- int col; +- int fg; +- int bg; +- +- if (!vc) +- return 0; +- +- if (vc->vc_can_do_color) +- return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char) +- : attr_bgcol(shift,vc->vc_video_erase_char); +- +- if (!info) +- return 0; +- +- col = mono_col(info); +- is_mono01 = info->fix.visual == FB_VISUAL_MONO01; +- +- if (attr_reverse(vc->vc_video_erase_char)) { +- fg = is_mono01 ? col : 0; +- bg = is_mono01 ? 0 : col; +- } +- else { +- fg = is_mono01 ? 0 : col; +- bg = is_mono01 ? col : 0; +- } +- +- return is_fg ? fg : bg; +-} +- +-#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0) +-#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1) +- + /* + * Scroll Method + */ +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index 2789ace7963427..9f4d65478554ad 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -78,14 +78,13 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vyres = GETVYRES(ops->p, info); + +- region.color = attr_bgcol_ec(bgshift,vc,info); ++ region.color = bg; + region.dx = sy * vc->vc_font.height; + region.dy = vyres - ((sx + width) * vc->vc_font.width); + region.height = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index 86a254c1b2b7b6..b18e31886da102 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -63,14 +63,13 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vxres = GETVXRES(ops->p, info); + +- region.color = attr_bgcol_ec(bgshift,vc,info); ++ region.color = bg; + region.dx = vxres - ((sy + height) * vc->vc_font.height); + region.dy = sx * vc->vc_font.width; + region.height = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 23bc045769d088..b6b074cfd9dc08 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -64,15 +64,14 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vyres = GETVYRES(ops->p, info); + u32 vxres = GETVXRES(ops->p, info); + +- region.color = attr_bgcol_ec(bgshift,vc,info); ++ region.color = bg; + region.dy = vyres - ((sy + height) * vc->vc_font.height); + region.dx = vxres - ((sx + width) * vc->vc_font.width); + region.width = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c +index 2768eff247ba46..b3aa0c6620c7d1 100644 +--- a/drivers/video/fbdev/core/tileblit.c ++++ b/drivers/video/fbdev/core/tileblit.c +@@ -32,16 +32,14 @@ static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fb_tilerect rect; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; +- int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; + + rect.index = vc->vc_video_erase_char & + ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); +- rect.fg = attr_fgcol_ec(fgshift, vc, info); +- rect.bg = attr_bgcol_ec(bgshift, vc, info); ++ rect.fg = fg; ++ rect.bg = bg; + rect.sx = sx; + rect.sy = sy; + rect.width = width; +@@ -76,7 +74,42 @@ static void tile_putcs(struct vc_data *vc, struct fb_info *info, + static void tile_clear_margins(struct vc_data *vc, struct fb_info *info, + int color, int bottom_only) + { +- return; ++ unsigned int cw = vc->vc_font.width; ++ unsigned int ch = vc->vc_font.height; ++ unsigned int rw = info->var.xres - (vc->vc_cols*cw); ++ unsigned int bh = info->var.yres - (vc->vc_rows*ch); ++ unsigned int rs = info->var.xres - rw; ++ unsigned int bs = info->var.yres - bh; ++ unsigned int vwt = info->var.xres_virtual / cw; ++ unsigned int vht = info->var.yres_virtual / ch; ++ struct fb_tilerect rect; ++ ++ rect.index = vc->vc_video_erase_char & ++ ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); ++ rect.fg = color; ++ rect.bg = color; ++ ++ if ((int) rw > 0 && !bottom_only) { ++ rect.sx = (info->var.xoffset + rs + cw - 1) / cw; ++ rect.sy = 0; ++ rect.width = (rw + cw - 1) / cw; ++ rect.height = vht; ++ if (rect.width + rect.sx > vwt) ++ rect.width = vwt - rect.sx; ++ if (rect.sx < vwt) ++ info->tileops->fb_tilefill(info, &rect); ++ } ++ ++ if ((int) bh > 0) { ++ rect.sx = info->var.xoffset / cw; ++ rect.sy = (info->var.yoffset + bs) / ch; ++ rect.width = rs / cw; ++ rect.height = (bh + ch - 1) / ch; ++ if (rect.height + rect.sy > vht) ++ rect.height = vht - rect.sy; ++ if (rect.sy < vht) ++ info->tileops->fb_tilefill(info, &rect); ++ } + } + + static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, +diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c +index 0bced82fa4940d..8cf1268a4e5545 100644 +--- a/drivers/video/fbdev/fsl-diu-fb.c ++++ b/drivers/video/fbdev/fsl-diu-fb.c +@@ -1827,6 +1827,7 @@ static void fsl_diu_remove(struct platform_device *pdev) + int i; + + data = dev_get_drvdata(&pdev->dev); ++ device_remove_file(&pdev->dev, &data->dev_attr); + disable_lcdc(&data->fsl_diu_info[0]); + + free_irq(data->irq, data->diu_reg); +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index 80669e05bf0ee4..c5f04234d9511a 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -2530,7 +2530,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq) + struct vring_virtqueue *vq = to_vvq(_vq); + + if (vq->event_triggered) +- vq->event_triggered = false; ++ data_race(vq->event_triggered = false); + + return vq->packed_ring ? virtqueue_enable_cb_delayed_packed(_vq) : + virtqueue_enable_cb_delayed_split(_vq); +diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c +index b72a858bbac702..001b2c9311254c 100644 +--- a/drivers/watchdog/aspeed_wdt.c ++++ b/drivers/watchdog/aspeed_wdt.c +@@ -11,21 +11,30 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + + static bool nowayout = WATCHDOG_NOWAYOUT; + module_param(nowayout, bool, 0); + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++struct aspeed_wdt_scu { ++ const char *compatible; ++ u32 reset_status_reg; ++ u32 wdt_reset_mask; ++ u32 wdt_reset_mask_shift; ++}; + + struct aspeed_wdt_config { + u32 ext_pulse_width_mask; + u32 irq_shift; + u32 irq_mask; ++ struct aspeed_wdt_scu scu; + }; + + struct aspeed_wdt { +@@ -39,18 +48,36 @@ static const struct aspeed_wdt_config ast2400_config = { + .ext_pulse_width_mask = 0xff, + .irq_shift = 0, + .irq_mask = 0, ++ .scu = { ++ .compatible = "aspeed,ast2400-scu", ++ .reset_status_reg = 0x3c, ++ .wdt_reset_mask = 0x1, ++ .wdt_reset_mask_shift = 1, ++ }, + }; + + static const struct aspeed_wdt_config ast2500_config = { + .ext_pulse_width_mask = 0xfffff, + .irq_shift = 12, + .irq_mask = GENMASK(31, 12), ++ .scu = { ++ .compatible = "aspeed,ast2500-scu", ++ .reset_status_reg = 0x3c, ++ .wdt_reset_mask = 0x1, ++ .wdt_reset_mask_shift = 2, ++ }, + }; + + static const struct aspeed_wdt_config ast2600_config = { + .ext_pulse_width_mask = 0xfffff, + .irq_shift = 0, + .irq_mask = GENMASK(31, 10), ++ .scu = { ++ .compatible = "aspeed,ast2600-scu", ++ .reset_status_reg = 0x74, ++ .wdt_reset_mask = 0xf, ++ .wdt_reset_mask_shift = 16, ++ }, + }; + + static const struct of_device_id aspeed_wdt_of_table[] = { +@@ -211,6 +238,56 @@ static int aspeed_wdt_restart(struct watchdog_device *wdd, + return 0; + } + ++static void aspeed_wdt_update_bootstatus(struct platform_device *pdev, ++ struct aspeed_wdt *wdt) ++{ ++ const struct resource *res; ++ struct aspeed_wdt_scu scu = wdt->cfg->scu; ++ struct regmap *scu_base; ++ u32 reset_mask_width; ++ u32 reset_mask_shift; ++ u32 idx = 0; ++ u32 status; ++ int ret; ++ ++ if (!of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt")) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ idx = ((intptr_t)wdt->base & 0x00000fff) / (uintptr_t)resource_size(res); ++ } ++ ++ scu_base = syscon_regmap_lookup_by_compatible(scu.compatible); ++ if (IS_ERR(scu_base)) { ++ wdt->wdd.bootstatus = WDIOS_UNKNOWN; ++ return; ++ } ++ ++ ret = regmap_read(scu_base, scu.reset_status_reg, &status); ++ if (ret) { ++ wdt->wdd.bootstatus = WDIOS_UNKNOWN; ++ return; ++ } ++ ++ reset_mask_width = hweight32(scu.wdt_reset_mask); ++ reset_mask_shift = scu.wdt_reset_mask_shift + ++ reset_mask_width * idx; ++ ++ if (status & (scu.wdt_reset_mask << reset_mask_shift)) ++ wdt->wdd.bootstatus = WDIOF_CARDRESET; ++ ++ /* clear wdt reset event flag */ ++ if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt") || ++ of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2500-wdt")) { ++ ret = regmap_read(scu_base, scu.reset_status_reg, &status); ++ if (!ret) { ++ status &= ~(scu.wdt_reset_mask << reset_mask_shift); ++ regmap_write(scu_base, scu.reset_status_reg, status); ++ } ++ } else { ++ regmap_write(scu_base, scu.reset_status_reg, ++ scu.wdt_reset_mask << reset_mask_shift); ++ } ++} ++ + /* access_cs0 shows if cs0 is accessible, hence the reverted bit */ + static ssize_t access_cs0_show(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -447,10 +524,10 @@ static int aspeed_wdt_probe(struct platform_device *pdev) + writel(duration - 1, wdt->base + WDT_RESET_WIDTH); + } + ++ aspeed_wdt_update_bootstatus(pdev, wdt); ++ + status = readl(wdt->base + WDT_TIMEOUT_STATUS); + if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) { +- wdt->wdd.bootstatus = WDIOF_CARDRESET; +- + if (of_device_is_compatible(np, "aspeed,ast2400-wdt") || + of_device_is_compatible(np, "aspeed,ast2500-wdt")) + wdt->wdd.groups = bswitch_groups; +diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c +index 544d3f9010b92a..1db82da56db62b 100644 +--- a/drivers/xen/platform-pci.c ++++ b/drivers/xen/platform-pci.c +@@ -26,6 +26,8 @@ + + #define DRV_NAME "xen-platform-pci" + ++#define PCI_DEVICE_ID_XEN_PLATFORM_XS61 0x0002 ++ + static unsigned long platform_mmio; + static unsigned long platform_mmio_alloc; + static unsigned long platform_mmiolen; +@@ -174,6 +176,8 @@ static int platform_pci_probe(struct pci_dev *pdev, + static const struct pci_device_id platform_pci_tbl[] = { + {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM_XS61, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} + }; + +diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c +index 25164d56c9d995..d3b6908110c6f0 100644 +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -966,9 +966,15 @@ static int __init xenbus_init(void) + if (xen_pv_domain()) + xen_store_domain_type = XS_PV; + if (xen_hvm_domain()) ++ { + xen_store_domain_type = XS_HVM; +- if (xen_hvm_domain() && xen_initial_domain()) +- xen_store_domain_type = XS_LOCAL; ++ err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); ++ if (err) ++ goto out_error; ++ xen_store_evtchn = (int)v; ++ if (!v && xen_initial_domain()) ++ xen_store_domain_type = XS_LOCAL; ++ } + if (xen_pv_domain() && !xen_start_info->store_evtchn) + xen_store_domain_type = XS_LOCAL; + if (xen_pv_domain() && xen_start_info->store_evtchn) +@@ -987,10 +993,6 @@ static int __init xenbus_init(void) + xen_store_interface = gfn_to_virt(xen_store_gfn); + break; + case XS_HVM: +- err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); +- if (err) +- goto out_error; +- xen_store_evtchn = (int)v; + err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); + if (err) + goto out_error; +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 434cf3d5f4cf18..226e6434a58a94 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -1885,6 +1885,17 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) + up_write(&space_info->groups_sem); + goto next; + } ++ ++ /* ++ * Cache the zone_unusable value before turning the block group ++ * to read only. As soon as the block group is read only it's ++ * zone_unusable value gets moved to the block group's read-only ++ * bytes and isn't available for calculations anymore. We also ++ * cache it before unlocking the block group, to prevent races ++ * (reports from KCSAN and such tools) with tasks updating it. ++ */ ++ zone_unusable = bg->zone_unusable; ++ + spin_unlock(&bg->lock); + + /* +@@ -1900,13 +1911,6 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) + goto next; + } + +- /* +- * Cache the zone_unusable value before turning the block group +- * to read only. As soon as the blog group is read only it's +- * zone_unusable value gets moved to the block group's read-only +- * bytes and isn't available for calculations anymore. +- */ +- zone_unusable = bg->zone_unusable; + ret = inc_block_group_ro(bg, 0); + up_write(&space_info->groups_sem); + if (ret < 0) +diff --git a/fs/btrfs/discard.c b/fs/btrfs/discard.c +index 944a7340f6a449..3981c941f5b556 100644 +--- a/fs/btrfs/discard.c ++++ b/fs/btrfs/discard.c +@@ -167,13 +167,7 @@ static bool remove_from_discard_list(struct btrfs_discard_ctl *discard_ctl, + block_group->discard_eligible_time = 0; + queued = !list_empty(&block_group->discard_list); + list_del_init(&block_group->discard_list); +- /* +- * If the block group is currently running in the discard workfn, we +- * don't want to deref it, since it's still being used by the workfn. +- * The workfn will notice this case and deref the block group when it is +- * finished. +- */ +- if (queued && !running) ++ if (queued) + btrfs_put_block_group(block_group); + + spin_unlock(&discard_ctl->lock); +@@ -260,9 +254,10 @@ static struct btrfs_block_group *peek_discard_list( + block_group->discard_cursor = block_group->start; + block_group->discard_state = BTRFS_DISCARD_EXTENTS; + } +- discard_ctl->block_group = block_group; + } + if (block_group) { ++ btrfs_get_block_group(block_group); ++ discard_ctl->block_group = block_group; + *discard_state = block_group->discard_state; + *discard_index = block_group->discard_index; + } +@@ -493,9 +488,20 @@ static void btrfs_discard_workfn(struct work_struct *work) + + block_group = peek_discard_list(discard_ctl, &discard_state, + &discard_index, now); +- if (!block_group || !btrfs_run_discard_work(discard_ctl)) ++ if (!block_group) + return; ++ if (!btrfs_run_discard_work(discard_ctl)) { ++ spin_lock(&discard_ctl->lock); ++ btrfs_put_block_group(block_group); ++ discard_ctl->block_group = NULL; ++ spin_unlock(&discard_ctl->lock); ++ return; ++ } + if (now < block_group->discard_eligible_time) { ++ spin_lock(&discard_ctl->lock); ++ btrfs_put_block_group(block_group); ++ discard_ctl->block_group = NULL; ++ spin_unlock(&discard_ctl->lock); + btrfs_discard_schedule_work(discard_ctl, false); + return; + } +@@ -547,15 +553,7 @@ static void btrfs_discard_workfn(struct work_struct *work) + spin_lock(&discard_ctl->lock); + discard_ctl->prev_discard = trimmed; + discard_ctl->prev_discard_time = now; +- /* +- * If the block group was removed from the discard list while it was +- * running in this workfn, then we didn't deref it, since this function +- * still owned that reference. But we set the discard_ctl->block_group +- * back to NULL, so we can use that condition to know that now we need +- * to deref the block_group. +- */ +- if (discard_ctl->block_group == NULL) +- btrfs_put_block_group(block_group); ++ btrfs_put_block_group(block_group); + discard_ctl->block_group = NULL; + __btrfs_discard_schedule_work(discard_ctl, now, false); + spin_unlock(&discard_ctl->lock); +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 2387210231f236..34a30d61b470c3 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -4313,6 +4313,14 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) + /* clear out the rbtree of defraggable inodes */ + btrfs_cleanup_defrag_inodes(fs_info); + ++ /* ++ * Handle the error fs first, as it will flush and wait for all ordered ++ * extents. This will generate delayed iputs, thus we want to handle ++ * it first. ++ */ ++ if (unlikely(BTRFS_FS_ERROR(fs_info))) ++ btrfs_error_commit_super(fs_info); ++ + /* + * Wait for any fixup workers to complete. + * If we don't wait for them here and they are still running by the time +@@ -4333,6 +4341,19 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) + */ + btrfs_flush_workqueue(fs_info->delalloc_workers); + ++ /* ++ * We can have ordered extents getting their last reference dropped from ++ * the fs_info->workers queue because for async writes for data bios we ++ * queue a work for that queue, at btrfs_wq_submit_bio(), that runs ++ * run_one_async_done() which calls btrfs_bio_end_io() in case the bio ++ * has an error, and that later function can do the final ++ * btrfs_put_ordered_extent() on the ordered extent attached to the bio, ++ * which adds a delayed iput for the inode. So we must flush the queue ++ * so that we don't have delayed iputs after committing the current ++ * transaction below and stopping the cleaner and transaction kthreads. ++ */ ++ btrfs_flush_workqueue(fs_info->workers); ++ + /* + * When finishing a compressed write bio we schedule a work queue item + * to finish an ordered extent - btrfs_finish_compressed_write_work() +@@ -4402,9 +4423,6 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) + btrfs_err(fs_info, "commit super ret %d", ret); + } + +- if (BTRFS_FS_ERROR(fs_info)) +- btrfs_error_commit_super(fs_info); +- + kthread_stop(fs_info->transaction_kthread); + kthread_stop(fs_info->cleaner_kthread); + +@@ -4541,10 +4559,6 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info) + /* cleanup FS via transaction */ + btrfs_cleanup_transaction(fs_info); + +- mutex_lock(&fs_info->cleaner_mutex); +- btrfs_run_delayed_iputs(fs_info); +- mutex_unlock(&fs_info->cleaner_mutex); +- + down_write(&fs_info->cleanup_work_sem); + up_write(&fs_info->cleanup_work_sem); + } +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index b2ae50dcca0fe0..ed08d8e5639f59 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -3565,10 +3565,10 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info, + return eb; + } + +-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS + struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, + u64 start) + { ++#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS + struct extent_buffer *eb, *exists = NULL; + int ret; + +@@ -3604,8 +3604,11 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, + free_eb: + btrfs_release_extent_buffer(eb); + return exists; +-} ++#else ++ /* Stub to avoid linker error when compiled with optimizations turned off. */ ++ return NULL; + #endif ++} + + static struct extent_buffer *grab_extent_buffer( + struct btrfs_fs_info *fs_info, struct page *page) +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 537e184b4b1dfc..474758c878fcab 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -2931,6 +2931,7 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra, + int ret; + + ASSERT(page_index <= last_index); ++again: + page = find_lock_page(inode->i_mapping, page_index); + if (!page) { + page_cache_sync_readahead(inode->i_mapping, ra, NULL, +@@ -2952,6 +2953,11 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra, + ret = -EIO; + goto release_page; + } ++ if (page->mapping != inode->i_mapping) { ++ unlock_page(page); ++ put_page(page); ++ goto again; ++ } + } + + /* +diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c +index 6be092bb814fdc..da49bdb70375b6 100644 +--- a/fs/btrfs/scrub.c ++++ b/fs/btrfs/scrub.c +@@ -1538,8 +1538,8 @@ static int scrub_find_fill_first_stripe(struct btrfs_block_group *bg, + u64 extent_gen; + int ret; + +- if (unlikely(!extent_root)) { +- btrfs_err(fs_info, "no valid extent root for scrub"); ++ if (unlikely(!extent_root || !csum_root)) { ++ btrfs_err(fs_info, "no valid extent or csum root for scrub"); + return -EUCLEAN; + } + memset(stripe->sectors, 0, sizeof(struct scrub_sector_verification) * +diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c +index aa1e6d88a72c7c..e2ead36e5be422 100644 +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -487,10 +487,8 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) + if (p->buf_len >= len) + return 0; + +- if (len > PATH_MAX) { +- WARN_ON(1); +- return -ENOMEM; +- } ++ if (WARN_ON(len > PATH_MAX)) ++ return -ENAMETOOLONG; + + path_len = p->end - p->start; + old_buf_len = p->buf_len; +diff --git a/fs/coredump.c b/fs/coredump.c +index 9d235fa14ab98f..d3a4f5dc2e362a 100644 +--- a/fs/coredump.c ++++ b/fs/coredump.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -56,6 +57,13 @@ + static bool dump_vma_snapshot(struct coredump_params *cprm); + static void free_vma_snapshot(struct coredump_params *cprm); + ++/* ++ * File descriptor number for the pidfd for the thread-group leader of ++ * the coredumping task installed into the usermode helper's file ++ * descriptor table. ++ */ ++#define COREDUMP_PIDFD_NUMBER 3 ++ + static int core_uses_pid; + static unsigned int core_pipe_limit; + static char core_pattern[CORENAME_MAX_SIZE] = "core"; +@@ -332,6 +340,27 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm, + case 'C': + err = cn_printf(cn, "%d", cprm->cpu); + break; ++ /* pidfd number */ ++ case 'F': { ++ /* ++ * Installing a pidfd only makes sense if ++ * we actually spawn a usermode helper. ++ */ ++ if (!ispipe) ++ break; ++ ++ /* ++ * Note that we'll install a pidfd for the ++ * thread-group leader. We know that task ++ * linkage hasn't been removed yet and even if ++ * this @current isn't the actual thread-group ++ * leader we know that the thread-group leader ++ * cannot be reaped until @current has exited. ++ */ ++ cprm->pid = task_tgid(current); ++ err = cn_printf(cn, "%d", COREDUMP_PIDFD_NUMBER); ++ break; ++ } + default: + break; + } +@@ -488,7 +517,7 @@ static void wait_for_dump_helpers(struct file *file) + } + + /* +- * umh_pipe_setup ++ * umh_coredump_setup + * helper function to customize the process used + * to collect the core in userspace. Specifically + * it sets up a pipe and installs it as fd 0 (stdin) +@@ -498,21 +527,61 @@ static void wait_for_dump_helpers(struct file *file) + * is a special value that we use to trap recursive + * core dumps + */ +-static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) ++static int umh_coredump_setup(struct subprocess_info *info, struct cred *new) + { + struct file *files[2]; ++ struct file *pidfs_file = NULL; + struct coredump_params *cp = (struct coredump_params *)info->data; +- int err = create_pipe_files(files, 0); ++ int err; ++ ++ if (cp->pid) { ++ int fd; ++ ++ fd = pidfd_prepare(cp->pid, 0, &pidfs_file); ++ if (fd < 0) ++ return fd; ++ ++ /* ++ * We don't care about the fd. We also cannot simply ++ * replace it below because dup2() will refuse to close ++ * this file descriptor if its in a larval state. So ++ * close it! ++ */ ++ put_unused_fd(fd); ++ ++ /* ++ * Usermode helpers are childen of either ++ * system_unbound_wq or of kthreadd. So we know that ++ * we're starting off with a clean file descriptor ++ * table. So we should always be able to use ++ * COREDUMP_PIDFD_NUMBER as our file descriptor value. ++ */ ++ err = replace_fd(COREDUMP_PIDFD_NUMBER, pidfs_file, 0); ++ if (err < 0) ++ goto out_fail; ++ ++ pidfs_file = NULL; ++ } ++ ++ err = create_pipe_files(files, 0); + if (err) +- return err; ++ goto out_fail; + + cp->file = files[1]; + + err = replace_fd(0, files[0], 0); + fput(files[0]); ++ if (err < 0) ++ goto out_fail; ++ + /* and disallow core files too */ + current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; + ++ err = 0; ++ ++out_fail: ++ if (pidfs_file) ++ fput(pidfs_file); + return err; + } + +@@ -589,7 +658,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) + } + + if (cprm.limit == 1) { +- /* See umh_pipe_setup() which sets RLIMIT_CORE = 1. ++ /* See umh_coredump_setup() which sets RLIMIT_CORE = 1. + * + * Normally core limits are irrelevant to pipes, since + * we're not writing to the file system, but we use +@@ -634,7 +703,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) + retval = -ENOMEM; + sub_info = call_usermodehelper_setup(helper_argv[0], + helper_argv, NULL, GFP_KERNEL, +- umh_pipe_setup, NULL, &cprm); ++ umh_coredump_setup, NULL, &cprm); + if (sub_info) + retval = call_usermodehelper_exec(sub_info, + UMH_WAIT_EXEC); +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 0618af36f5506b..3c9ab6461579c9 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -1826,8 +1826,8 @@ static int dlm_tcp_listen_validate(void) + { + /* We don't support multi-homed hosts */ + if (dlm_local_count > 1) { +- log_print("TCP protocol can't handle multi-homed hosts, try SCTP"); +- return -EINVAL; ++ log_print("Detect multi-homed hosts but use only the first IP address."); ++ log_print("Try SCTP, if you want to enable multi-link."); + } + + return 0; +diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c +index 396474e9e2bffe..3a2dfc59fb40fc 100644 +--- a/fs/ext4/balloc.c ++++ b/fs/ext4/balloc.c +@@ -641,8 +641,8 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi, + /* Hm, nope. Are (enough) root reserved clusters available? */ + if (uid_eq(sbi->s_resuid, current_fsuid()) || + (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) || +- capable(CAP_SYS_RESOURCE) || +- (flags & EXT4_MB_USE_ROOT_BLOCKS)) { ++ (flags & EXT4_MB_USE_ROOT_BLOCKS) || ++ capable(CAP_SYS_RESOURCE)) { + + if (free_clusters >= (nclusters + dirty_clusters + + resv_clusters)) +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 60455c84a93742..81fe87fcbfa068 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -273,7 +273,8 @@ struct ext4_system_blocks { + /* + * Flags for ext4_io_end->flags + */ +-#define EXT4_IO_END_UNWRITTEN 0x0001 ++#define EXT4_IO_END_UNWRITTEN 0x0001 ++#define EXT4_IO_END_FAILED 0x0002 + + struct ext4_io_end_vec { + struct list_head list; /* list of io_end_vec */ +@@ -2994,6 +2995,8 @@ extern int ext4_inode_attach_jinode(struct inode *inode); + extern int ext4_can_truncate(struct inode *inode); + extern int ext4_truncate(struct inode *); + extern int ext4_break_layouts(struct inode *); ++extern int ext4_truncate_page_cache_block_range(struct inode *inode, ++ loff_t start, loff_t end); + extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length); + extern void ext4_set_inode_flags(struct inode *, bool init); + extern int ext4_alloc_da_blocks(struct inode *inode); +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 32218ac7f50fe2..39e3661a80c433 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4660,22 +4660,13 @@ static long ext4_zero_range(struct file *file, loff_t offset, + goto out_mutex; + } + +- /* +- * For journalled data we need to write (and checkpoint) pages +- * before discarding page cache to avoid inconsitent data on +- * disk in case of crash before zeroing trans is committed. +- */ +- if (ext4_should_journal_data(inode)) { +- ret = filemap_write_and_wait_range(mapping, start, +- end - 1); +- if (ret) { +- filemap_invalidate_unlock(mapping); +- goto out_mutex; +- } ++ /* Now release the pages and zero block aligned part of pages */ ++ ret = ext4_truncate_page_cache_block_range(inode, start, end); ++ if (ret) { ++ filemap_invalidate_unlock(mapping); ++ goto out_mutex; + } + +- /* Now release the pages and zero block aligned part of pages */ +- truncate_pagecache_range(inode, start, end - 1); + inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); + + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index d3d28e65872027..86245e27be18db 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -3892,6 +3893,68 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, + return ret; + } + ++static inline void ext4_truncate_folio(struct inode *inode, ++ loff_t start, loff_t end) ++{ ++ unsigned long blocksize = i_blocksize(inode); ++ struct folio *folio; ++ ++ /* Nothing to be done if no complete block needs to be truncated. */ ++ if (round_up(start, blocksize) >= round_down(end, blocksize)) ++ return; ++ ++ folio = filemap_lock_folio(inode->i_mapping, start >> PAGE_SHIFT); ++ if (IS_ERR(folio)) ++ return; ++ ++ if (folio_mkclean(folio)) ++ folio_mark_dirty(folio); ++ folio_unlock(folio); ++ folio_put(folio); ++} ++ ++int ext4_truncate_page_cache_block_range(struct inode *inode, ++ loff_t start, loff_t end) ++{ ++ unsigned long blocksize = i_blocksize(inode); ++ int ret; ++ ++ /* ++ * For journalled data we need to write (and checkpoint) pages ++ * before discarding page cache to avoid inconsitent data on disk ++ * in case of crash before freeing or unwritten converting trans ++ * is committed. ++ */ ++ if (ext4_should_journal_data(inode)) { ++ ret = filemap_write_and_wait_range(inode->i_mapping, start, ++ end - 1); ++ if (ret) ++ return ret; ++ goto truncate_pagecache; ++ } ++ ++ /* ++ * If the block size is less than the page size, the file's mapped ++ * blocks within one page could be freed or converted to unwritten. ++ * So it's necessary to remove writable userspace mappings, and then ++ * ext4_page_mkwrite() can be called during subsequent write access ++ * to these partial folios. ++ */ ++ if (!IS_ALIGNED(start | end, PAGE_SIZE) && ++ blocksize < PAGE_SIZE && start < inode->i_size) { ++ loff_t page_boundary = round_up(start, PAGE_SIZE); ++ ++ ext4_truncate_folio(inode, start, min(page_boundary, end)); ++ if (end > page_boundary) ++ ext4_truncate_folio(inode, ++ round_down(end, PAGE_SIZE), end); ++ } ++ ++truncate_pagecache: ++ truncate_pagecache_range(inode, start, end - 1); ++ return 0; ++} ++ + static void ext4_wait_dax_page(struct inode *inode) + { + filemap_invalidate_unlock(inode->i_mapping); +@@ -3946,17 +4009,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) + + trace_ext4_punch_hole(inode, offset, length, 0); + +- /* +- * Write out all dirty pages to avoid race conditions +- * Then release them. +- */ +- if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { +- ret = filemap_write_and_wait_range(mapping, offset, +- offset + length - 1); +- if (ret) +- return ret; +- } +- + inode_lock(inode); + + /* No need to punch hole beyond i_size */ +@@ -4018,8 +4070,11 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) + ret = ext4_update_disksize_before_punch(inode, offset, length); + if (ret) + goto out_dio; +- truncate_pagecache_range(inode, first_block_offset, +- last_block_offset); ++ ++ ret = ext4_truncate_page_cache_block_range(inode, ++ first_block_offset, last_block_offset + 1); ++ if (ret) ++ goto out_dio; + } + + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index 7ab4f5a9bf5b87..7287dbfe13f120 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -181,14 +181,25 @@ static int ext4_end_io_end(ext4_io_end_t *io_end) + "list->prev 0x%p\n", + io_end, inode->i_ino, io_end->list.next, io_end->list.prev); + +- io_end->handle = NULL; /* Following call will use up the handle */ +- ret = ext4_convert_unwritten_io_end_vec(handle, io_end); ++ /* ++ * Do not convert the unwritten extents if data writeback fails, ++ * or stale data may be exposed. ++ */ ++ io_end->handle = NULL; /* Following call will use up the handle */ ++ if (unlikely(io_end->flag & EXT4_IO_END_FAILED)) { ++ ret = -EIO; ++ if (handle) ++ jbd2_journal_free_reserved(handle); ++ } else { ++ ret = ext4_convert_unwritten_io_end_vec(handle, io_end); ++ } + if (ret < 0 && !ext4_forced_shutdown(inode->i_sb)) { + ext4_msg(inode->i_sb, KERN_EMERG, + "failed to convert unwritten extents to written " + "extents -- potential data loss! " + "(inode %lu, error %d)", inode->i_ino, ret); + } ++ + ext4_clear_io_unwritten_flag(io_end); + ext4_release_io_end(io_end); + return ret; +@@ -344,6 +355,7 @@ static void ext4_end_bio(struct bio *bio) + bio->bi_status, inode->i_ino, + (unsigned long long) + bi_sector >> (inode->i_blkbits - 9)); ++ io_end->flag |= EXT4_IO_END_FAILED; + mapping_set_error(inode->i_mapping, + blk_status_to_errno(bio->bi_status)); + } +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 751c879271e05e..d2b58f940aab5e 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -2821,6 +2821,13 @@ static int ext4_check_opt_consistency(struct fs_context *fc, + } + + if (is_remount) { ++ if (!sbi->s_journal && ++ ctx_test_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT)) { ++ ext4_msg(NULL, KERN_WARNING, ++ "Remounting fs w/o journal so ignoring data_err option"); ++ ctx_clear_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT); ++ } ++ + if (ctx_test_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS) && + (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)) { + ext4_msg(NULL, KERN_ERR, "can't mount with " +@@ -5421,6 +5428,11 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) + "data=, fs mounted w/o journal"); + goto failed_mount3a; + } ++ if (test_opt(sb, DATA_ERR_ABORT)) { ++ ext4_msg(sb, KERN_ERR, ++ "can't mount with data_err=abort, fs mounted w/o journal"); ++ goto failed_mount3a; ++ } + sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM; + clear_opt(sb, JOURNAL_CHECKSUM); + clear_opt(sb, DATA_FLAGS); +@@ -6771,6 +6783,7 @@ static int ext4_reconfigure(struct fs_context *fc) + { + struct super_block *sb = fc->root->d_sb; + int ret; ++ bool old_ro = sb_rdonly(sb); + + fc->s_fs_info = EXT4_SB(sb); + +@@ -6782,9 +6795,9 @@ static int ext4_reconfigure(struct fs_context *fc) + if (ret < 0) + return ret; + +- ext4_msg(sb, KERN_INFO, "re-mounted %pU %s. Quota mode: %s.", +- &sb->s_uuid, sb_rdonly(sb) ? "ro" : "r/w", +- ext4_quota_mode(sb)); ++ ext4_msg(sb, KERN_INFO, "re-mounted %pU%s.", ++ &sb->s_uuid, ++ (old_ro != sb_rdonly(sb)) ? (sb_rdonly(sb) ? " ro" : " r/w") : ""); + + return 0; + } +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 180feefc4a9ceb..c4b0661888a159 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -61,6 +61,12 @@ struct f2fs_attr { + int id; + }; + ++struct f2fs_base_attr { ++ struct attribute attr; ++ ssize_t (*show)(struct f2fs_base_attr *a, char *buf); ++ ssize_t (*store)(struct f2fs_base_attr *a, const char *buf, size_t len); ++}; ++ + static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf); + +@@ -791,6 +797,25 @@ static void f2fs_sb_release(struct kobject *kobj) + complete(&sbi->s_kobj_unregister); + } + ++static ssize_t f2fs_base_attr_show(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ struct f2fs_base_attr *a = container_of(attr, ++ struct f2fs_base_attr, attr); ++ ++ return a->show ? a->show(a, buf) : 0; ++} ++ ++static ssize_t f2fs_base_attr_store(struct kobject *kobj, ++ struct attribute *attr, ++ const char *buf, size_t len) ++{ ++ struct f2fs_base_attr *a = container_of(attr, ++ struct f2fs_base_attr, attr); ++ ++ return a->store ? a->store(a, buf, len) : 0; ++} ++ + /* + * Note that there are three feature list entries: + * 1) /sys/fs/f2fs/features +@@ -809,14 +834,13 @@ static void f2fs_sb_release(struct kobject *kobj) + * please add new on-disk feature in this list only. + * - ref. F2FS_SB_FEATURE_RO_ATTR() + */ +-static ssize_t f2fs_feature_show(struct f2fs_attr *a, +- struct f2fs_sb_info *sbi, char *buf) ++static ssize_t f2fs_feature_show(struct f2fs_base_attr *a, char *buf) + { + return sysfs_emit(buf, "supported\n"); + } + + #define F2FS_FEATURE_RO_ATTR(_name) \ +-static struct f2fs_attr f2fs_attr_##_name = { \ ++static struct f2fs_base_attr f2fs_base_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = 0444 }, \ + .show = f2fs_feature_show, \ + } +@@ -1166,37 +1190,38 @@ static struct attribute *f2fs_attrs[] = { + }; + ATTRIBUTE_GROUPS(f2fs); + ++#define BASE_ATTR_LIST(name) (&f2fs_base_attr_##name.attr) + static struct attribute *f2fs_feat_attrs[] = { + #ifdef CONFIG_FS_ENCRYPTION +- ATTR_LIST(encryption), +- ATTR_LIST(test_dummy_encryption_v2), ++ BASE_ATTR_LIST(encryption), ++ BASE_ATTR_LIST(test_dummy_encryption_v2), + #if IS_ENABLED(CONFIG_UNICODE) +- ATTR_LIST(encrypted_casefold), ++ BASE_ATTR_LIST(encrypted_casefold), + #endif + #endif /* CONFIG_FS_ENCRYPTION */ + #ifdef CONFIG_BLK_DEV_ZONED +- ATTR_LIST(block_zoned), ++ BASE_ATTR_LIST(block_zoned), + #endif +- ATTR_LIST(atomic_write), +- ATTR_LIST(extra_attr), +- ATTR_LIST(project_quota), +- ATTR_LIST(inode_checksum), +- ATTR_LIST(flexible_inline_xattr), +- ATTR_LIST(quota_ino), +- ATTR_LIST(inode_crtime), +- ATTR_LIST(lost_found), ++ BASE_ATTR_LIST(atomic_write), ++ BASE_ATTR_LIST(extra_attr), ++ BASE_ATTR_LIST(project_quota), ++ BASE_ATTR_LIST(inode_checksum), ++ BASE_ATTR_LIST(flexible_inline_xattr), ++ BASE_ATTR_LIST(quota_ino), ++ BASE_ATTR_LIST(inode_crtime), ++ BASE_ATTR_LIST(lost_found), + #ifdef CONFIG_FS_VERITY +- ATTR_LIST(verity), ++ BASE_ATTR_LIST(verity), + #endif +- ATTR_LIST(sb_checksum), ++ BASE_ATTR_LIST(sb_checksum), + #if IS_ENABLED(CONFIG_UNICODE) +- ATTR_LIST(casefold), ++ BASE_ATTR_LIST(casefold), + #endif +- ATTR_LIST(readonly), ++ BASE_ATTR_LIST(readonly), + #ifdef CONFIG_F2FS_FS_COMPRESSION +- ATTR_LIST(compression), ++ BASE_ATTR_LIST(compression), + #endif +- ATTR_LIST(pin_file), ++ BASE_ATTR_LIST(pin_file), + NULL, + }; + ATTRIBUTE_GROUPS(f2fs_feat); +@@ -1263,9 +1288,14 @@ static struct kset f2fs_kset = { + .kobj = {.ktype = &f2fs_ktype}, + }; + ++static const struct sysfs_ops f2fs_feat_attr_ops = { ++ .show = f2fs_base_attr_show, ++ .store = f2fs_base_attr_store, ++}; ++ + static const struct kobj_type f2fs_feat_ktype = { + .default_groups = f2fs_feat_groups, +- .sysfs_ops = &f2fs_attr_ops, ++ .sysfs_ops = &f2fs_feat_attr_ops, + }; + + static struct kobject f2fs_feat = { +diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c +index e4d6cc0d2332a4..82951a535d2d4d 100644 +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -1121,6 +1121,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, + else if (err == -EINTR) + fuse_invalidate_attr(inode); + ++ if (err == -ENOSYS) ++ err = -EPERM; + return err; + } + +diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c +index 2c0908a3021026..687670075d2256 100644 +--- a/fs/gfs2/glock.c ++++ b/fs/gfs2/glock.c +@@ -853,11 +853,12 @@ static void run_queue(struct gfs2_glock *gl, const int nonblock) + __releases(&gl->gl_lockref.lock) + __acquires(&gl->gl_lockref.lock) + { +- struct gfs2_holder *gh = NULL; ++ struct gfs2_holder *gh; + + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) + return; + ++ /* While a demote is in progress, the GLF_LOCK flag must be set. */ + GLOCK_BUG_ON(gl, test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)); + + if (test_bit(GLF_DEMOTE, &gl->gl_flags) && +@@ -869,18 +870,22 @@ __acquires(&gl->gl_lockref.lock) + set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); + GLOCK_BUG_ON(gl, gl->gl_demote_state == LM_ST_EXCLUSIVE); + gl->gl_target = gl->gl_demote_state; ++ do_xmote(gl, NULL, gl->gl_target); ++ return; + } else { + if (test_bit(GLF_DEMOTE, &gl->gl_flags)) + gfs2_demote_wake(gl); + if (do_promote(gl)) + goto out_unlock; + gh = find_first_waiter(gl); ++ if (!gh) ++ goto out_unlock; + gl->gl_target = gh->gh_state; + if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) + do_error(gl, 0); /* Fail queued try locks */ ++ do_xmote(gl, gh, gl->gl_target); ++ return; + } +- do_xmote(gl, gh, gl->gl_target); +- return; + + out_sched: + clear_bit(GLF_LOCK, &gl->gl_flags); +diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c +index 421c0d360836e0..19ec3253748331 100644 +--- a/fs/jbd2/recovery.c ++++ b/fs/jbd2/recovery.c +@@ -286,21 +286,22 @@ static int fc_do_one_pass(journal_t *journal, + int jbd2_journal_recover(journal_t *journal) + { + int err, err2; +- journal_superblock_t * sb; +- + struct recovery_info info; + errseq_t wb_err; + struct address_space *mapping; + + memset(&info, 0, sizeof(info)); +- sb = journal->j_superblock; + + /* + * The journal superblock's s_start field (the current log head) + * is always zero if, and only if, the journal was cleanly +- * unmounted. ++ * unmounted. We use its in-memory version j_tail here because ++ * jbd2_journal_wipe() could have updated it without updating journal ++ * superblock. + */ +- if (!sb->s_start) { ++ if (!journal->j_tail) { ++ journal_superblock_t *sb = journal->j_superblock; ++ + jbd2_debug(1, "No recovery required, last transaction %d, head block %u\n", + be32_to_cpu(sb->s_sequence), be32_to_cpu(sb->s_head)); + journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; +diff --git a/fs/namespace.c b/fs/namespace.c +index 450f4198b8cdd8..ef3b2ae2957ec3 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -636,12 +636,8 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq) + smp_mb(); // see mntput_no_expire() and do_umount() + if (likely(!read_seqretry(&mount_lock, seq))) + return 0; +- if (bastard->mnt_flags & MNT_SYNC_UMOUNT) { +- mnt_add_count(mnt, -1); +- return 1; +- } + lock_mount_hash(); +- if (unlikely(bastard->mnt_flags & MNT_DOOMED)) { ++ if (unlikely(bastard->mnt_flags & (MNT_SYNC_UMOUNT | MNT_DOOMED))) { + mnt_add_count(mnt, -1); + unlock_mount_hash(); + return 1; +diff --git a/fs/nfs/client.c b/fs/nfs/client.c +index 62607d52bfa5e7..aa09f930eeaf7e 100644 +--- a/fs/nfs/client.c ++++ b/fs/nfs/client.c +@@ -1080,6 +1080,8 @@ struct nfs_server *nfs_create_server(struct fs_context *fc) + if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) + server->namelen = NFS2_MAXNAMLEN; + } ++ /* Linux 'subtree_check' borkenness mandates this setting */ ++ server->fh_expire_type = NFS_FH_VOL_RENAME; + + if (!(fattr->valid & NFS_ATTR_FATTR)) { + error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh, +diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c +index 55cfa1c4e0a65d..bbd582d8a7dc93 100644 +--- a/fs/nfs/delegation.c ++++ b/fs/nfs/delegation.c +@@ -297,7 +297,8 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi) + if (delegation == NULL) + goto out; + spin_lock(&delegation->lock); +- if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { ++ if (delegation->inode && ++ !test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { + clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags); + /* Refcount matched in nfs_end_delegation_return() */ + ret = nfs_get_delegation(delegation); +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index 39f7549afcf5bd..38918638423596 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -2642,6 +2642,18 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data) + unblock_revalidate(new_dentry); + } + ++static bool nfs_rename_is_unsafe_cross_dir(struct dentry *old_dentry, ++ struct dentry *new_dentry) ++{ ++ struct nfs_server *server = NFS_SB(old_dentry->d_sb); ++ ++ if (old_dentry->d_parent != new_dentry->d_parent) ++ return false; ++ if (server->fh_expire_type & NFS_FH_RENAME_UNSAFE) ++ return !(server->fh_expire_type & NFS_FH_NOEXPIRE_WITH_OPEN); ++ return true; ++} ++ + /* + * RENAME + * FIXME: Some nfsds, like the Linux user space nfsd, may generate a +@@ -2729,7 +2741,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, + + } + +- if (S_ISREG(old_inode->i_mode)) ++ if (S_ISREG(old_inode->i_mode) && ++ nfs_rename_is_unsafe_cross_dir(old_dentry, new_dentry)) + nfs_sync_inode(old_inode); + task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, + must_unblock ? nfs_unblock_rename : NULL); +diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c +index acf4b88889dc38..d5f1fbfd9a0c7f 100644 +--- a/fs/nfs/filelayout/filelayoutdev.c ++++ b/fs/nfs/filelayout/filelayoutdev.c +@@ -75,6 +75,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + struct page *scratch; + struct list_head dsaddrs; + struct nfs4_pnfs_ds_addr *da; ++ struct net *net = server->nfs_client->cl_net; + + /* set up xdr stream */ + scratch = alloc_page(gfp_flags); +@@ -158,8 +159,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + + mp_count = be32_to_cpup(p); /* multipath count */ + for (j = 0; j < mp_count; j++) { +- da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net, +- &stream, gfp_flags); ++ da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); + if (da) + list_add_tail(&da->da_node, &dsaddrs); + } +@@ -169,7 +169,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + goto out_err_free_deviceid; + } + +- dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); ++ dsaddr->ds_list[i] = nfs4_pnfs_ds_add(net, &dsaddrs, gfp_flags); + if (!dsaddr->ds_list[i]) + goto out_err_drain_dsaddrs; + +diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c +index 2b3c5eea1f1345..0bc537de1b2958 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayout.c ++++ b/fs/nfs/flexfilelayout/flexfilelayout.c +@@ -1255,6 +1255,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg, + case -ECONNRESET: + case -EHOSTDOWN: + case -EHOSTUNREACH: ++ case -ENETDOWN: + case -ENETUNREACH: + case -EADDRINUSE: + case -ENOBUFS: +diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +index e028f5a0ef5f65..d21c5ecfbf1cc3 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c ++++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +@@ -49,6 +49,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + struct nfs4_pnfs_ds_addr *da; + struct nfs4_ff_layout_ds *new_ds = NULL; + struct nfs4_ff_ds_version *ds_versions = NULL; ++ struct net *net = server->nfs_client->cl_net; + u32 mp_count; + u32 version_count; + __be32 *p; +@@ -80,8 +81,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + + for (i = 0; i < mp_count; i++) { + /* multipath ds */ +- da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net, +- &stream, gfp_flags); ++ da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); + if (da) + list_add_tail(&da->da_node, &dsaddrs); + } +@@ -149,7 +149,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + new_ds->ds_versions = ds_versions; + new_ds->ds_versions_cnt = version_count; + +- new_ds->ds = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); ++ new_ds->ds = nfs4_pnfs_ds_add(net, &dsaddrs, gfp_flags); + if (!new_ds->ds) + goto out_err_drain_dsaddrs; + +diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c +index 56bbf59bda3cf6..06230baaa554e7 100644 +--- a/fs/nfs/inode.c ++++ b/fs/nfs/inode.c +@@ -74,6 +74,8 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) + + int nfs_wait_bit_killable(struct wait_bit_key *key, int mode) + { ++ if (unlikely(nfs_current_task_exiting())) ++ return -EINTR; + schedule(); + if (signal_pending_state(mode, current)) + return -ERESTARTSYS; +diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h +index ca49d999159eb1..c29ad2e1d41635 100644 +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -865,6 +865,11 @@ static inline u32 nfs_stateid_hash(const nfs4_stateid *stateid) + NFS4_STATEID_OTHER_SIZE); + } + ++static inline bool nfs_current_task_exiting(void) ++{ ++ return (current->flags & PF_EXITING) != 0; ++} ++ + static inline bool nfs_error_is_fatal(int err) + { + switch (err) { +diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c +index 4bf208a0a8e994..715753f41fb072 100644 +--- a/fs/nfs/nfs3proc.c ++++ b/fs/nfs/nfs3proc.c +@@ -39,7 +39,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) + __set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); + schedule_timeout(NFS_JUKEBOX_RETRY_TIME); + res = -ERESTARTSYS; +- } while (!fatal_signal_pending(current)); ++ } while (!fatal_signal_pending(current) && !nfs_current_task_exiting()); + return res; + } + +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index c140427e322ced..1b94a55215e7de 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -422,6 +422,8 @@ static int nfs4_delay_killable(long *timeout) + { + might_sleep(); + ++ if (unlikely(nfs_current_task_exiting())) ++ return -EINTR; + __set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); + schedule_timeout(nfs4_update_delay(timeout)); + if (!__fatal_signal_pending(current)) +@@ -433,6 +435,8 @@ static int nfs4_delay_interruptible(long *timeout) + { + might_sleep(); + ++ if (unlikely(nfs_current_task_exiting())) ++ return -EINTR; + __set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE_UNSAFE); + schedule_timeout(nfs4_update_delay(timeout)); + if (!signal_pending(current)) +@@ -1712,7 +1716,8 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, + rcu_read_unlock(); + trace_nfs4_open_stateid_update_wait(state->inode, stateid, 0); + +- if (!fatal_signal_pending(current)) { ++ if (!fatal_signal_pending(current) && ++ !nfs_current_task_exiting()) { + if (schedule_timeout(5*HZ) == 0) + status = -EAGAIN; + else +@@ -3494,7 +3499,7 @@ static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst, + write_sequnlock(&state->seqlock); + trace_nfs4_close_stateid_update_wait(state->inode, dst, 0); + +- if (fatal_signal_pending(current)) ++ if (fatal_signal_pending(current) || nfs_current_task_exiting()) + status = -EINTR; + else + if (schedule_timeout(5*HZ) != 0) +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index 794bb4aa588d39..9fc71dc090c254 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -2741,7 +2741,15 @@ static void nfs4_state_manager(struct nfs_client *clp) + pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s" + " with error %d\n", section_sep, section, + clp->cl_hostname, -status); +- ssleep(1); ++ switch (status) { ++ case -ENETDOWN: ++ case -ENETUNREACH: ++ nfs_mark_client_ready(clp, -EIO); ++ break; ++ default: ++ ssleep(1); ++ break; ++ } + out_drain: + memalloc_nofs_restore(memflags); + nfs4_end_drain_session(clp); +diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h +index d886c8226d8fec..79996d7dad0f76 100644 +--- a/fs/nfs/pnfs.h ++++ b/fs/nfs/pnfs.h +@@ -59,6 +59,7 @@ struct nfs4_pnfs_ds { + struct list_head ds_node; /* nfs4_pnfs_dev_hlist dev_dslist */ + char *ds_remotestr; /* comma sep list of addrs */ + struct list_head ds_addrs; ++ const struct net *ds_net; + struct nfs_client *ds_clp; + refcount_t ds_count; + unsigned long ds_state; +@@ -405,7 +406,8 @@ int pnfs_generic_commit_pagelist(struct inode *inode, + int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max); + void pnfs_generic_write_commit_done(struct rpc_task *task, void *data); + void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds); +-struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, ++struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(const struct net *net, ++ struct list_head *dsaddrs, + gfp_t gfp_flags); + void nfs4_pnfs_v3_ds_connect_unload(void); + int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, +diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c +index 88e061bd711b74..1b317c44da126b 100644 +--- a/fs/nfs/pnfs_nfs.c ++++ b/fs/nfs/pnfs_nfs.c +@@ -651,12 +651,12 @@ _same_data_server_addrs_locked(const struct list_head *dsaddrs1, + * Lookup DS by addresses. nfs4_ds_cache_lock is held + */ + static struct nfs4_pnfs_ds * +-_data_server_lookup_locked(const struct list_head *dsaddrs) ++_data_server_lookup_locked(const struct net *net, const struct list_head *dsaddrs) + { + struct nfs4_pnfs_ds *ds; + + list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) +- if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs)) ++ if (ds->ds_net == net && _same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs)) + return ds; + return NULL; + } +@@ -763,7 +763,7 @@ nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags) + * uncached and return cached struct nfs4_pnfs_ds. + */ + struct nfs4_pnfs_ds * +-nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) ++nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_flags) + { + struct nfs4_pnfs_ds *tmp_ds, *ds = NULL; + char *remotestr; +@@ -781,13 +781,14 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) + remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags); + + spin_lock(&nfs4_ds_cache_lock); +- tmp_ds = _data_server_lookup_locked(dsaddrs); ++ tmp_ds = _data_server_lookup_locked(net, dsaddrs); + if (tmp_ds == NULL) { + INIT_LIST_HEAD(&ds->ds_addrs); + list_splice_init(dsaddrs, &ds->ds_addrs); + ds->ds_remotestr = remotestr; + refcount_set(&ds->ds_count, 1); + INIT_LIST_HEAD(&ds->ds_node); ++ ds->ds_net = net; + ds->ds_clp = NULL; + list_add(&ds->ds_node, &nfs4_data_server_cache); + dprintk("%s add new data server %s\n", __func__, +diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c +index 0859122684425f..dd4dc70e4aaab7 100644 +--- a/fs/orangefs/inode.c ++++ b/fs/orangefs/inode.c +@@ -23,9 +23,9 @@ static int orangefs_writepage_locked(struct page *page, + struct orangefs_write_range *wr = NULL; + struct iov_iter iter; + struct bio_vec bv; +- size_t len, wlen; ++ size_t wlen; + ssize_t ret; +- loff_t off; ++ loff_t len, off; + + set_page_writeback(page); + +@@ -92,8 +92,7 @@ static int orangefs_writepages_work(struct orangefs_writepages *ow, + struct orangefs_write_range *wrp, wr; + struct iov_iter iter; + ssize_t ret; +- size_t len; +- loff_t off; ++ loff_t len, off; + int i; + + len = i_size_read(inode); +diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c +index 7dbbf3b6d98d3c..a1c97cd2720a68 100644 +--- a/fs/pstore/inode.c ++++ b/fs/pstore/inode.c +@@ -264,7 +264,7 @@ static void parse_options(char *options) + static int pstore_show_options(struct seq_file *m, struct dentry *root) + { + if (kmsg_bytes != CONFIG_PSTORE_DEFAULT_KMSG_BYTES) +- seq_printf(m, ",kmsg_bytes=%lu", kmsg_bytes); ++ seq_printf(m, ",kmsg_bytes=%u", kmsg_bytes); + return 0; + } + +diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h +index 801d6c0b170c3a..a0fc511969100c 100644 +--- a/fs/pstore/internal.h ++++ b/fs/pstore/internal.h +@@ -6,7 +6,7 @@ + #include + #include + +-extern unsigned long kmsg_bytes; ++extern unsigned int kmsg_bytes; + + #ifdef CONFIG_PSTORE_FTRACE + extern void pstore_register_ftrace(void); +@@ -35,7 +35,7 @@ static inline void pstore_unregister_pmsg(void) {} + + extern struct pstore_info *psinfo; + +-extern void pstore_set_kmsg_bytes(int); ++extern void pstore_set_kmsg_bytes(unsigned int bytes); + extern void pstore_get_records(int); + extern void pstore_get_backend_records(struct pstore_info *psi, + struct dentry *root, int quiet); +diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c +index 03425928d2fb3c..ef62389212b608 100644 +--- a/fs/pstore/platform.c ++++ b/fs/pstore/platform.c +@@ -92,8 +92,8 @@ module_param(compress, charp, 0444); + MODULE_PARM_DESC(compress, "compression to use"); + + /* How much of the kernel log to snapshot */ +-unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES; +-module_param(kmsg_bytes, ulong, 0444); ++unsigned int kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES; ++module_param(kmsg_bytes, uint, 0444); + MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)"); + + static void *compress_workspace; +@@ -107,9 +107,9 @@ static void *compress_workspace; + static char *big_oops_buf; + static size_t max_compressed_size; + +-void pstore_set_kmsg_bytes(int bytes) ++void pstore_set_kmsg_bytes(unsigned int bytes) + { +- kmsg_bytes = bytes; ++ WRITE_ONCE(kmsg_bytes, bytes); + } + + /* Tag each group of saved records with a sequence number */ +@@ -278,6 +278,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason) + { + struct kmsg_dump_iter iter; ++ unsigned int remaining = READ_ONCE(kmsg_bytes); + unsigned long total = 0; + const char *why; + unsigned int part = 1; +@@ -300,7 +301,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, + kmsg_dump_rewind(&iter); + + oopscount++; +- while (total < kmsg_bytes) { ++ while (total < remaining) { + char *dst; + size_t dst_size; + int header_size; +diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c +index db9076da2182ad..bf32bc22ebd69f 100644 +--- a/fs/smb/client/cifsacl.c ++++ b/fs/smb/client/cifsacl.c +@@ -811,7 +811,23 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, + return; + + for (i = 0; i < num_aces; ++i) { ++ if (end_of_acl - acl_base < acl_size) ++ break; ++ + ppace[i] = (struct smb_ace *) (acl_base + acl_size); ++ acl_base = (char *)ppace[i]; ++ acl_size = offsetof(struct smb_ace, sid) + ++ offsetof(struct smb_sid, sub_auth); ++ ++ if (end_of_acl - acl_base < acl_size || ++ ppace[i]->sid.num_subauth == 0 || ++ ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || ++ (end_of_acl - acl_base < ++ acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || ++ (le16_to_cpu(ppace[i]->size) < ++ acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) ++ break; ++ + #ifdef CONFIG_CIFS_DEBUG2 + dump_ace(ppace[i], end_of_acl); + #endif +@@ -855,7 +871,6 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, + (void *)ppace[i], + sizeof(struct smb_ace)); */ + +- acl_base = (char *)ppace[i]; + acl_size = le16_to_cpu(ppace[i]->size); + } + +diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h +index c46d418c1c0c3e..ca33f6cd6a8004 100644 +--- a/fs/smb/client/cifspdu.h ++++ b/fs/smb/client/cifspdu.h +@@ -1226,10 +1226,9 @@ typedef struct smb_com_query_information_rsp { + typedef struct smb_com_setattr_req { + struct smb_hdr hdr; /* wct = 8 */ + __le16 attr; +- __le16 time_low; +- __le16 time_high; ++ __le32 last_write_time; + __le16 reserved[5]; /* must be zero */ +- __u16 ByteCount; ++ __le16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char fileName[]; + } __attribute__((packed)) SETATTR_REQ; +diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h +index 7f97e54686524b..c6d325666b5cd8 100644 +--- a/fs/smb/client/cifsproto.h ++++ b/fs/smb/client/cifsproto.h +@@ -31,6 +31,9 @@ extern void cifs_small_buf_release(void *); + extern void free_rsp_buf(int, void *); + extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, + unsigned int /* length */); ++extern int smb_send_kvec(struct TCP_Server_Info *server, ++ struct msghdr *msg, ++ size_t *sent); + extern unsigned int _get_xid(void); + extern void _free_xid(unsigned int); + #define get_xid() \ +@@ -395,6 +398,10 @@ extern int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon); + extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, + struct kstatfs *FSData); + ++extern int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, ++ const char *fileName, __le32 attributes, __le64 write_time, ++ const struct nls_table *nls_codepage, ++ struct cifs_sb_info *cifs_sb); + extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const FILE_BASIC_INFO *data, + const struct nls_table *nls_codepage, +diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c +index 769950adb7763b..b91184ebce02c5 100644 +--- a/fs/smb/client/cifssmb.c ++++ b/fs/smb/client/cifssmb.c +@@ -5157,6 +5157,63 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, + return rc; + } + ++int ++SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, ++ const char *fileName, __le32 attributes, __le64 write_time, ++ const struct nls_table *nls_codepage, ++ struct cifs_sb_info *cifs_sb) ++{ ++ SETATTR_REQ *pSMB; ++ SETATTR_RSP *pSMBr; ++ struct timespec64 ts; ++ int bytes_returned; ++ int name_len; ++ int rc; ++ ++ cifs_dbg(FYI, "In %s path %s\n", __func__, fileName); ++ ++retry: ++ rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifsConvertToUTF16((__le16 *) pSMB->fileName, ++ fileName, PATH_MAX, nls_codepage, ++ cifs_remap(cifs_sb)); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { ++ name_len = copy_path_name(pSMB->fileName, fileName); ++ } ++ /* Only few attributes can be set by this command, others are not accepted by Win9x. */ ++ pSMB->attr = cpu_to_le16(le32_to_cpu(attributes) & ++ (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE)); ++ /* Zero write time value (in both NT and SETATTR formats) means to not change it. */ ++ if (le64_to_cpu(write_time) != 0) { ++ ts = cifs_NTtimeToUnix(write_time); ++ pSMB->last_write_time = cpu_to_le32(ts.tv_sec); ++ } ++ pSMB->BufferFormat = 0x04; ++ name_len++; /* account for buffer type byte */ ++ inc_rfc1001_len(pSMB, (__u16)name_len); ++ pSMB->ByteCount = cpu_to_le16(name_len); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) ++ cifs_dbg(FYI, "Send error in %s = %d\n", __func__, rc); ++ ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto retry; ++ ++ return rc; ++} ++ + /* Some legacy servers such as NT4 require that the file times be set on + an open handle, rather than by pathname - this is awkward due to + potential access conflicts on the open, but it is unavoidable for these +diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c +index 54aba8d642ee75..3faaee33ad4558 100644 +--- a/fs/smb/client/connect.c ++++ b/fs/smb/client/connect.c +@@ -3051,8 +3051,10 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) + * sessinit is sent but no second negprot + */ + struct rfc1002_session_packet req = {}; +- struct smb_hdr *smb_buf = (struct smb_hdr *)&req; ++ struct msghdr msg = {}; ++ struct kvec iov = {}; + unsigned int len; ++ size_t sent; + + req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name); + +@@ -3081,10 +3083,18 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) + * As per rfc1002, @len must be the number of bytes that follows the + * length field of a rfc1002 session request payload. + */ +- len = sizeof(req) - offsetof(struct rfc1002_session_packet, trailer.session_req); ++ len = sizeof(req.trailer.session_req); ++ req.type = RFC1002_SESSION_REQUEST; ++ req.flags = 0; ++ req.length = cpu_to_be16(len); ++ len += offsetof(typeof(req), trailer.session_req); ++ iov.iov_base = &req; ++ iov.iov_len = len; ++ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, len); ++ rc = smb_send_kvec(server, &msg, &sent); ++ if (rc < 0 || len != sent) ++ return (rc == -EINTR || rc == -EAGAIN) ? rc : -ECONNABORTED; + +- smb_buf->smb_buf_length = cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | len); +- rc = smb_send(server, smb_buf, len); + /* + * RFC1001 layer in at least one server requires very short break before + * negprot presumably because not expecting negprot to follow so fast. +@@ -3093,7 +3103,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) + */ + usleep_range(1000, 2000); + +- return rc; ++ return 0; + } + + static int +@@ -3946,11 +3956,13 @@ int + cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server) + { ++ bool in_retry = false; + int rc = 0; + + if (!server->ops->need_neg || !server->ops->negotiate) + return -ENOSYS; + ++retry: + /* only send once per connect */ + spin_lock(&server->srv_lock); + if (server->tcpStatus != CifsGood && +@@ -3970,6 +3982,14 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, + spin_unlock(&server->srv_lock); + + rc = server->ops->negotiate(xid, ses, server); ++ if (rc == -EAGAIN) { ++ /* Allow one retry attempt */ ++ if (!in_retry) { ++ in_retry = true; ++ goto retry; ++ } ++ rc = -EHOSTDOWN; ++ } + if (rc == 0) { + spin_lock(&server->srv_lock); + if (server->tcpStatus == CifsInNegotiate) +diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c +index d2e291ef104ec0..137d03781d5268 100644 +--- a/fs/smb/client/fs_context.c ++++ b/fs/smb/client/fs_context.c +@@ -1249,6 +1249,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, + case Opt_rsize: + ctx->rsize = result.uint_32; + ctx->got_rsize = true; ++ ctx->vol_rsize = ctx->rsize; + break; + case Opt_wsize: + ctx->wsize = result.uint_32; +@@ -1264,6 +1265,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, + ctx->wsize, PAGE_SIZE); + } + } ++ ctx->vol_wsize = ctx->wsize; + break; + case Opt_acregmax: + if (result.uint_32 > CIFS_MAX_ACTIMEO / HZ) { +diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h +index bbd2063ab838d3..d0a2043ea44682 100644 +--- a/fs/smb/client/fs_context.h ++++ b/fs/smb/client/fs_context.h +@@ -253,6 +253,9 @@ struct smb3_fs_context { + bool use_client_guid:1; + /* reuse existing guid for multichannel */ + u8 client_guid[SMB2_CLIENT_GUID_SIZE]; ++ /* User-specified original r/wsize value */ ++ unsigned int vol_rsize; ++ unsigned int vol_wsize; + unsigned int bsize; + unsigned int rasize; + unsigned int rsize; +diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c +index d86da949a91905..007da0a699cb0a 100644 +--- a/fs/smb/client/link.c ++++ b/fs/smb/client/link.c +@@ -257,7 +257,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_open_parms oparms; + struct cifs_io_parms io_parms = {0}; + int buf_type = CIFS_NO_BUFFER; +- FILE_ALL_INFO file_info; ++ struct cifs_open_info_data query_data; + + oparms = (struct cifs_open_parms) { + .tcon = tcon, +@@ -269,11 +269,11 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + .fid = &fid, + }; + +- rc = CIFS_open(xid, &oparms, &oplock, &file_info); ++ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data); + if (rc) + return rc; + +- if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { ++ if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { + rc = -ENOENT; + /* it's not a symlink */ + goto out; +@@ -312,7 +312,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + .fid = &fid, + }; + +- rc = CIFS_open(xid, &oparms, &oplock, NULL); ++ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); + if (rc) + return rc; + +diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c +index 75929a0a56f969..e616be8196deda 100644 +--- a/fs/smb/client/readdir.c ++++ b/fs/smb/client/readdir.c +@@ -733,7 +733,10 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, + else + cifs_buf_release(cfile->srch_inf. + ntwrk_buf_start); ++ /* Reset all pointers to the network buffer to prevent stale references */ + cfile->srch_inf.ntwrk_buf_start = NULL; ++ cfile->srch_inf.srch_entries_start = NULL; ++ cfile->srch_inf.last_entry = NULL; + } + rc = initiate_cifs_search(xid, file, full_path); + if (rc) { +@@ -756,11 +759,11 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, + rc = server->ops->query_dir_next(xid, tcon, &cfile->fid, + search_flags, + &cfile->srch_inf); ++ if (rc) ++ return -ENOENT; + /* FindFirst/Next set last_entry to NULL on malformed reply */ + if (cfile->srch_inf.last_entry) + cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); +- if (rc) +- return -ENOENT; + } + if (index_to_find < cfile->srch_inf.index_of_last_entry) { + /* we found the buffer that contains the entry */ +diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c +index caa1d852ece49c..e62d9cc592e0c8 100644 +--- a/fs/smb/client/smb1ops.c ++++ b/fs/smb/client/smb1ops.c +@@ -426,13 +426,6 @@ cifs_negotiate(const unsigned int xid, + { + int rc; + rc = CIFSSMBNegotiate(xid, ses, server); +- if (rc == -EAGAIN) { +- /* retry only once on 1st time connection */ +- set_credits(server, 1); +- rc = CIFSSMBNegotiate(xid, ses, server); +- if (rc == -EAGAIN) +- rc = -EHOSTDOWN; +- } + return rc; + } + +@@ -444,8 +437,8 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int wsize; + + /* start with specified wsize, or default */ +- if (ctx->wsize) +- wsize = ctx->wsize; ++ if (ctx->got_wsize) ++ wsize = ctx->vol_wsize; + else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) + wsize = CIFS_DEFAULT_IOSIZE; + else +@@ -497,7 +490,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + else + defsize = server->maxBuf - sizeof(READ_RSP); + +- rsize = ctx->rsize ? ctx->rsize : defsize; ++ rsize = ctx->got_rsize ? ctx->vol_rsize : defsize; + + /* + * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to +@@ -548,24 +541,104 @@ static int cifs_query_path_info(const unsigned int xid, + const char *full_path, + struct cifs_open_info_data *data) + { +- int rc; ++ int rc = -EOPNOTSUPP; + FILE_ALL_INFO fi = {}; ++ struct cifs_search_info search_info = {}; ++ bool non_unicode_wildcard = false; + + data->symlink = false; + data->adjust_tz = false; + +- /* could do find first instead but this returns more info */ +- rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls, +- cifs_remap(cifs_sb)); + /* +- * BB optimize code so we do not make the above call when server claims +- * no NT SMB support and the above call failed at least once - set flag +- * in tcon or mount. ++ * First try CIFSSMBQPathInfo() function which returns more info ++ * (NumberOfLinks) than CIFSFindFirst() fallback function. ++ * Some servers like Win9x do not support SMB_QUERY_FILE_ALL_INFO over ++ * TRANS2_QUERY_PATH_INFORMATION, but supports it with filehandle over ++ * TRANS2_QUERY_FILE_INFORMATION (function CIFSSMBQFileInfo(). But SMB ++ * Open command on non-NT servers works only for files, does not work ++ * for directories. And moreover Win9x SMB server returns bogus data in ++ * SMB_QUERY_FILE_ALL_INFO Attributes field. So for non-NT servers, ++ * do not even use CIFSSMBQPathInfo() or CIFSSMBQFileInfo() function. ++ */ ++ if (tcon->ses->capabilities & CAP_NT_SMBS) ++ rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, ++ cifs_sb->local_nls, cifs_remap(cifs_sb)); ++ ++ /* ++ * Non-UNICODE variant of fallback functions below expands wildcards, ++ * so they cannot be used for querying paths with wildcard characters. + */ +- if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { ++ if (rc && !(tcon->ses->capabilities & CAP_UNICODE) && strpbrk(full_path, "*?\"><")) ++ non_unicode_wildcard = true; ++ ++ /* ++ * Then fallback to CIFSFindFirst() which works also with non-NT servers ++ * but does not does not provide NumberOfLinks. ++ */ ++ if ((rc == -EOPNOTSUPP || rc == -EINVAL) && ++ !non_unicode_wildcard) { ++ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) ++ search_info.info_level = SMB_FIND_FILE_INFO_STANDARD; ++ else ++ search_info.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO; ++ rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb, NULL, ++ CIFS_SEARCH_CLOSE_ALWAYS | CIFS_SEARCH_CLOSE_AT_END, ++ &search_info, false); ++ if (rc == 0) { ++ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) { ++ FIND_FILE_STANDARD_INFO *di; ++ int offset = tcon->ses->server->timeAdj; ++ ++ di = (FIND_FILE_STANDARD_INFO *)search_info.srch_entries_start; ++ fi.CreationTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( ++ di->CreationDate, di->CreationTime, offset))); ++ fi.LastAccessTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( ++ di->LastAccessDate, di->LastAccessTime, offset))); ++ fi.LastWriteTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( ++ di->LastWriteDate, di->LastWriteTime, offset))); ++ fi.ChangeTime = fi.LastWriteTime; ++ fi.Attributes = cpu_to_le32(le16_to_cpu(di->Attributes)); ++ fi.AllocationSize = cpu_to_le64(le32_to_cpu(di->AllocationSize)); ++ fi.EndOfFile = cpu_to_le64(le32_to_cpu(di->DataSize)); ++ } else { ++ FILE_FULL_DIRECTORY_INFO *di; ++ ++ di = (FILE_FULL_DIRECTORY_INFO *)search_info.srch_entries_start; ++ fi.CreationTime = di->CreationTime; ++ fi.LastAccessTime = di->LastAccessTime; ++ fi.LastWriteTime = di->LastWriteTime; ++ fi.ChangeTime = di->ChangeTime; ++ fi.Attributes = di->ExtFileAttributes; ++ fi.AllocationSize = di->AllocationSize; ++ fi.EndOfFile = di->EndOfFile; ++ fi.EASize = di->EaSize; ++ } ++ fi.NumberOfLinks = cpu_to_le32(1); ++ fi.DeletePending = 0; ++ fi.Directory = !!(le32_to_cpu(fi.Attributes) & ATTR_DIRECTORY); ++ cifs_buf_release(search_info.ntwrk_buf_start); ++ } else if (!full_path[0]) { ++ /* ++ * CIFSFindFirst() does not work on root path if the ++ * root path was exported on the server from the top ++ * level path (drive letter). ++ */ ++ rc = -EOPNOTSUPP; ++ } ++ } ++ ++ /* ++ * If everything failed then fallback to the legacy SMB command ++ * SMB_COM_QUERY_INFORMATION which works with all servers, but ++ * provide just few information. ++ */ ++ if ((rc == -EOPNOTSUPP || rc == -EINVAL) && !non_unicode_wildcard) { + rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls, + cifs_remap(cifs_sb)); + data->adjust_tz = true; ++ } else if ((rc == -EOPNOTSUPP || rc == -EINVAL) && non_unicode_wildcard) { ++ /* Path with non-UNICODE wildcard character cannot exist. */ ++ rc = -ENOENT; + } + + if (!rc) { +@@ -662,6 +735,13 @@ static int cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, + int rc; + FILE_ALL_INFO fi = {}; + ++ /* ++ * CIFSSMBQFileInfo() for non-NT servers returns bogus data in ++ * Attributes fields. So do not use this command for non-NT servers. ++ */ ++ if (!(tcon->ses->capabilities & CAP_NT_SMBS)) ++ return -EOPNOTSUPP; ++ + if (cfile->symlink_target) { + data->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); + if (!data->symlink_target) +@@ -832,6 +912,9 @@ smb_set_file_info(struct inode *inode, const char *full_path, + struct cifs_fid fid; + struct cifs_open_parms oparms; + struct cifsFileInfo *open_file; ++ FILE_BASIC_INFO new_buf; ++ struct cifs_open_info_data query_data; ++ __le64 write_time = buf->LastWriteTime; + struct cifsInodeInfo *cinode = CIFS_I(inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink = NULL; +@@ -839,20 +922,58 @@ smb_set_file_info(struct inode *inode, const char *full_path, + + /* if the file is already open for write, just use that fileid */ + open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY); ++ + if (open_file) { + fid.netfid = open_file->fid.netfid; + netpid = open_file->pid; + tcon = tlink_tcon(open_file->tlink); +- goto set_via_filehandle; ++ } else { ++ tlink = cifs_sb_tlink(cifs_sb); ++ if (IS_ERR(tlink)) { ++ rc = PTR_ERR(tlink); ++ tlink = NULL; ++ goto out; ++ } ++ tcon = tlink_tcon(tlink); + } + +- tlink = cifs_sb_tlink(cifs_sb); +- if (IS_ERR(tlink)) { +- rc = PTR_ERR(tlink); +- tlink = NULL; +- goto out; ++ /* ++ * Non-NT servers interprets zero time value in SMB_SET_FILE_BASIC_INFO ++ * over TRANS2_SET_FILE_INFORMATION as a valid time value. NT servers ++ * interprets zero time value as do not change existing value on server. ++ * API of ->set_file_info() callback expects that zero time value has ++ * the NT meaning - do not change. Therefore if server is non-NT and ++ * some time values in "buf" are zero, then fetch missing time values. ++ */ ++ if (!(tcon->ses->capabilities & CAP_NT_SMBS) && ++ (!buf->CreationTime || !buf->LastAccessTime || ++ !buf->LastWriteTime || !buf->ChangeTime)) { ++ rc = cifs_query_path_info(xid, tcon, cifs_sb, full_path, &query_data); ++ if (rc) { ++ if (open_file) { ++ cifsFileInfo_put(open_file); ++ open_file = NULL; ++ } ++ goto out; ++ } ++ /* ++ * Original write_time from buf->LastWriteTime is preserved ++ * as SMBSetInformation() interprets zero as do not change. ++ */ ++ new_buf = *buf; ++ buf = &new_buf; ++ if (!buf->CreationTime) ++ buf->CreationTime = query_data.fi.CreationTime; ++ if (!buf->LastAccessTime) ++ buf->LastAccessTime = query_data.fi.LastAccessTime; ++ if (!buf->LastWriteTime) ++ buf->LastWriteTime = query_data.fi.LastWriteTime; ++ if (!buf->ChangeTime) ++ buf->ChangeTime = query_data.fi.ChangeTime; + } +- tcon = tlink_tcon(tlink); ++ ++ if (open_file) ++ goto set_via_filehandle; + + rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, + cifs_sb); +@@ -873,8 +994,45 @@ smb_set_file_info(struct inode *inode, const char *full_path, + .fid = &fid, + }; + +- cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); +- rc = CIFS_open(xid, &oparms, &oplock, NULL); ++ if (S_ISDIR(inode->i_mode) && !(tcon->ses->capabilities & CAP_NT_SMBS)) { ++ /* Opening directory path is not possible on non-NT servers. */ ++ rc = -EOPNOTSUPP; ++ } else { ++ /* ++ * Use cifs_open_file() instead of CIFS_open() as the ++ * cifs_open_file() selects the correct function which ++ * works also on non-NT servers. ++ */ ++ rc = cifs_open_file(xid, &oparms, &oplock, NULL); ++ /* ++ * Opening path for writing on non-NT servers is not ++ * possible when the read-only attribute is already set. ++ * Non-NT server in this case returns -EACCES. For those ++ * servers the only possible way how to clear the read-only ++ * bit is via SMB_COM_SETATTR command. ++ */ ++ if (rc == -EACCES && ++ (cinode->cifsAttrs & ATTR_READONLY) && ++ le32_to_cpu(buf->Attributes) != 0 && /* 0 = do not change attrs */ ++ !(le32_to_cpu(buf->Attributes) & ATTR_READONLY) && ++ !(tcon->ses->capabilities & CAP_NT_SMBS)) ++ rc = -EOPNOTSUPP; ++ } ++ ++ /* Fallback to SMB_COM_SETATTR command when absolutelty needed. */ ++ if (rc == -EOPNOTSUPP) { ++ cifs_dbg(FYI, "calling SetInformation since SetPathInfo for attrs/times not supported by this server\n"); ++ rc = SMBSetInformation(xid, tcon, full_path, ++ buf->Attributes != 0 ? buf->Attributes : cpu_to_le32(cinode->cifsAttrs), ++ write_time, ++ cifs_sb->local_nls, cifs_sb); ++ if (rc == 0) ++ cinode->cifsAttrs = le32_to_cpu(buf->Attributes); ++ else ++ rc = -EACCES; ++ goto out; ++ } ++ + if (rc != 0) { + if (rc == -EIO) + rc = -EINVAL; +@@ -882,6 +1040,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, + } + + netpid = current->tgid; ++ cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for attrs/times not supported by this server\n"); + + set_via_filehandle: + rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid); +@@ -892,6 +1051,21 @@ smb_set_file_info(struct inode *inode, const char *full_path, + CIFSSMBClose(xid, tcon, fid.netfid); + else + cifsFileInfo_put(open_file); ++ ++ /* ++ * Setting the read-only bit is not honered on non-NT servers when done ++ * via open-semantics. So for setting it, use SMB_COM_SETATTR command. ++ * This command works only after the file is closed, so use it only when ++ * operation was called without the filehandle. ++ */ ++ if (open_file == NULL && ++ !(tcon->ses->capabilities & CAP_NT_SMBS) && ++ le32_to_cpu(buf->Attributes) & ATTR_READONLY) { ++ SMBSetInformation(xid, tcon, full_path, ++ buf->Attributes, ++ 0 /* do not change write time */, ++ cifs_sb->local_nls, cifs_sb); ++ } + out: + if (tlink != NULL) + cifs_put_tlink(tlink); +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index db9c807115c605..d7f2835e0b1cc1 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -107,16 +107,25 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 + int err_buftype = CIFS_NO_BUFFER; + struct cifs_fid *fid = oparms->fid; + struct network_resiliency_req nr_ioctl_req; ++ bool retry_without_read_attributes = false; + + smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb); + if (smb2_path == NULL) + return -ENOMEM; + +- oparms->desired_access |= FILE_READ_ATTRIBUTES; ++ if (!(oparms->desired_access & FILE_READ_ATTRIBUTES)) { ++ oparms->desired_access |= FILE_READ_ATTRIBUTES; ++ retry_without_read_attributes = true; ++ } + smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH; + + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + &err_buftype); ++ if (rc == -EACCES && retry_without_read_attributes) { ++ oparms->desired_access &= ~FILE_READ_ATTRIBUTES; ++ rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, ++ &err_buftype); ++ } + if (rc && data) { + struct smb2_hdr *hdr = err_iov.iov_base; + +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index b809a616728f27..4e3eacbec96d14 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -428,12 +428,20 @@ smb2_negotiate(const unsigned int xid, + server->CurrentMid = 0; + spin_unlock(&server->mid_lock); + rc = SMB2_negotiate(xid, ses, server); +- /* BB we probably don't need to retry with modern servers */ +- if (rc == -EAGAIN) +- rc = -EHOSTDOWN; + return rc; + } + ++static inline unsigned int ++prevent_zero_iosize(unsigned int size, const char *type) ++{ ++ if (size == 0) { ++ cifs_dbg(VFS, "SMB: Zero %ssize calculated, using minimum value %u\n", ++ type, CIFS_MIN_DEFAULT_IOSIZE); ++ return CIFS_MIN_DEFAULT_IOSIZE; ++ } ++ return size; ++} ++ + static unsigned int + smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + { +@@ -441,12 +449,12 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int wsize; + + /* start with specified wsize, or default */ +- wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE; ++ wsize = ctx->got_wsize ? ctx->vol_wsize : CIFS_DEFAULT_IOSIZE; + wsize = min_t(unsigned int, wsize, server->max_write); + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); + +- return wsize; ++ return prevent_zero_iosize(wsize, "w"); + } + + static unsigned int +@@ -456,7 +464,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int wsize; + + /* start with specified wsize, or default */ +- wsize = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE; ++ wsize = ctx->got_wsize ? ctx->vol_wsize : SMB3_DEFAULT_IOSIZE; + wsize = min_t(unsigned int, wsize, server->max_write); + #ifdef CONFIG_CIFS_SMB_DIRECT + if (server->rdma) { +@@ -478,7 +486,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); + +- return wsize; ++ return prevent_zero_iosize(wsize, "w"); + } + + static unsigned int +@@ -488,13 +496,13 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int rsize; + + /* start with specified rsize, or default */ +- rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE; ++ rsize = ctx->got_rsize ? ctx->vol_rsize : CIFS_DEFAULT_IOSIZE; + rsize = min_t(unsigned int, rsize, server->max_read); + + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); + +- return rsize; ++ return prevent_zero_iosize(rsize, "r"); + } + + static unsigned int +@@ -504,7 +512,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int rsize; + + /* start with specified rsize, or default */ +- rsize = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE; ++ rsize = ctx->got_rsize ? ctx->vol_rsize : SMB3_DEFAULT_IOSIZE; + rsize = min_t(unsigned int, rsize, server->max_read); + #ifdef CONFIG_CIFS_SMB_DIRECT + if (server->rdma) { +@@ -527,7 +535,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); + +- return rsize; ++ return prevent_zero_iosize(rsize, "r"); + } + + /* +diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c +index ddf1a3aafee5c6..2269963e500819 100644 +--- a/fs/smb/client/transport.c ++++ b/fs/smb/client/transport.c +@@ -178,7 +178,7 @@ delete_mid(struct mid_q_entry *mid) + * Our basic "send data to server" function. Should be called with srv_mutex + * held. The caller is responsible for handling the results. + */ +-static int ++int + smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, + size_t *sent) + { +diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h +index c3ee42188d252e..1af827ae757e0d 100644 +--- a/fs/smb/common/smb2pdu.h ++++ b/fs/smb/common/smb2pdu.h +@@ -95,6 +95,9 @@ + */ + #define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024) + ++/* According to MS-SMB2 specification The minimum recommended value is 65536.*/ ++#define CIFS_MIN_DEFAULT_IOSIZE (65536) ++ + /* + * SMB2 Header Definition + * +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index 72294764d4c20c..e564432643ea30 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -146,12 +146,9 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) + { + struct oplock_info *opinfo; + +- if (list_empty(&ci->m_op_list)) +- return NULL; +- + down_read(&ci->m_lock); +- opinfo = list_first_entry(&ci->m_op_list, struct oplock_info, +- op_entry); ++ opinfo = list_first_entry_or_null(&ci->m_op_list, struct oplock_info, ++ op_entry); + if (opinfo) { + if (opinfo->conn == NULL || + !atomic_inc_not_zero(&opinfo->refcount)) +diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c +index f6616d687365a3..3bbf2382706056 100644 +--- a/fs/smb/server/vfs.c ++++ b/fs/smb/server/vfs.c +@@ -426,10 +426,15 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n", + *pos, count); + ++ if (*pos >= XATTR_SIZE_MAX) { ++ pr_err("stream write position %lld is out of bounds\n", *pos); ++ return -EINVAL; ++ } ++ + size = *pos + count; + if (size > XATTR_SIZE_MAX) { + size = XATTR_SIZE_MAX; +- count = (*pos + count) - XATTR_SIZE_MAX; ++ count = XATTR_SIZE_MAX - *pos; + } + + v_len = ksmbd_vfs_getcasexattr(idmap, +@@ -443,13 +448,6 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + goto out; + } + +- if (v_len <= *pos) { +- pr_err("stream write position %lld is out of bounds (stream length: %zd)\n", +- *pos, v_len); +- err = -EINVAL; +- goto out; +- } +- + if (v_len < size) { + wbuf = kvzalloc(size, GFP_KERNEL); + if (!wbuf) { +diff --git a/include/crypto/hash.h b/include/crypto/hash.h +index f7c2a22cd776da..c0d472fdc82e6c 100644 +--- a/include/crypto/hash.h ++++ b/include/crypto/hash.h +@@ -153,6 +153,7 @@ struct ahash_request { + * This is a counterpart to @init_tfm, used to remove + * various changes set in @init_tfm. + * @clone_tfm: Copy transform into new object, may allocate memory. ++ * @reqsize: Size of the request context. + * @halg: see struct hash_alg_common + */ + struct ahash_alg { +@@ -169,6 +170,8 @@ struct ahash_alg { + void (*exit_tfm)(struct crypto_ahash *tfm); + int (*clone_tfm)(struct crypto_ahash *dst, struct crypto_ahash *src); + ++ unsigned int reqsize; ++ + struct hash_alg_common halg; + }; + +diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h +index 9a022caacf9361..f3e7e3e5078dbc 100644 +--- a/include/drm/drm_atomic.h ++++ b/include/drm/drm_atomic.h +@@ -372,8 +372,27 @@ struct drm_atomic_state { + * + * Allow full modeset. This is used by the ATOMIC IOCTL handler to + * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should +- * never consult this flag, instead looking at the output of +- * drm_atomic_crtc_needs_modeset(). ++ * generally not consult this flag, but instead look at the output of ++ * drm_atomic_crtc_needs_modeset(). The detailed rules are: ++ * ++ * - Drivers must not consult @allow_modeset in the atomic commit path. ++ * Use drm_atomic_crtc_needs_modeset() instead. ++ * ++ * - Drivers must consult @allow_modeset before adding unrelated struct ++ * drm_crtc_state to this commit by calling ++ * drm_atomic_get_crtc_state(). See also the warning in the ++ * documentation for that function. ++ * ++ * - Drivers must never change this flag, it is under the exclusive ++ * control of userspace. ++ * ++ * - Drivers may consult @allow_modeset in the atomic check path, if ++ * they have the choice between an optimal hardware configuration ++ * which requires a modeset, and a less optimal configuration which ++ * can be committed without a modeset. An example would be suboptimal ++ * scanout FIFO allocation resulting in increased idle power ++ * consumption. This allows userspace to avoid flickering and delays ++ * for the normal composition loop at reasonable cost. + */ + bool allow_modeset : 1; + /** +diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h +index 7c2ec139c464ad..a578068169f19a 100644 +--- a/include/drm/drm_gem.h ++++ b/include/drm/drm_gem.h +@@ -35,6 +35,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -557,6 +558,18 @@ static inline bool drm_gem_object_is_shared_for_memory_stats(struct drm_gem_obje + return (obj->handle_count > 1) || obj->dma_buf; + } + ++/** ++ * drm_gem_is_imported() - Tests if GEM object's buffer has been imported ++ * @obj: the GEM object ++ * ++ * Returns: ++ * True if the GEM object's buffer has been imported, false otherwise ++ */ ++static inline bool drm_gem_is_imported(const struct drm_gem_object *obj) ++{ ++ return !!obj->import_attach; ++} ++ + #ifdef CONFIG_LOCKDEP + /** + * drm_gem_gpuva_set_lock() - Set the lock protecting accesses to the gpuva list. +diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h +index d4f2c8706042cd..2331cd8174fe3f 100644 +--- a/include/linux/bpf-cgroup.h ++++ b/include/linux/bpf-cgroup.h +@@ -106,6 +106,7 @@ struct bpf_prog_list { + struct bpf_prog *prog; + struct bpf_cgroup_link *link; + struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]; ++ u32 flags; + }; + + int cgroup_bpf_inherit(struct cgroup *cgrp); +diff --git a/include/linux/coredump.h b/include/linux/coredump.h +index d3eba436015087..c1b4c8c70caebd 100644 +--- a/include/linux/coredump.h ++++ b/include/linux/coredump.h +@@ -28,6 +28,7 @@ struct coredump_params { + int vma_count; + size_t vma_data_size; + struct core_vma_metadata *vma_meta; ++ struct pid *pid; + }; + + /* +diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h +index f0ccca16a0aca1..608e8296ba206a 100644 +--- a/include/linux/dma-mapping.h ++++ b/include/linux/dma-mapping.h +@@ -600,10 +600,14 @@ static inline int dma_mmap_wc(struct device *dev, + #else + #define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) + #define DEFINE_DMA_UNMAP_LEN(LEN_NAME) +-#define dma_unmap_addr(PTR, ADDR_NAME) (0) +-#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +-#define dma_unmap_len(PTR, LEN_NAME) (0) +-#define dma_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) ++#define dma_unmap_addr(PTR, ADDR_NAME) \ ++ ({ typeof(PTR) __p __maybe_unused = PTR; 0; }) ++#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) \ ++ do { typeof(PTR) __p __maybe_unused = PTR; } while (0) ++#define dma_unmap_len(PTR, LEN_NAME) \ ++ ({ typeof(PTR) __p __maybe_unused = PTR; 0; }) ++#define dma_unmap_len_set(PTR, LEN_NAME, VAL) \ ++ do { typeof(PTR) __p __maybe_unused = PTR; } while (0) + #endif + + #endif /* _LINUX_DMA_MAPPING_H */ +diff --git a/include/linux/highmem.h b/include/linux/highmem.h +index 75607d4ba26cb7..714966d5701e00 100644 +--- a/include/linux/highmem.h ++++ b/include/linux/highmem.h +@@ -448,7 +448,7 @@ static inline void memcpy_from_folio(char *to, struct folio *folio, + const char *from = kmap_local_folio(folio, offset); + size_t chunk = len; + +- if (folio_test_highmem(folio) && ++ if (folio_test_partial_kmap(folio) && + chunk > PAGE_SIZE - offset_in_page(offset)) + chunk = PAGE_SIZE - offset_in_page(offset); + memcpy(to, from, chunk); +@@ -469,7 +469,7 @@ static inline void memcpy_to_folio(struct folio *folio, size_t offset, + char *to = kmap_local_folio(folio, offset); + size_t chunk = len; + +- if (folio_test_highmem(folio) && ++ if (folio_test_partial_kmap(folio) && + chunk > PAGE_SIZE - offset_in_page(offset)) + chunk = PAGE_SIZE - offset_in_page(offset); + memcpy(to, from, chunk); +@@ -501,7 +501,7 @@ static inline size_t memcpy_from_file_folio(char *to, struct folio *folio, + size_t offset = offset_in_folio(folio, pos); + char *from = kmap_local_folio(folio, offset); + +- if (folio_test_highmem(folio)) { ++ if (folio_test_partial_kmap(folio)) { + offset = offset_in_page(offset); + len = min_t(size_t, len, PAGE_SIZE - offset); + } else +diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h +index 8f77bb0f4ae0ca..05f8b7d7d1e968 100644 +--- a/include/linux/hrtimer.h ++++ b/include/linux/hrtimer.h +@@ -237,6 +237,7 @@ struct hrtimer_cpu_base { + ktime_t softirq_expires_next; + struct hrtimer *softirq_next_timer; + struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; ++ call_single_data_t csd; + } ____cacheline_aligned; + + static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) +diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h +index af8a771a053c51..d79851c5fabd86 100644 +--- a/include/linux/ipv6.h ++++ b/include/linux/ipv6.h +@@ -199,6 +199,7 @@ struct inet6_cork { + struct ipv6_txoptions *opt; + u8 hop_limit; + u8 tclass; ++ u8 dontfrag:1; + }; + + /* struct ipv6_pinfo - ipv6 private area */ +diff --git a/include/linux/lzo.h b/include/linux/lzo.h +index e95c7d1092b286..4d30e3624acd23 100644 +--- a/include/linux/lzo.h ++++ b/include/linux/lzo.h +@@ -24,10 +24,18 @@ + int lzo1x_1_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + ++/* Same as above but does not write more than dst_len to dst. */ ++int lzo1x_1_compress_safe(const unsigned char *src, size_t src_len, ++ unsigned char *dst, size_t *dst_len, void *wrkmem); ++ + /* This requires 'wrkmem' of size LZO1X_1_MEM_COMPRESS */ + int lzorle1x_1_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + ++/* Same as above but does not write more than dst_len to dst. */ ++int lzorle1x_1_compress_safe(const unsigned char *src, size_t src_len, ++ unsigned char *dst, size_t *dst_len, void *wrkmem); ++ + /* safe decompression with overrun testing */ + int lzo1x_decompress_safe(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len); +diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h +index 27f42f713c891c..86f0f2a25a3d63 100644 +--- a/include/linux/mlx4/device.h ++++ b/include/linux/mlx4/device.h +@@ -1135,7 +1135,7 @@ int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_buf *buf); + +-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order); ++int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, unsigned int order); + void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db); + + int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, +diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h +index 3fb428ce7d1c7c..b6b9a4dfa4fb92 100644 +--- a/include/linux/mlx5/fs.h ++++ b/include/linux/mlx5/fs.h +@@ -40,6 +40,8 @@ + + #define MLX5_SET_CFG(p, f, v) MLX5_SET(create_flow_group_in, p, f, v) + ++#define MLX5_FS_MAX_POOL_SIZE BIT(30) ++ + enum mlx5_flow_destination_type { + MLX5_FLOW_DESTINATION_TYPE_NONE, + MLX5_FLOW_DESTINATION_TYPE_VPORT, +diff --git a/include/linux/msi.h b/include/linux/msi.h +index ddace8c34dcf95..2cf15cf5d060ad 100644 +--- a/include/linux/msi.h ++++ b/include/linux/msi.h +@@ -171,6 +171,10 @@ struct msi_desc_data { + * @dev: Pointer to the device which uses this descriptor + * @msg: The last set MSI message cached for reuse + * @affinity: Optional pointer to a cpu affinity mask for this descriptor ++ * @iommu_msi_iova: Optional shifted IOVA from the IOMMU to override the msi_addr. ++ * Only used if iommu_msi_shift != 0 ++ * @iommu_msi_shift: Indicates how many bits of the original address should be ++ * preserved when using iommu_msi_iova. + * @sysfs_attr: Pointer to sysfs device attribute + * + * @write_msi_msg: Callback that may be called when the MSI message +@@ -189,7 +193,8 @@ struct msi_desc { + struct msi_msg msg; + struct irq_affinity_desc *affinity; + #ifdef CONFIG_IRQ_MSI_IOMMU +- const void *iommu_cookie; ++ u64 iommu_msi_iova : 58; ++ u64 iommu_msi_shift : 6; + #endif + #ifdef CONFIG_SYSFS + struct device_attribute *sysfs_attrs; +@@ -306,28 +311,14 @@ struct msi_desc *msi_next_desc(struct device *dev, unsigned int domid, + + #define msi_desc_to_dev(desc) ((desc)->dev) + +-#ifdef CONFIG_IRQ_MSI_IOMMU +-static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc) +-{ +- return desc->iommu_cookie; +-} +- +-static inline void msi_desc_set_iommu_cookie(struct msi_desc *desc, +- const void *iommu_cookie) +-{ +- desc->iommu_cookie = iommu_cookie; +-} +-#else +-static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc) ++static inline void msi_desc_set_iommu_msi_iova(struct msi_desc *desc, u64 msi_iova, ++ unsigned int msi_shift) + { +- return NULL; +-} +- +-static inline void msi_desc_set_iommu_cookie(struct msi_desc *desc, +- const void *iommu_cookie) +-{ +-} ++#ifdef CONFIG_IRQ_MSI_IOMMU ++ desc->iommu_msi_iova = msi_iova >> msi_shift; ++ desc->iommu_msi_shift = msi_shift; + #endif ++} + + int msi_domain_insert_msi_desc(struct device *dev, unsigned int domid, + struct msi_desc *init_desc); +diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h +index 86d96e00c2e3de..374b1b208bd89e 100644 +--- a/include/linux/nfs_fs_sb.h ++++ b/include/linux/nfs_fs_sb.h +@@ -199,6 +199,15 @@ struct nfs_server { + char *fscache_uniq; /* Uniquifier (or NULL) */ + #endif + ++ /* The following #defines numerically match the NFSv4 equivalents */ ++#define NFS_FH_NOEXPIRE_WITH_OPEN (0x1) ++#define NFS_FH_VOLATILE_ANY (0x2) ++#define NFS_FH_VOL_MIGRATION (0x4) ++#define NFS_FH_VOL_RENAME (0x8) ++#define NFS_FH_RENAME_UNSAFE (NFS_FH_VOLATILE_ANY | NFS_FH_VOL_RENAME) ++ u32 fh_expire_type; /* V4 bitmask representing file ++ handle volatility type for ++ this filesystem */ + u32 pnfs_blksize; /* layout_blksize attr */ + #if IS_ENABLED(CONFIG_NFS_V4) + u32 attr_bitmask[3];/* V4 bitmask representing the set +@@ -222,9 +231,6 @@ struct nfs_server { + u32 acl_bitmask; /* V4 bitmask representing the ACEs + that are supported on this + filesystem */ +- u32 fh_expire_type; /* V4 bitmask representing file +- handle volatility type for +- this filesystem */ + struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */ + struct rpc_wait_queue roc_rpcwaitq; + void *pnfs_ld_data; /* per mount point data */ +diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h +index a77f3a7d21d12f..36d0961f1672fd 100644 +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -551,6 +551,13 @@ PAGEFLAG(Readahead, readahead, PF_NO_COMPOUND) + PAGEFLAG_FALSE(HighMem, highmem) + #endif + ++/* Does kmap_local_folio() only allow access to one page of the folio? */ ++#ifdef CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP ++#define folio_test_partial_kmap(f) true ++#else ++#define folio_test_partial_kmap(f) folio_test_highmem(f) ++#endif ++ + #ifdef CONFIG_SWAP + static __always_inline bool folio_test_swapcache(struct folio *folio) + { +diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h +index fcb834dd75c240..90c782749b0558 100644 +--- a/include/linux/perf_event.h ++++ b/include/linux/perf_event.h +@@ -1016,7 +1016,13 @@ struct perf_output_handle { + struct perf_buffer *rb; + unsigned long wakeup; + unsigned long size; +- u64 aux_flags; ++ union { ++ u64 flags; /* perf_output*() */ ++ u64 aux_flags; /* perf_aux_output*() */ ++ struct { ++ u64 skip_read : 1; ++ }; ++ }; + union { + void *addr; + unsigned long head; +diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h +index 72da69cc5764f3..27531a0b3a6e72 100644 +--- a/include/linux/rcupdate.h ++++ b/include/linux/rcupdate.h +@@ -97,9 +97,9 @@ static inline void __rcu_read_lock(void) + + static inline void __rcu_read_unlock(void) + { +- preempt_enable(); + if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD)) + rcu_read_unlock_strict(); ++ preempt_enable(); + } + + static inline int rcu_preempt_depth(void) +diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h +index 126f6b418f6afc..559f758bf2eaa8 100644 +--- a/include/linux/rcutree.h ++++ b/include/linux/rcutree.h +@@ -104,7 +104,7 @@ extern int rcu_scheduler_active; + void rcu_end_inkernel_boot(void); + bool rcu_inkernel_boot_has_ended(void); + bool rcu_is_watching(void); +-#ifndef CONFIG_PREEMPTION ++#ifndef CONFIG_PREEMPT_RCU + void rcu_all_qs(void); + #endif + +diff --git a/include/linux/trace.h b/include/linux/trace.h +index fdcd76b7be83d7..7eaad857dee04f 100644 +--- a/include/linux/trace.h ++++ b/include/linux/trace.h +@@ -72,8 +72,8 @@ static inline int unregister_ftrace_export(struct trace_export *export) + static inline void trace_printk_init_buffers(void) + { + } +-static inline int trace_array_printk(struct trace_array *tr, unsigned long ip, +- const char *fmt, ...) ++static inline __printf(3, 4) ++int trace_array_printk(struct trace_array *tr, unsigned long ip, const char *fmt, ...) + { + return 0; + } +diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h +index 3691e0e76a1a20..62147eecf931da 100644 +--- a/include/linux/trace_seq.h ++++ b/include/linux/trace_seq.h +@@ -79,8 +79,8 @@ extern __printf(2, 3) + void trace_seq_printf(struct trace_seq *s, const char *fmt, ...); + extern __printf(2, 0) + void trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args); +-extern void +-trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); ++extern __printf(2, 0) ++void trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); + extern int trace_print_seq(struct seq_file *m, struct trace_seq *s); + extern int trace_seq_to_user(struct trace_seq *s, char __user *ubuf, + int cnt); +@@ -104,8 +104,8 @@ static inline __printf(2, 3) + void trace_seq_printf(struct trace_seq *s, const char *fmt, ...) + { + } +-static inline void +-trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) ++static inline __printf(2, 0) ++void trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) + { + } + +diff --git a/include/linux/usb/r8152.h b/include/linux/usb/r8152.h +index 33a4c146dc19c4..2ca60828f28bb6 100644 +--- a/include/linux/usb/r8152.h ++++ b/include/linux/usb/r8152.h +@@ -30,6 +30,7 @@ + #define VENDOR_ID_NVIDIA 0x0955 + #define VENDOR_ID_TPLINK 0x2357 + #define VENDOR_ID_DLINK 0x2001 ++#define VENDOR_ID_DELL 0x413c + #define VENDOR_ID_ASUS 0x0b05 + + #if IS_REACHABLE(CONFIG_USB_RTL8152) +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index b4fcd0164048ed..0740dfc6c04881 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -822,7 +822,9 @@ struct v4l2_subdev_state { + * possible configuration from the remote end, likely calling + * this operation as close as possible to stream on time. The + * operation shall fail if the pad index it has been called on +- * is not valid or in case of unrecoverable failures. ++ * is not valid or in case of unrecoverable failures. The ++ * config argument has been memset to 0 just before calling ++ * the op. + * + * @set_routing: enable or disable data connection routes described in the + * subdevice routing table. +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index 77bf30203d3cf6..b6eedf7650da59 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -8,21 +8,46 @@ + #include + #include + +-void unix_inflight(struct user_struct *user, struct file *fp); +-void unix_notinflight(struct user_struct *user, struct file *fp); +-void unix_destruct_scm(struct sk_buff *skb); +-void io_uring_destruct_scm(struct sk_buff *skb); ++#if IS_ENABLED(CONFIG_UNIX) ++struct unix_sock *unix_get_socket(struct file *filp); ++#else ++static inline struct unix_sock *unix_get_socket(struct file *filp) ++{ ++ return NULL; ++} ++#endif ++ ++extern unsigned int unix_tot_inflight; ++void unix_add_edges(struct scm_fp_list *fpl, struct unix_sock *receiver); ++void unix_del_edges(struct scm_fp_list *fpl); ++void unix_update_edges(struct unix_sock *receiver); ++int unix_prepare_fpl(struct scm_fp_list *fpl); ++void unix_destroy_fpl(struct scm_fp_list *fpl); + void unix_gc(void); +-void wait_for_unix_gc(void); +-struct sock *unix_get_socket(struct file *filp); ++void wait_for_unix_gc(struct scm_fp_list *fpl); ++ ++struct unix_vertex { ++ struct list_head edges; ++ struct list_head entry; ++ struct list_head scc_entry; ++ unsigned long out_degree; ++ unsigned long index; ++ unsigned long scc_index; ++}; ++ ++struct unix_edge { ++ struct unix_sock *predecessor; ++ struct unix_sock *successor; ++ struct list_head vertex_entry; ++ struct list_head stack_entry; ++}; ++ + struct sock *unix_peer_get(struct sock *sk); + + #define UNIX_HASH_MOD (256 - 1) + #define UNIX_HASH_SIZE (256 * 2) + #define UNIX_HASH_BITS 8 + +-extern unsigned int unix_tot_inflight; +- + struct unix_address { + refcount_t refcnt; + int len; +@@ -42,6 +67,7 @@ struct unix_skb_parms { + + struct scm_stat { + atomic_t nr_fds; ++ unsigned long nr_unix_fds; + }; + + #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb)) +@@ -54,12 +80,9 @@ struct unix_sock { + struct path path; + struct mutex iolock, bindlock; + struct sock *peer; +- struct list_head link; +- unsigned long inflight; ++ struct sock *listener; ++ struct unix_vertex *vertex; + spinlock_t lock; +- unsigned long gc_flags; +-#define UNIX_GC_CANDIDATE 0 +-#define UNIX_GC_MAYBE_CYCLE 1 + struct socket_wq peer_wq; + wait_queue_entry_t peer_wake; + struct scm_stat scm_stat; +diff --git a/include/net/scm.h b/include/net/scm.h +index e8c76b4be2fe71..059e287745dc39 100644 +--- a/include/net/scm.h ++++ b/include/net/scm.h +@@ -22,9 +22,20 @@ struct scm_creds { + kgid_t gid; + }; + ++#ifdef CONFIG_UNIX ++struct unix_edge; ++#endif ++ + struct scm_fp_list { + short count; ++ short count_unix; + short max; ++#ifdef CONFIG_UNIX ++ bool inflight; ++ bool dead; ++ struct list_head vertices; ++ struct unix_edge *edges; ++#endif + struct user_struct *user; + struct file *fp[SCM_MAX_FD]; + }; +diff --git a/include/net/xfrm.h b/include/net/xfrm.h +index b33d27e42cff38..fd550c0b563450 100644 +--- a/include/net/xfrm.h ++++ b/include/net/xfrm.h +@@ -228,7 +228,6 @@ struct xfrm_state { + + /* Data for encapsulator */ + struct xfrm_encap_tmpl *encap; +- struct sock __rcu *encap_sk; + + /* Data for care-of address */ + xfrm_address_t *coaddr; +diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h +index fe05121169589f..555ea3d142a46b 100644 +--- a/include/rdma/uverbs_std_types.h ++++ b/include/rdma/uverbs_std_types.h +@@ -34,7 +34,7 @@ + static inline void *_uobj_get_obj_read(struct ib_uobject *uobj) + { + if (IS_ERR(uobj)) +- return NULL; ++ return ERR_CAST(uobj); + return uobj->object; + } + #define uobj_get_obj_read(_object, _type, _id, _attrs) \ +diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h +index 5497dc9c396a5a..b58dc869cf77eb 100644 +--- a/include/sound/hda_codec.h ++++ b/include/sound/hda_codec.h +@@ -196,6 +196,7 @@ struct hda_codec { + /* beep device */ + struct hda_beep *beep; + unsigned int beep_mode; ++ bool beep_just_power_on; + + /* widget capabilities cache */ + u32 *wcaps; +diff --git a/include/sound/pcm.h b/include/sound/pcm.h +index 2a815373dac1d9..ed4449cbdf8033 100644 +--- a/include/sound/pcm.h ++++ b/include/sound/pcm.h +@@ -1427,6 +1427,8 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s + #define snd_pcm_lib_mmap_iomem NULL + #endif + ++void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime); ++ + /** + * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer + * @dma: DMA number +diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h +index 3c4d5ef6d44636..8ea1674069fe81 100644 +--- a/include/trace/events/btrfs.h ++++ b/include/trace/events/btrfs.h +@@ -1956,7 +1956,7 @@ DECLARE_EVENT_CLASS(btrfs__prelim_ref, + TP_PROTO(const struct btrfs_fs_info *fs_info, + const struct prelim_ref *oldref, + const struct prelim_ref *newref, u64 tree_size), +- TP_ARGS(fs_info, newref, oldref, tree_size), ++ TP_ARGS(fs_info, oldref, newref, tree_size), + + TP_STRUCT__entry_btrfs( + __field( u64, root_id ) +diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h +index 431bc700bcfb93..c7f904a72af217 100644 +--- a/include/uapi/linux/bpf.h ++++ b/include/uapi/linux/bpf.h +@@ -1140,6 +1140,7 @@ enum bpf_perf_event_type { + #define BPF_F_BEFORE (1U << 3) + #define BPF_F_AFTER (1U << 4) + #define BPF_F_ID (1U << 5) ++#define BPF_F_PREORDER (1U << 6) + #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */ + + /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the +diff --git a/include/uapi/linux/idxd.h b/include/uapi/linux/idxd.h +index 606b52e88ce335..3d1987e1bb2dd6 100644 +--- a/include/uapi/linux/idxd.h ++++ b/include/uapi/linux/idxd.h +@@ -31,6 +31,7 @@ enum idxd_scmd_stat { + IDXD_SCMD_WQ_IRQ_ERR = 0x80100000, + IDXD_SCMD_WQ_USER_NO_IOMMU = 0x80110000, + IDXD_SCMD_DEV_EVL_ERR = 0x80120000, ++ IDXD_SCMD_WQ_NO_DRV_NAME = 0x80200000, + }; + + #define IDXD_SCMD_SOFTERR_MASK 0x80000000 +diff --git a/include/ufs/ufs_quirks.h b/include/ufs/ufs_quirks.h +index 41ff44dfa1db3f..f52de5ed1b3b6e 100644 +--- a/include/ufs/ufs_quirks.h ++++ b/include/ufs/ufs_quirks.h +@@ -107,4 +107,10 @@ struct ufs_dev_quirk { + */ + #define UFS_DEVICE_QUIRK_DELAY_AFTER_LPM (1 << 11) + ++/* ++ * Some ufs devices may need more time to be in hibern8 before exiting. ++ * Enable this quirk to give it an additional 100us. ++ */ ++#define UFS_DEVICE_QUIRK_PA_HIBER8TIME (1 << 12) ++ + #endif /* UFS_QUIRKS_H_ */ +diff --git a/io_uring/fdinfo.c b/io_uring/fdinfo.c +index 976e9500f6518c..a26cf840e623d6 100644 +--- a/io_uring/fdinfo.c ++++ b/io_uring/fdinfo.c +@@ -81,11 +81,11 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f) + seq_printf(m, "SqMask:\t0x%x\n", sq_mask); + seq_printf(m, "SqHead:\t%u\n", sq_head); + seq_printf(m, "SqTail:\t%u\n", sq_tail); +- seq_printf(m, "CachedSqHead:\t%u\n", ctx->cached_sq_head); ++ seq_printf(m, "CachedSqHead:\t%u\n", data_race(ctx->cached_sq_head)); + seq_printf(m, "CqMask:\t0x%x\n", cq_mask); + seq_printf(m, "CqHead:\t%u\n", cq_head); + seq_printf(m, "CqTail:\t%u\n", cq_tail); +- seq_printf(m, "CachedCqTail:\t%u\n", ctx->cached_cq_tail); ++ seq_printf(m, "CachedCqTail:\t%u\n", data_race(ctx->cached_cq_tail)); + seq_printf(m, "SQEs:\t%u\n", sq_tail - sq_head); + sq_entries = min(sq_tail - sq_head, ctx->sq_entries); + for (i = 0; i < sq_entries; i++) { +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index db592fa549b738..43b46098279a16 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -701,6 +701,7 @@ static void __io_cqring_overflow_flush(struct io_ring_ctx *ctx) + * to care for a non-real case. + */ + if (need_resched()) { ++ ctx->cqe_sentinel = ctx->cqe_cached; + io_cq_unlock_post(ctx); + mutex_unlock(&ctx->uring_lock); + cond_resched(); +diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c +index cf2eb0895d403c..684fb450ad086f 100644 +--- a/kernel/bpf/cgroup.c ++++ b/kernel/bpf/cgroup.c +@@ -369,7 +369,7 @@ static struct bpf_prog *prog_list_prog(struct bpf_prog_list *pl) + /* count number of elements in the list. + * it's slow but the list cannot be long + */ +-static u32 prog_list_length(struct hlist_head *head) ++static u32 prog_list_length(struct hlist_head *head, int *preorder_cnt) + { + struct bpf_prog_list *pl; + u32 cnt = 0; +@@ -377,6 +377,8 @@ static u32 prog_list_length(struct hlist_head *head) + hlist_for_each_entry(pl, head, node) { + if (!prog_list_prog(pl)) + continue; ++ if (preorder_cnt && (pl->flags & BPF_F_PREORDER)) ++ (*preorder_cnt)++; + cnt++; + } + return cnt; +@@ -400,7 +402,7 @@ static bool hierarchy_allows_attach(struct cgroup *cgrp, + + if (flags & BPF_F_ALLOW_MULTI) + return true; +- cnt = prog_list_length(&p->bpf.progs[atype]); ++ cnt = prog_list_length(&p->bpf.progs[atype], NULL); + WARN_ON_ONCE(cnt > 1); + if (cnt == 1) + return !!(flags & BPF_F_ALLOW_OVERRIDE); +@@ -423,12 +425,12 @@ static int compute_effective_progs(struct cgroup *cgrp, + struct bpf_prog_array *progs; + struct bpf_prog_list *pl; + struct cgroup *p = cgrp; +- int cnt = 0; ++ int i, j, cnt = 0, preorder_cnt = 0, fstart, bstart, init_bstart; + + /* count number of effective programs by walking parents */ + do { + if (cnt == 0 || (p->bpf.flags[atype] & BPF_F_ALLOW_MULTI)) +- cnt += prog_list_length(&p->bpf.progs[atype]); ++ cnt += prog_list_length(&p->bpf.progs[atype], &preorder_cnt); + p = cgroup_parent(p); + } while (p); + +@@ -439,20 +441,34 @@ static int compute_effective_progs(struct cgroup *cgrp, + /* populate the array with effective progs */ + cnt = 0; + p = cgrp; ++ fstart = preorder_cnt; ++ bstart = preorder_cnt - 1; + do { + if (cnt > 0 && !(p->bpf.flags[atype] & BPF_F_ALLOW_MULTI)) + continue; + ++ init_bstart = bstart; + hlist_for_each_entry(pl, &p->bpf.progs[atype], node) { + if (!prog_list_prog(pl)) + continue; + +- item = &progs->items[cnt]; ++ if (pl->flags & BPF_F_PREORDER) { ++ item = &progs->items[bstart]; ++ bstart--; ++ } else { ++ item = &progs->items[fstart]; ++ fstart++; ++ } + item->prog = prog_list_prog(pl); + bpf_cgroup_storages_assign(item->cgroup_storage, + pl->storage); + cnt++; + } ++ ++ /* reverse pre-ordering progs at this cgroup level */ ++ for (i = bstart + 1, j = init_bstart; i < j; i++, j--) ++ swap(progs->items[i], progs->items[j]); ++ + } while ((p = cgroup_parent(p))); + + *array = progs; +@@ -663,7 +679,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp, + */ + return -EPERM; + +- if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS) ++ if (prog_list_length(progs, NULL) >= BPF_CGROUP_MAX_PROGS) + return -E2BIG; + + pl = find_attach_entry(progs, prog, link, replace_prog, +@@ -698,6 +714,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp, + + pl->prog = prog; + pl->link = link; ++ pl->flags = flags; + bpf_cgroup_storages_assign(pl->storage, storage); + cgrp->bpf.flags[atype] = saved_flags; + +@@ -1073,7 +1090,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, + lockdep_is_held(&cgroup_mutex)); + total_cnt += bpf_prog_array_length(effective); + } else { +- total_cnt += prog_list_length(&cgrp->bpf.progs[atype]); ++ total_cnt += prog_list_length(&cgrp->bpf.progs[atype], NULL); + } + } + +@@ -1105,7 +1122,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, + u32 id; + + progs = &cgrp->bpf.progs[atype]; +- cnt = min_t(int, prog_list_length(progs), total_cnt); ++ cnt = min_t(int, prog_list_length(progs, NULL), total_cnt); + i = 0; + hlist_for_each_entry(pl, progs, node) { + prog = prog_list_prog(pl); +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index fc34f72702cc40..8a3eadf17f785d 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -2212,7 +2212,7 @@ static long bpf_for_each_hash_elem(struct bpf_map *map, bpf_callback_t callback_ + b = &htab->buckets[i]; + rcu_read_lock(); + head = &b->head; +- hlist_nulls_for_each_entry_rcu(elem, n, head, hash_node) { ++ hlist_nulls_for_each_entry_safe(elem, n, head, hash_node) { + key = elem->key; + if (is_percpu) { + /* current cpu value for percpu map */ +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index f089a616301119..b66349f892f25e 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -3900,7 +3900,8 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, + #define BPF_F_ATTACH_MASK_BASE \ + (BPF_F_ALLOW_OVERRIDE | \ + BPF_F_ALLOW_MULTI | \ +- BPF_F_REPLACE) ++ BPF_F_REPLACE | \ ++ BPF_F_PREORDER) + + #define BPF_F_ATTACH_MASK_MPROG \ + (BPF_F_REPLACE | \ +@@ -4442,6 +4443,8 @@ static int bpf_prog_get_info_by_fd(struct file *file, + info.recursion_misses = stats.misses; + + info.verified_insns = prog->aux->verified_insns; ++ if (prog->aux->btf) ++ info.btf_id = btf_obj_id(prog->aux->btf); + + if (!bpf_capable()) { + info.jited_prog_len = 0; +@@ -4588,8 +4591,6 @@ static int bpf_prog_get_info_by_fd(struct file *file, + } + } + +- if (prog->aux->btf) +- info.btf_id = btf_obj_id(prog->aux->btf); + info.attach_btf_id = prog->aux->attach_btf_id; + if (attach_btf) + info.attach_btf_obj_id = btf_obj_id(attach_btf); +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 756e179a1efe3e..1f9ae600e4455c 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -16014,12 +16014,16 @@ static void clean_verifier_state(struct bpf_verifier_env *env, + static void clean_live_states(struct bpf_verifier_env *env, int insn, + struct bpf_verifier_state *cur) + { ++ struct bpf_verifier_state *loop_entry; + struct bpf_verifier_state_list *sl; + + sl = *explored_state(env, insn); + while (sl) { + if (sl->state.branches) + goto next; ++ loop_entry = get_loop_entry(&sl->state); ++ if (loop_entry && loop_entry->branches) ++ goto next; + if (sl->state.insn_idx != insn || + !same_callsites(&sl->state, cur)) + goto next; +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 3ccf80dfa587a3..e8ef062f6ca058 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -90,7 +90,7 @@ + DEFINE_MUTEX(cgroup_mutex); + DEFINE_SPINLOCK(css_set_lock); + +-#ifdef CONFIG_PROVE_RCU ++#if (defined CONFIG_PROVE_RCU || defined CONFIG_LOCKDEP) + EXPORT_SYMBOL_GPL(cgroup_mutex); + EXPORT_SYMBOL_GPL(css_set_lock); + #endif +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 987807b1040ae0..5dd6424e62fa89 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -1163,6 +1163,12 @@ static void perf_assert_pmu_disabled(struct pmu *pmu) + WARN_ON_ONCE(*this_cpu_ptr(pmu->pmu_disable_count) == 0); + } + ++static inline void perf_pmu_read(struct perf_event *event) ++{ ++ if (event->state == PERF_EVENT_STATE_ACTIVE) ++ event->pmu->read(event); ++} ++ + static void get_ctx(struct perf_event_context *ctx) + { + refcount_inc(&ctx->refcount); +@@ -3397,8 +3403,7 @@ static void __perf_event_sync_stat(struct perf_event *event, + * we know the event must be on the current CPU, therefore we + * don't need to use it. + */ +- if (event->state == PERF_EVENT_STATE_ACTIVE) +- event->pmu->read(event); ++ perf_pmu_read(event); + + perf_event_update_time(event); + +@@ -4524,15 +4529,8 @@ static void __perf_event_read(void *info) + + pmu->read(event); + +- for_each_sibling_event(sub, event) { +- if (sub->state == PERF_EVENT_STATE_ACTIVE) { +- /* +- * Use sibling's PMU rather than @event's since +- * sibling could be on different (eg: software) PMU. +- */ +- sub->pmu->read(sub); +- } +- } ++ for_each_sibling_event(sub, event) ++ perf_pmu_read(sub); + + data->ret = pmu->commit_txn(pmu); + +@@ -7297,9 +7295,8 @@ static void perf_output_read_group(struct perf_output_handle *handle, + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = running; + +- if ((leader != event) && +- (leader->state == PERF_EVENT_STATE_ACTIVE)) +- leader->pmu->read(leader); ++ if ((leader != event) && !handle->skip_read) ++ perf_pmu_read(leader); + + values[n++] = perf_event_count(leader); + if (read_format & PERF_FORMAT_ID) +@@ -7312,9 +7309,8 @@ static void perf_output_read_group(struct perf_output_handle *handle, + for_each_sibling_event(sub, leader) { + n = 0; + +- if ((sub != event) && +- (sub->state == PERF_EVENT_STATE_ACTIVE)) +- sub->pmu->read(sub); ++ if ((sub != event) && !handle->skip_read) ++ perf_pmu_read(sub); + + values[n++] = perf_event_count(sub); + if (read_format & PERF_FORMAT_ID) +@@ -7369,6 +7365,9 @@ void perf_output_sample(struct perf_output_handle *handle, + { + u64 sample_type = data->type; + ++ if (data->sample_flags & PERF_SAMPLE_READ) ++ handle->skip_read = 1; ++ + perf_output_put(handle, *header); + + if (sample_type & PERF_SAMPLE_IDENTIFIER) +diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c +index 6c2cb4e4f48dab..8f3f624419aa92 100644 +--- a/kernel/events/hw_breakpoint.c ++++ b/kernel/events/hw_breakpoint.c +@@ -950,9 +950,10 @@ static int hw_breakpoint_event_init(struct perf_event *bp) + return -ENOENT; + + /* +- * no branch sampling for breakpoint events ++ * Check if breakpoint type is supported before proceeding. ++ * Also, no branch sampling for breakpoint events. + */ +- if (has_branch_stack(bp)) ++ if (!hw_breakpoint_slots_cached(find_slot_idx(bp->attr.bp_type)) || has_branch_stack(bp)) + return -EOPNOTSUPP; + + err = register_perf_hw_breakpoint(bp); +diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c +index 52de76ef8723b8..dc1193b779c080 100644 +--- a/kernel/events/ring_buffer.c ++++ b/kernel/events/ring_buffer.c +@@ -181,6 +181,7 @@ __perf_output_begin(struct perf_output_handle *handle, + + handle->rb = rb; + handle->event = event; ++ handle->flags = 0; + + have_lost = local_read(&rb->lost); + if (unlikely(have_lost)) { +diff --git a/kernel/fork.c b/kernel/fork.c +index 97f433fb4b5ef4..7966c9a1c163d1 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -518,10 +518,6 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) + vma_numab_state_init(new); + dup_anon_vma_name(orig, new); + +- /* track_pfn_copy() will later take care of copying internal state. */ +- if (unlikely(new->vm_flags & VM_PFNMAP)) +- untrack_pfn_clear(new); +- + return new; + } + +@@ -715,6 +711,11 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, + tmp = vm_area_dup(mpnt); + if (!tmp) + goto fail_nomem; ++ ++ /* track_pfn_copy() will later take care of copying internal state. */ ++ if (unlikely(tmp->vm_flags & VM_PFNMAP)) ++ untrack_pfn_clear(tmp); ++ + retval = vma_dup_policy(mpnt, tmp); + if (retval) + goto fail_nomem_policy; +diff --git a/kernel/padata.c b/kernel/padata.c +index 071d8cad807871..93cd7704ab63e6 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -358,7 +358,8 @@ static void padata_reorder(struct parallel_data *pd) + * To avoid UAF issue, add pd ref here, and put pd ref after reorder_work finish. + */ + padata_get_pd(pd); +- queue_work(pinst->serial_wq, &pd->reorder_work); ++ if (!queue_work(pinst->serial_wq, &pd->reorder_work)) ++ padata_put_pd(pd); + } + } + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index dcdf449615bdac..51c43e0f9b29b5 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3119,7 +3119,12 @@ void console_unblank(void) + */ + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +- if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) { ++ short flags = console_srcu_read_flags(c); ++ ++ if (flags & CON_SUSPENDED) ++ continue; ++ ++ if ((flags & CON_ENABLED) && c->unblank) { + found_unblank = true; + break; + } +@@ -3156,7 +3161,12 @@ void console_unblank(void) + + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +- if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) ++ short flags = console_srcu_read_flags(c); ++ ++ if (flags & CON_SUSPENDED) ++ continue; ++ ++ if ((flags & CON_ENABLED) && c->unblank) + c->unblank(); + } + console_srcu_read_unlock(cookie); +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 41021080ad258d..94b715139f52d9 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -821,8 +821,17 @@ void rcu_read_unlock_strict(void) + { + struct rcu_data *rdp; + +- if (irqs_disabled() || preempt_count() || !rcu_state.gp_kthread) ++ if (irqs_disabled() || in_atomic_preempt_off() || !rcu_state.gp_kthread) + return; ++ ++ /* ++ * rcu_report_qs_rdp() can only be invoked with a stable rdp and ++ * from the local CPU. ++ * ++ * The in_atomic_preempt_off() check ensures that we come here holding ++ * the last preempt_count (which will get dropped once we return to ++ * __rcu_read_unlock(). ++ */ + rdp = this_cpu_ptr(&rcu_data); + rdp->cpu_no_qs.b.norm = false; + rcu_report_qs_rdp(rdp); +@@ -963,13 +972,16 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) + */ + static void rcu_flavor_sched_clock_irq(int user) + { +- if (user || rcu_is_cpu_rrupt_from_idle()) { ++ if (user || rcu_is_cpu_rrupt_from_idle() || ++ (IS_ENABLED(CONFIG_PREEMPT_COUNT) && ++ (preempt_count() == HARDIRQ_OFFSET))) { + + /* + * Get here if this CPU took its interrupt from user +- * mode or from the idle loop, and if this is not a +- * nested interrupt. In this case, the CPU is in +- * a quiescent state, so note it. ++ * mode, from the idle loop without this being a nested ++ * interrupt, or while not holding the task preempt count ++ * (with PREEMPT_COUNT=y). In this case, the CPU is in a ++ * quiescent state, so note it. + * + * No memory barrier is required here because rcu_qs() + * references only CPU-local variables that other CPUs +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 268e2a49b964e0..6ce3028e6e852f 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -73,10 +73,10 @@ unsigned int sysctl_sched_tunable_scaling = SCHED_TUNABLESCALING_LOG; + /* + * Minimal preemption granularity for CPU-bound tasks: + * +- * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds) ++ * (default: 0.70 msec * (1 + ilog(ncpus)), units: nanoseconds) + */ +-unsigned int sysctl_sched_base_slice = 750000ULL; +-static unsigned int normalized_sysctl_sched_base_slice = 750000ULL; ++unsigned int sysctl_sched_base_slice = 700000ULL; ++static unsigned int normalized_sysctl_sched_base_slice = 700000ULL; + + /* + * After fork, child runs first. If set to 0 (default) then +diff --git a/kernel/softirq.c b/kernel/softirq.c +index f24d80cf20bd35..d9e37f3fa13039 100644 +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -125,6 +125,18 @@ static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = { + .lock = INIT_LOCAL_LOCK(softirq_ctrl.lock), + }; + ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++static struct lock_class_key bh_lock_key; ++struct lockdep_map bh_lock_map = { ++ .name = "local_bh", ++ .key = &bh_lock_key, ++ .wait_type_outer = LD_WAIT_FREE, ++ .wait_type_inner = LD_WAIT_CONFIG, /* PREEMPT_RT makes BH preemptible. */ ++ .lock_type = LD_LOCK_PERCPU, ++}; ++EXPORT_SYMBOL_GPL(bh_lock_map); ++#endif ++ + /** + * local_bh_blocked() - Check for idle whether BH processing is blocked + * +@@ -147,6 +159,8 @@ void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) + + WARN_ON_ONCE(in_hardirq()); + ++ lock_map_acquire_read(&bh_lock_map); ++ + /* First entry of a task into a BH disabled section? */ + if (!current->softirq_disable_cnt) { + if (preemptible()) { +@@ -210,6 +224,8 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) + WARN_ON_ONCE(in_hardirq()); + lockdep_assert_irqs_enabled(); + ++ lock_map_release(&bh_lock_map); ++ + local_irq_save(flags); + curcnt = __this_cpu_read(softirq_ctrl.cnt); + +@@ -260,6 +276,8 @@ static inline void ksoftirqd_run_begin(void) + /* Counterpart to ksoftirqd_run_begin() */ + static inline void ksoftirqd_run_end(void) + { ++ /* pairs with the lock_map_acquire_read() in ksoftirqd_run_begin() */ ++ lock_map_release(&bh_lock_map); + __local_bh_enable(SOFTIRQ_OFFSET, true); + WARN_ON_ONCE(in_interrupt()); + local_irq_enable(); +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 877535b06e73aa..6d9da768604d68 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -58,6 +58,8 @@ + #define HRTIMER_ACTIVE_SOFT (HRTIMER_ACTIVE_HARD << MASK_SHIFT) + #define HRTIMER_ACTIVE_ALL (HRTIMER_ACTIVE_SOFT | HRTIMER_ACTIVE_HARD) + ++static void retrigger_next_event(void *arg); ++ + /* + * The timer bases: + * +@@ -111,7 +113,8 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = + .clockid = CLOCK_TAI, + .get_time = &ktime_get_clocktai, + }, +- } ++ }, ++ .csd = CSD_INIT(retrigger_next_event, NULL) + }; + + static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = { +@@ -124,6 +127,14 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = { + [CLOCK_TAI] = HRTIMER_BASE_TAI, + }; + ++static inline bool hrtimer_base_is_online(struct hrtimer_cpu_base *base) ++{ ++ if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) ++ return true; ++ else ++ return likely(base->online); ++} ++ + /* + * Functions and macros which are different for UP/SMP systems are kept in a + * single place +@@ -178,27 +189,54 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, + } + + /* +- * We do not migrate the timer when it is expiring before the next +- * event on the target cpu. When high resolution is enabled, we cannot +- * reprogram the target cpu hardware and we would cause it to fire +- * late. To keep it simple, we handle the high resolution enabled and +- * disabled case similar. ++ * Check if the elected target is suitable considering its next ++ * event and the hotplug state of the current CPU. ++ * ++ * If the elected target is remote and its next event is after the timer ++ * to queue, then a remote reprogram is necessary. However there is no ++ * guarantee the IPI handling the operation would arrive in time to meet ++ * the high resolution deadline. In this case the local CPU becomes a ++ * preferred target, unless it is offline. ++ * ++ * High and low resolution modes are handled the same way for simplicity. + * + * Called with cpu_base->lock of target cpu held. + */ +-static int +-hrtimer_check_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base) ++static bool hrtimer_suitable_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base, ++ struct hrtimer_cpu_base *new_cpu_base, ++ struct hrtimer_cpu_base *this_cpu_base) + { + ktime_t expires; + ++ /* ++ * The local CPU clockevent can be reprogrammed. Also get_target_base() ++ * guarantees it is online. ++ */ ++ if (new_cpu_base == this_cpu_base) ++ return true; ++ ++ /* ++ * The offline local CPU can't be the default target if the ++ * next remote target event is after this timer. Keep the ++ * elected new base. An IPI will we issued to reprogram ++ * it as a last resort. ++ */ ++ if (!hrtimer_base_is_online(this_cpu_base)) ++ return true; ++ + expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset); +- return expires < new_base->cpu_base->expires_next; ++ ++ return expires >= new_base->cpu_base->expires_next; + } + +-static inline +-struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, +- int pinned) ++static inline struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, int pinned) + { ++ if (!hrtimer_base_is_online(base)) { ++ int cpu = cpumask_any_and(cpu_online_mask, housekeeping_cpumask(HK_TYPE_TIMER)); ++ ++ return &per_cpu(hrtimer_bases, cpu); ++ } ++ + #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) + if (static_branch_likely(&timers_migration_enabled) && !pinned) + return &per_cpu(hrtimer_bases, get_nohz_timer_target()); +@@ -249,8 +287,8 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, + raw_spin_unlock(&base->cpu_base->lock); + raw_spin_lock(&new_base->cpu_base->lock); + +- if (new_cpu_base != this_cpu_base && +- hrtimer_check_target(timer, new_base)) { ++ if (!hrtimer_suitable_target(timer, new_base, new_cpu_base, ++ this_cpu_base)) { + raw_spin_unlock(&new_base->cpu_base->lock); + raw_spin_lock(&base->cpu_base->lock); + new_cpu_base = this_cpu_base; +@@ -259,8 +297,7 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, + } + WRITE_ONCE(timer->base, new_base); + } else { +- if (new_cpu_base != this_cpu_base && +- hrtimer_check_target(timer, new_base)) { ++ if (!hrtimer_suitable_target(timer, new_base, new_cpu_base, this_cpu_base)) { + new_cpu_base = this_cpu_base; + goto again; + } +@@ -720,8 +757,6 @@ static inline int hrtimer_is_hres_enabled(void) + return hrtimer_hres_enabled; + } + +-static void retrigger_next_event(void *arg); +- + /* + * Switch to high resolution mode + */ +@@ -1208,6 +1243,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + u64 delta_ns, const enum hrtimer_mode mode, + struct hrtimer_clock_base *base) + { ++ struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); + struct hrtimer_clock_base *new_base; + bool force_local, first; + +@@ -1219,9 +1255,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + * and enforce reprogramming after it is queued no matter whether + * it is the new first expiring timer again or not. + */ +- force_local = base->cpu_base == this_cpu_ptr(&hrtimer_bases); ++ force_local = base->cpu_base == this_cpu_base; + force_local &= base->cpu_base->next_timer == timer; + ++ /* ++ * Don't force local queuing if this enqueue happens on a unplugged ++ * CPU after hrtimer_cpu_dying() has been invoked. ++ */ ++ force_local &= this_cpu_base->online; ++ + /* + * Remove an active timer from the queue. In case it is not queued + * on the current CPU, make sure that remove_hrtimer() updates the +@@ -1251,8 +1293,27 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + } + + first = enqueue_hrtimer(timer, new_base, mode); +- if (!force_local) +- return first; ++ if (!force_local) { ++ /* ++ * If the current CPU base is online, then the timer is ++ * never queued on a remote CPU if it would be the first ++ * expiring timer there. ++ */ ++ if (hrtimer_base_is_online(this_cpu_base)) ++ return first; ++ ++ /* ++ * Timer was enqueued remote because the current base is ++ * already offline. If the timer is the first to expire, ++ * kick the remote CPU to reprogram the clock event. ++ */ ++ if (first) { ++ struct hrtimer_cpu_base *new_cpu_base = new_base->cpu_base; ++ ++ smp_call_function_single_async(new_cpu_base->cpu, &new_cpu_base->csd); ++ } ++ return 0; ++ } + + /* + * Timer was forced to stay on the current CPU to avoid +diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c +index b924f0f096fa44..7534069f603334 100644 +--- a/kernel/time/posix-timers.c ++++ b/kernel/time/posix-timers.c +@@ -118,6 +118,7 @@ static int posix_timer_add(struct k_itimer *timer) + return id; + } + spin_unlock(&hash_lock); ++ cond_resched(); + } + /* POSIX return code when no timer ID could be allocated */ + return -EAGAIN; +diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c +index ed7d6ad694fba6..20a5e6962b6967 100644 +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -46,7 +46,7 @@ static void + print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer, + int idx, u64 now) + { +- SEQ_printf(m, " #%d: <%pK>, %ps", idx, taddr, timer->function); ++ SEQ_printf(m, " #%d: <%p>, %ps", idx, taddr, timer->function); + SEQ_printf(m, ", S:%02x", timer->state); + SEQ_printf(m, "\n"); + SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n", +@@ -98,7 +98,7 @@ print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, + static void + print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now) + { +- SEQ_printf(m, " .base: %pK\n", base); ++ SEQ_printf(m, " .base: %p\n", base); + SEQ_printf(m, " .index: %d\n", base->index); + + SEQ_printf(m, " .resolution: %u nsecs\n", hrtimer_resolution); +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 95868c31573007..43d19b69c635b2 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -3487,10 +3487,9 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) + } + EXPORT_SYMBOL_GPL(trace_vbprintk); + +-__printf(3, 0) +-static int +-__trace_array_vprintk(struct trace_buffer *buffer, +- unsigned long ip, const char *fmt, va_list args) ++static __printf(3, 0) ++int __trace_array_vprintk(struct trace_buffer *buffer, ++ unsigned long ip, const char *fmt, va_list args) + { + struct trace_event_call *call = &event_print; + struct ring_buffer_event *event; +@@ -3543,7 +3542,6 @@ __trace_array_vprintk(struct trace_buffer *buffer, + return len; + } + +-__printf(3, 0) + int trace_array_vprintk(struct trace_array *tr, + unsigned long ip, const char *fmt, va_list args) + { +@@ -3573,7 +3571,6 @@ int trace_array_vprintk(struct trace_array *tr, + * Note, trace_array_init_printk() must be called on @tr before this + * can be used. + */ +-__printf(3, 0) + int trace_array_printk(struct trace_array *tr, + unsigned long ip, const char *fmt, ...) + { +@@ -3618,7 +3615,6 @@ int trace_array_init_printk(struct trace_array *tr) + } + EXPORT_SYMBOL_GPL(trace_array_init_printk); + +-__printf(3, 4) + int trace_array_printk_buf(struct trace_buffer *buffer, + unsigned long ip, const char *fmt, ...) + { +@@ -3634,7 +3630,6 @@ int trace_array_printk_buf(struct trace_buffer *buffer, + return ret; + } + +-__printf(2, 0) + int trace_vprintk(unsigned long ip, const char *fmt, va_list args) + { + return trace_array_vprintk(&global_trace, ip, fmt, args); +diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h +index db0d2641125e7e..faf892aecdf490 100644 +--- a/kernel/trace/trace.h ++++ b/kernel/trace/trace.h +@@ -800,13 +800,15 @@ static inline void __init disable_tracing_selftest(const char *reason) + + extern void *head_page(struct trace_array_cpu *data); + extern unsigned long long ns2usecs(u64 nsec); +-extern int +-trace_vbprintk(unsigned long ip, const char *fmt, va_list args); +-extern int +-trace_vprintk(unsigned long ip, const char *fmt, va_list args); +-extern int +-trace_array_vprintk(struct trace_array *tr, +- unsigned long ip, const char *fmt, va_list args); ++ ++__printf(2, 0) ++int trace_vbprintk(unsigned long ip, const char *fmt, va_list args); ++__printf(2, 0) ++int trace_vprintk(unsigned long ip, const char *fmt, va_list args); ++__printf(3, 0) ++int trace_array_vprintk(struct trace_array *tr, ++ unsigned long ip, const char *fmt, va_list args); ++__printf(3, 4) + int trace_array_printk_buf(struct trace_buffer *buffer, + unsigned long ip, const char *fmt, ...); + void trace_printk_seq(struct trace_seq *s); +diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c +index fde0aa24414800..a75a9ca46b5940 100644 +--- a/lib/dynamic_queue_limits.c ++++ b/lib/dynamic_queue_limits.c +@@ -116,7 +116,7 @@ EXPORT_SYMBOL(dql_completed); + void dql_reset(struct dql *dql) + { + /* Reset all dynamic values */ +- dql->limit = 0; ++ dql->limit = dql->min_limit; + dql->num_queued = 0; + dql->num_completed = 0; + dql->last_obj_cnt = 0; +diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile +index 2f58fafbbdddc0..fc7b2b7ef4b20e 100644 +--- a/lib/lzo/Makefile ++++ b/lib/lzo/Makefile +@@ -1,5 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0-only +-lzo_compress-objs := lzo1x_compress.o ++lzo_compress-objs := lzo1x_compress.o lzo1x_compress_safe.o + lzo_decompress-objs := lzo1x_decompress_safe.o + + obj-$(CONFIG_LZO_COMPRESS) += lzo_compress.o +diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c +index 9d31e7126606ac..f00dff9b9d4e1b 100644 +--- a/lib/lzo/lzo1x_compress.c ++++ b/lib/lzo/lzo1x_compress.c +@@ -18,11 +18,22 @@ + #include + #include "lzodefs.h" + +-static noinline size_t +-lzo1x_1_do_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- size_t ti, void *wrkmem, signed char *state_offset, +- const unsigned char bitstream_version) ++#undef LZO_UNSAFE ++ ++#ifndef LZO_SAFE ++#define LZO_UNSAFE 1 ++#define LZO_SAFE(name) name ++#define HAVE_OP(x) 1 ++#endif ++ ++#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun ++ ++static noinline int ++LZO_SAFE(lzo1x_1_do_compress)(const unsigned char *in, size_t in_len, ++ unsigned char **out, unsigned char *op_end, ++ size_t *tp, void *wrkmem, ++ signed char *state_offset, ++ const unsigned char bitstream_version) + { + const unsigned char *ip; + unsigned char *op; +@@ -30,8 +41,9 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + const unsigned char * const ip_end = in + in_len - 20; + const unsigned char *ii; + lzo_dict_t * const dict = (lzo_dict_t *) wrkmem; ++ size_t ti = *tp; + +- op = out; ++ op = *out; + ip = in; + ii = ip; + ip += ti < 4 ? 4 - ti : 0; +@@ -116,25 +128,32 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + if (t != 0) { + if (t <= 3) { + op[*state_offset] |= t; ++ NEED_OP(4); + COPY4(op, ii); + op += t; + } else if (t <= 16) { ++ NEED_OP(17); + *op++ = (t - 3); + COPY8(op, ii); + COPY8(op + 8, ii + 8); + op += t; + } else { + if (t <= 18) { ++ NEED_OP(1); + *op++ = (t - 3); + } else { + size_t tt = t - 18; ++ NEED_OP(1); + *op++ = 0; + while (unlikely(tt > 255)) { + tt -= 255; ++ NEED_OP(1); + *op++ = 0; + } ++ NEED_OP(1); + *op++ = tt; + } ++ NEED_OP(t); + do { + COPY8(op, ii); + COPY8(op + 8, ii + 8); +@@ -151,6 +170,7 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + if (unlikely(run_length)) { + ip += run_length; + run_length -= MIN_ZERO_RUN_LENGTH; ++ NEED_OP(4); + put_unaligned_le32((run_length << 21) | 0xfffc18 + | (run_length & 0x7), op); + op += 4; +@@ -243,10 +263,12 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + ip += m_len; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { + m_off -= 1; ++ NEED_OP(2); + *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = (m_off >> 3); + } else if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; ++ NEED_OP(1); + if (m_len <= M3_MAX_LEN) + *op++ = (M3_MARKER | (m_len - 2)); + else { +@@ -254,14 +276,18 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + *op++ = M3_MARKER | 0; + while (unlikely(m_len > 255)) { + m_len -= 255; ++ NEED_OP(1); + *op++ = 0; + } ++ NEED_OP(1); + *op++ = (m_len); + } ++ NEED_OP(2); + *op++ = (m_off << 2); + *op++ = (m_off >> 6); + } else { + m_off -= 0x4000; ++ NEED_OP(1); + if (m_len <= M4_MAX_LEN) + *op++ = (M4_MARKER | ((m_off >> 11) & 8) + | (m_len - 2)); +@@ -282,11 +308,14 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + m_len -= M4_MAX_LEN; + *op++ = (M4_MARKER | ((m_off >> 11) & 8)); + while (unlikely(m_len > 255)) { ++ NEED_OP(1); + m_len -= 255; + *op++ = 0; + } ++ NEED_OP(1); + *op++ = (m_len); + } ++ NEED_OP(2); + *op++ = (m_off << 2); + *op++ = (m_off >> 6); + } +@@ -295,14 +324,20 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + ii = ip; + goto next; + } +- *out_len = op - out; +- return in_end - (ii - ti); ++ *out = op; ++ *tp = in_end - (ii - ti); ++ return LZO_E_OK; ++ ++output_overrun: ++ return LZO_E_OUTPUT_OVERRUN; + } + +-static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- void *wrkmem, const unsigned char bitstream_version) ++static int LZO_SAFE(lzogeneric1x_1_compress)( ++ const unsigned char *in, size_t in_len, ++ unsigned char *out, size_t *out_len, ++ void *wrkmem, const unsigned char bitstream_version) + { ++ unsigned char * const op_end = out + *out_len; + const unsigned char *ip = in; + unsigned char *op = out; + unsigned char *data_start; +@@ -326,14 +361,18 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, + while (l > 20) { + size_t ll = min_t(size_t, l, m4_max_offset + 1); + uintptr_t ll_end = (uintptr_t) ip + ll; ++ int err; ++ + if ((ll_end + ((t + ll) >> 5)) <= ll_end) + break; + BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS); + memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); +- t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem, +- &state_offset, bitstream_version); ++ err = LZO_SAFE(lzo1x_1_do_compress)( ++ ip, ll, &op, op_end, &t, wrkmem, ++ &state_offset, bitstream_version); ++ if (err != LZO_E_OK) ++ return err; + ip += ll; +- op += *out_len; + l -= ll; + } + t += l; +@@ -342,20 +381,26 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, + const unsigned char *ii = in + in_len - t; + + if (op == data_start && t <= 238) { ++ NEED_OP(1); + *op++ = (17 + t); + } else if (t <= 3) { + op[state_offset] |= t; + } else if (t <= 18) { ++ NEED_OP(1); + *op++ = (t - 3); + } else { + size_t tt = t - 18; ++ NEED_OP(1); + *op++ = 0; + while (tt > 255) { + tt -= 255; ++ NEED_OP(1); + *op++ = 0; + } ++ NEED_OP(1); + *op++ = tt; + } ++ NEED_OP(t); + if (t >= 16) do { + COPY8(op, ii); + COPY8(op + 8, ii + 8); +@@ -368,31 +413,38 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, + } while (--t > 0); + } + ++ NEED_OP(3); + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = op - out; + return LZO_E_OK; ++ ++output_overrun: ++ return LZO_E_OUTPUT_OVERRUN; + } + +-int lzo1x_1_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- void *wrkmem) ++int LZO_SAFE(lzo1x_1_compress)(const unsigned char *in, size_t in_len, ++ unsigned char *out, size_t *out_len, ++ void *wrkmem) + { +- return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0); ++ return LZO_SAFE(lzogeneric1x_1_compress)( ++ in, in_len, out, out_len, wrkmem, 0); + } + +-int lzorle1x_1_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- void *wrkmem) ++int LZO_SAFE(lzorle1x_1_compress)(const unsigned char *in, size_t in_len, ++ unsigned char *out, size_t *out_len, ++ void *wrkmem) + { +- return lzogeneric1x_1_compress(in, in_len, out, out_len, +- wrkmem, LZO_VERSION); ++ return LZO_SAFE(lzogeneric1x_1_compress)( ++ in, in_len, out, out_len, wrkmem, LZO_VERSION); + } + +-EXPORT_SYMBOL_GPL(lzo1x_1_compress); +-EXPORT_SYMBOL_GPL(lzorle1x_1_compress); ++EXPORT_SYMBOL_GPL(LZO_SAFE(lzo1x_1_compress)); ++EXPORT_SYMBOL_GPL(LZO_SAFE(lzorle1x_1_compress)); + ++#ifndef LZO_UNSAFE + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("LZO1X-1 Compressor"); ++#endif +diff --git a/lib/lzo/lzo1x_compress_safe.c b/lib/lzo/lzo1x_compress_safe.c +new file mode 100644 +index 00000000000000..371c9f84949281 +--- /dev/null ++++ b/lib/lzo/lzo1x_compress_safe.c +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * LZO1X Compressor from LZO ++ * ++ * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer ++ * ++ * The full LZO package can be found at: ++ * http://www.oberhumer.com/opensource/lzo/ ++ * ++ * Changed for Linux kernel use by: ++ * Nitin Gupta ++ * Richard Purdie ++ */ ++ ++#define LZO_SAFE(name) name##_safe ++#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) ++ ++#include "lzo1x_compress.c" +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index 9bf5a69e20d87a..2d2cada8a8a4c8 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -1266,7 +1266,6 @@ void mem_cgroup_scan_tasks(struct mem_cgroup *memcg, + { + struct mem_cgroup *iter; + int ret = 0; +- int i = 0; + + BUG_ON(mem_cgroup_is_root(memcg)); + +@@ -1276,10 +1275,9 @@ void mem_cgroup_scan_tasks(struct mem_cgroup *memcg, + + css_task_iter_start(&iter->css, CSS_TASK_ITER_PROCS, &it); + while (!ret && (task = css_task_iter_next(&it))) { +- /* Avoid potential softlockup warning */ +- if ((++i & 1023) == 0) +- cond_resched(); + ret = fn(task, arg); ++ /* Avoid potential softlockup warning */ ++ cond_resched(); + } + css_task_iter_end(&it); + if (ret) { +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 74737c35082b45..44011ebecddf01 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -4038,6 +4038,14 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, + } + + retry: ++ /* ++ * Deal with possible cpuset update races or zonelist updates to avoid ++ * infinite retries. ++ */ ++ if (check_retry_cpuset(cpuset_mems_cookie, ac) || ++ check_retry_zonelist(zonelist_iter_cookie)) ++ goto restart; ++ + /* Ensure kswapd doesn't accidentally go to sleep as long as we loop */ + if (alloc_flags & ALLOC_KSWAPD) + wake_all_kswapds(order, gfp_mask, ac); +diff --git a/net/Makefile b/net/Makefile +index 4c4dc535453dff..45f3fbaae644e1 100644 +--- a/net/Makefile ++++ b/net/Makefile +@@ -17,7 +17,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/ + obj-$(CONFIG_INET) += ipv4/ + obj-$(CONFIG_TLS) += tls/ + obj-$(CONFIG_XFRM) += xfrm/ +-obj-$(CONFIG_UNIX_SCM) += unix/ ++obj-$(CONFIG_UNIX) += unix/ + obj-y += ipv6/ + obj-$(CONFIG_BPFILTER) += bpfilter/ + obj-$(CONFIG_PACKET) += packet/ +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 72ee41b894a520..1c54e812ef1f78 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -1411,7 +1411,8 @@ static void l2cap_request_info(struct l2cap_conn *conn) + sizeof(req), &req); + } + +-static bool l2cap_check_enc_key_size(struct hci_conn *hcon) ++static bool l2cap_check_enc_key_size(struct hci_conn *hcon, ++ struct l2cap_chan *chan) + { + /* The minimum encryption key size needs to be enforced by the + * host stack before establishing any L2CAP connections. The +@@ -1425,7 +1426,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon) + int min_key_size = hcon->hdev->min_enc_key_size; + + /* On FIPS security level, key size must be 16 bytes */ +- if (hcon->sec_level == BT_SECURITY_FIPS) ++ if (chan->sec_level == BT_SECURITY_FIPS) + min_key_size = 16; + + return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) || +@@ -1453,7 +1454,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) + !__l2cap_no_conn_pending(chan)) + return; + +- if (l2cap_check_enc_key_size(conn->hcon)) ++ if (l2cap_check_enc_key_size(conn->hcon, chan)) + l2cap_start_connection(chan); + else + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); +@@ -1528,7 +1529,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) + continue; + } + +- if (l2cap_check_enc_key_size(conn->hcon)) ++ if (l2cap_check_enc_key_size(conn->hcon, chan)) + l2cap_start_connection(chan); + else + l2cap_chan_close(chan, ECONNREFUSED); +@@ -3955,7 +3956,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, + /* Check if the ACL is secure enough (if not SDP) */ + if (psm != cpu_to_le16(L2CAP_PSM_SDP) && + (!hci_conn_check_link_mode(conn->hcon) || +- !l2cap_check_enc_key_size(conn->hcon))) { ++ !l2cap_check_enc_key_size(conn->hcon, pchan))) { + conn->disc_reason = HCI_ERROR_AUTH_FAILURE; + result = L2CAP_CR_SEC_BLOCK; + goto response; +@@ -7323,7 +7324,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) + } + + if (chan->state == BT_CONNECT) { +- if (!status && l2cap_check_enc_key_size(hcon)) ++ if (!status && l2cap_check_enc_key_size(hcon, chan)) + l2cap_start_connection(chan); + else + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); +@@ -7333,7 +7334,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) + struct l2cap_conn_rsp rsp; + __u16 res, stat; + +- if (!status && l2cap_check_enc_key_size(hcon)) { ++ if (!status && l2cap_check_enc_key_size(hcon, chan)) { + if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { + res = L2CAP_CR_PEND; + stat = L2CAP_CS_AUTHOR_PEND; +diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c +index 7305f5f8215cac..96bea0c8408fec 100644 +--- a/net/bridge/br_mdb.c ++++ b/net/bridge/br_mdb.c +@@ -1030,7 +1030,7 @@ static int br_mdb_add_group(const struct br_mdb_config *cfg, + + /* host join */ + if (!port) { +- if (mp->host_joined) { ++ if (mp->host_joined && !(cfg->nlflags & NLM_F_REPLACE)) { + NL_SET_ERR_MSG_MOD(extack, "Group is already joined by host"); + return -EEXIST; + } +diff --git a/net/bridge/br_nf_core.c b/net/bridge/br_nf_core.c +index 98aea5485aaef4..a8c67035e23c00 100644 +--- a/net/bridge/br_nf_core.c ++++ b/net/bridge/br_nf_core.c +@@ -65,17 +65,14 @@ static struct dst_ops fake_dst_ops = { + * ipt_REJECT needs it. Future netfilter modules might + * require us to fill additional fields. + */ +-static const u32 br_dst_default_metrics[RTAX_MAX] = { +- [RTAX_MTU - 1] = 1500, +-}; +- + void br_netfilter_rtable_init(struct net_bridge *br) + { + struct rtable *rt = &br->fake_rtable; + + rcuref_init(&rt->dst.__rcuref, 1); + rt->dst.dev = br->dev; +- dst_init_metrics(&rt->dst, br_dst_default_metrics, true); ++ dst_init_metrics(&rt->dst, br->metrics, false); ++ dst_metric_set(&rt->dst, RTAX_MTU, br->dev->mtu); + rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE; + rt->dst.ops = &fake_dst_ops; + } +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h +index 72d80fd943a8a2..9197b511e45972 100644 +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -502,6 +502,7 @@ struct net_bridge { + struct rtable fake_rtable; + struct rt6_info fake_rt6_info; + }; ++ u32 metrics[RTAX_MAX]; + #endif + u16 group_fwd_mask; + u16 group_fwd_mask_required; +diff --git a/net/can/bcm.c b/net/can/bcm.c +index a1f5db0fd5d4fd..75653584f31b94 100644 +--- a/net/can/bcm.c ++++ b/net/can/bcm.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -120,6 +121,7 @@ struct bcm_op { + struct canfd_frame last_sframe; + struct sock *sk; + struct net_device *rx_reg_dev; ++ spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */ + }; + + struct bcm_sock { +@@ -205,7 +207,9 @@ static int bcm_proc_show(struct seq_file *m, void *v) + seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex)); + seq_printf(m, " <<<\n"); + +- list_for_each_entry(op, &bo->rx_ops, list) { ++ rcu_read_lock(); ++ ++ list_for_each_entry_rcu(op, &bo->rx_ops, list) { + + unsigned long reduction; + +@@ -261,6 +265,9 @@ static int bcm_proc_show(struct seq_file *m, void *v) + seq_printf(m, "# sent %ld\n", op->frames_abs); + } + seq_putc(m, '\n'); ++ ++ rcu_read_unlock(); ++ + return 0; + } + #endif /* CONFIG_PROC_FS */ +@@ -273,13 +280,18 @@ static void bcm_can_tx(struct bcm_op *op) + { + struct sk_buff *skb; + struct net_device *dev; +- struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe; ++ struct canfd_frame *cf; + int err; + + /* no target device? => exit */ + if (!op->ifindex) + return; + ++ /* read currframe under lock protection */ ++ spin_lock_bh(&op->bcm_tx_lock); ++ cf = op->frames + op->cfsiz * op->currframe; ++ spin_unlock_bh(&op->bcm_tx_lock); ++ + dev = dev_get_by_index(sock_net(op->sk), op->ifindex); + if (!dev) { + /* RFC: should this bcm_op remove itself here? */ +@@ -300,6 +312,10 @@ static void bcm_can_tx(struct bcm_op *op) + skb->dev = dev; + can_skb_set_owner(skb, op->sk); + err = can_send(skb, 1); ++ ++ /* update currframe and count under lock protection */ ++ spin_lock_bh(&op->bcm_tx_lock); ++ + if (!err) + op->frames_abs++; + +@@ -308,6 +324,11 @@ static void bcm_can_tx(struct bcm_op *op) + /* reached last frame? */ + if (op->currframe >= op->nframes) + op->currframe = 0; ++ ++ if (op->count > 0) ++ op->count--; ++ ++ spin_unlock_bh(&op->bcm_tx_lock); + out: + dev_put(dev); + } +@@ -404,7 +425,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) + struct bcm_msg_head msg_head; + + if (op->kt_ival1 && (op->count > 0)) { +- op->count--; ++ bcm_can_tx(op); + if (!op->count && (op->flags & TX_COUNTEVT)) { + + /* create notification to user */ +@@ -419,7 +440,6 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) + + bcm_send_to_user(op, &msg_head, NULL, 0); + } +- bcm_can_tx(op); + + } else if (op->kt_ival2) { + bcm_can_tx(op); +@@ -801,7 +821,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, + REGMASK(op->can_id), + bcm_rx_handler, op); + +- list_del(&op->list); ++ list_del_rcu(&op->list); + bcm_remove_op(op); + return 1; /* done */ + } +@@ -821,7 +841,7 @@ static int bcm_delete_tx_op(struct list_head *ops, struct bcm_msg_head *mh, + list_for_each_entry_safe(op, n, ops, list) { + if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) && + (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) { +- list_del(&op->list); ++ list_del_rcu(&op->list); + bcm_remove_op(op); + return 1; /* done */ + } +@@ -914,6 +934,27 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + } + op->flags = msg_head->flags; + ++ /* only lock for unlikely count/nframes/currframe changes */ ++ if (op->nframes != msg_head->nframes || ++ op->flags & TX_RESET_MULTI_IDX || ++ op->flags & SETTIMER) { ++ ++ spin_lock_bh(&op->bcm_tx_lock); ++ ++ if (op->nframes != msg_head->nframes || ++ op->flags & TX_RESET_MULTI_IDX) { ++ /* potentially update changed nframes */ ++ op->nframes = msg_head->nframes; ++ /* restart multiple frame transmission */ ++ op->currframe = 0; ++ } ++ ++ if (op->flags & SETTIMER) ++ op->count = msg_head->count; ++ ++ spin_unlock_bh(&op->bcm_tx_lock); ++ } ++ + } else { + /* insert new BCM operation for the given can_id */ + +@@ -921,9 +962,14 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + if (!op) + return -ENOMEM; + ++ spin_lock_init(&op->bcm_tx_lock); + op->can_id = msg_head->can_id; + op->cfsiz = CFSIZ(msg_head->flags); + op->flags = msg_head->flags; ++ op->nframes = msg_head->nframes; ++ ++ if (op->flags & SETTIMER) ++ op->count = msg_head->count; + + /* create array for CAN frames and copy the data */ + if (msg_head->nframes > 1) { +@@ -982,22 +1028,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + + } /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */ + +- if (op->nframes != msg_head->nframes) { +- op->nframes = msg_head->nframes; +- /* start multiple frame transmission with index 0 */ +- op->currframe = 0; +- } +- +- /* check flags */ +- +- if (op->flags & TX_RESET_MULTI_IDX) { +- /* start multiple frame transmission with index 0 */ +- op->currframe = 0; +- } +- + if (op->flags & SETTIMER) { + /* set timer values */ +- op->count = msg_head->count; + op->ival1 = msg_head->ival1; + op->ival2 = msg_head->ival2; + op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1); +@@ -1014,11 +1046,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + op->flags |= TX_ANNOUNCE; + } + +- if (op->flags & TX_ANNOUNCE) { ++ if (op->flags & TX_ANNOUNCE) + bcm_can_tx(op); +- if (op->count) +- op->count--; +- } + + if (op->flags & STARTTIMER) + bcm_tx_start_timer(op); +@@ -1234,7 +1263,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + bcm_rx_handler, op, "bcm", sk); + if (err) { + /* this bcm rx op is broken -> remove it */ +- list_del(&op->list); ++ list_del_rcu(&op->list); + bcm_remove_op(op); + return err; + } +diff --git a/net/core/pktgen.c b/net/core/pktgen.c +index 359e24c3f22cab..6afea369ca2132 100644 +--- a/net/core/pktgen.c ++++ b/net/core/pktgen.c +@@ -897,6 +897,10 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) + pkt_dev->nr_labels = 0; + do { + __u32 tmp; ++ ++ if (n >= MAX_MPLS_LABELS) ++ return -E2BIG; ++ + len = hex32_arg(&buffer[i], 8, &tmp); + if (len <= 0) + return len; +@@ -908,8 +912,6 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) + return -EFAULT; + i++; + n++; +- if (n >= MAX_MPLS_LABELS) +- return -E2BIG; + } while (c == ','); + + pkt_dev->nr_labels = n; +@@ -1875,8 +1877,8 @@ static ssize_t pktgen_thread_write(struct file *file, + i = len; + + /* Read variable name */ +- +- len = strn_len(&user_buffer[i], sizeof(name) - 1); ++ max = min(sizeof(name) - 1, count - i); ++ len = strn_len(&user_buffer[i], max); + if (len < 0) + return len; + +@@ -1906,7 +1908,8 @@ static ssize_t pktgen_thread_write(struct file *file, + if (!strcmp(name, "add_device")) { + char f[32]; + memset(f, 0, 32); +- len = strn_len(&user_buffer[i], sizeof(f) - 1); ++ max = min(sizeof(f) - 1, count - i); ++ len = strn_len(&user_buffer[i], max); + if (len < 0) { + ret = len; + goto out; +diff --git a/net/core/scm.c b/net/core/scm.c +index 737917c7ac6276..431bfb3ea39290 100644 +--- a/net/core/scm.c ++++ b/net/core/scm.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + + /* +@@ -85,8 +86,15 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + return -ENOMEM; + *fplp = fpl; + fpl->count = 0; ++ fpl->count_unix = 0; + fpl->max = SCM_MAX_FD; + fpl->user = NULL; ++#if IS_ENABLED(CONFIG_UNIX) ++ fpl->inflight = false; ++ fpl->dead = false; ++ fpl->edges = NULL; ++ INIT_LIST_HEAD(&fpl->vertices); ++#endif + } + fpp = &fpl->fp[fpl->count]; + +@@ -109,6 +117,9 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + fput(file); + return -EINVAL; + } ++ if (unix_get_socket(file)) ++ fpl->count_unix++; ++ + *fpp++ = file; + fpl->count++; + } +@@ -371,8 +382,14 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) + if (new_fpl) { + for (i = 0; i < fpl->count; i++) + get_file(fpl->fp[i]); ++ + new_fpl->max = new_fpl->count; + new_fpl->user = get_uid(fpl->user); ++#if IS_ENABLED(CONFIG_UNIX) ++ new_fpl->inflight = false; ++ new_fpl->edges = NULL; ++ INIT_LIST_HEAD(&new_fpl->vertices); ++#endif + } + return new_fpl; + } +diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c +index eeace9b509cec7..49fd664f50fc01 100644 +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -118,47 +118,16 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + } + + #ifdef CONFIG_INET_ESPINTCP +-struct esp_tcp_sk { +- struct sock *sk; +- struct rcu_head rcu; +-}; +- +-static void esp_free_tcp_sk(struct rcu_head *head) +-{ +- struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu); +- +- sock_put(esk->sk); +- kfree(esk); +-} +- + static struct sock *esp_find_tcp_sk(struct xfrm_state *x) + { + struct xfrm_encap_tmpl *encap = x->encap; + struct net *net = xs_net(x); +- struct esp_tcp_sk *esk; + __be16 sport, dport; +- struct sock *nsk; + struct sock *sk; + +- sk = rcu_dereference(x->encap_sk); +- if (sk && sk->sk_state == TCP_ESTABLISHED) +- return sk; +- + spin_lock_bh(&x->lock); + sport = encap->encap_sport; + dport = encap->encap_dport; +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (sk && sk == nsk) { +- esk = kmalloc(sizeof(*esk), GFP_ATOMIC); +- if (!esk) { +- spin_unlock_bh(&x->lock); +- return ERR_PTR(-ENOMEM); +- } +- RCU_INIT_POINTER(x->encap_sk, NULL); +- esk->sk = sk; +- call_rcu(&esk->rcu, esp_free_tcp_sk); +- } + spin_unlock_bh(&x->lock); + + sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, x->id.daddr.a4, +@@ -171,20 +140,6 @@ static struct sock *esp_find_tcp_sk(struct xfrm_state *x) + return ERR_PTR(-EINVAL); + } + +- spin_lock_bh(&x->lock); +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (encap->encap_sport != sport || +- encap->encap_dport != dport) { +- sock_put(sk); +- sk = nsk ?: ERR_PTR(-EREMCHG); +- } else if (sk == nsk) { +- sock_put(sk); +- } else { +- rcu_assign_pointer(x->encap_sk, sk); +- } +- spin_unlock_bh(&x->lock); +- + return sk; + } + +@@ -207,6 +162,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb) + err = espintcp_push_skb(sk, skb); + bh_unlock_sock(sk); + ++ sock_put(sk); ++ + out: + rcu_read_unlock(); + return err; +@@ -391,6 +348,8 @@ static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x, + if (IS_ERR(sk)) + return ERR_CAST(sk); + ++ sock_put(sk); ++ + *lenp = htons(len); + esph = (struct ip_esp_hdr *)(lenp + 1); + +diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c +index 90ce87ffed4617..7993ff46de23ca 100644 +--- a/net/ipv4/fib_frontend.c ++++ b/net/ipv4/fib_frontend.c +@@ -829,19 +829,33 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, + } + } + ++ if (cfg->fc_dst_len > 32) { ++ NL_SET_ERR_MSG(extack, "Invalid prefix length"); ++ err = -EINVAL; ++ goto errout; ++ } ++ ++ if (cfg->fc_dst_len < 32 && (ntohl(cfg->fc_dst) << cfg->fc_dst_len)) { ++ NL_SET_ERR_MSG(extack, "Invalid prefix for given prefix length"); ++ err = -EINVAL; ++ goto errout; ++ } ++ + if (cfg->fc_nh_id) { + if (cfg->fc_oif || cfg->fc_gw_family || + cfg->fc_encap || cfg->fc_mp) { + NL_SET_ERR_MSG(extack, + "Nexthop specification and nexthop id are mutually exclusive"); +- return -EINVAL; ++ err = -EINVAL; ++ goto errout; + } + } + + if (has_gw && has_via) { + NL_SET_ERR_MSG(extack, + "Nexthop configuration can not contain both GATEWAY and VIA"); +- return -EINVAL; ++ err = -EINVAL; ++ goto errout; + } + + if (!cfg->fc_table) +diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c +index 513f475c6a534e..298a9944a3d1e8 100644 +--- a/net/ipv4/fib_rules.c ++++ b/net/ipv4/fib_rules.c +@@ -222,9 +222,9 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, + struct nlattr **tb, + struct netlink_ext_ack *extack) + { +- struct net *net = sock_net(skb->sk); ++ struct fib4_rule *rule4 = (struct fib4_rule *)rule; ++ struct net *net = rule->fr_net; + int err = -EINVAL; +- struct fib4_rule *rule4 = (struct fib4_rule *) rule; + + if (!inet_validate_dscp(frh->tos)) { + NL_SET_ERR_MSG(extack, +diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c +index 77b97c48da5ea8..fa54b36b241ac0 100644 +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1192,22 +1192,6 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp, + return 0; + } + +-static bool fib_valid_key_len(u32 key, u8 plen, struct netlink_ext_ack *extack) +-{ +- if (plen > KEYLENGTH) { +- NL_SET_ERR_MSG(extack, "Invalid prefix length"); +- return false; +- } +- +- if ((plen < KEYLENGTH) && (key << plen)) { +- NL_SET_ERR_MSG(extack, +- "Invalid prefix for given prefix length"); +- return false; +- } +- +- return true; +-} +- + static void fib_remove_alias(struct trie *t, struct key_vector *tp, + struct key_vector *l, struct fib_alias *old); + +@@ -1228,9 +1212,6 @@ int fib_table_insert(struct net *net, struct fib_table *tb, + + key = ntohl(cfg->fc_dst); + +- if (!fib_valid_key_len(key, plen, extack)) +- return -EINVAL; +- + pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); + + fi = fib_create_info(cfg, extack); +@@ -1723,9 +1704,6 @@ int fib_table_delete(struct net *net, struct fib_table *tb, + + key = ntohl(cfg->fc_dst); + +- if (!fib_valid_key_len(key, plen, extack)) +- return -EINVAL; +- + l = fib_find_node(t, &tp, key); + if (!l) + return -ESRCH; +diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c +index 7967ff7e02f794..60e81f6b1c6d4e 100644 +--- a/net/ipv4/inet_hashtables.c ++++ b/net/ipv4/inet_hashtables.c +@@ -1231,22 +1231,37 @@ int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo) + { + unsigned int locksz = sizeof(spinlock_t); + unsigned int i, nblocks = 1; ++ spinlock_t *ptr = NULL; + +- if (locksz != 0) { +- /* allocate 2 cache lines or at least one spinlock per cpu */ +- nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U); +- nblocks = roundup_pow_of_two(nblocks * num_possible_cpus()); ++ if (locksz == 0) ++ goto set_mask; + +- /* no more locks than number of hash buckets */ +- nblocks = min(nblocks, hashinfo->ehash_mask + 1); ++ /* Allocate 2 cache lines or at least one spinlock per cpu. */ ++ nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U) * num_possible_cpus(); + +- hashinfo->ehash_locks = kvmalloc_array(nblocks, locksz, GFP_KERNEL); +- if (!hashinfo->ehash_locks) +- return -ENOMEM; ++ /* At least one page per NUMA node. */ ++ nblocks = max(nblocks, num_online_nodes() * PAGE_SIZE / locksz); ++ ++ nblocks = roundup_pow_of_two(nblocks); ++ ++ /* No more locks than number of hash buckets. */ ++ nblocks = min(nblocks, hashinfo->ehash_mask + 1); + +- for (i = 0; i < nblocks; i++) +- spin_lock_init(&hashinfo->ehash_locks[i]); ++ if (num_online_nodes() > 1) { ++ /* Use vmalloc() to allow NUMA policy to spread pages ++ * on all available nodes if desired. ++ */ ++ ptr = vmalloc_array(nblocks, locksz); ++ } ++ if (!ptr) { ++ ptr = kvmalloc_array(nblocks, locksz, GFP_KERNEL); ++ if (!ptr) ++ return -ENOMEM; + } ++ for (i = 0; i < nblocks; i++) ++ spin_lock_init(&ptr[i]); ++ hashinfo->ehash_locks = ptr; ++set_mask: + hashinfo->ehash_locks_mask = nblocks - 1; + return 0; + } +diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c +index 890c15510b4210..f261e29adc7c2e 100644 +--- a/net/ipv4/ip_gre.c ++++ b/net/ipv4/ip_gre.c +@@ -140,7 +140,6 @@ static int ipgre_err(struct sk_buff *skb, u32 info, + const struct iphdr *iph; + const int type = icmp_hdr(skb)->type; + const int code = icmp_hdr(skb)->code; +- unsigned int data_len = 0; + struct ip_tunnel *t; + + if (tpi->proto == htons(ETH_P_TEB)) +@@ -181,7 +180,6 @@ static int ipgre_err(struct sk_buff *skb, u32 info, + case ICMP_TIME_EXCEEDED: + if (code != ICMP_EXC_TTL) + return 0; +- data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ + break; + + case ICMP_REDIRECT: +@@ -189,10 +187,16 @@ static int ipgre_err(struct sk_buff *skb, u32 info, + } + + #if IS_ENABLED(CONFIG_IPV6) +- if (tpi->proto == htons(ETH_P_IPV6) && +- !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, +- type, data_len)) +- return 0; ++ if (tpi->proto == htons(ETH_P_IPV6)) { ++ unsigned int data_len = 0; ++ ++ if (type == ICMP_TIME_EXCEEDED) ++ data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ ++ ++ if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, ++ type, data_len)) ++ return 0; ++ } + #endif + + if (t->parms.iph.daddr == 0 || +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 10d38ec0ff5acd..a172248b667837 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -425,6 +425,20 @@ static bool tcp_ecn_rcv_ecn_echo(const struct tcp_sock *tp, const struct tcphdr + return false; + } + ++static void tcp_count_delivered_ce(struct tcp_sock *tp, u32 ecn_count) ++{ ++ tp->delivered_ce += ecn_count; ++} ++ ++/* Updates the delivered and delivered_ce counts */ ++static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered, ++ bool ece_ack) ++{ ++ tp->delivered += delivered; ++ if (ece_ack) ++ tcp_count_delivered_ce(tp, delivered); ++} ++ + /* Buffer size and advertised window tuning. + * + * 1. Tuning sk->sk_sndbuf, when connection enters established state. +@@ -1137,15 +1151,6 @@ void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb) + } + } + +-/* Updates the delivered and delivered_ce counts */ +-static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered, +- bool ece_ack) +-{ +- tp->delivered += delivered; +- if (ece_ack) +- tp->delivered_ce += delivered; +-} +- + /* This procedure tags the retransmission queue when SACKs arrive. + * + * We have three tag bits: SACKED(S), RETRANS(R) and LOST(L). +@@ -3816,12 +3821,23 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) + } + } + +-static inline void tcp_in_ack_event(struct sock *sk, u32 flags) ++static void tcp_in_ack_event(struct sock *sk, int flag) + { + const struct inet_connection_sock *icsk = inet_csk(sk); + +- if (icsk->icsk_ca_ops->in_ack_event) +- icsk->icsk_ca_ops->in_ack_event(sk, flags); ++ if (icsk->icsk_ca_ops->in_ack_event) { ++ u32 ack_ev_flags = 0; ++ ++ if (flag & FLAG_WIN_UPDATE) ++ ack_ev_flags |= CA_ACK_WIN_UPDATE; ++ if (flag & FLAG_SLOWPATH) { ++ ack_ev_flags |= CA_ACK_SLOWPATH; ++ if (flag & FLAG_ECE) ++ ack_ev_flags |= CA_ACK_ECE; ++ } ++ ++ icsk->icsk_ca_ops->in_ack_event(sk, ack_ev_flags); ++ } + } + + /* Congestion control has updated the cwnd already. So if we're in +@@ -3938,12 +3954,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + tcp_snd_una_update(tp, ack); + flag |= FLAG_WIN_UPDATE; + +- tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE); +- + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPACKS); + } else { +- u32 ack_ev_flags = CA_ACK_SLOWPATH; +- + if (ack_seq != TCP_SKB_CB(skb)->end_seq) + flag |= FLAG_DATA; + else +@@ -3955,19 +3967,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, + &sack_state); + +- if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) { ++ if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) + flag |= FLAG_ECE; +- ack_ev_flags |= CA_ACK_ECE; +- } + + if (sack_state.sack_delivered) + tcp_count_delivered(tp, sack_state.sack_delivered, + flag & FLAG_ECE); +- +- if (flag & FLAG_WIN_UPDATE) +- ack_ev_flags |= CA_ACK_WIN_UPDATE; +- +- tcp_in_ack_event(sk, ack_ev_flags); + } + + /* This is a deviation from RFC3168 since it states that: +@@ -3994,6 +3999,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + + tcp_rack_update_reo_wnd(sk, &rs); + ++ tcp_in_ack_event(sk, flag); ++ + if (tp->tlp_high_seq) + tcp_process_tlp_ack(sk, ack, flag); + +@@ -4025,6 +4032,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + return 1; + + no_queue: ++ tcp_in_ack_event(sk, flag); + /* If data was DSACKed, see if we can undo a cwnd reduction. */ + if (flag & FLAG_DSACKING_ACK) { + tcp_fastretrans_alert(sk, prior_snd_una, num_dupack, &flag, +diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c +index 62bb9651133c4d..7e4c8628cf9835 100644 +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -135,47 +135,16 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + } + + #ifdef CONFIG_INET6_ESPINTCP +-struct esp_tcp_sk { +- struct sock *sk; +- struct rcu_head rcu; +-}; +- +-static void esp_free_tcp_sk(struct rcu_head *head) +-{ +- struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu); +- +- sock_put(esk->sk); +- kfree(esk); +-} +- + static struct sock *esp6_find_tcp_sk(struct xfrm_state *x) + { + struct xfrm_encap_tmpl *encap = x->encap; + struct net *net = xs_net(x); +- struct esp_tcp_sk *esk; + __be16 sport, dport; +- struct sock *nsk; + struct sock *sk; + +- sk = rcu_dereference(x->encap_sk); +- if (sk && sk->sk_state == TCP_ESTABLISHED) +- return sk; +- + spin_lock_bh(&x->lock); + sport = encap->encap_sport; + dport = encap->encap_dport; +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (sk && sk == nsk) { +- esk = kmalloc(sizeof(*esk), GFP_ATOMIC); +- if (!esk) { +- spin_unlock_bh(&x->lock); +- return ERR_PTR(-ENOMEM); +- } +- RCU_INIT_POINTER(x->encap_sk, NULL); +- esk->sk = sk; +- call_rcu(&esk->rcu, esp_free_tcp_sk); +- } + spin_unlock_bh(&x->lock); + + sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, &x->id.daddr.in6, +@@ -188,20 +157,6 @@ static struct sock *esp6_find_tcp_sk(struct xfrm_state *x) + return ERR_PTR(-EINVAL); + } + +- spin_lock_bh(&x->lock); +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (encap->encap_sport != sport || +- encap->encap_dport != dport) { +- sock_put(sk); +- sk = nsk ?: ERR_PTR(-EREMCHG); +- } else if (sk == nsk) { +- sock_put(sk); +- } else { +- rcu_assign_pointer(x->encap_sk, sk); +- } +- spin_unlock_bh(&x->lock); +- + return sk; + } + +@@ -224,6 +179,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb) + err = espintcp_push_skb(sk, skb); + bh_unlock_sock(sk); + ++ sock_put(sk); ++ + out: + rcu_read_unlock(); + return err; +@@ -427,6 +384,8 @@ static struct ip_esp_hdr *esp6_output_tcp_encap(struct xfrm_state *x, + if (IS_ERR(sk)) + return ERR_CAST(sk); + ++ sock_put(sk); ++ + *lenp = htons(len); + esph = (struct ip_esp_hdr *)(lenp + 1); + +diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c +index 6eeab21512ba98..e0f0c5f8cccdaa 100644 +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -350,9 +350,9 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, + struct nlattr **tb, + struct netlink_ext_ack *extack) + { ++ struct fib6_rule *rule6 = (struct fib6_rule *)rule; ++ struct net *net = rule->fr_net; + int err = -EINVAL; +- struct net *net = sock_net(skb->sk); +- struct fib6_rule *rule6 = (struct fib6_rule *) rule; + + if (!inet_validate_dscp(frh->tos)) { + NL_SET_ERR_MSG(extack, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index c86d5dca29df01..28777b14224048 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1452,6 +1452,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, + } + v6_cork->hop_limit = ipc6->hlimit; + v6_cork->tclass = ipc6->tclass; ++ v6_cork->dontfrag = ipc6->dontfrag; + if (rt->dst.flags & DST_XFRM_TUNNEL) + mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? + READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst); +@@ -1485,7 +1486,7 @@ static int __ip6_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, + int len, int odd, struct sk_buff *skb), + void *from, size_t length, int transhdrlen, +- unsigned int flags, struct ipcm6_cookie *ipc6) ++ unsigned int flags) + { + struct sk_buff *skb, *skb_prev = NULL; + struct inet_cork *cork = &cork_full->base; +@@ -1541,7 +1542,7 @@ static int __ip6_append_data(struct sock *sk, + if (headersize + transhdrlen > mtu) + goto emsgsize; + +- if (cork->length + length > mtu - headersize && ipc6->dontfrag && ++ if (cork->length + length > mtu - headersize && v6_cork->dontfrag && + (sk->sk_protocol == IPPROTO_UDP || + sk->sk_protocol == IPPROTO_ICMPV6 || + sk->sk_protocol == IPPROTO_RAW)) { +@@ -1913,7 +1914,7 @@ int ip6_append_data(struct sock *sk, + + return __ip6_append_data(sk, &sk->sk_write_queue, &inet->cork, + &np->cork, sk_page_frag(sk), getfrag, +- from, length, transhdrlen, flags, ipc6); ++ from, length, transhdrlen, flags); + } + EXPORT_SYMBOL_GPL(ip6_append_data); + +@@ -2118,7 +2119,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk, + err = __ip6_append_data(sk, &queue, cork, &v6_cork, + ¤t->task_frag, getfrag, from, + length + exthdrlen, transhdrlen + exthdrlen, +- flags, ipc6); ++ flags); + if (err) { + __ip6_flush_pending_frames(sk, &queue, cork, &v6_cork); + return ERR_PTR(err); +diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c +index cc25fec44f8502..19f3de3c24ef1c 100644 +--- a/net/llc/af_llc.c ++++ b/net/llc/af_llc.c +@@ -888,15 +888,15 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + if (sk->sk_type != SOCK_STREAM) + goto copy_uaddr; + ++ /* Partial read */ ++ if (used + offset < skb_len) ++ continue; ++ + if (!(flags & MSG_PEEK)) { + skb_unlink(skb, &sk->sk_receive_queue); + kfree_skb(skb); + *seq = 0; + } +- +- /* Partial read */ +- if (used + offset < skb_len) +- continue; + } while (len > 0); + + out: +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 42e2c84ed2484a..2c7e139efd532f 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2959,7 +2959,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, + if (tx) + ieee80211_flush_queues(local, sdata, false); + +- drv_mgd_complete_tx(sdata->local, sdata, &info); ++ if (tx || frame_buf) ++ drv_mgd_complete_tx(sdata->local, sdata, &info); + + /* clear AP addr only after building the needed mgmt frames */ + eth_zero_addr(sdata->deflink.u.mgd.bssid); +@@ -7821,7 +7822,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, + req->reason_code, false); +- drv_mgd_complete_tx(sdata->local, sdata, &info); + return 0; + } + +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index 559665467b04dd..1d5de1d9f008d8 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -621,7 +621,9 @@ static struct ctl_table nf_ct_sysctl_table[] = { + .data = &nf_conntrack_max, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_INT_MAX, + }, + [NF_SYSCTL_CT_COUNT] = { + .procname = "nf_conntrack_count", +@@ -657,7 +659,9 @@ static struct ctl_table nf_ct_sysctl_table[] = { + .data = &nf_ct_expect_max, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ONE, ++ .extra2 = SYSCTL_INT_MAX, + }, + [NF_SYSCTL_CT_ACCT] = { + .procname = "nf_conntrack_acct", +@@ -951,7 +955,9 @@ static struct ctl_table nf_ct_netfilter_table[] = { + .data = &nf_conntrack_max, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_INT_MAX, + }, + { } + }; +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index 5d9cccfac4a155..afcb83d469ff60 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -175,6 +175,11 @@ struct hfsc_sched { + + #define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */ + ++static bool cl_in_el_or_vttree(struct hfsc_class *cl) ++{ ++ return ((cl->cl_flags & HFSC_FSC) && cl->cl_nactive) || ++ ((cl->cl_flags & HFSC_RSC) && !RB_EMPTY_NODE(&cl->el_node)); ++} + + /* + * eligible tree holds backlogged classes being sorted by their eligible times. +@@ -1040,6 +1045,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (cl == NULL) + return -ENOBUFS; + ++ RB_CLEAR_NODE(&cl->el_node); ++ + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); + if (err) { + kfree(cl); +@@ -1570,7 +1577,10 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) + return err; + } + +- if (first && !cl->cl_nactive) { ++ sch->qstats.backlog += len; ++ sch->q.qlen++; ++ ++ if (first && !cl_in_el_or_vttree(cl)) { + if (cl->cl_flags & HFSC_RSC) + init_ed(cl, len); + if (cl->cl_flags & HFSC_FSC) +@@ -1585,9 +1595,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) + + } + +- sch->qstats.backlog += len; +- sch->q.qlen++; +- + return NET_XMIT_SUCCESS; + } + +diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c +index dbcc72b43d0c08..d44d7f427fc948 100644 +--- a/net/smc/smc_pnet.c ++++ b/net/smc/smc_pnet.c +@@ -1084,14 +1084,16 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev, + struct smc_init_info *ini) + { + u8 ndev_pnetid[SMC_MAX_PNETID_LEN]; ++ struct net_device *base_ndev; + struct net *net; + +- ndev = pnet_find_base_ndev(ndev); ++ base_ndev = pnet_find_base_ndev(ndev); + net = dev_net(ndev); +- if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port, ++ if (smc_pnetid_by_dev_port(base_ndev->dev.parent, base_ndev->dev_port, + ndev_pnetid) && ++ smc_pnet_find_ndev_pnetid_by_table(base_ndev, ndev_pnetid) && + smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid)) { +- smc_pnet_find_rdma_dev(ndev, ini); ++ smc_pnet_find_rdma_dev(base_ndev, ini); + return; /* pnetid could not be determined */ + } + _smc_pnet_find_roce_by_pnetid(ndev_pnetid, ini, NULL, net); +diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c +index 142ee6554848a6..4ffb2bcaf3648e 100644 +--- a/net/sunrpc/clnt.c ++++ b/net/sunrpc/clnt.c +@@ -275,9 +275,6 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt, + old = rcu_dereference_protected(clnt->cl_xprt, + lockdep_is_held(&clnt->cl_lock)); + +- if (!xprt_bound(xprt)) +- clnt->cl_autobind = 1; +- + clnt->cl_timeout = timeout; + rcu_assign_pointer(clnt->cl_xprt, xprt); + spin_unlock(&clnt->cl_lock); +diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c +index 102c3818bc54d4..53bcca365fb1cd 100644 +--- a/net/sunrpc/rpcb_clnt.c ++++ b/net/sunrpc/rpcb_clnt.c +@@ -820,9 +820,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) + } + + trace_rpcb_setport(child, map->r_status, map->r_port); +- xprt->ops->set_port(xprt, map->r_port); +- if (map->r_port) ++ if (map->r_port) { ++ xprt->ops->set_port(xprt, map->r_port); + xprt_set_bound(xprt); ++ } + } + + /* +diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c +index 9b45fbdc90cabe..73bc39281ef5f5 100644 +--- a/net/sunrpc/sched.c ++++ b/net/sunrpc/sched.c +@@ -276,6 +276,8 @@ EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); + + static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode) + { ++ if (unlikely(current->flags & PF_EXITING)) ++ return -EINTR; + schedule(); + if (signal_pending_state(mode, current)) + return -ERESTARTSYS; +diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c +index c524421ec65252..8584893b478510 100644 +--- a/net/tipc/crypto.c ++++ b/net/tipc/crypto.c +@@ -817,12 +817,16 @@ static int tipc_aead_encrypt(struct tipc_aead *aead, struct sk_buff *skb, + goto exit; + } + ++ /* Get net to avoid freed tipc_crypto when delete namespace */ ++ get_net(aead->crypto->net); ++ + /* Now, do encrypt */ + rc = crypto_aead_encrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) + return rc; + + tipc_bearer_put(b); ++ put_net(aead->crypto->net); + + exit: + kfree(ctx); +@@ -860,6 +864,7 @@ static void tipc_aead_encrypt_done(void *data, int err) + kfree(tx_ctx); + tipc_bearer_put(b); + tipc_aead_put(aead); ++ put_net(net); + } + + /** +diff --git a/net/unix/Kconfig b/net/unix/Kconfig +index 28b232f281ab16..8b5d04210d7cf1 100644 +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -16,11 +16,6 @@ config UNIX + + Say Y unless you know what you are doing. + +-config UNIX_SCM +- bool +- depends on UNIX +- default y +- + config AF_UNIX_OOB + bool + depends on UNIX +diff --git a/net/unix/Makefile b/net/unix/Makefile +index 20491825b4d0da..4ddd125c4642c7 100644 +--- a/net/unix/Makefile ++++ b/net/unix/Makefile +@@ -11,5 +11,3 @@ unix-$(CONFIG_BPF_SYSCALL) += unix_bpf.o + + obj-$(CONFIG_UNIX_DIAG) += unix_diag.o + unix_diag-y := diag.o +- +-obj-$(CONFIG_UNIX_SCM) += scm.o +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index ab23c8d72122b2..236a2cd2bc93d2 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -117,8 +117,6 @@ + #include + #include + +-#include "scm.h" +- + static atomic_long_t unix_nr_socks; + static struct hlist_head bsd_socket_buckets[UNIX_HASH_SIZE / 2]; + static spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2]; +@@ -980,11 +978,11 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern, + sk->sk_max_ack_backlog = READ_ONCE(net->unx.sysctl_max_dgram_qlen); + sk->sk_destruct = unix_sock_destructor; + u = unix_sk(sk); +- u->inflight = 0; ++ u->listener = NULL; ++ u->vertex = NULL; + u->path.dentry = NULL; + u->path.mnt = NULL; + spin_lock_init(&u->lock); +- INIT_LIST_HEAD(&u->link); + mutex_init(&u->iolock); /* single task reading lock */ + mutex_init(&u->bindlock); /* single task binding lock */ + init_waitqueue_head(&u->peer_wait); +@@ -1583,6 +1581,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, + newsk->sk_type = sk->sk_type; + init_peercred(newsk); + newu = unix_sk(newsk); ++ newu->listener = other; + RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); + otheru = unix_sk(other); + +@@ -1678,8 +1677,8 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags, + bool kern) + { + struct sock *sk = sock->sk; +- struct sock *tsk; + struct sk_buff *skb; ++ struct sock *tsk; + int err; + + err = -EOPNOTSUPP; +@@ -1709,6 +1708,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags, + + /* attach accepted sock to socket */ + unix_state_lock(tsk); ++ unix_update_edges(unix_sk(tsk)); + newsock->state = SS_CONNECTED; + unix_sock_inherit_flags(sock, newsock); + sock_graft(tsk, newsock); +@@ -1752,51 +1752,65 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) + return err; + } + ++/* The "user->unix_inflight" variable is protected by the garbage ++ * collection lock, and we just read it locklessly here. If you go ++ * over the limit, there might be a tiny race in actually noticing ++ * it across threads. Tough. ++ */ ++static inline bool too_many_unix_fds(struct task_struct *p) ++{ ++ struct user_struct *user = current_user(); ++ ++ if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) ++ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); ++ return false; ++} ++ ++static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ if (too_many_unix_fds(current)) ++ return -ETOOMANYREFS; ++ ++ /* Need to duplicate file references for the sake of garbage ++ * collection. Otherwise a socket in the fps might become a ++ * candidate for GC while the skb is not yet queued. ++ */ ++ UNIXCB(skb).fp = scm_fp_dup(scm->fp); ++ if (!UNIXCB(skb).fp) ++ return -ENOMEM; ++ ++ if (unix_prepare_fpl(UNIXCB(skb).fp)) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ scm->fp = UNIXCB(skb).fp; ++ UNIXCB(skb).fp = NULL; ++ ++ unix_destroy_fpl(scm->fp); ++} ++ + static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) + { + scm->fp = scm_fp_dup(UNIXCB(skb).fp); ++} + +- /* +- * Garbage collection of unix sockets starts by selecting a set of +- * candidate sockets which have reference only from being in flight +- * (total_refs == inflight_refs). This condition is checked once during +- * the candidate collection phase, and candidates are marked as such, so +- * that non-candidates can later be ignored. While inflight_refs is +- * protected by unix_gc_lock, total_refs (file count) is not, hence this +- * is an instantaneous decision. +- * +- * Once a candidate, however, the socket must not be reinstalled into a +- * file descriptor while the garbage collection is in progress. +- * +- * If the above conditions are met, then the directed graph of +- * candidates (*) does not change while unix_gc_lock is held. +- * +- * Any operations that changes the file count through file descriptors +- * (dup, close, sendmsg) does not change the graph since candidates are +- * not installed in fds. +- * +- * Dequeing a candidate via recvmsg would install it into an fd, but +- * that takes unix_gc_lock to decrement the inflight count, so it's +- * serialized with garbage collection. +- * +- * MSG_PEEK is special in that it does not change the inflight count, +- * yet does install the socket into an fd. The following lock/unlock +- * pair is to ensure serialization with garbage collection. It must be +- * done between incrementing the file count and installing the file into +- * an fd. +- * +- * If garbage collection starts after the barrier provided by the +- * lock/unlock, then it will see the elevated refcount and not mark this +- * as a candidate. If a garbage collection is already in progress +- * before the file count was incremented, then the lock/unlock pair will +- * ensure that garbage collection is finished before progressing to +- * installing the fd. +- * +- * (*) A -> B where B is on the queue of A or B is on the queue of C +- * which is on the queue of listening socket A. +- */ +- spin_lock(&unix_gc_lock); +- spin_unlock(&unix_gc_lock); ++static void unix_destruct_scm(struct sk_buff *skb) ++{ ++ struct scm_cookie scm; ++ ++ memset(&scm, 0, sizeof(scm)); ++ scm.pid = UNIXCB(skb).pid; ++ if (UNIXCB(skb).fp) ++ unix_detach_fds(&scm, skb); ++ ++ /* Alas, it calls VFS */ ++ /* So fscking what? fput() had been SMP-safe since the last Summer */ ++ scm_destroy(&scm); ++ sock_wfree(skb); + } + + static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) +@@ -1855,8 +1869,10 @@ static void scm_stat_add(struct sock *sk, struct sk_buff *skb) + struct scm_fp_list *fp = UNIXCB(skb).fp; + struct unix_sock *u = unix_sk(sk); + +- if (unlikely(fp && fp->count)) ++ if (unlikely(fp && fp->count)) { + atomic_add(fp->count, &u->scm_stat.nr_fds); ++ unix_add_edges(fp, u); ++ } + } + + static void scm_stat_del(struct sock *sk, struct sk_buff *skb) +@@ -1864,8 +1880,10 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb) + struct scm_fp_list *fp = UNIXCB(skb).fp; + struct unix_sock *u = unix_sk(sk); + +- if (unlikely(fp && fp->count)) ++ if (unlikely(fp && fp->count)) { + atomic_sub(fp->count, &u->scm_stat.nr_fds); ++ unix_del_edges(fp); ++ } + } + + /* +@@ -1885,11 +1903,12 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, + long timeo; + int err; + +- wait_for_unix_gc(); + err = scm_send(sock, msg, &scm, false); + if (err < 0) + return err; + ++ wait_for_unix_gc(scm.fp); ++ + err = -EOPNOTSUPP; + if (msg->msg_flags&MSG_OOB) + goto out; +@@ -2157,11 +2176,12 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, + bool fds_sent = false; + int data_len; + +- wait_for_unix_gc(); + err = scm_send(sock, msg, &scm, false); + if (err < 0) + return err; + ++ wait_for_unix_gc(scm.fp); ++ + err = -EOPNOTSUPP; + if (msg->msg_flags & MSG_OOB) { + #if IS_ENABLED(CONFIG_AF_UNIX_OOB) +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 2a758531e10271..23efb78fe9ef4b 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -81,278 +81,551 @@ + #include + #include + +-#include "scm.h" ++struct unix_sock *unix_get_socket(struct file *filp) ++{ ++ struct inode *inode = file_inode(filp); ++ ++ /* Socket ? */ ++ if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { ++ struct socket *sock = SOCKET_I(inode); ++ const struct proto_ops *ops; ++ struct sock *sk = sock->sk; + +-/* Internal data structures and random procedures: */ ++ ops = READ_ONCE(sock->ops); + +-static LIST_HEAD(gc_candidates); +-static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); ++ /* PF_UNIX ? */ ++ if (sk && ops && ops->family == PF_UNIX) ++ return unix_sk(sk); ++ } + +-static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), +- struct sk_buff_head *hitlist) ++ return NULL; ++} ++ ++static struct unix_vertex *unix_edge_successor(struct unix_edge *edge) + { +- struct sk_buff *skb; +- struct sk_buff *next; +- +- spin_lock(&x->sk_receive_queue.lock); +- skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { +- /* Do we have file descriptors ? */ +- if (UNIXCB(skb).fp) { +- bool hit = false; +- /* Process the descriptors of this socket */ +- int nfd = UNIXCB(skb).fp->count; +- struct file **fp = UNIXCB(skb).fp->fp; +- +- while (nfd--) { +- /* Get the socket the fd matches if it indeed does so */ +- struct sock *sk = unix_get_socket(*fp++); +- +- if (sk) { +- struct unix_sock *u = unix_sk(sk); +- +- /* Ignore non-candidates, they could +- * have been added to the queues after +- * starting the garbage collection +- */ +- if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { +- hit = true; +- +- func(u); +- } +- } +- } +- if (hit && hitlist != NULL) { +- __skb_unlink(skb, &x->sk_receive_queue); +- __skb_queue_tail(hitlist, skb); +- } +- } ++ /* If an embryo socket has a fd, ++ * the listener indirectly holds the fd's refcnt. ++ */ ++ if (edge->successor->listener) ++ return unix_sk(edge->successor->listener)->vertex; ++ ++ return edge->successor->vertex; ++} ++ ++static bool unix_graph_maybe_cyclic; ++static bool unix_graph_grouped; ++ ++static void unix_update_graph(struct unix_vertex *vertex) ++{ ++ /* If the receiver socket is not inflight, no cyclic ++ * reference could be formed. ++ */ ++ if (!vertex) ++ return; ++ ++ unix_graph_maybe_cyclic = true; ++ unix_graph_grouped = false; ++} ++ ++static LIST_HEAD(unix_unvisited_vertices); ++ ++enum unix_vertex_index { ++ UNIX_VERTEX_INDEX_MARK1, ++ UNIX_VERTEX_INDEX_MARK2, ++ UNIX_VERTEX_INDEX_START, ++}; ++ ++static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1; ++ ++static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge) ++{ ++ struct unix_vertex *vertex = edge->predecessor->vertex; ++ ++ if (!vertex) { ++ vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry); ++ vertex->index = unix_vertex_unvisited_index; ++ vertex->out_degree = 0; ++ INIT_LIST_HEAD(&vertex->edges); ++ INIT_LIST_HEAD(&vertex->scc_entry); ++ ++ list_move_tail(&vertex->entry, &unix_unvisited_vertices); ++ edge->predecessor->vertex = vertex; + } +- spin_unlock(&x->sk_receive_queue.lock); ++ ++ vertex->out_degree++; ++ list_add_tail(&edge->vertex_entry, &vertex->edges); ++ ++ unix_update_graph(unix_edge_successor(edge)); + } + +-static void scan_children(struct sock *x, void (*func)(struct unix_sock *), +- struct sk_buff_head *hitlist) ++static void unix_del_edge(struct scm_fp_list *fpl, struct unix_edge *edge) + { +- if (x->sk_state != TCP_LISTEN) { +- scan_inflight(x, func, hitlist); +- } else { +- struct sk_buff *skb; +- struct sk_buff *next; +- struct unix_sock *u; +- LIST_HEAD(embryos); ++ struct unix_vertex *vertex = edge->predecessor->vertex; + +- /* For a listening socket collect the queued embryos +- * and perform a scan on them as well. +- */ +- spin_lock(&x->sk_receive_queue.lock); +- skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { +- u = unix_sk(skb->sk); ++ if (!fpl->dead) ++ unix_update_graph(unix_edge_successor(edge)); + +- /* An embryo cannot be in-flight, so it's safe +- * to use the list link. +- */ +- BUG_ON(!list_empty(&u->link)); +- list_add_tail(&u->link, &embryos); +- } +- spin_unlock(&x->sk_receive_queue.lock); ++ list_del(&edge->vertex_entry); ++ vertex->out_degree--; + +- while (!list_empty(&embryos)) { +- u = list_entry(embryos.next, struct unix_sock, link); +- scan_inflight(&u->sk, func, hitlist); +- list_del_init(&u->link); +- } ++ if (!vertex->out_degree) { ++ edge->predecessor->vertex = NULL; ++ list_move_tail(&vertex->entry, &fpl->vertices); + } + } + +-static void dec_inflight(struct unix_sock *usk) ++static void unix_free_vertices(struct scm_fp_list *fpl) + { +- usk->inflight--; ++ struct unix_vertex *vertex, *next_vertex; ++ ++ list_for_each_entry_safe(vertex, next_vertex, &fpl->vertices, entry) { ++ list_del(&vertex->entry); ++ kfree(vertex); ++ } + } + +-static void inc_inflight(struct unix_sock *usk) ++static DEFINE_SPINLOCK(unix_gc_lock); ++unsigned int unix_tot_inflight; ++ ++void unix_add_edges(struct scm_fp_list *fpl, struct unix_sock *receiver) + { +- usk->inflight++; ++ int i = 0, j = 0; ++ ++ spin_lock(&unix_gc_lock); ++ ++ if (!fpl->count_unix) ++ goto out; ++ ++ do { ++ struct unix_sock *inflight = unix_get_socket(fpl->fp[j++]); ++ struct unix_edge *edge; ++ ++ if (!inflight) ++ continue; ++ ++ edge = fpl->edges + i++; ++ edge->predecessor = inflight; ++ edge->successor = receiver; ++ ++ unix_add_edge(fpl, edge); ++ } while (i < fpl->count_unix); ++ ++ receiver->scm_stat.nr_unix_fds += fpl->count_unix; ++ WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + fpl->count_unix); ++out: ++ WRITE_ONCE(fpl->user->unix_inflight, fpl->user->unix_inflight + fpl->count); ++ ++ spin_unlock(&unix_gc_lock); ++ ++ fpl->inflight = true; ++ ++ unix_free_vertices(fpl); + } + +-static void inc_inflight_move_tail(struct unix_sock *u) ++void unix_del_edges(struct scm_fp_list *fpl) + { +- u->inflight++; ++ struct unix_sock *receiver; ++ int i = 0; ++ ++ spin_lock(&unix_gc_lock); + +- /* If this still might be part of a cycle, move it to the end +- * of the list, so that it's checked even if it was already +- * passed over ++ if (!fpl->count_unix) ++ goto out; ++ ++ do { ++ struct unix_edge *edge = fpl->edges + i++; ++ ++ unix_del_edge(fpl, edge); ++ } while (i < fpl->count_unix); ++ ++ if (!fpl->dead) { ++ receiver = fpl->edges[0].successor; ++ receiver->scm_stat.nr_unix_fds -= fpl->count_unix; ++ } ++ WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - fpl->count_unix); ++out: ++ WRITE_ONCE(fpl->user->unix_inflight, fpl->user->unix_inflight - fpl->count); ++ ++ spin_unlock(&unix_gc_lock); ++ ++ fpl->inflight = false; ++} ++ ++void unix_update_edges(struct unix_sock *receiver) ++{ ++ /* nr_unix_fds is only updated under unix_state_lock(). ++ * If it's 0 here, the embryo socket is not part of the ++ * inflight graph, and GC will not see it, so no lock needed. + */ +- if (test_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags)) +- list_move_tail(&u->link, &gc_candidates); ++ if (!receiver->scm_stat.nr_unix_fds) { ++ receiver->listener = NULL; ++ } else { ++ spin_lock(&unix_gc_lock); ++ unix_update_graph(unix_sk(receiver->listener)->vertex); ++ receiver->listener = NULL; ++ spin_unlock(&unix_gc_lock); ++ } + } + +-static bool gc_in_progress; +-#define UNIX_INFLIGHT_TRIGGER_GC 16000 ++int unix_prepare_fpl(struct scm_fp_list *fpl) ++{ ++ struct unix_vertex *vertex; ++ int i; ++ ++ if (!fpl->count_unix) ++ return 0; ++ ++ for (i = 0; i < fpl->count_unix; i++) { ++ vertex = kmalloc(sizeof(*vertex), GFP_KERNEL); ++ if (!vertex) ++ goto err; ++ ++ list_add(&vertex->entry, &fpl->vertices); ++ } ++ ++ fpl->edges = kvmalloc_array(fpl->count_unix, sizeof(*fpl->edges), ++ GFP_KERNEL_ACCOUNT); ++ if (!fpl->edges) ++ goto err; ++ ++ return 0; + +-void wait_for_unix_gc(void) ++err: ++ unix_free_vertices(fpl); ++ return -ENOMEM; ++} ++ ++void unix_destroy_fpl(struct scm_fp_list *fpl) + { +- /* If number of inflight sockets is insane, +- * force a garbage collect right now. +- * Paired with the WRITE_ONCE() in unix_inflight(), +- * unix_notinflight() and gc_in_progress(). +- */ +- if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && +- !READ_ONCE(gc_in_progress)) +- unix_gc(); +- wait_event(unix_gc_wait, !READ_ONCE(gc_in_progress)); ++ if (fpl->inflight) ++ unix_del_edges(fpl); ++ ++ kvfree(fpl->edges); ++ unix_free_vertices(fpl); + } + +-/* The external entry point: unix_gc() */ +-void unix_gc(void) ++static bool unix_vertex_dead(struct unix_vertex *vertex) + { +- struct sk_buff *next_skb, *skb; ++ struct unix_edge *edge; + struct unix_sock *u; +- struct unix_sock *next; +- struct sk_buff_head hitlist; +- struct list_head cursor; +- LIST_HEAD(not_cycle_list); ++ long total_ref; + +- spin_lock(&unix_gc_lock); ++ list_for_each_entry(edge, &vertex->edges, vertex_entry) { ++ struct unix_vertex *next_vertex = unix_edge_successor(edge); + +- /* Avoid a recursive GC. */ +- if (gc_in_progress) +- goto out; ++ /* The vertex's fd can be received by a non-inflight socket. */ ++ if (!next_vertex) ++ return false; + +- /* Paired with READ_ONCE() in wait_for_unix_gc(). */ +- WRITE_ONCE(gc_in_progress, true); ++ /* The vertex's fd can be received by an inflight socket in ++ * another SCC. ++ */ ++ if (next_vertex->scc_index != vertex->scc_index) ++ return false; ++ } + +- /* First, select candidates for garbage collection. Only +- * in-flight sockets are considered, and from those only ones +- * which don't have any external reference. +- * +- * Holding unix_gc_lock will protect these candidates from +- * being detached, and hence from gaining an external +- * reference. Since there are no possible receivers, all +- * buffers currently on the candidates' queues stay there +- * during the garbage collection. +- * +- * We also know that no new candidate can be added onto the +- * receive queues. Other, non candidate sockets _can_ be +- * added to queue, so we must make sure only to touch +- * candidates. +- * +- * Embryos, though never candidates themselves, affect which +- * candidates are reachable by the garbage collector. Before +- * being added to a listener's queue, an embryo may already +- * receive data carrying SCM_RIGHTS, potentially making the +- * passed socket a candidate that is not yet reachable by the +- * collector. It becomes reachable once the embryo is +- * enqueued. Therefore, we must ensure that no SCM-laden +- * embryo appears in a (candidate) listener's queue between +- * consecutive scan_children() calls. +- */ +- list_for_each_entry_safe(u, next, &gc_inflight_list, link) { +- struct sock *sk = &u->sk; +- long total_refs; +- +- total_refs = file_count(sk->sk_socket->file); +- +- BUG_ON(!u->inflight); +- BUG_ON(total_refs < u->inflight); +- if (total_refs == u->inflight) { +- list_move_tail(&u->link, &gc_candidates); +- __set_bit(UNIX_GC_CANDIDATE, &u->gc_flags); +- __set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags); +- +- if (sk->sk_state == TCP_LISTEN) { +- unix_state_lock_nested(sk, U_LOCK_GC_LISTENER); +- unix_state_unlock(sk); ++ /* No receiver exists out of the same SCC. */ ++ ++ edge = list_first_entry(&vertex->edges, typeof(*edge), vertex_entry); ++ u = edge->predecessor; ++ total_ref = file_count(u->sk.sk_socket->file); ++ ++ /* If not close()d, total_ref > out_degree. */ ++ if (total_ref != vertex->out_degree) ++ return false; ++ ++ return true; ++} ++ ++enum unix_recv_queue_lock_class { ++ U_RECVQ_LOCK_NORMAL, ++ U_RECVQ_LOCK_EMBRYO, ++}; ++ ++static void unix_collect_queue(struct unix_sock *u, struct sk_buff_head *hitlist) ++{ ++ skb_queue_splice_init(&u->sk.sk_receive_queue, hitlist); ++ ++#if IS_ENABLED(CONFIG_AF_UNIX_OOB) ++ if (u->oob_skb) { ++ WARN_ON_ONCE(skb_unref(u->oob_skb)); ++ u->oob_skb = NULL; ++ } ++#endif ++} ++ ++static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist) ++{ ++ struct unix_vertex *vertex; ++ ++ list_for_each_entry_reverse(vertex, scc, scc_entry) { ++ struct sk_buff_head *queue; ++ struct unix_edge *edge; ++ struct unix_sock *u; ++ ++ edge = list_first_entry(&vertex->edges, typeof(*edge), vertex_entry); ++ u = edge->predecessor; ++ queue = &u->sk.sk_receive_queue; ++ ++ spin_lock(&queue->lock); ++ ++ if (u->sk.sk_state == TCP_LISTEN) { ++ struct sk_buff *skb; ++ ++ skb_queue_walk(queue, skb) { ++ struct sk_buff_head *embryo_queue = &skb->sk->sk_receive_queue; ++ ++ /* listener -> embryo order, the inversion never happens. */ ++ spin_lock_nested(&embryo_queue->lock, U_RECVQ_LOCK_EMBRYO); ++ unix_collect_queue(unix_sk(skb->sk), hitlist); ++ spin_unlock(&embryo_queue->lock); + } ++ } else { ++ unix_collect_queue(u, hitlist); + } ++ ++ spin_unlock(&queue->lock); + } ++} + +- /* Now remove all internal in-flight reference to children of +- * the candidates. +- */ +- list_for_each_entry(u, &gc_candidates, link) +- scan_children(&u->sk, dec_inflight, NULL); ++static bool unix_scc_cyclic(struct list_head *scc) ++{ ++ struct unix_vertex *vertex; ++ struct unix_edge *edge; + +- /* Restore the references for children of all candidates, +- * which have remaining references. Do this recursively, so +- * only those remain, which form cyclic references. +- * +- * Use a "cursor" link, to make the list traversal safe, even +- * though elements might be moved about. ++ /* SCC containing multiple vertices ? */ ++ if (!list_is_singular(scc)) ++ return true; ++ ++ vertex = list_first_entry(scc, typeof(*vertex), scc_entry); ++ ++ /* Self-reference or a embryo-listener circle ? */ ++ list_for_each_entry(edge, &vertex->edges, vertex_entry) { ++ if (unix_edge_successor(edge) == vertex) ++ return true; ++ } ++ ++ return false; ++} ++ ++static LIST_HEAD(unix_visited_vertices); ++static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2; ++ ++static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_index, ++ struct sk_buff_head *hitlist) ++{ ++ LIST_HEAD(vertex_stack); ++ struct unix_edge *edge; ++ LIST_HEAD(edge_stack); ++ ++next_vertex: ++ /* Push vertex to vertex_stack and mark it as on-stack ++ * (index >= UNIX_VERTEX_INDEX_START). ++ * The vertex will be popped when finalising SCC later. + */ +- list_add(&cursor, &gc_candidates); +- while (cursor.next != &gc_candidates) { +- u = list_entry(cursor.next, struct unix_sock, link); ++ list_add(&vertex->scc_entry, &vertex_stack); ++ ++ vertex->index = *last_index; ++ vertex->scc_index = *last_index; ++ (*last_index)++; ++ ++ /* Explore neighbour vertices (receivers of the current vertex's fd). */ ++ list_for_each_entry(edge, &vertex->edges, vertex_entry) { ++ struct unix_vertex *next_vertex = unix_edge_successor(edge); ++ ++ if (!next_vertex) ++ continue; ++ ++ if (next_vertex->index == unix_vertex_unvisited_index) { ++ /* Iterative deepening depth first search ++ * ++ * 1. Push a forward edge to edge_stack and set ++ * the successor to vertex for the next iteration. ++ */ ++ list_add(&edge->stack_entry, &edge_stack); + +- /* Move cursor to after the current position. */ +- list_move(&cursor, &u->link); ++ vertex = next_vertex; ++ goto next_vertex; + +- if (u->inflight) { +- list_move_tail(&u->link, ¬_cycle_list); +- __clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags); +- scan_children(&u->sk, inc_inflight_move_tail, NULL); ++ /* 2. Pop the edge directed to the current vertex ++ * and restore the ancestor for backtracking. ++ */ ++prev_vertex: ++ edge = list_first_entry(&edge_stack, typeof(*edge), stack_entry); ++ list_del_init(&edge->stack_entry); ++ ++ next_vertex = vertex; ++ vertex = edge->predecessor->vertex; ++ ++ /* If the successor has a smaller scc_index, two vertices ++ * are in the same SCC, so propagate the smaller scc_index ++ * to skip SCC finalisation. ++ */ ++ vertex->scc_index = min(vertex->scc_index, next_vertex->scc_index); ++ } else if (next_vertex->index != unix_vertex_grouped_index) { ++ /* Loop detected by a back/cross edge. ++ * ++ * The successor is on vertex_stack, so two vertices are in ++ * the same SCC. If the successor has a smaller *scc_index*, ++ * propagate it to skip SCC finalisation. ++ */ ++ vertex->scc_index = min(vertex->scc_index, next_vertex->scc_index); ++ } else { ++ /* The successor was already grouped as another SCC */ + } + } +- list_del(&cursor); + +- /* Now gc_candidates contains only garbage. Restore original +- * inflight counters for these as well, and remove the skbuffs +- * which are creating the cycle(s). +- */ +- skb_queue_head_init(&hitlist); +- list_for_each_entry(u, &gc_candidates, link) { +- scan_children(&u->sk, inc_inflight, &hitlist); ++ if (vertex->index == vertex->scc_index) { ++ struct unix_vertex *v; ++ struct list_head scc; ++ bool scc_dead = true; + +-#if IS_ENABLED(CONFIG_AF_UNIX_OOB) +- if (u->oob_skb) { +- kfree_skb(u->oob_skb); +- u->oob_skb = NULL; ++ /* SCC finalised. ++ * ++ * If the scc_index was not updated, all the vertices above on ++ * vertex_stack are in the same SCC. Group them using scc_entry. ++ */ ++ __list_cut_position(&scc, &vertex_stack, &vertex->scc_entry); ++ ++ list_for_each_entry_reverse(v, &scc, scc_entry) { ++ /* Don't restart DFS from this vertex in unix_walk_scc(). */ ++ list_move_tail(&v->entry, &unix_visited_vertices); ++ ++ /* Mark vertex as off-stack. */ ++ v->index = unix_vertex_grouped_index; ++ ++ if (scc_dead) ++ scc_dead = unix_vertex_dead(v); + } +-#endif ++ ++ if (scc_dead) ++ unix_collect_skb(&scc, hitlist); ++ else if (!unix_graph_maybe_cyclic) ++ unix_graph_maybe_cyclic = unix_scc_cyclic(&scc); ++ ++ list_del(&scc); + } + +- /* not_cycle_list contains those sockets which do not make up a +- * cycle. Restore these to the inflight list. ++ /* Need backtracking ? */ ++ if (!list_empty(&edge_stack)) ++ goto prev_vertex; ++} ++ ++static void unix_walk_scc(struct sk_buff_head *hitlist) ++{ ++ unsigned long last_index = UNIX_VERTEX_INDEX_START; ++ ++ unix_graph_maybe_cyclic = false; ++ ++ /* Visit every vertex exactly once. ++ * __unix_walk_scc() moves visited vertices to unix_visited_vertices. + */ +- while (!list_empty(¬_cycle_list)) { +- u = list_entry(not_cycle_list.next, struct unix_sock, link); +- __clear_bit(UNIX_GC_CANDIDATE, &u->gc_flags); +- list_move_tail(&u->link, &gc_inflight_list); ++ while (!list_empty(&unix_unvisited_vertices)) { ++ struct unix_vertex *vertex; ++ ++ vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry); ++ __unix_walk_scc(vertex, &last_index, hitlist); + } + +- spin_unlock(&unix_gc_lock); ++ list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices); ++ swap(unix_vertex_unvisited_index, unix_vertex_grouped_index); + +- /* We need io_uring to clean its registered files, ignore all io_uring +- * originated skbs. It's fine as io_uring doesn't keep references to +- * other io_uring instances and so killing all other files in the cycle +- * will put all io_uring references forcing it to go through normal +- * release.path eventually putting registered files. +- */ +- skb_queue_walk_safe(&hitlist, skb, next_skb) { +- if (skb->destructor == io_uring_destruct_scm) { +- __skb_unlink(skb, &hitlist); +- skb_queue_tail(&skb->sk->sk_receive_queue, skb); ++ unix_graph_grouped = true; ++} ++ ++static void unix_walk_scc_fast(struct sk_buff_head *hitlist) ++{ ++ unix_graph_maybe_cyclic = false; ++ ++ while (!list_empty(&unix_unvisited_vertices)) { ++ struct unix_vertex *vertex; ++ struct list_head scc; ++ bool scc_dead = true; ++ ++ vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry); ++ list_add(&scc, &vertex->scc_entry); ++ ++ list_for_each_entry_reverse(vertex, &scc, scc_entry) { ++ list_move_tail(&vertex->entry, &unix_visited_vertices); ++ ++ if (scc_dead) ++ scc_dead = unix_vertex_dead(vertex); + } ++ ++ if (scc_dead) ++ unix_collect_skb(&scc, hitlist); ++ else if (!unix_graph_maybe_cyclic) ++ unix_graph_maybe_cyclic = unix_scc_cyclic(&scc); ++ ++ list_del(&scc); + } + +- /* Here we are. Hitlist is filled. Die. */ +- __skb_queue_purge(&hitlist); ++ list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices); ++} ++ ++static bool gc_in_progress; ++ ++static void __unix_gc(struct work_struct *work) ++{ ++ struct sk_buff_head hitlist; ++ struct sk_buff *skb; + + spin_lock(&unix_gc_lock); + +- /* There could be io_uring registered files, just push them back to +- * the inflight list +- */ +- list_for_each_entry_safe(u, next, &gc_candidates, link) +- list_move_tail(&u->link, &gc_inflight_list); ++ if (!unix_graph_maybe_cyclic) { ++ spin_unlock(&unix_gc_lock); ++ goto skip_gc; ++ } ++ ++ __skb_queue_head_init(&hitlist); ++ ++ if (unix_graph_grouped) ++ unix_walk_scc_fast(&hitlist); ++ else ++ unix_walk_scc(&hitlist); + +- /* All candidates should have been detached by now. */ +- BUG_ON(!list_empty(&gc_candidates)); ++ spin_unlock(&unix_gc_lock); ++ ++ skb_queue_walk(&hitlist, skb) { ++ if (UNIXCB(skb).fp) ++ UNIXCB(skb).fp->dead = true; ++ } + +- /* Paired with READ_ONCE() in wait_for_unix_gc(). */ ++ __skb_queue_purge(&hitlist); ++skip_gc: + WRITE_ONCE(gc_in_progress, false); ++} + +- wake_up(&unix_gc_wait); ++static DECLARE_WORK(unix_gc_work, __unix_gc); + +- out: +- spin_unlock(&unix_gc_lock); ++void unix_gc(void) ++{ ++ WRITE_ONCE(gc_in_progress, true); ++ queue_work(system_unbound_wq, &unix_gc_work); ++} ++ ++#define UNIX_INFLIGHT_TRIGGER_GC 16000 ++#define UNIX_INFLIGHT_SANE_USER (SCM_MAX_FD * 8) ++ ++void wait_for_unix_gc(struct scm_fp_list *fpl) ++{ ++ /* If number of inflight sockets is insane, ++ * force a garbage collect right now. ++ * ++ * Paired with the WRITE_ONCE() in unix_inflight(), ++ * unix_notinflight(), and __unix_gc(). ++ */ ++ if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && ++ !READ_ONCE(gc_in_progress)) ++ unix_gc(); ++ ++ /* Penalise users who want to send AF_UNIX sockets ++ * but whose sockets have not been received yet. ++ */ ++ if (!fpl || !fpl->count_unix || ++ READ_ONCE(fpl->user->unix_inflight) < UNIX_INFLIGHT_SANE_USER) ++ return; ++ ++ if (READ_ONCE(gc_in_progress)) ++ flush_work(&unix_gc_work); + } +diff --git a/net/unix/scm.c b/net/unix/scm.c +deleted file mode 100644 +index e92f2fad64105d..00000000000000 +--- a/net/unix/scm.c ++++ /dev/null +@@ -1,161 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "scm.h" +- +-unsigned int unix_tot_inflight; +-EXPORT_SYMBOL(unix_tot_inflight); +- +-LIST_HEAD(gc_inflight_list); +-EXPORT_SYMBOL(gc_inflight_list); +- +-DEFINE_SPINLOCK(unix_gc_lock); +-EXPORT_SYMBOL(unix_gc_lock); +- +-struct sock *unix_get_socket(struct file *filp) +-{ +- struct sock *u_sock = NULL; +- struct inode *inode = file_inode(filp); +- +- /* Socket ? */ +- if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { +- struct socket *sock = SOCKET_I(inode); +- const struct proto_ops *ops = READ_ONCE(sock->ops); +- struct sock *s = sock->sk; +- +- /* PF_UNIX ? */ +- if (s && ops && ops->family == PF_UNIX) +- u_sock = s; +- } +- +- return u_sock; +-} +-EXPORT_SYMBOL(unix_get_socket); +- +-/* Keep the number of times in flight count for the file +- * descriptor if it is for an AF_UNIX socket. +- */ +-void unix_inflight(struct user_struct *user, struct file *fp) +-{ +- struct sock *s = unix_get_socket(fp); +- +- spin_lock(&unix_gc_lock); +- +- if (s) { +- struct unix_sock *u = unix_sk(s); +- +- if (!u->inflight) { +- BUG_ON(!list_empty(&u->link)); +- list_add_tail(&u->link, &gc_inflight_list); +- } else { +- BUG_ON(list_empty(&u->link)); +- } +- u->inflight++; +- /* Paired with READ_ONCE() in wait_for_unix_gc() */ +- WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1); +- } +- WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1); +- spin_unlock(&unix_gc_lock); +-} +- +-void unix_notinflight(struct user_struct *user, struct file *fp) +-{ +- struct sock *s = unix_get_socket(fp); +- +- spin_lock(&unix_gc_lock); +- +- if (s) { +- struct unix_sock *u = unix_sk(s); +- +- BUG_ON(!u->inflight); +- BUG_ON(list_empty(&u->link)); +- +- u->inflight--; +- if (!u->inflight) +- list_del_init(&u->link); +- /* Paired with READ_ONCE() in wait_for_unix_gc() */ +- WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1); +- } +- WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1); +- spin_unlock(&unix_gc_lock); +-} +- +-/* +- * The "user->unix_inflight" variable is protected by the garbage +- * collection lock, and we just read it locklessly here. If you go +- * over the limit, there might be a tiny race in actually noticing +- * it across threads. Tough. +- */ +-static inline bool too_many_unix_fds(struct task_struct *p) +-{ +- struct user_struct *user = current_user(); +- +- if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) +- return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); +- return false; +-} +- +-int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +-{ +- int i; +- +- if (too_many_unix_fds(current)) +- return -ETOOMANYREFS; +- +- /* +- * Need to duplicate file references for the sake of garbage +- * collection. Otherwise a socket in the fps might become a +- * candidate for GC while the skb is not yet queued. +- */ +- UNIXCB(skb).fp = scm_fp_dup(scm->fp); +- if (!UNIXCB(skb).fp) +- return -ENOMEM; +- +- for (i = scm->fp->count - 1; i >= 0; i--) +- unix_inflight(scm->fp->user, scm->fp->fp[i]); +- return 0; +-} +-EXPORT_SYMBOL(unix_attach_fds); +- +-void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) +-{ +- int i; +- +- scm->fp = UNIXCB(skb).fp; +- UNIXCB(skb).fp = NULL; +- +- for (i = scm->fp->count-1; i >= 0; i--) +- unix_notinflight(scm->fp->user, scm->fp->fp[i]); +-} +-EXPORT_SYMBOL(unix_detach_fds); +- +-void unix_destruct_scm(struct sk_buff *skb) +-{ +- struct scm_cookie scm; +- +- memset(&scm, 0, sizeof(scm)); +- scm.pid = UNIXCB(skb).pid; +- if (UNIXCB(skb).fp) +- unix_detach_fds(&scm, skb); +- +- /* Alas, it calls VFS */ +- /* So fscking what? fput() had been SMP-safe since the last Summer */ +- scm_destroy(&scm); +- sock_wfree(skb); +-} +-EXPORT_SYMBOL(unix_destruct_scm); +- +-void io_uring_destruct_scm(struct sk_buff *skb) +-{ +- unix_destruct_scm(skb); +-} +-EXPORT_SYMBOL(io_uring_destruct_scm); +diff --git a/net/unix/scm.h b/net/unix/scm.h +deleted file mode 100644 +index 5a255a477f1609..00000000000000 +--- a/net/unix/scm.h ++++ /dev/null +@@ -1,10 +0,0 @@ +-#ifndef NET_UNIX_SCM_H +-#define NET_UNIX_SCM_H +- +-extern struct list_head gc_inflight_list; +-extern spinlock_t unix_gc_lock; +- +-int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb); +-void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb); +- +-#endif +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index 68b3f9e7edffd4..2edb0f868c5738 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1603,6 +1603,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) + struct xfrm_policy *delpol; + struct hlist_head *chain; + ++ /* Sanitize mark before store */ ++ policy->mark.v &= policy->mark.m; ++ + spin_lock_bh(&net->xfrm.xfrm_policy_lock); + chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); + if (chain) +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index 8a6e8656d014f2..86029cf5358c7a 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -754,9 +754,6 @@ int __xfrm_state_delete(struct xfrm_state *x) + net->xfrm.state_num--; + spin_unlock(&net->xfrm.xfrm_state_lock); + +- if (x->encap_sk) +- sock_put(rcu_dereference_raw(x->encap_sk)); +- + xfrm_dev_state_delete(x); + + /* All xfrm_state objects are created by xfrm_state_alloc. +@@ -1478,6 +1475,9 @@ static void __xfrm_state_insert(struct xfrm_state *x) + + list_add(&x->km.all, &net->xfrm.state_all); + ++ /* Sanitize mark before store */ ++ x->mark.v &= x->mark.m; ++ + h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, + x->props.reqid, x->props.family); + XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h, +diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile +index 3fa16412db15ca..927d72659173e0 100644 +--- a/samples/bpf/Makefile ++++ b/samples/bpf/Makefile +@@ -392,7 +392,7 @@ $(obj)/%.o: $(src)/%.c + @echo " CLANG-bpf " $@ + $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(BPF_EXTRA_CFLAGS) \ + -I$(obj) -I$(srctree)/tools/testing/selftests/bpf/ \ +- -I$(LIBBPF_INCLUDE) \ ++ -I$(LIBBPF_INCLUDE) $(CLANG_SYS_INCLUDES) \ + -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ + -D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \ + -Wno-gnu-variable-sized-type-not-at-end \ +diff --git a/scripts/config b/scripts/config +index ff88e2faefd35c..ea475c07de283e 100755 +--- a/scripts/config ++++ b/scripts/config +@@ -32,6 +32,7 @@ commands: + Disable option directly after other option + --module-after|-M beforeopt option + Turn option into module directly after other option ++ --refresh Refresh the config using old settings + + commands can be repeated multiple times + +@@ -124,16 +125,22 @@ undef_var() { + txt_delete "^# $name is not set" "$FN" + } + +-if [ "$1" = "--file" ]; then +- FN="$2" +- if [ "$FN" = "" ] ; then +- usage ++FN=.config ++CMDS=() ++while [[ $# -gt 0 ]]; do ++ if [ "$1" = "--file" ]; then ++ if [ "$2" = "" ]; then ++ usage ++ fi ++ FN="$2" ++ shift 2 ++ else ++ CMDS+=("$1") ++ shift + fi +- shift 2 +-else +- FN=.config +-fi ++done + ++set -- "${CMDS[@]}" + if [ "$1" = "" ] ; then + usage + fi +@@ -217,9 +224,8 @@ while [ "$1" != "" ] ; do + set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A" + ;; + +- # undocumented because it ignores --file (fixme) + --refresh) +- yes "" | make oldconfig ++ yes "" | make oldconfig KCONFIG_CONFIG=$FN + ;; + + *) +diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh +index 0b7952471c18f6..79c09b378be816 100755 +--- a/scripts/kconfig/merge_config.sh ++++ b/scripts/kconfig/merge_config.sh +@@ -112,8 +112,8 @@ INITFILE=$1 + shift; + + if [ ! -r "$INITFILE" ]; then +- echo "The base file '$INITFILE' does not exist. Exit." >&2 +- exit 1 ++ echo "The base file '$INITFILE' does not exist. Creating one..." >&2 ++ touch "$INITFILE" + fi + + MERGE_LIST=$* +diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c +index 98308a2bdef6e0..068edb0d79f736 100644 +--- a/security/integrity/ima/ima_main.c ++++ b/security/integrity/ima/ima_main.c +@@ -235,7 +235,9 @@ static int process_measurement(struct file *file, const struct cred *cred, + &allowed_algos); + violation_check = ((func == FILE_CHECK || func == MMAP_CHECK || + func == MMAP_CHECK_REQPROT) && +- (ima_policy_flag & IMA_MEASURE)); ++ (ima_policy_flag & IMA_MEASURE) && ++ ((action & IMA_MEASURE) || ++ (file->f_mode & FMODE_WRITE))); + if (!action && !violation_check) + return 0; + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 5dd1e164f9b13d..1e35c9f807b2b6 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -830,7 +830,7 @@ static int smk_open_cipso(struct inode *inode, struct file *file) + static ssize_t smk_set_cipso(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, int format) + { +- struct netlbl_lsm_catmap *old_cat, *new_cat = NULL; ++ struct netlbl_lsm_catmap *old_cat; + struct smack_known *skp; + struct netlbl_lsm_secattr ncats; + char mapcatset[SMK_CIPSOLEN]; +@@ -917,22 +917,15 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, + + smack_catset_bit(cat, mapcatset); + } +- ncats.flags = 0; +- if (catlen == 0) { +- ncats.attr.mls.cat = NULL; +- ncats.attr.mls.lvl = maplevel; +- new_cat = netlbl_catmap_alloc(GFP_ATOMIC); +- if (new_cat) +- new_cat->next = ncats.attr.mls.cat; +- ncats.attr.mls.cat = new_cat; +- skp->smk_netlabel.flags &= ~(1U << 3); +- rc = 0; +- } else { +- rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); +- } ++ ++ rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); + if (rc >= 0) { + old_cat = skp->smk_netlabel.attr.mls.cat; + rcu_assign_pointer(skp->smk_netlabel.attr.mls.cat, ncats.attr.mls.cat); ++ if (ncats.attr.mls.cat) ++ skp->smk_netlabel.flags |= NETLBL_SECATTR_MLS_CAT; ++ else ++ skp->smk_netlabel.flags &= ~(u32)NETLBL_SECATTR_MLS_CAT; + skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; + synchronize_rcu(); + netlbl_catmap_free(old_cat); +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index 728c211142d145..471de2d1b37ad1 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -1085,8 +1085,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) + runtime->oss.params = 0; + runtime->oss.prepare = 1; + runtime->oss.buffer_used = 0; +- if (runtime->dma_area) +- snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); ++ snd_pcm_runtime_buffer_set_silence(runtime); + + runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index e40de64ec85cb5..31fc20350fd96e 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -703,6 +703,17 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) + atomic_inc(&runtime->buffer_accessing); + } + ++/* fill the PCM buffer with the current silence format; called from pcm_oss.c */ ++void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime) ++{ ++ snd_pcm_buffer_access_lock(runtime); ++ if (runtime->dma_area) ++ snd_pcm_format_set_silence(runtime->format, runtime->dma_area, ++ bytes_to_samples(runtime, runtime->dma_bytes)); ++ snd_pcm_buffer_access_unlock(runtime); ++} ++EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence); ++ + #if IS_ENABLED(CONFIG_SND_PCM_OSS) + #define is_oss_stream(substream) ((substream)->oss.oss) + #else +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 49f6763c3250dd..31428cdc0f63d7 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -1169,8 +1169,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait) + if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) { + + /* check if data is available in the pool */ +- if (!snd_seq_write_pool_allocated(client) || +- snd_seq_pool_poll_wait(client->pool, file, wait)) ++ if (snd_seq_pool_poll_wait(client->pool, file, wait)) + mask |= EPOLLOUT | EPOLLWRNORM; + } + +@@ -2584,8 +2583,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table + if (client == NULL) + return -ENXIO; + +- if (! snd_seq_write_pool_allocated(client)) +- return 1; + if (snd_seq_pool_poll_wait(client->pool, file, wait)) + return 1; + return 0; +diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c +index b603bb93f89603..692860deec0c3d 100644 +--- a/sound/core/seq/seq_memory.c ++++ b/sound/core/seq/seq_memory.c +@@ -429,6 +429,7 @@ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, + poll_table *wait) + { + poll_wait(file, &pool->output_sleep, wait); ++ guard(spinlock_irq)(&pool->lock); + return snd_seq_output_ok(pool); + } + +diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c +index e63621bcb21427..1a684e47d4d189 100644 +--- a/sound/pci/hda/hda_beep.c ++++ b/sound/pci/hda/hda_beep.c +@@ -31,8 +31,9 @@ static void generate_tone(struct hda_beep *beep, int tone) + beep->power_hook(beep, true); + beep->playing = 1; + } +- snd_hda_codec_write(codec, beep->nid, 0, +- AC_VERB_SET_BEEP_CONTROL, tone); ++ if (!codec->beep_just_power_on) ++ snd_hda_codec_write(codec, beep->nid, 0, ++ AC_VERB_SET_BEEP_CONTROL, tone); + if (!tone && beep->playing) { + beep->playing = 0; + if (beep->power_hook) +@@ -212,10 +213,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) + struct hda_beep *beep; + int err; + +- if (!snd_hda_get_bool_hint(codec, "beep")) +- return 0; /* disabled explicitly by hints */ +- if (codec->beep_mode == HDA_BEEP_MODE_OFF) +- return 0; /* disabled by module option */ ++ if (!codec->beep_just_power_on) { ++ if (!snd_hda_get_bool_hint(codec, "beep")) ++ return 0; /* disabled explicitly by hints */ ++ if (codec->beep_mode == HDA_BEEP_MODE_OFF) ++ return 0; /* disabled by module option */ ++ } + + beep = kzalloc(sizeof(*beep), GFP_KERNEL); + if (beep == NULL) +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 2f3f295f2b0cb5..440b934cdc284a 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -24,6 +24,7 @@ + #include + #include "hda_local.h" + #include "hda_auto_parser.h" ++#include "hda_beep.h" + #include "hda_jack.h" + #include "hda_generic.h" + #include "hda_component.h" +@@ -6789,6 +6790,41 @@ static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec, + } + } + ++/* GPIO1 = amplifier on/off */ ++static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec, ++ const struct hda_fixup *fix, ++ int action) ++{ ++ struct alc_spec *spec = codec->spec; ++ static const hda_nid_t conn[] = { 0x02 }; ++ static const struct hda_pintbl pincfgs[] = { ++ { 0x14, 0x90170110 }, /* front/high speakers */ ++ { 0x17, 0x90170130 }, /* back/bass speakers */ ++ { } ++ }; ++ ++ // enable mute led ++ alc285_fixup_hp_mute_led_coefbit(codec, fix, action); ++ ++ switch (action) { ++ case HDA_FIXUP_ACT_PRE_PROBE: ++ /* needed for amp of back speakers */ ++ spec->gpio_mask |= 0x01; ++ spec->gpio_dir |= 0x01; ++ snd_hda_apply_pincfgs(codec, pincfgs); ++ /* share DAC to have unified volume control */ ++ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn); ++ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); ++ break; ++ case HDA_FIXUP_ACT_INIT: ++ /* need to toggle GPIO to enable the amp of back speakers */ ++ alc_update_gpio_data(codec, 0x01, true); ++ msleep(100); ++ alc_update_gpio_data(codec, 0x01, false); ++ break; ++ } ++} ++ + static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec, + const struct hda_fixup *fix, int action) + { +@@ -6861,6 +6897,30 @@ static void alc285_fixup_hp_envy_x360(struct hda_codec *codec, + } + } + ++static void alc285_fixup_hp_beep(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ if (action == HDA_FIXUP_ACT_PRE_PROBE) { ++ codec->beep_just_power_on = true; ++ } else if (action == HDA_FIXUP_ACT_INIT) { ++#ifdef CONFIG_SND_HDA_INPUT_BEEP ++ /* ++ * Just enable loopback to internal speaker and headphone jack. ++ * Disable amplification to get about the same beep volume as ++ * was on pure BIOS setup before loading the driver. ++ */ ++ alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13)); ++ ++ snd_hda_enable_beep_device(codec, 1); ++ ++#if !IS_ENABLED(CONFIG_INPUT_PCSPKR) ++ dev_warn_once(hda_codec_dev(codec), ++ "enable CONFIG_INPUT_PCSPKR to get PC beeps\n"); ++#endif ++#endif ++ } ++} ++ + /* for hda_fixup_thinkpad_acpi() */ + #include "thinkpad_helper.c" + +@@ -7376,6 +7436,7 @@ enum { + ALC280_FIXUP_HP_9480M, + ALC245_FIXUP_HP_X360_AMP, + ALC285_FIXUP_HP_SPECTRE_X360_EB1, ++ ALC285_FIXUP_HP_SPECTRE_X360_DF1, + ALC285_FIXUP_HP_ENVY_X360, + ALC288_FIXUP_DELL_HEADSET_MODE, + ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, +@@ -7477,6 +7538,7 @@ enum { + ALC285_FIXUP_HP_GPIO_LED, + ALC285_FIXUP_HP_MUTE_LED, + ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED, ++ ALC285_FIXUP_HP_BEEP_MICMUTE_LED, + ALC236_FIXUP_HP_MUTE_LED_COEFBIT2, + ALC236_FIXUP_HP_GPIO_LED, + ALC236_FIXUP_HP_MUTE_LED, +@@ -9064,6 +9126,12 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_spectre_x360_mute_led, + }, ++ [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc285_fixup_hp_beep, ++ .chained = true, ++ .chain_id = ALC285_FIXUP_HP_MUTE_LED, ++ }, + [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc236_fixup_hp_mute_led_coefbit2, +@@ -9407,6 +9475,10 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_spectre_x360_eb1 + }, ++ [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc285_fixup_hp_spectre_x360_df1 ++ }, + [ALC285_FIXUP_HP_ENVY_X360] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_envy_x360, +@@ -10006,6 +10078,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), + SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), ++ SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1), + SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), + SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), +@@ -10016,7 +10089,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), +- SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), ++ SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED), + SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), + SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED), +@@ -10501,6 +10574,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), ++ SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC), + SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), + SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), +@@ -10754,6 +10828,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { + {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"}, ++ {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"}, + {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"}, + {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"}, + {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"}, +diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c +index 0b8e88b19888ec..6d8455c1bee6d8 100644 +--- a/sound/soc/codecs/cs42l43-jack.c ++++ b/sound/soc/codecs/cs42l43-jack.c +@@ -642,6 +642,10 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv) + + reinit_completion(&priv->type_detect); + ++ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK); ++ + cs42l43_start_hs_bias(priv, true); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT); +@@ -653,6 +657,9 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv) + CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT); + cs42l43_stop_hs_bias(priv); + ++ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, 0); ++ + if (!time_left) + return -ETIMEDOUT; + +diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h +index c234f2f4276a12..78ada3a5bfae55 100644 +--- a/sound/soc/codecs/mt6359-accdet.h ++++ b/sound/soc/codecs/mt6359-accdet.h +@@ -123,6 +123,15 @@ struct mt6359_accdet { + struct workqueue_struct *jd_workqueue; + }; + ++#if IS_ENABLED(CONFIG_SND_SOC_MT6359_ACCDET) + int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack); ++#else ++static inline int ++mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, ++ struct snd_soc_jack *jack) ++{ ++ return -EOPNOTSUPP; ++} ++#endif + #endif +diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c +index 9d6431338fb715..329549936bd5c3 100644 +--- a/sound/soc/codecs/pcm3168a.c ++++ b/sound/soc/codecs/pcm3168a.c +@@ -494,9 +494,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, + } + break; + case 24: +- if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) || +- (format == SND_SOC_DAIFMT_DSP_B)) { +- dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n"); ++ if (!provider_mode && ((format == SND_SOC_DAIFMT_DSP_A) || ++ (format == SND_SOC_DAIFMT_DSP_B))) { ++ dev_err(component->dev, "24-bit slots not supported in consumer mode using DSP\n"); + return -EINVAL; + } + break; +diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c +index c382cb6be60256..c0bb1b4b2dcb59 100644 +--- a/sound/soc/codecs/rt722-sdca-sdw.c ++++ b/sound/soc/codecs/rt722-sdca-sdw.c +@@ -28,9 +28,50 @@ static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) + 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, + 0): +- case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, +- 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, +- RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, RT722_SDCA_CTL_SELECTED_MODE, ++ 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, ++ RT722_SDCA_CTL_FU_MUTE, CH_L) ... ++ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, ++ RT722_SDCA_CTL_FU_MUTE, CH_R): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D, ++ RT722_SDCA_CTL_SELECTED_MODE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, ++ RT722_SDCA_CTL_FU_MUTE, CH_L) ... ++ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, ++ RT722_SDCA_CTL_FU_MUTE, CH_R): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, ++ RT722_SDCA_CTL_FU_MUTE, CH_01) ... ++ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, ++ RT722_SDCA_CTL_FU_MUTE, CH_04): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, ++ RT722_SDCA_CTL_VENDOR_DEF, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, ++ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... ++ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, ++ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, ++ RT722_SDCA_CTL_FU_MUTE, CH_L) ... ++ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, ++ RT722_SDCA_CTL_FU_MUTE, CH_R): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, ++ RT722_SDCA_CTL_VENDOR_DEF, CH_08): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: + return true; + default: +@@ -74,6 +115,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re + case 0x5600000 ... 0x5600007: + case 0x5700000 ... 0x5700004: + case 0x5800000 ... 0x5800004: ++ case 0x5810000: + case 0x5b00003: + case 0x5c00011: + case 0x5d00006: +@@ -81,6 +123,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re + case 0x5f00030: + case 0x6100000 ... 0x6100051: + case 0x6100055 ... 0x6100057: ++ case 0x6100060: + case 0x6100062: + case 0x6100064 ... 0x6100065: + case 0x6100067: +diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c +index e87a07eee97377..72d6356b898148 100644 +--- a/sound/soc/codecs/tas2764.c ++++ b/sound/soc/codecs/tas2764.c +@@ -182,33 +182,6 @@ static SOC_ENUM_SINGLE_DECL( + static const struct snd_kcontrol_new tas2764_asi1_mux = + SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum); + +-static int tas2764_dac_event(struct snd_soc_dapm_widget *w, +- struct snd_kcontrol *kcontrol, int event) +-{ +- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); +- struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); +- int ret; +- +- switch (event) { +- case SND_SOC_DAPM_POST_PMU: +- tas2764->dac_powered = true; +- ret = tas2764_update_pwr_ctrl(tas2764); +- break; +- case SND_SOC_DAPM_PRE_PMD: +- tas2764->dac_powered = false; +- ret = tas2764_update_pwr_ctrl(tas2764); +- break; +- default: +- dev_err(tas2764->dev, "Unsupported event\n"); +- return -EINVAL; +- } +- +- if (ret < 0) +- return ret; +- +- return 0; +-} +- + static const struct snd_kcontrol_new isense_switch = + SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1); + static const struct snd_kcontrol_new vsense_switch = +@@ -221,8 +194,7 @@ static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = { + 1, &isense_switch), + SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, + 1, &vsense_switch), +- SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event, +- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), ++ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OUT"), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON") +@@ -243,9 +215,28 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) + { + struct tas2764_priv *tas2764 = + snd_soc_component_get_drvdata(dai->component); ++ int ret; ++ ++ if (!mute) { ++ tas2764->dac_powered = true; ++ ret = tas2764_update_pwr_ctrl(tas2764); ++ if (ret) ++ return ret; ++ } + + tas2764->unmuted = !mute; +- return tas2764_update_pwr_ctrl(tas2764); ++ ret = tas2764_update_pwr_ctrl(tas2764); ++ if (ret) ++ return ret; ++ ++ if (mute) { ++ tas2764->dac_powered = false; ++ ret = tas2764_update_pwr_ctrl(tas2764); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; + } + + static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) +@@ -636,6 +627,7 @@ static const struct reg_default tas2764_reg_defaults[] = { + { TAS2764_TDM_CFG2, 0x0a }, + { TAS2764_TDM_CFG3, 0x10 }, + { TAS2764_TDM_CFG5, 0x42 }, ++ { TAS2764_INT_CLK_CFG, 0x19 }, + }; + + static const struct regmap_range_cfg tas2764_regmap_ranges[] = { +@@ -653,6 +645,7 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = { + static bool tas2764_volatile_register(struct device *dev, unsigned int reg) + { + switch (reg) { ++ case TAS2764_SW_RST: + case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: + case TAS2764_INT_CLK_CFG: + return true; +diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c +index 7128bcf3a743e1..bb304de5cc38a3 100644 +--- a/sound/soc/fsl/imx-card.c ++++ b/sound/soc/fsl/imx-card.c +@@ -517,7 +517,7 @@ static int imx_card_parse_of(struct imx_card_data *data) + if (!card->dai_link) + return -ENOMEM; + +- data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); ++ data->link_data = devm_kcalloc(dev, num_links, sizeof(*link_data), GFP_KERNEL); + if (!data->link_data) + return -ENOMEM; + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index ce80adc30fe946..6a85e8fdcae646 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -576,6 +576,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, ++ { /* Acer Aspire SW3-013 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"), ++ }, ++ .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | ++ BYT_RT5640_JD_SRC_JD2_IN4N | ++ BYT_RT5640_OVCD_TH_2000UA | ++ BYT_RT5640_OVCD_SF_0P75 | ++ BYT_RT5640_DIFF_MIC | ++ BYT_RT5640_SSP0_AIF1 | ++ BYT_RT5640_MCLK_EN), ++ }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +index e69c1bb2cb2395..7f411b85778237 100644 +--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c ++++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +@@ -58,7 +58,15 @@ static const char *aud_clks[MT8188_CLK_NUM] = { + [MT8188_CLK_AUD_ADC] = "aud_adc", + [MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires", + [MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp", ++ [MT8188_CLK_AUD_AFE_DMIC1] = "aud_afe_dmic1", ++ [MT8188_CLK_AUD_AFE_DMIC2] = "aud_afe_dmic2", ++ [MT8188_CLK_AUD_AFE_DMIC3] = "aud_afe_dmic3", ++ [MT8188_CLK_AUD_AFE_DMIC4] = "aud_afe_dmic4", + [MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires", ++ [MT8188_CLK_AUD_DMIC_HIRES1] = "aud_dmic_hires1", ++ [MT8188_CLK_AUD_DMIC_HIRES2] = "aud_dmic_hires2", ++ [MT8188_CLK_AUD_DMIC_HIRES3] = "aud_dmic_hires3", ++ [MT8188_CLK_AUD_DMIC_HIRES4] = "aud_dmic_hires4", + [MT8188_CLK_AUD_I2SIN] = "aud_i2sin", + [MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in", + [MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out", +diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +index ec53c171c170a8..c6c78d684f3ee1 100644 +--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h ++++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +@@ -54,7 +54,15 @@ enum { + MT8188_CLK_AUD_ADC, + MT8188_CLK_AUD_DAC_HIRES, + MT8188_CLK_AUD_A1SYS_HP, ++ MT8188_CLK_AUD_AFE_DMIC1, ++ MT8188_CLK_AUD_AFE_DMIC2, ++ MT8188_CLK_AUD_AFE_DMIC3, ++ MT8188_CLK_AUD_AFE_DMIC4, + MT8188_CLK_AUD_ADC_HIRES, ++ MT8188_CLK_AUD_DMIC_HIRES1, ++ MT8188_CLK_AUD_DMIC_HIRES2, ++ MT8188_CLK_AUD_DMIC_HIRES3, ++ MT8188_CLK_AUD_DMIC_HIRES4, + MT8188_CLK_AUD_I2SIN, + MT8188_CLK_AUD_TDM_IN, + MT8188_CLK_AUD_I2S_OUT, +diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +index 11f30b183520ff..4a304bffef8bab 100644 +--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c ++++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +@@ -2855,10 +2855,6 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg) + case AFE_DMIC3_SRC_DEBUG_MON0: + case AFE_DMIC3_UL_SRC_MON0: + case AFE_DMIC3_UL_SRC_MON1: +- case DMIC_GAIN1_CUR: +- case DMIC_GAIN2_CUR: +- case DMIC_GAIN3_CUR: +- case DMIC_GAIN4_CUR: + case ETDM_IN1_MONITOR: + case ETDM_IN2_MONITOR: + case ETDM_OUT1_MONITOR: +diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c +index 88a7169336d61f..580eb20b0771a8 100644 +--- a/sound/soc/qcom/sm8250.c ++++ b/sound/soc/qcom/sm8250.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -39,9 +40,11 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); ++ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; ++ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; + } +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 9a828e55c4f9e7..507743c87e402d 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -275,10 +275,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + + if (dai->driver->ops && + dai->driver->ops->xlate_tdm_slot_mask) +- dai->driver->ops->xlate_tdm_slot_mask(slots, +- &tx_mask, &rx_mask); ++ ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + else +- snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); ++ ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); ++ if (ret) ++ goto err; + + for_each_pcm_streams(stream) + snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]); +@@ -287,6 +288,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + dai->driver->ops->set_tdm_slot) + ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, + slots, slot_width); ++err: + return soc_dai_ret(dai, ret); + } + EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); +diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c +index b4cfc34d00ee63..eff1355cc3df00 100644 +--- a/sound/soc/soc-ops.c ++++ b/sound/soc/soc-ops.c +@@ -638,6 +638,33 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, + } + EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); + ++static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl) ++{ ++ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; ++ struct snd_ctl_elem_value uctl; ++ int ret; ++ ++ if (!mc->platform_max) ++ return 0; ++ ++ ret = kctl->get(kctl, &uctl); ++ if (ret < 0) ++ return ret; ++ ++ if (uctl.value.integer.value[0] > mc->platform_max) ++ uctl.value.integer.value[0] = mc->platform_max; ++ ++ if (snd_soc_volsw_is_stereo(mc) && ++ uctl.value.integer.value[1] > mc->platform_max) ++ uctl.value.integer.value[1] = mc->platform_max; ++ ++ ret = kctl->put(kctl, &uctl); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ + /** + * snd_soc_limit_volume - Set new limit to an existing volume control. + * +@@ -662,7 +689,7 @@ int snd_soc_limit_volume(struct snd_soc_card *card, + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + if (max <= mc->max - mc->min) { + mc->platform_max = max; +- ret = 0; ++ ret = snd_soc_clip_to_platform_max(kctl); + } + } + return ret; +diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c +index b4cdcec33e1209..84145209dec493 100644 +--- a/sound/soc/sof/ipc4-control.c ++++ b/sound/soc/sof/ipc4-control.c +@@ -483,6 +483,14 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, + return -EINVAL; + } + ++ /* Check header id */ ++ if (header.numid != SOF_CTRL_CMD_BINARY) { ++ dev_err_ratelimited(scomp->dev, ++ "Incorrect numid for bytes put %d\n", ++ header.numid); ++ return -EINVAL; ++ } ++ + /* Verify the ABI header first */ + if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr))) + return -EFAULT; +@@ -565,7 +573,8 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, + if (data_size > size) + return -ENOSPC; + +- header.numid = scontrol->comp_id; ++ /* Set header id and length */ ++ header.numid = SOF_CTRL_CMD_BINARY; + header.length = data_size; + + if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) +diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c +index e8acf60c27a743..bb5df0d214e367 100644 +--- a/sound/soc/sof/ipc4-pcm.c ++++ b/sound/soc/sof/ipc4-pcm.c +@@ -621,7 +621,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm + return -ENOMEM; + } + +- if (!support_info) ++ /* Delay reporting is only supported on playback */ ++ if (!support_info || stream == SNDRV_PCM_STREAM_CAPTURE) + continue; + + stream_info = kzalloc(sizeof(*stream_info), GFP_KERNEL); +diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c +index 7afded323150c8..c18a1fdd40ee38 100644 +--- a/sound/soc/sof/topology.c ++++ b/sound/soc/sof/topology.c +@@ -1057,7 +1057,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, + struct snd_sof_dai *dai) + { + struct snd_soc_card *card = scomp->card; +- struct snd_soc_pcm_runtime *rtd; ++ struct snd_soc_pcm_runtime *rtd, *full, *partial; + struct snd_soc_dai *cpu_dai; + int stream; + int i; +@@ -1074,12 +1074,22 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, + else + goto end; + ++ full = NULL; ++ partial = NULL; + list_for_each_entry(rtd, &card->rtd_list, list) { + /* does stream match DAI link ? */ +- if (!rtd->dai_link->stream_name || +- !strstr(rtd->dai_link->stream_name, w->sname)) +- continue; ++ if (rtd->dai_link->stream_name) { ++ if (!strcmp(rtd->dai_link->stream_name, w->sname)) { ++ full = rtd; ++ break; ++ } else if (strstr(rtd->dai_link->stream_name, w->sname)) { ++ partial = rtd; ++ } ++ } ++ } + ++ rtd = full ? full : partial; ++ if (rtd) { + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + /* + * Please create DAI widget in the right order +diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c +index f0a5fd90110182..0d7758cc84c638 100644 +--- a/sound/soc/sunxi/sun4i-codec.c ++++ b/sound/soc/sunxi/sun4i-codec.c +@@ -25,6 +25,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -239,6 +240,7 @@ struct sun4i_codec { + struct clk *clk_module; + struct reset_control *rst; + struct gpio_desc *gpio_pa; ++ struct gpio_desc *gpio_hp; + + /* ADC_FIFOC register is at different offset on different SoCs */ + struct regmap_field *reg_adc_fifoc; +@@ -1277,6 +1279,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { + .ops = &dummy_dai_ops, + }; + ++static struct snd_soc_jack sun4i_headphone_jack; ++ ++static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = { ++ { .pin = "Headphone", .mask = SND_JACK_HEADPHONE }, ++}; ++ ++static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = { ++ .name = "hp-det", ++ .report = SND_JACK_HEADPHONE, ++ .debounce_time = 150, ++}; ++ ++static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_card *card = rtd->card; ++ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); ++ int ret; ++ ++ if (scodec->gpio_hp) { ++ ret = snd_soc_card_jack_new_pins(card, "Headphone Jack", ++ SND_JACK_HEADPHONE, ++ &sun4i_headphone_jack, ++ sun4i_headphone_jack_pins, ++ ARRAY_SIZE(sun4i_headphone_jack_pins)); ++ if (ret) { ++ dev_err(rtd->dev, ++ "Headphone jack creation failed: %d\n", ret); ++ return ret; ++ } ++ ++ sun4i_headphone_jack_gpio.desc = scodec->gpio_hp; ++ ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1, ++ &sun4i_headphone_jack_gpio); ++ ++ if (ret) { ++ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, + int *num_links) + { +@@ -1302,6 +1347,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, + link->codecs->name = dev_name(dev); + link->platforms->name = dev_name(dev); + link->dai_fmt = SND_SOC_DAIFMT_I2S; ++ link->init = sun4i_codec_machine_init; + + *num_links = 1; + +@@ -1742,6 +1788,13 @@ static int sun4i_codec_probe(struct platform_device *pdev) + return ret; + } + ++ scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); ++ if (IS_ERR(scodec->gpio_hp)) { ++ ret = PTR_ERR(scodec->gpio_hp); ++ dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n"); ++ return ret; ++ } ++ + /* reg_field setup */ + scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, + scodec->regmap, +diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c +index 9b75639434b815..0a764426d93586 100644 +--- a/tools/bpf/bpftool/common.c ++++ b/tools/bpf/bpftool/common.c +@@ -461,10 +461,11 @@ int get_fd_type(int fd) + p_err("can't read link type: %s", strerror(errno)); + return -1; + } +- if (n == sizeof(path)) { ++ if (n == sizeof(buf)) { + p_err("can't read link type: path too long!"); + return -1; + } ++ buf[n] = '\0'; + + if (strstr(buf, "bpf-map")) + return BPF_OBJ_MAP; +diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build +index fac42486a8cf0b..27f4ee9cb4db4a 100644 +--- a/tools/build/Makefile.build ++++ b/tools/build/Makefile.build +@@ -141,6 +141,10 @@ objprefix := $(subst ./,,$(OUTPUT)$(dir)/) + obj-y := $(addprefix $(objprefix),$(obj-y)) + subdir-obj-y := $(addprefix $(objprefix),$(subdir-obj-y)) + ++# Separate out test log files from real build objects. ++test-y := $(filter %_log, $(obj-y)) ++obj-y := $(filter-out %_log, $(obj-y)) ++ + # Final '$(obj)-in.o' object + in-target := $(objprefix)$(obj)-in.o + +@@ -151,7 +155,7 @@ $(subdir-y): + + $(sort $(subdir-obj-y)): $(subdir-y) ; + +-$(in-target): $(obj-y) FORCE ++$(in-target): $(obj-y) $(test-y) FORCE + $(call rule_mkdir) + $(call if_changed,$(host)ld_multi) + +diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h +index 977ec094bc2a6c..2a90f04a4160db 100644 +--- a/tools/include/uapi/linux/bpf.h ++++ b/tools/include/uapi/linux/bpf.h +@@ -1140,6 +1140,7 @@ enum bpf_perf_event_type { + #define BPF_F_BEFORE (1U << 3) + #define BPF_F_AFTER (1U << 4) + #define BPF_F_ID (1U << 5) ++#define BPF_F_PREORDER (1U << 6) + #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */ + + /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 2fad178949efe9..fa2abe56e845d9 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -1802,7 +1802,7 @@ static int set_kcfg_value_str(struct extern_desc *ext, char *ext_val, + } + + len = strlen(value); +- if (value[len - 1] != '"') { ++ if (len < 2 || value[len - 1] != '"') { + pr_warn("extern (kcfg) '%s': invalid string config '%s'\n", + ext->name, value); + return -EINVAL; +diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c +index ae61ae5b02bf88..0871f86c6b6666 100644 +--- a/tools/net/ynl/lib/ynl.c ++++ b/tools/net/ynl/lib/ynl.c +@@ -368,7 +368,7 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) + "Invalid attribute (binary %s)", policy->name); + return -1; + case YNL_PT_NUL_STR: +- if ((!policy->len || len <= policy->len) && !data[len - 1]) ++ if (len && (!policy->len || len <= policy->len) && !data[len - 1]) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (string %s)", policy->name); +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index a1b14378bab045..f8e676a6e6f8e9 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -3287,7 +3287,7 @@ static int handle_insn_ops(struct instruction *insn, + if (update_cfi_state(insn, next_insn, &state->cfi, op)) + return 1; + +- if (!insn->alt_group) ++ if (!opts.uaccess || !insn->alt_group) + continue; + + if (op->dest.type == OP_DEST_PUSHF) { +@@ -3754,6 +3754,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + return 0; + + case INSN_STAC: ++ if (!opts.uaccess) ++ break; ++ + if (state.uaccess) { + WARN_INSN(insn, "recursive UACCESS enable"); + return 1; +@@ -3763,6 +3766,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + break; + + case INSN_CLAC: ++ if (!opts.uaccess) ++ break; ++ + if (!state.uaccess && func) { + WARN_INSN(insn, "redundant UACCESS disable"); + return 1; +@@ -4238,7 +4244,8 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, + if (!insn || insn->ignore || insn->visited) + return 0; + +- state->uaccess = sym->uaccess_safe; ++ if (opts.uaccess) ++ state->uaccess = sym->uaccess_safe; + + ret = validate_branch(file, insn_func(insn), insn, *state); + if (ret) +@@ -4685,8 +4692,10 @@ int check(struct objtool_file *file) + init_cfi_state(&force_undefined_cfi); + force_undefined_cfi.force_undefined = true; + +- if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) ++ if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) { ++ ret = -1; + goto out; ++ } + + cfi_hash_add(&init_cfi); + cfi_hash_add(&func_cfi); +@@ -4703,7 +4712,7 @@ int check(struct objtool_file *file) + if (opts.retpoline) { + ret = validate_retpoline(file); + if (ret < 0) +- return ret; ++ goto out; + warnings += ret; + } + +@@ -4739,7 +4748,7 @@ int check(struct objtool_file *file) + */ + ret = validate_unrets(file); + if (ret < 0) +- return ret; ++ goto out; + warnings += ret; + } + +@@ -4802,7 +4811,7 @@ int check(struct objtool_file *file) + if (opts.prefix) { + ret = add_prefix_symbols(file); + if (ret < 0) +- return ret; ++ goto out; + warnings += ret; + } + +diff --git a/tools/testing/kunit/qemu_configs/x86_64.py b/tools/testing/kunit/qemu_configs/x86_64.py +index dc794907686304..4a6bf4e048f5b0 100644 +--- a/tools/testing/kunit/qemu_configs/x86_64.py ++++ b/tools/testing/kunit/qemu_configs/x86_64.py +@@ -7,4 +7,6 @@ CONFIG_SERIAL_8250_CONSOLE=y''', + qemu_arch='x86_64', + kernel_path='arch/x86/boot/bzImage', + kernel_command_line='console=ttyS0', +- extra_qemu_params=[]) ++ # qboot is faster than SeaBIOS and doesn't mess up ++ # the terminal. ++ extra_qemu_params=['-bios', 'qboot.rom']) +diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c b/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c +index 2d0796314862ac..0a99fd404f6dc0 100644 +--- a/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c ++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c +@@ -68,7 +68,6 @@ static void test_sockmap_ktls_disconnect_after_delete(int family, int map) + goto close_cli; + + err = disconnect(cli); +- ASSERT_OK(err, "disconnect"); + + close_cli: + close(cli); +diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh +index a3678dfe5848a2..c151374ddf0402 100755 +--- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh ++++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh +@@ -149,7 +149,7 @@ cfg_test_host_common() + check_err $? "Failed to add $name host entry" + + bridge mdb replace dev br0 port br0 grp $grp $state vid 10 &> /dev/null +- check_fail $? "Managed to replace $name host entry" ++ check_err $? "Failed to replace $name host entry" + + bridge mdb del dev br0 port br0 grp $grp $state vid 10 + bridge mdb get dev br0 grp $grp vid 10 &> /dev/null +diff --git a/tools/testing/selftests/net/gro.sh b/tools/testing/selftests/net/gro.sh +index 342ad27f631b15..e771f5f7faa26a 100755 +--- a/tools/testing/selftests/net/gro.sh ++++ b/tools/testing/selftests/net/gro.sh +@@ -95,5 +95,6 @@ trap cleanup EXIT + if [[ "${test}" == "all" ]]; then + run_all_tests + else +- run_test "${proto}" "${test}" ++ exit_code=$(run_test "${proto}" "${test}") ++ exit $exit_code + fi; diff --git a/patch/kernel/archive/rockchip-6.14/0000.patching_config.yaml b/patch/kernel/archive/rockchip-6.15/0000.patching_config.yaml similarity index 95% rename from patch/kernel/archive/rockchip-6.14/0000.patching_config.yaml rename to patch/kernel/archive/rockchip-6.15/0000.patching_config.yaml index 8520014943bb..51feb95998b6 100644 --- a/patch/kernel/archive/rockchip-6.14/0000.patching_config.yaml +++ b/patch/kernel/archive/rockchip-6.15/0000.patching_config.yaml @@ -1,10 +1,10 @@ config: # Just some info stuff; not used by the patching scripts - name: rockchip-6.14 + name: rockchip-6.15 kind: kernel type: mainline # or: vendor - branch: linux-6.14.y - last-known-good-tag: v6.14 + branch: linux-6.15.y + last-known-good-tag: v6.15.0 maintainers: - { github: paolo.sabatino, name: Paolo Sabatino, email: paolo.sabatino@gmail.com, armbian-forum: jock } diff --git a/patch/kernel/archive/rockchip-6.14/armbian.series b/patch/kernel/archive/rockchip-6.15/armbian.series similarity index 100% rename from patch/kernel/archive/rockchip-6.14/armbian.series rename to patch/kernel/archive/rockchip-6.15/armbian.series diff --git a/patch/kernel/archive/rockchip-6.14/dt/rk322x-box.dts b/patch/kernel/archive/rockchip-6.15/dt/rk322x-box.dts similarity index 100% rename from patch/kernel/archive/rockchip-6.14/dt/rk322x-box.dts rename to patch/kernel/archive/rockchip-6.15/dt/rk322x-box.dts diff --git a/patch/kernel/archive/rockchip-6.14/dt/rk3288-xt-q8l-v10.dts b/patch/kernel/archive/rockchip-6.15/dt/rk3288-xt-q8l-v10.dts similarity index 100% rename from patch/kernel/archive/rockchip-6.14/dt/rk3288-xt-q8l-v10.dts rename to patch/kernel/archive/rockchip-6.15/dt/rk3288-xt-q8l-v10.dts diff --git a/patch/kernel/archive/rockchip-6.14/kernel-6.8-tools-cgroup-makefile.patch b/patch/kernel/archive/rockchip-6.15/kernel-6.8-tools-cgroup-makefile.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/kernel-6.8-tools-cgroup-makefile.patch rename to patch/kernel/archive/rockchip-6.15/kernel-6.8-tools-cgroup-makefile.patch diff --git a/patch/kernel/archive/rockchip-6.14/libreelec.series b/patch/kernel/archive/rockchip-6.15/libreelec.series similarity index 100% rename from patch/kernel/archive/rockchip-6.14/libreelec.series rename to patch/kernel/archive/rockchip-6.15/libreelec.series diff --git a/patch/kernel/archive/rockchip-6.14/overlay/Makefile b/patch/kernel/archive/rockchip-6.15/overlay/Makefile similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/Makefile rename to patch/kernel/archive/rockchip-6.15/overlay/Makefile diff --git a/patch/kernel/archive/rockchip-6.14/overlay/README.rk322x-overlays b/patch/kernel/archive/rockchip-6.15/overlay/README.rk322x-overlays similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/README.rk322x-overlays rename to patch/kernel/archive/rockchip-6.15/overlay/README.rk322x-overlays diff --git a/patch/kernel/archive/rockchip-6.14/overlay/README.rockchip-overlays b/patch/kernel/archive/rockchip-6.15/overlay/README.rockchip-overlays similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/README.rockchip-overlays rename to patch/kernel/archive/rockchip-6.15/overlay/README.rockchip-overlays diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-bt-8723cs.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-bt-8723cs.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-bt-8723cs.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-bt-8723cs.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-cpu-hs-lv.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-cpu-hs-lv.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-cpu-hs-lv.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-cpu-hs-lv.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-cpu-hs.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-cpu-hs.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-cpu-hs.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-cpu-hs.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-cpu-stability.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-cpu-stability.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-cpu-stability.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-cpu-stability.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-330.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-330.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-330.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-330.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-528.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-528.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-528.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-528.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-660.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-660.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-660.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-660.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-800.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-800.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-ddr3-800.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-ddr3-800.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-ddr-ph180.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-ddr-ph180.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-ddr-ph180.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-ddr-ph180.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-ddr-ph45.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-ddr-ph45.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-ddr-ph45.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-ddr-ph45.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-hs200.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-hs200.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-hs200.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-hs200.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-pins.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-pins.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc-pins.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc-pins.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-emmc.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-emmc.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-fixup.scr-cmd b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-fixup.scr-cmd similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-fixup.scr-cmd rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-fixup.scr-cmd diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-ir-wakeup.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-ir-wakeup.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-ir-wakeup.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-ir-wakeup.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf-default.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf-default.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf-default.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf-default.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf1.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf1.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf1.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf1.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf2.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf2.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf2.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf2.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf3.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf3.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf3.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf3.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf4.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf4.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf4.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf4.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf5.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf5.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf5.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf5.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf6.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf6.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf6.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf6.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf7.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf7.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf7.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf7.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf8.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf8.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-led-conf8.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-led-conf8.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-nand.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-nand.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-nand.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-nand.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-usb-otg-peripheral.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-usb-otg-peripheral.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-usb-otg-peripheral.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-usb-otg-peripheral.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rk322x-wlan-alt-wiring.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rk322x-wlan-alt-wiring.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rk322x-wlan-alt-wiring.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rk322x-wlan-alt-wiring.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-ds1307.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-ds1307.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-ds1307.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-ds1307.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-ds1307.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-ds1307.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-ds1307.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-ds1307.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-fixup.scr-cmd b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-fixup.scr-cmd similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-fixup.scr-cmd rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-fixup.scr-cmd diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c1.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c1.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c1.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c1.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c1.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c1.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c1.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c1.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c4.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c4.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c4.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c4.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c4.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c4.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-i2c4.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-i2c4.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-pwm1.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-pwm1.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-pwm1.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-pwm1.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-pwm2.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-pwm2.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-pwm2.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-pwm2.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-pwm3.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-pwm3.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-pwm3.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-pwm3.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi0.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi0.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi0.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi0.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi0.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi0.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi0.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi0.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi2.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi2.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi2.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi2.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi2.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi2.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spi2.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spi2.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev0.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev0.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev0.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev0.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev0.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev0.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev0.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev0.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev2.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev2.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev2.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev2.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev2.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev2.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-spidev2.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-spidev2.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart1.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart1.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart1.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart1.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart1.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart1.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart1.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart1.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart2.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart2.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart2.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart2.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart2.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart2.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart2.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart2.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart3.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart3.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart3.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart3.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart3.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart3.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart3.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart3.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart4.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart4.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart4.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart4.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart4.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart4.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-uart4.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-uart4.dtso diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-w1-gpio.dtbo b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-w1-gpio.dtbo similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-w1-gpio.dtbo rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-w1-gpio.dtbo diff --git a/patch/kernel/archive/rockchip-6.14/overlay/rockchip-w1-gpio.dtso b/patch/kernel/archive/rockchip-6.15/overlay/rockchip-w1-gpio.dtso similarity index 100% rename from patch/kernel/archive/rockchip-6.14/overlay/rockchip-w1-gpio.dtso rename to patch/kernel/archive/rockchip-6.15/overlay/rockchip-w1-gpio.dtso diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/bt-broadcom-serdev-workaround.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/bt-broadcom-serdev-workaround.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/bt-broadcom-serdev-workaround.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/bt-broadcom-serdev-workaround.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/clk-rk322x-composite-mmc-clk.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/clk-rk322x-composite-mmc-clk.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/clk-rk322x-composite-mmc-clk.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/clk-rk322x-composite-mmc-clk.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/clk-rockchip-max-frac-divider.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/clk-rockchip-max-frac-divider.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/clk-rockchip-max-frac-divider.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/clk-rockchip-max-frac-divider.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/driver-rk322x-audio-codec.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/driver-rk322x-audio-codec.patch similarity index 99% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/driver-rk322x-audio-codec.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/driver-rk322x-audio-codec.patch index a3c56bcf1814..a4492b9d3cc9 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.armbian/driver-rk322x-audio-codec.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.armbian/driver-rk322x-audio-codec.patch @@ -212,10 +212,10 @@ index 000000000000..197e7e2e0d8b + unsigned int val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBS_CFS: ++ case SND_SOC_DAIFMT_CBC_CFC: + val |= PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE; + break; -+ case SND_SOC_DAIFMT_CBM_CFM: ++ case SND_SOC_DAIFMT_CBP_CFP: + val |= PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER; + break; + default: diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/driver-rk3288-gpiomem.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/driver-rk3288-gpiomem.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/driver-rk3288-gpiomem.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/driver-rk3288-gpiomem.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/driver-tinkerboard-alc4040-codec.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/driver-tinkerboard-alc4040-codec.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/driver-tinkerboard-alc4040-codec.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/driver-tinkerboard-alc4040-codec.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/drm-rk322x-plane-overlay.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/drm-rk322x-plane-overlay.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/drm-rk322x-plane-overlay.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/drm-rk322x-plane-overlay.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/drm-rk322x-yuv-10bit-modes.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/drm-rk322x-yuv-10bit-modes.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/drm-rk322x-yuv-10bit-modes.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/drm-rk322x-yuv-10bit-modes.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/drm-rockchip-hardware-cursor.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/drm-rockchip-hardware-cursor.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/drm-rockchip-hardware-cursor.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/drm-rockchip-hardware-cursor.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-fan.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-fan.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-fan.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-fan.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-hevc-rga.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-hevc-rga.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-hevc-rga.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-hevc-rga.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-mali-gpu.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-mali-gpu.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-mali-gpu.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-mali-gpu.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-regulator-fix.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-regulator-fix.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-miqi-regulator-fix.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-miqi-regulator-fix.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk322x-iep-node.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk322x-iep-node.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk322x-iep-node.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk322x-iep-node.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk322x-pinctrl-nand.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk322x-pinctrl-nand.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk322x-pinctrl-nand.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk322x-pinctrl-nand.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-disable-serial-dma.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-disable-serial-dma.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-disable-serial-dma.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-disable-serial-dma.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-fix-mmc-aliases.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-fix-mmc-aliases.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-fix-mmc-aliases.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-fix-mmc-aliases.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-gpu-500mhz-opp.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-gpu-500mhz-opp.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-gpu-500mhz-opp.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-gpu-500mhz-opp.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-pinctrl-spi2.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-pinctrl-spi2.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-pinctrl-spi2.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-pinctrl-spi2.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-thermal-rearrange-zones.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-thermal-rearrange-zones.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-rk3288-thermal-rearrange-zones.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-rk3288-thermal-rearrange-zones.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-bt-rtl8723bs.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-bt-rtl8723bs.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-bt-rtl8723bs.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-bt-rtl8723bs.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-bt-uart-pins.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-bt-uart-pins.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-bt-uart-pins.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-bt-uart-pins.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-hevc-rga.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-hevc-rga.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-hevc-rga.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-hevc-rga.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-sdio-wifi.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-sdio-wifi.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-sdio-wifi.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-sdio-wifi.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-sdmmc-properties.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-sdmmc-properties.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-sdmmc-properties.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-sdmmc-properties.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-spi-interface.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-spi-interface.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-tinkerboard-spi-interface.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-tinkerboard-spi-interface.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/dts-veyron-flag-cache-flush.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/dts-veyron-flag-cache-flush.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/dts-veyron-flag-cache-flush.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/dts-veyron-flag-cache-flush.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-add-overlay-compilation-support.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-add-overlay-compilation-support.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-add-overlay-compilation-support.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-add-overlay-compilation-support.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-add-overlay-configfs.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-add-overlay-configfs.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-add-overlay-configfs.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-add-overlay-configfs.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-add-restart-handler-for-act8846.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-add-restart-handler-for-act8846.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-add-restart-handler-for-act8846.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-add-restart-handler-for-act8846.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-fix-rk3288-reset-on-wake-quirk.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-fix-rk3288-reset-on-wake-quirk.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-fix-rk3288-reset-on-wake-quirk.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-fix-rk3288-reset-on-wake-quirk.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-fix-wait-peripheral.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-fix-wait-peripheral.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-fix-wait-peripheral.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-fix-wait-peripheral.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-fix-wait-time.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-fix-wait-time.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-fix-wait-time.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-fix-wait-time.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-nak-gadget.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-nak-gadget.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-dwc2-nak-gadget.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-dwc2-nak-gadget.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-fix-reboot-from-kwiboo.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-fix-reboot-from-kwiboo.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-fix-reboot-from-kwiboo.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-fix-reboot-from-kwiboo.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-increase-spdif-dma-burst.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-increase-spdif-dma-burst.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-increase-spdif-dma-burst.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-increase-spdif-dma-burst.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-linux-export-mm-trace-rss-stats.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-linux-export-mm-trace-rss-stats.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-linux-export-mm-trace-rss-stats.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-linux-export-mm-trace-rss-stats.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-01-fix-periodic-transfers.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-01-fix-periodic-transfers.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-01-fix-periodic-transfers.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-01-fix-periodic-transfers.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-02-add-support-for-interleaved-transfers.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-02-add-support-for-interleaved-transfers.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-02-add-support-for-interleaved-transfers.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-02-add-support-for-interleaved-transfers.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-04-bigger-mcode-buffer.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-04-bigger-mcode-buffer.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-04-bigger-mcode-buffer.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-04-bigger-mcode-buffer.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-05-fix-unbalanced-power-down.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-05-fix-unbalanced-power-down.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-05-fix-unbalanced-power-down.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-05-fix-unbalanced-power-down.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-06-fix-buffer-underruns.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-06-fix-buffer-underruns.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-pl330-06-fix-buffer-underruns.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-pl330-06-fix-buffer-underruns.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-rk322x-gpio-ir-driver.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-rk322x-gpio-ir-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-rk322x-gpio-ir-driver.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-rk322x-gpio-ir-driver.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-rockchip-various-fixes.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-rockchip-various-fixes.patch similarity index 96% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/general-rockchip-various-fixes.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/general-rockchip-various-fixes.patch index 00d644bde46b..4eaa12cec3a7 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.armbian/general-rockchip-various-fixes.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.armbian/general-rockchip-various-fixes.patch @@ -599,41 +599,42 @@ index 1889e78e1..6209f51b3 100644 cell = nvmem_cell_get(inno->dev, "cpu-version"); if (IS_ERR(cell)) { if (PTR_ERR(cell) == -EPROBE_DEFER) + diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c -index fddb4022c..9583c76b4 100644 +index 03bcf79a461f..200047473d59 100644 --- a/drivers/pmdomain/rockchip/pm-domains.c +++ b/drivers/pmdomain/rockchip/pm-domains.c -@@ -73,6 +73,7 @@ struct rockchip_pm_domain { +@@ -95,6 +95,7 @@ struct rockchip_pm_domain { struct regmap **qos_regmap; u32 *qos_save_regs[MAX_QOS_REGS_NUM]; int num_clks; + bool is_ignore_pwr; struct clk_bulk_data *clks; - }; - -@@ -361,6 +362,9 @@ static int rockchip_pd_power_on(struct generic_pm_domain *domain) - { + struct device_node *node; + struct regulator *supply; +@@ -664,6 +665,9 @@ static int rockchip_pd_power_on(struct generic_pm_domain *domain) struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + int ret; + if (pd->is_ignore_pwr) + return 0; + - return rockchip_pd_power(pd, true); - } - -@@ -368,6 +372,9 @@ static int rockchip_pd_power_off(struct generic_pm_domain *domain) - { + ret = rockchip_pd_regulator_enable(pd); + if (ret) { + dev_err(pd->pmu->dev, "Failed to enable supply: %d\n", ret); +@@ -682,6 +686,9 @@ static int rockchip_pd_power_off(struct generic_pm_domain *domain) struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + int ret; + if (pd->is_ignore_pwr) + return 0; + - return rockchip_pd_power(pd, false); - } - -@@ -447,6 +454,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, - pd->info = pd_info; + ret = rockchip_pd_power(pd, false); + if (ret) + return ret; +@@ -770,6 +777,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, pd->pmu = pmu; + pd->node = node; + if (!pd_info->pwr_mask) + pd->is_ignore_pwr = true; @@ -641,15 +642,15 @@ index fddb4022c..9583c76b4 100644 pd->num_clks = of_clk_get_parent_count(node); if (pd->num_clks > 0) { pd->clks = devm_kcalloc(pmu->dev, pd->num_clks, -@@ -600,6 +610,7 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, +@@ -915,6 +925,7 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, + struct device_node *parent) { - struct device_node *np; struct generic_pm_domain *child_domain, *parent_domain; + struct rockchip_pm_domain *child_pd, *parent_pd; int error; - for_each_child_of_node(parent, np) { -@@ -640,6 +651,18 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, + for_each_child_of_node_scoped(parent, np) { +@@ -955,6 +966,18 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, parent_domain->name, child_domain->name); } @@ -667,8 +668,7 @@ index fddb4022c..9583c76b4 100644 + rockchip_pm_add_subdomain(pmu, np); } - + -- 2.25.1 - diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/ir-keymap-rk322x-box.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/ir-keymap-rk322x-box.patch similarity index 91% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/ir-keymap-rk322x-box.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/ir-keymap-rk322x-box.patch index 2c10b95bc042..c451a36481fe 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.armbian/ir-keymap-rk322x-box.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.armbian/ir-keymap-rk322x-box.patch @@ -11,17 +11,17 @@ Subject: [PATCH] add generic rk322x tv box remote controller keymap create mode 100644 drivers/media/rc/keymaps/rc-rk322x-tvbox.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 5fe5c9e1a46..1aa49b78a65 100644 +index d04572627cdd..a543bb3ef864 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile -@@ -99,6 +99,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ +@@ -106,6 +106,7 @@ obj-$(CONFIG_RC_MAP) += \ rc-rc6-mce.o \ rc-real-audio-220-32-keys.o \ rc-reddo.o \ + rc-rk322x-tvbox.o \ + rc-siemens-gigaset-rc20.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ - rc-tanix-tx3mini.o \ diff --git a/drivers/media/rc/keymaps/rc-rk322x-tvbox.c b/drivers/media/rc/keymaps/rc-rk322x-tvbox.c new file mode 100644 index 00000000000..91e24ee52ee @@ -103,17 +103,17 @@ index 00000000000..91e24ee52ee +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paolo Sabatino"); diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index 793b54342df..35aba84be9f 100644 +index d90e4611b066..14d6a50defed 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h -@@ -310,6 +310,7 @@ struct rc_map *rc_map_get(const char *name); +@@ -313,6 +313,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_RC6_MCE "rc-rc6-mce" #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" #define RC_MAP_REDDO "rc-reddo" +#define RC_MAP_RK322X_TVBOX "rc-rk322x-tvbox" + #define RC_MAP_SIEMENS_GIGASET_RC20 "rc-siemens-gigaset-rc20" #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" - #define RC_MAP_SU3000 "rc-su3000" -- 2.30.2 diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/ir-keymap-xt-q8l-v10.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/ir-keymap-xt-q8l-v10.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/ir-keymap-xt-q8l-v10.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/ir-keymap-xt-q8l-v10.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/misc-tinkerboard-spi-interface.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/misc-tinkerboard-spi-interface.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/misc-tinkerboard-spi-interface.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/misc-tinkerboard-spi-interface.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/mmc-tinkerboard-sdmmc-reboot-fix.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/mmc-tinkerboard-sdmmc-reboot-fix.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/mmc-tinkerboard-sdmmc-reboot-fix.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/mmc-tinkerboard-sdmmc-reboot-fix.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-01-sipv2-calls.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-01-sipv2-calls.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-01-sipv2-calls.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-01-sipv2-calls.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-02-sip-constants.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-02-sip-constants.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-02-sip-constants.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-02-sip-constants.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-03-dfi-driver.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-03-dfi-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-03-dfi-driver.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-03-dfi-driver.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-04-driver.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-04-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dmc-driver-04-driver.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dmc-driver-04-driver.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dwc2-no-clock-gating.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dwc2-no-clock-gating.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-dwc2-no-clock-gating.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-dwc2-no-clock-gating.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-usb-reset-props.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-usb-reset-props.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/rk322x-usb-reset-props.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/rk322x-usb-reset-props.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-ath9k-no-bulk-EP3-EP4.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-ath9k-no-bulk-EP3-EP4.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-ath9k-no-bulk-EP3-EP4.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-ath9k-no-bulk-EP3-EP4.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-brcmfmac-add-bcm43342.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-brcmfmac-add-bcm43342.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-brcmfmac-add-bcm43342.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-brcmfmac-add-bcm43342.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-brcmfmac-ap6330-firmware.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-brcmfmac-ap6330-firmware.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-brcmfmac-ap6330-firmware.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-brcmfmac-ap6330-firmware.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-driver-esp8089.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-driver-esp8089.patch similarity index 99% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-driver-esp8089.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-driver-esp8089.patch index 727afc1b843e..a8e34e49f74a 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-driver-esp8089.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-driver-esp8089.patch @@ -3858,7 +3858,7 @@ index 000000000000..14186365fdd4 + + if (evif->ap_up) { + evif->beacon_interval = 0; -+ del_timer_sync(&evif->beacon_timer); ++ timer_delete_sync(&evif->beacon_timer); + evif->ap_up = false; + } + epub->vif = NULL; @@ -4101,7 +4101,7 @@ index 000000000000..14186365fdd4 + __func__, + info->beacon_int); + evif->beacon_interval = 0; -+ del_timer_sync(&evif->beacon_timer); ++ timer_delete_sync(&evif->beacon_timer); + sip_send_bss_info_update(epub, evif, + (u8 *) info-> + bssid, 2); @@ -6324,7 +6324,7 @@ index 000000000000..6602a1e22ab1 + + if (atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE) { + atomic_set(&sip->credit_status, RECALC_CREDIT_DISABLE); -+ del_timer_sync(&sip->credit_timer); ++ timer_delete_sync(&sip->credit_timer); + } else + esp_dbg(ESP_SHOW, "maybe bogus credit"); +} diff --git a/patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-driver-ssv6051.patch b/patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-driver-ssv6051.patch similarity index 99% rename from patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-driver-ssv6051.patch rename to patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-driver-ssv6051.patch index 669c07b57441..24dbdd59e25d 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.armbian/wifi-driver-ssv6051.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.armbian/wifi-driver-ssv6051.patch @@ -1,131 +1,73 @@ -From 3f30a652fb3e6ead83f65312d0240d5c9ea8c340 Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Paolo Sabatino Date: Wed, 2 Nov 2022 15:40:06 +0000 -Subject: [PATCH] add ssv6xxx wifi driver +Subject: add ssv6xxx wifi driver --- - drivers/net/wireless/Kconfig | 1 + - drivers/net/wireless/Makefile | 1 + - drivers/net/wireless/ssv6051/Kconfig | 11 + - drivers/net/wireless/ssv6051/Makefile | 26 + - drivers/net/wireless/ssv6051/Makefile.bak | 107 + - .../ssv6051/firmware/ssv6051-wifi.cfg | 91 + - drivers/net/wireless/ssv6051/hci/hctrl.h | 178 + - drivers/net/wireless/ssv6051/hci/ssv_hci.c | 967 + - drivers/net/wireless/ssv6051/hci/ssv_hci.h | 77 + - drivers/net/wireless/ssv6051/hwif/hwif.h | 84 + - drivers/net/wireless/ssv6051/hwif/sdio/sdio.c | 1254 ++ - .../net/wireless/ssv6051/hwif/sdio/sdio_def.h | 80 + - drivers/net/wireless/ssv6051/include/cabrio.h | 28 + - .../net/wireless/ssv6051/include/ssv6200.h | 76 + - .../wireless/ssv6051/include/ssv6200_aux.h | 18221 ++++++++++++++++ - .../wireless/ssv6051/include/ssv6200_common.h | 452 + - .../ssv6051/include/ssv6200_configuration.h | 317 + - .../wireless/ssv6051/include/ssv6200_reg.h | 9694 ++++++++ - .../ssv6051/include/ssv6200_reg_sim.h | 176 + - .../net/wireless/ssv6051/include/ssv_cfg.h | 60 + - .../ssv6051/include/ssv_firmware_version.h | 25 + - .../wireless/ssv6051/include/ssv_version.h | 12 + - .../net/wireless/ssv6051/platform-config.mak | 97 + - drivers/net/wireless/ssv6051/rules.mak | 19 + - drivers/net/wireless/ssv6051/smac/ampdu.c | 2111 ++ - drivers/net/wireless/ssv6051/smac/ampdu.h | 215 + - drivers/net/wireless/ssv6051/smac/ap.c | 598 + - drivers/net/wireless/ssv6051/smac/ap.h | 41 + - drivers/net/wireless/ssv6051/smac/dev.c | 3880 ++++ - drivers/net/wireless/ssv6051/smac/dev.h | 445 + - drivers/net/wireless/ssv6051/smac/dev_tbl.h | 141 + - drivers/net/wireless/ssv6051/smac/drv_comm.h | 61 + - drivers/net/wireless/ssv6051/smac/efuse.c | 334 + - drivers/net/wireless/ssv6051/smac/efuse.h | 40 + - drivers/net/wireless/ssv6051/smac/init.c | 1347 ++ - drivers/net/wireless/ssv6051/smac/init.h | 23 + - drivers/net/wireless/ssv6051/smac/lib.c | 33 + - drivers/net/wireless/ssv6051/smac/lib.h | 23 + - .../net/wireless/ssv6051/smac/linux_80211.h | 24 + - drivers/net/wireless/ssv6051/smac/p2p.c | 305 + - drivers/net/wireless/ssv6051/smac/p2p.h | 58 + - drivers/net/wireless/ssv6051/smac/sar.c | 208 + - drivers/net/wireless/ssv6051/smac/sar.h | 63 + - drivers/net/wireless/ssv6051/smac/sec.h | 52 + - drivers/net/wireless/ssv6051/smac/smartlink.c | 340 + - .../wireless/ssv6051/smac/ssv6xxx_debugfs.c | 223 + - .../wireless/ssv6051/smac/ssv6xxx_debugfs.h | 27 + - .../net/wireless/ssv6051/smac/ssv_cfgvendor.c | 1384 ++ - .../net/wireless/ssv6051/smac/ssv_cfgvendor.h | 247 + - drivers/net/wireless/ssv6051/smac/ssv_ht_rc.c | 546 + - drivers/net/wireless/ssv6051/smac/ssv_ht_rc.h | 31 + - drivers/net/wireless/ssv6051/smac/ssv_pm.c | 19 + - drivers/net/wireless/ssv6051/smac/ssv_pm.h | 20 + - drivers/net/wireless/ssv6051/smac/ssv_rc.c | 1716 ++ - drivers/net/wireless/ssv6051/smac/ssv_rc.h | 50 + - .../net/wireless/ssv6051/smac/ssv_rc_common.h | 175 + - .../wireless/ssv6051/ssv6051-generic-wlan.c | 76 + - .../net/wireless/ssv6051/ssvdevice/ssv_cmd.c | 1765 ++ - .../net/wireless/ssv6051/ssvdevice/ssv_cmd.h | 50 + - .../wireless/ssv6051/ssvdevice/ssvdevice.c | 256 + - 60 files changed, 48983 insertions(+) - create mode 100644 drivers/net/wireless/ssv6051/Kconfig - create mode 100644 drivers/net/wireless/ssv6051/Makefile - create mode 100644 drivers/net/wireless/ssv6051/Makefile.bak - create mode 100644 drivers/net/wireless/ssv6051/firmware/ssv6051-wifi.cfg - create mode 100644 drivers/net/wireless/ssv6051/hci/hctrl.h - create mode 100644 drivers/net/wireless/ssv6051/hci/ssv_hci.c - create mode 100644 drivers/net/wireless/ssv6051/hci/ssv_hci.h - create mode 100644 drivers/net/wireless/ssv6051/hwif/hwif.h - create mode 100644 drivers/net/wireless/ssv6051/hwif/sdio/sdio.c - create mode 100644 drivers/net/wireless/ssv6051/hwif/sdio/sdio_def.h - create mode 100644 drivers/net/wireless/ssv6051/include/cabrio.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv6200.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv6200_aux.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv6200_common.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv6200_configuration.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv6200_reg.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv6200_reg_sim.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv_cfg.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv_firmware_version.h - create mode 100644 drivers/net/wireless/ssv6051/include/ssv_version.h - create mode 100644 drivers/net/wireless/ssv6051/platform-config.mak - create mode 100644 drivers/net/wireless/ssv6051/rules.mak - create mode 100644 drivers/net/wireless/ssv6051/smac/ampdu.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ampdu.h - create mode 100644 drivers/net/wireless/ssv6051/smac/ap.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ap.h - create mode 100644 drivers/net/wireless/ssv6051/smac/dev.c - create mode 100644 drivers/net/wireless/ssv6051/smac/dev.h - create mode 100644 drivers/net/wireless/ssv6051/smac/dev_tbl.h - create mode 100644 drivers/net/wireless/ssv6051/smac/drv_comm.h - create mode 100644 drivers/net/wireless/ssv6051/smac/efuse.c - create mode 100644 drivers/net/wireless/ssv6051/smac/efuse.h - create mode 100644 drivers/net/wireless/ssv6051/smac/init.c - create mode 100644 drivers/net/wireless/ssv6051/smac/init.h - create mode 100644 drivers/net/wireless/ssv6051/smac/lib.c - create mode 100644 drivers/net/wireless/ssv6051/smac/lib.h - create mode 100644 drivers/net/wireless/ssv6051/smac/linux_80211.h - create mode 100644 drivers/net/wireless/ssv6051/smac/p2p.c - create mode 100644 drivers/net/wireless/ssv6051/smac/p2p.h - create mode 100644 drivers/net/wireless/ssv6051/smac/sar.c - create mode 100644 drivers/net/wireless/ssv6051/smac/sar.h - create mode 100644 drivers/net/wireless/ssv6051/smac/sec.h - create mode 100644 drivers/net/wireless/ssv6051/smac/smartlink.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.h - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.h - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_ht_rc.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_ht_rc.h - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_pm.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_pm.h - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_rc.c - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_rc.h - create mode 100644 drivers/net/wireless/ssv6051/smac/ssv_rc_common.h - create mode 100644 drivers/net/wireless/ssv6051/ssv6051-generic-wlan.c - create mode 100644 drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.c - create mode 100644 drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.h - create mode 100644 drivers/net/wireless/ssv6051/ssvdevice/ssvdevice.c + drivers/net/wireless/Kconfig | 1 + + drivers/net/wireless/Makefile | 1 + + drivers/net/wireless/ssv6051/Kconfig | 11 + + drivers/net/wireless/ssv6051/Makefile | 26 + + drivers/net/wireless/ssv6051/Makefile.bak | 107 + + drivers/net/wireless/ssv6051/firmware/ssv6051-wifi.cfg | 91 + + drivers/net/wireless/ssv6051/hci/hctrl.h | 178 + + drivers/net/wireless/ssv6051/hci/ssv_hci.c | 967 + + drivers/net/wireless/ssv6051/hci/ssv_hci.h | 77 + + drivers/net/wireless/ssv6051/hwif/hwif.h | 84 + + drivers/net/wireless/ssv6051/hwif/sdio/sdio.c | 1254 + + drivers/net/wireless/ssv6051/hwif/sdio/sdio_def.h | 80 + + drivers/net/wireless/ssv6051/include/cabrio.h | 28 + + drivers/net/wireless/ssv6051/include/ssv6200.h | 76 + + drivers/net/wireless/ssv6051/include/ssv6200_aux.h | 18221 ++++++++++ + drivers/net/wireless/ssv6051/include/ssv6200_common.h | 452 + + drivers/net/wireless/ssv6051/include/ssv6200_configuration.h | 317 + + drivers/net/wireless/ssv6051/include/ssv6200_reg.h | 9694 +++++ + drivers/net/wireless/ssv6051/include/ssv6200_reg_sim.h | 176 + + drivers/net/wireless/ssv6051/include/ssv_cfg.h | 60 + + drivers/net/wireless/ssv6051/include/ssv_firmware_version.h | 25 + + drivers/net/wireless/ssv6051/include/ssv_version.h | 12 + + drivers/net/wireless/ssv6051/platform-config.mak | 97 + + drivers/net/wireless/ssv6051/rules.mak | 19 + + drivers/net/wireless/ssv6051/smac/ampdu.c | 2111 ++ + drivers/net/wireless/ssv6051/smac/ampdu.h | 215 + + drivers/net/wireless/ssv6051/smac/ap.c | 598 + + drivers/net/wireless/ssv6051/smac/ap.h | 41 + + drivers/net/wireless/ssv6051/smac/dev.c | 3881 ++ + drivers/net/wireless/ssv6051/smac/dev.h | 445 + + drivers/net/wireless/ssv6051/smac/dev_tbl.h | 141 + + drivers/net/wireless/ssv6051/smac/drv_comm.h | 61 + + drivers/net/wireless/ssv6051/smac/efuse.c | 334 + + drivers/net/wireless/ssv6051/smac/efuse.h | 40 + + drivers/net/wireless/ssv6051/smac/init.c | 1347 + + drivers/net/wireless/ssv6051/smac/init.h | 23 + + drivers/net/wireless/ssv6051/smac/lib.c | 33 + + drivers/net/wireless/ssv6051/smac/lib.h | 23 + + drivers/net/wireless/ssv6051/smac/linux_80211.h | 24 + + drivers/net/wireless/ssv6051/smac/p2p.c | 305 + + drivers/net/wireless/ssv6051/smac/p2p.h | 58 + + drivers/net/wireless/ssv6051/smac/sar.c | 208 + + drivers/net/wireless/ssv6051/smac/sar.h | 63 + + drivers/net/wireless/ssv6051/smac/sec.h | 52 + + drivers/net/wireless/ssv6051/smac/smartlink.c | 340 + + drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.c | 223 + + drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.h | 27 + + drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.c | 1384 + + drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.h | 247 + + drivers/net/wireless/ssv6051/smac/ssv_ht_rc.c | 546 + + drivers/net/wireless/ssv6051/smac/ssv_ht_rc.h | 31 + + drivers/net/wireless/ssv6051/smac/ssv_pm.c | 19 + + drivers/net/wireless/ssv6051/smac/ssv_pm.h | 20 + + drivers/net/wireless/ssv6051/smac/ssv_rc.c | 1716 + + drivers/net/wireless/ssv6051/smac/ssv_rc.h | 50 + + drivers/net/wireless/ssv6051/smac/ssv_rc_common.h | 175 + + drivers/net/wireless/ssv6051/ssv6051-generic-wlan.c | 76 + + drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.c | 1765 + + drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.h | 50 + + drivers/net/wireless/ssv6051/ssvdevice/ssvdevice.c | 256 + + 60 files changed, 48982 insertions(+) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig -index de5e37846397..aa2cac9abdd3 100644 +index 111111111111..222222222222 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -18,6 +18,7 @@ menuconfig WLAN @@ -137,7 +79,7 @@ index de5e37846397..aa2cac9abdd3 100644 source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/atmel/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile -index 92ffd2cef51c..8b56a42e97a6 100644 +index 111111111111..222222222222 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -3,6 +3,7 @@ @@ -150,7 +92,7 @@ index 92ffd2cef51c..8b56a42e97a6 100644 obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/ diff --git a/drivers/net/wireless/ssv6051/Kconfig b/drivers/net/wireless/ssv6051/Kconfig new file mode 100644 -index 000000000000..7706ad52ed7b +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/Kconfig @@ -0,0 +1,11 @@ @@ -167,7 +109,7 @@ index 000000000000..7706ad52ed7b + diff --git a/drivers/net/wireless/ssv6051/Makefile b/drivers/net/wireless/ssv6051/Makefile new file mode 100644 -index 000000000000..985d730f3d50 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/Makefile @@ -0,0 +1,26 @@ @@ -176,8 +118,8 @@ index 000000000000..985d730f3d50 +include $(src)/platform-config.mak + +ccflags-y += \ -+ -I $(srctree)/$(src) \ -+ -I $(srctree)/$(src)/include ++ -I $(src) \ ++ -I $(src)/include + +obj-$(CONFIG_SSV6051) += ssv6051.o +ssv6051-objs += \ @@ -199,7 +141,7 @@ index 000000000000..985d730f3d50 + diff --git a/drivers/net/wireless/ssv6051/Makefile.bak b/drivers/net/wireless/ssv6051/Makefile.bak new file mode 100644 -index 000000000000..2733fa4dd3b7 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/Makefile.bak @@ -0,0 +1,107 @@ @@ -312,7 +254,7 @@ index 000000000000..2733fa4dd3b7 +.PHONY: all modules clean install diff --git a/drivers/net/wireless/ssv6051/firmware/ssv6051-wifi.cfg b/drivers/net/wireless/ssv6051/firmware/ssv6051-wifi.cfg new file mode 100644 -index 000000000000..c072960f6dea +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/firmware/ssv6051-wifi.cfg @@ -0,0 +1,91 @@ @@ -409,7 +351,7 @@ index 000000000000..c072960f6dea +################################################## diff --git a/drivers/net/wireless/ssv6051/hci/hctrl.h b/drivers/net/wireless/ssv6051/hci/hctrl.h new file mode 100644 -index 000000000000..95218c8040e7 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/hci/hctrl.h @@ -0,0 +1,178 @@ @@ -593,7 +535,7 @@ index 000000000000..95218c8040e7 +#endif diff --git a/drivers/net/wireless/ssv6051/hci/ssv_hci.c b/drivers/net/wireless/ssv6051/hci/ssv_hci.c new file mode 100644 -index 000000000000..9fedbeb55754 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/hci/ssv_hci.c @@ -0,0 +1,967 @@ @@ -1566,7 +1508,7 @@ index 000000000000..9fedbeb55754 +EXPORT_SYMBOL(ssv6xxx_hci_exit); diff --git a/drivers/net/wireless/ssv6051/hci/ssv_hci.h b/drivers/net/wireless/ssv6051/hci/ssv_hci.h new file mode 100644 -index 000000000000..dd166c607d5d +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/hci/ssv_hci.h @@ -0,0 +1,77 @@ @@ -1649,7 +1591,7 @@ index 000000000000..dd166c607d5d +#endif diff --git a/drivers/net/wireless/ssv6051/hwif/hwif.h b/drivers/net/wireless/ssv6051/hwif/hwif.h new file mode 100644 -index 000000000000..6b5263d157d8 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/hwif/hwif.h @@ -0,0 +1,84 @@ @@ -1739,7 +1681,7 @@ index 000000000000..6b5263d157d8 +#endif diff --git a/drivers/net/wireless/ssv6051/hwif/sdio/sdio.c b/drivers/net/wireless/ssv6051/hwif/sdio/sdio.c new file mode 100644 -index 000000000000..273777cd0485 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/hwif/sdio/sdio.c @@ -0,0 +1,1254 @@ @@ -2999,7 +2941,7 @@ index 000000000000..273777cd0485 +EXPORT_SYMBOL(ssv6xxx_sdio_exit); diff --git a/drivers/net/wireless/ssv6051/hwif/sdio/sdio_def.h b/drivers/net/wireless/ssv6051/hwif/sdio/sdio_def.h new file mode 100644 -index 000000000000..57aefd3bf9fa +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/hwif/sdio/sdio_def.h @@ -0,0 +1,80 @@ @@ -3085,7 +3027,7 @@ index 000000000000..57aefd3bf9fa +#endif diff --git a/drivers/net/wireless/ssv6051/include/cabrio.h b/drivers/net/wireless/ssv6051/include/cabrio.h new file mode 100644 -index 000000000000..0b1327865c6b +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/cabrio.h @@ -0,0 +1,28 @@ @@ -3119,7 +3061,7 @@ index 000000000000..0b1327865c6b +#endif diff --git a/drivers/net/wireless/ssv6051/include/ssv6200.h b/drivers/net/wireless/ssv6051/include/ssv6200.h new file mode 100644 -index 000000000000..22eaceaf285d +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv6200.h @@ -0,0 +1,76 @@ @@ -3201,7 +3143,7 @@ index 000000000000..22eaceaf285d +#endif diff --git a/drivers/net/wireless/ssv6051/include/ssv6200_aux.h b/drivers/net/wireless/ssv6051/include/ssv6200_aux.h new file mode 100644 -index 000000000000..03ec3f07d330 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv6200_aux.h @@ -0,0 +1,18221 @@ @@ -21428,7 +21370,7 @@ index 000000000000..03ec3f07d330 +#define SRAM_TAG_15_SZ 16 diff --git a/drivers/net/wireless/ssv6051/include/ssv6200_common.h b/drivers/net/wireless/ssv6051/include/ssv6200_common.h new file mode 100644 -index 000000000000..e6d30f3714f7 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv6200_common.h @@ -0,0 +1,452 @@ @@ -21886,7 +21828,7 @@ index 000000000000..e6d30f3714f7 +#endif diff --git a/drivers/net/wireless/ssv6051/include/ssv6200_configuration.h b/drivers/net/wireless/ssv6051/include/ssv6200_configuration.h new file mode 100644 -index 000000000000..0327393de3f5 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv6200_configuration.h @@ -0,0 +1,317 @@ @@ -22209,7 +22151,7 @@ index 000000000000..0327393de3f5 +}; diff --git a/drivers/net/wireless/ssv6051/include/ssv6200_reg.h b/drivers/net/wireless/ssv6051/include/ssv6200_reg.h new file mode 100644 -index 000000000000..d4a99b25d61f +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv6200_reg.h @@ -0,0 +1,9694 @@ @@ -31909,7 +31851,7 @@ index 000000000000..d4a99b25d61f +#define DEF_TAG_SRAM0_F_STATUS_7() (REG32(ADR_TAG_SRAM0_F_STATUS_7)) = (0x00000000) diff --git a/drivers/net/wireless/ssv6051/include/ssv6200_reg_sim.h b/drivers/net/wireless/ssv6051/include/ssv6200_reg_sim.h new file mode 100644 -index 000000000000..e15a481ba300 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv6200_reg_sim.h @@ -0,0 +1,176 @@ @@ -32091,7 +32033,7 @@ index 000000000000..e15a481ba300 +}; diff --git a/drivers/net/wireless/ssv6051/include/ssv_cfg.h b/drivers/net/wireless/ssv6051/include/ssv_cfg.h new file mode 100644 -index 000000000000..79b75619936e +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv_cfg.h @@ -0,0 +1,60 @@ @@ -32157,7 +32099,7 @@ index 000000000000..79b75619936e +#endif diff --git a/drivers/net/wireless/ssv6051/include/ssv_firmware_version.h b/drivers/net/wireless/ssv6051/include/ssv_firmware_version.h new file mode 100644 -index 000000000000..7fabbe308f9d +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv_firmware_version.h @@ -0,0 +1,25 @@ @@ -32188,7 +32130,7 @@ index 000000000000..7fabbe308f9d +#endif diff --git a/drivers/net/wireless/ssv6051/include/ssv_version.h b/drivers/net/wireless/ssv6051/include/ssv_version.h new file mode 100644 -index 000000000000..99be5354f783 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/include/ssv_version.h @@ -0,0 +1,12 @@ @@ -32206,7 +32148,7 @@ index 000000000000..99be5354f783 +#endif diff --git a/drivers/net/wireless/ssv6051/platform-config.mak b/drivers/net/wireless/ssv6051/platform-config.mak new file mode 100644 -index 000000000000..b1b6f0510d28 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/platform-config.mak @@ -0,0 +1,97 @@ @@ -32310,7 +32252,7 @@ index 000000000000..b1b6f0510d28 \ No newline at end of file diff --git a/drivers/net/wireless/ssv6051/rules.mak b/drivers/net/wireless/ssv6051/rules.mak new file mode 100644 -index 000000000000..b3262852249c +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/rules.mak @@ -0,0 +1,19 @@ @@ -32335,7 +32277,7 @@ index 000000000000..b3262852249c + M=$(KBUILD_DIR) modules_install diff --git a/drivers/net/wireless/ssv6051/smac/ampdu.c b/drivers/net/wireless/ssv6051/smac/ampdu.c new file mode 100644 -index 000000000000..846830f3d209 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ampdu.c @@ -0,0 +1,2111 @@ @@ -34452,7 +34394,7 @@ index 000000000000..846830f3d209 +} diff --git a/drivers/net/wireless/ssv6051/smac/ampdu.h b/drivers/net/wireless/ssv6051/smac/ampdu.h new file mode 100644 -index 000000000000..faa61c4f9297 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ampdu.h @@ -0,0 +1,215 @@ @@ -34673,7 +34615,7 @@ index 000000000000..faa61c4f9297 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/ap.c b/drivers/net/wireless/ssv6051/smac/ap.c new file mode 100644 -index 000000000000..0f2ba6a31a05 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ap.c @@ -0,0 +1,598 @@ @@ -35277,7 +35219,7 @@ index 000000000000..0f2ba6a31a05 +} diff --git a/drivers/net/wireless/ssv6051/smac/ap.h b/drivers/net/wireless/ssv6051/smac/ap.h new file mode 100644 -index 000000000000..93b5275715b5 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ap.h @@ -0,0 +1,41 @@ @@ -35324,10 +35266,10 @@ index 000000000000..93b5275715b5 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/dev.c b/drivers/net/wireless/ssv6051/smac/dev.c new file mode 100644 -index 000000000000..cd93fa42648b +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/dev.c -@@ -0,0 +1,3884 @@ +@@ -0,0 +1,3881 @@ +/* + * Copyright (c) 2015 South Silicon Valley Microelectronics Inc. + * Copyright (c) 2015 iComm Corporation @@ -37520,7 +37462,7 @@ index 000000000000..cd93fa42648b + } + sc->watchdog_flag = WD_SLEEP; + mutex_unlock(&sc->mutex); -+ del_timer_sync(&sc->watchdog_timeout); ++ timer_delete_sync(&sc->watchdog_timeout); +#ifdef CONFIG_SSV_SMARTLINK + { + extern void ksmartlink_exit(void); @@ -38511,9 +38453,6 @@ index 000000000000..cd93fa42648b + .conf_tx = ssv6200_conf_tx, + .ampdu_action = ssv6200_ampdu_action, + .wake_tx_queue = ieee80211_handle_wake_tx_queue, -+ .add_chanctx = ieee80211_emulate_add_chanctx, -+ .remove_chanctx = ieee80211_emulate_remove_chanctx, -+ .change_chanctx = ieee80211_emulate_change_chanctx, +#ifdef CONFIG_PM + .suspend = ssv6xxx_suspend, + .resume = ssv6xxx_resume, @@ -39214,7 +39153,7 @@ index 000000000000..cd93fa42648b +#endif diff --git a/drivers/net/wireless/ssv6051/smac/dev.h b/drivers/net/wireless/ssv6051/smac/dev.h new file mode 100644 -index 000000000000..0a6357624b1c +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/dev.h @@ -0,0 +1,445 @@ @@ -39665,7 +39604,7 @@ index 000000000000..0a6357624b1c +#endif diff --git a/drivers/net/wireless/ssv6051/smac/dev_tbl.h b/drivers/net/wireless/ssv6051/smac/dev_tbl.h new file mode 100644 -index 000000000000..5c49d0bde6a6 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/dev_tbl.h @@ -0,0 +1,141 @@ @@ -39812,7 +39751,7 @@ index 000000000000..5c49d0bde6a6 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/drv_comm.h b/drivers/net/wireless/ssv6051/smac/drv_comm.h new file mode 100644 -index 000000000000..f04fbae004c3 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/drv_comm.h @@ -0,0 +1,61 @@ @@ -39879,7 +39818,7 @@ index 000000000000..f04fbae004c3 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/efuse.c b/drivers/net/wireless/ssv6051/smac/efuse.c new file mode 100644 -index 000000000000..9a1f3f5488f2 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/efuse.c @@ -0,0 +1,334 @@ @@ -40219,7 +40158,7 @@ index 000000000000..9a1f3f5488f2 +} diff --git a/drivers/net/wireless/ssv6051/smac/efuse.h b/drivers/net/wireless/ssv6051/smac/efuse.h new file mode 100644 -index 000000000000..c25280c5abad +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/efuse.h @@ -0,0 +1,40 @@ @@ -40265,7 +40204,7 @@ index 000000000000..c25280c5abad +#endif diff --git a/drivers/net/wireless/ssv6051/smac/init.c b/drivers/net/wireless/ssv6051/smac/init.c new file mode 100644 -index 000000000000..592c52a28381 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/init.c @@ -0,0 +1,1347 @@ @@ -40732,7 +40671,7 @@ index 000000000000..592c52a28381 + ssv6xxx_rate_control_unregister(); + cancel_delayed_work_sync(&sc->bcast_tx_work); + //ssv6xxx_watchdog_controller(sc->sh ,(u8)SSV6XXX_HOST_CMD_WATCHDOG_STOP); -+ del_timer_sync(&sc->watchdog_timeout); ++ timer_delete_sync(&sc->watchdog_timeout); + cancel_delayed_work(&sc->thermal_monitor_work); + sc->ps_status = PWRSV_PREPARE; + flush_workqueue(sc->thermal_wq); @@ -41618,7 +41557,7 @@ index 000000000000..592c52a28381 +EXPORT_SYMBOL(ssv6xxx_exit); diff --git a/drivers/net/wireless/ssv6051/smac/init.h b/drivers/net/wireless/ssv6051/smac/init.h new file mode 100644 -index 000000000000..97994d00d4da +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/init.h @@ -0,0 +1,23 @@ @@ -41647,7 +41586,7 @@ index 000000000000..97994d00d4da +#endif diff --git a/drivers/net/wireless/ssv6051/smac/lib.c b/drivers/net/wireless/ssv6051/smac/lib.c new file mode 100644 -index 000000000000..ccf0974b0f20 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/lib.c @@ -0,0 +1,33 @@ @@ -41686,7 +41625,7 @@ index 000000000000..ccf0974b0f20 +} diff --git a/drivers/net/wireless/ssv6051/smac/lib.h b/drivers/net/wireless/ssv6051/smac/lib.h new file mode 100644 -index 000000000000..266cf7afac95 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/lib.h @@ -0,0 +1,23 @@ @@ -41715,7 +41654,7 @@ index 000000000000..266cf7afac95 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/linux_80211.h b/drivers/net/wireless/ssv6051/smac/linux_80211.h new file mode 100644 -index 000000000000..e268808e3c93 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/linux_80211.h @@ -0,0 +1,24 @@ @@ -41745,7 +41684,7 @@ index 000000000000..e268808e3c93 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/p2p.c b/drivers/net/wireless/ssv6051/smac/p2p.c new file mode 100644 -index 000000000000..60fd8effd6ec +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/p2p.c @@ -0,0 +1,305 @@ @@ -42056,7 +41995,7 @@ index 000000000000..60fd8effd6ec +#endif diff --git a/drivers/net/wireless/ssv6051/smac/p2p.h b/drivers/net/wireless/ssv6051/smac/p2p.h new file mode 100644 -index 000000000000..a5bb99c61bb0 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/p2p.h @@ -0,0 +1,58 @@ @@ -42120,7 +42059,7 @@ index 000000000000..a5bb99c61bb0 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/sar.c b/drivers/net/wireless/ssv6051/smac/sar.c new file mode 100644 -index 000000000000..44a47a5c7a0f +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/sar.c @@ -0,0 +1,208 @@ @@ -42334,7 +42273,7 @@ index 000000000000..44a47a5c7a0f +} diff --git a/drivers/net/wireless/ssv6051/smac/sar.h b/drivers/net/wireless/ssv6051/smac/sar.h new file mode 100644 -index 000000000000..291d58f236eb +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/sar.h @@ -0,0 +1,63 @@ @@ -42403,7 +42342,7 @@ index 000000000000..291d58f236eb +#endif diff --git a/drivers/net/wireless/ssv6051/smac/sec.h b/drivers/net/wireless/ssv6051/smac/sec.h new file mode 100644 -index 000000000000..04a0f47c8ce2 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/sec.h @@ -0,0 +1,52 @@ @@ -42461,7 +42400,7 @@ index 000000000000..04a0f47c8ce2 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/smartlink.c b/drivers/net/wireless/ssv6051/smac/smartlink.c new file mode 100644 -index 000000000000..69e8d5118e09 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/smartlink.c @@ -0,0 +1,340 @@ @@ -42807,7 +42746,7 @@ index 000000000000..69e8d5118e09 +EXPORT_SYMBOL(ksmartlink_exit); diff --git a/drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.c b/drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.c new file mode 100644 -index 000000000000..9be5ea96e7f9 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.c @@ -0,0 +1,223 @@ @@ -43036,7 +42975,7 @@ index 000000000000..9be5ea96e7f9 +}; diff --git a/drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.h b/drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.h new file mode 100644 -index 000000000000..39caceadda4a +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv6xxx_debugfs.h @@ -0,0 +1,27 @@ @@ -43069,7 +43008,7 @@ index 000000000000..39caceadda4a +#endif diff --git a/drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.c b/drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.c new file mode 100644 -index 000000000000..f0135447b1f3 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.c @@ -0,0 +1,1384 @@ @@ -44459,7 +44398,7 @@ index 000000000000..f0135447b1f3 +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(SSV_VENDOR_EXT_SUPPORT) */ diff --git a/drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.h b/drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.h new file mode 100644 -index 000000000000..6d8696fcd220 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_cfgvendor.h @@ -0,0 +1,247 @@ @@ -44712,7 +44651,7 @@ index 000000000000..6d8696fcd220 +#endif /* _RTW_CFGVENDOR_H_ */ diff --git a/drivers/net/wireless/ssv6051/smac/ssv_ht_rc.c b/drivers/net/wireless/ssv6051/smac/ssv_ht_rc.c new file mode 100644 -index 000000000000..fae819c43400 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_ht_rc.c @@ -0,0 +1,546 @@ @@ -45264,7 +45203,7 @@ index 000000000000..fae819c43400 +} diff --git a/drivers/net/wireless/ssv6051/smac/ssv_ht_rc.h b/drivers/net/wireless/ssv6051/smac/ssv_ht_rc.h new file mode 100644 -index 000000000000..275c3356e036 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_ht_rc.h @@ -0,0 +1,31 @@ @@ -45301,7 +45240,7 @@ index 000000000000..275c3356e036 +#endif diff --git a/drivers/net/wireless/ssv6051/smac/ssv_pm.c b/drivers/net/wireless/ssv6051/smac/ssv_pm.c new file mode 100644 -index 000000000000..fc3be2013f61 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_pm.c @@ -0,0 +1,19 @@ @@ -45326,7 +45265,7 @@ index 000000000000..fc3be2013f61 +#include "sar.h" diff --git a/drivers/net/wireless/ssv6051/smac/ssv_pm.h b/drivers/net/wireless/ssv6051/smac/ssv_pm.h new file mode 100644 -index 000000000000..9be260dd904e +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_pm.h @@ -0,0 +1,20 @@ @@ -45352,7 +45291,7 @@ index 000000000000..9be260dd904e +#endif diff --git a/drivers/net/wireless/ssv6051/smac/ssv_rc.c b/drivers/net/wireless/ssv6051/smac/ssv_rc.c new file mode 100644 -index 000000000000..9c3574285364 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_rc.c @@ -0,0 +1,1716 @@ @@ -47074,7 +47013,7 @@ index 000000000000..9c3574285364 +} diff --git a/drivers/net/wireless/ssv6051/smac/ssv_rc.h b/drivers/net/wireless/ssv6051/smac/ssv_rc.h new file mode 100644 -index 000000000000..911c182897fa +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_rc.h @@ -0,0 +1,50 @@ @@ -47130,7 +47069,7 @@ index 000000000000..911c182897fa +#endif diff --git a/drivers/net/wireless/ssv6051/smac/ssv_rc_common.h b/drivers/net/wireless/ssv6051/smac/ssv_rc_common.h new file mode 100644 -index 000000000000..13f3fdd8072b +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/smac/ssv_rc_common.h @@ -0,0 +1,175 @@ @@ -47311,7 +47250,7 @@ index 000000000000..13f3fdd8072b +#endif diff --git a/drivers/net/wireless/ssv6051/ssv6051-generic-wlan.c b/drivers/net/wireless/ssv6051/ssv6051-generic-wlan.c new file mode 100644 -index 000000000000..10a9a77081db +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/ssv6051-generic-wlan.c @@ -0,0 +1,76 @@ @@ -47393,7 +47332,7 @@ index 000000000000..10a9a77081db + diff --git a/drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.c b/drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.c new file mode 100644 -index 000000000000..503df1ea6dc3 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.c @@ -0,0 +1,1765 @@ @@ -49164,7 +49103,7 @@ index 000000000000..503df1ea6dc3 +} diff --git a/drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.h b/drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.h new file mode 100644 -index 000000000000..d96bfcc54954 +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/ssvdevice/ssv_cmd.h @@ -0,0 +1,50 @@ @@ -49220,7 +49159,7 @@ index 000000000000..d96bfcc54954 +#endif diff --git a/drivers/net/wireless/ssv6051/ssvdevice/ssvdevice.c b/drivers/net/wireless/ssv6051/ssvdevice/ssvdevice.c new file mode 100644 -index 000000000000..eb848553798f +index 000000000000..111111111111 --- /dev/null +++ b/drivers/net/wireless/ssv6051/ssvdevice/ssvdevice.c @@ -0,0 +1,256 @@ @@ -49481,5 +49420,5 @@ index 000000000000..eb848553798f +EXPORT_SYMBOL(ssvdevice_init); +EXPORT_SYMBOL(ssvdevice_exit); -- -2.34.1 +Armbian diff --git a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-0002-rockchip-from-list.patch b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-0002-rockchip-from-list.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-0002-rockchip-from-list.patch rename to patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-0002-rockchip-from-list.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-0011-v4l2-from-list.patch b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-0011-v4l2-from-list.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-0011-v4l2-from-list.patch rename to patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-0011-v4l2-from-list.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1000-drm-rockchip.patch b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1000-drm-rockchip.patch similarity index 99% rename from patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1000-drm-rockchip.patch rename to patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1000-drm-rockchip.patch index a38ea8bbf5bf..6cf71cac04bd 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1000-drm-rockchip.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1000-drm-rockchip.patch @@ -2514,3 +2514,4 @@ index 49619f794061..9915bf124374 100644 } port = of_get_child_by_name(dev->of_node, "port"); + diff --git a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1001-v4l2-rockchip.patch b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1001-v4l2-rockchip.patch similarity index 99% rename from patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1001-v4l2-rockchip.patch rename to patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1001-v4l2-rockchip.patch index 0875e0412e35..631c4ea7eab7 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1001-v4l2-rockchip.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1001-v4l2-rockchip.patch @@ -9,7 +9,7 @@ Signed-off-by: Jonas Karlman drivers/staging/media/rkvdec/rkvdec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/dfrivers/staging/media/rkvdec/rkvdec.c +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index 4f5436c89e08..eaf2f133a264 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c diff --git a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1002-for-libreelec.patch b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1002-for-libreelec.patch similarity index 90% rename from patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1002-for-libreelec.patch rename to patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1002-for-libreelec.patch index a69442fbf88a..8a7de931e36a 100644 --- a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-1002-for-libreelec.patch +++ b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-1002-for-libreelec.patch @@ -11,11 +11,26 @@ is running at the same time (voltage to high) Signed-off-by: Alex Bee --- - .../arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 4 +++ + .../arm64/boot/dts/rockchip/rk3328-roc.dtsi | 4 +++ .../arm64/boot/dts/rockchip/rk3328-rock64.dts | 4 +++ arch/arm64/boot/dts/rockchip/rk3328.dtsi | 35 +++++++++++++++++++ 3 files changed, 43 insertions(+) +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi b/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi +index aa22a0c22265..51c7723d6762 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi +@@ -166,6 +166,10 @@ &gmac2io { + status = "okay"; + }; + ++&gpu { ++ mali-supply = <&vdd_logic>; ++}; ++ + &hdmi { + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index f69a38f42d2d..c198a8a7f95a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -232,6 +247,49 @@ index 40bf808642b9..27a1799027c2 100644 rockchip,hw-tshut-mode = <0>; rockchip,hw-tshut-polarity = <0>; +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 27 Feb 2021 18:01:13 +0100 +Subject: [PATCH] arm64: dts: rockchip: Add ir-receiver node for RK3328 ROC CC + +Signed-off-by: Alex Bee +--- + arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi b/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi +index 51c7723d6762..cf321302daec 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi +@@ -88,6 +88,13 @@ vcc_phy: vcc-phy-regulator { + regulator-boot-on; + }; + ++ ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; ++ pinctrl-0 = <&ir_int>; ++ pinctrl-names = "default"; ++ }; ++ + leds { + compatible = "gpio-leds"; + +@@ -312,6 +319,13 @@ &io_domains { + }; + + &pinctrl { ++ ++ ir { ++ ir_int: ir-int { ++ rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; + From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Mon, 1 Mar 2021 21:24:15 +0100 diff --git a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-2000-v4l2-wip-rkvdec-hevc.patch b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-2000-v4l2-wip-rkvdec-hevc.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-2000-v4l2-wip-rkvdec-hevc.patch rename to patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-2000-v4l2-wip-rkvdec-hevc.patch diff --git a/patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-2001-v4l2-wip-iep-driver.patch b/patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-2001-v4l2-wip-iep-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip-6.14/patches.libreelec/linux-2001-v4l2-wip-iep-driver.patch rename to patch/kernel/archive/rockchip-6.15/patches.libreelec/linux-2001-v4l2-wip-iep-driver.patch diff --git a/patch/kernel/archive/rockchip-6.14/series.conf b/patch/kernel/archive/rockchip-6.15/series.conf similarity index 100% rename from patch/kernel/archive/rockchip-6.14/series.conf rename to patch/kernel/archive/rockchip-6.15/series.conf diff --git a/patch/kernel/archive/rockchip64-6.12/dt/rk3399-am40.dts b/patch/kernel/archive/rockchip64-6.12/dt/rk3399-am40.dts index 9c402bc137e1..a9f293851c35 100644 --- a/patch/kernel/archive/rockchip64-6.12/dt/rk3399-am40.dts +++ b/patch/kernel/archive/rockchip64-6.12/dt/rk3399-am40.dts @@ -18,6 +18,7 @@ ethernet0 = &gmac; mmc0 = &sdhci; mmc1 = &sdmmc; + rtc0 = &pt7c4563; /* * The rk808 circuit design on this board does not have the ability to maintain real-time time after a power outage. * Registering rk808 as rtc99 (most kernel configurations read time from rtc0) can prevent the kernel from reading the time (2013) from rk808 during startup. @@ -499,6 +500,20 @@ &i2c4 { status = "okay"; + i2c-scl-rising-time-ns = <300>; + i2c-scl-falling-time-ns = <300>; + + pt7c4563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "rtc_xin32k"; + wakeup-source; + interrupt-parent = <&gpio0>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&rtc_int>; + pinctrl-names = "default"; + }; }; &i2s2 { @@ -583,6 +598,12 @@ }; }; + rtc { + rtc_int: rtc-int { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + usb2 { vcc5v0_host_en: vcc5v0-hots-en { rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/patch/kernel/archive/rockchip64-6.12/dt/rk3566-nanopi-r3s-lts.dts b/patch/kernel/archive/rockchip64-6.12/dt/rk3566-nanopi-r3s-lts.dts new file mode 100644 index 000000000000..e3305f4044db --- /dev/null +++ b/patch/kernel/archive/rockchip64-6.12/dt/rk3566-nanopi-r3s-lts.dts @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * Copyright (c) 2024 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyelec.com) + */ + +/dts-v1/; + +#include "rk3566-nanopi-r3s.dts" + +/ { + compatible = "friendlyarm,nanopi-r3s-lts", "rockchip,rk3566"; + model = "FriendlyElec NanoPi R3S LTS"; + + hdmi-con { + compatible = "hdmi-connector"; + type = "d"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; +}; + +&hdmi { + avdd-0v9-supply = <&vdda_0v9>; + avdd-1v8-supply = <&vcca1v8_image>; + status = "okay"; +}; + +&hdmi_in { + hdmi_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi>; + }; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdmi_sound { + status = "okay"; +}; + +&i2s0_8ch { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi_in_vp0>; + }; +}; diff --git a/patch/kernel/archive/rockchip64-6.12/rk3588-0133-drm-rockchip-vop2-Improve-display-modes-handling.patch b/patch/kernel/archive/rockchip64-6.12/rk3588-0133-drm-rockchip-vop2-Improve-display-modes-handling.patch deleted file mode 100644 index 4caa301abf58..000000000000 --- a/patch/kernel/archive/rockchip64-6.12/rk3588-0133-drm-rockchip-vop2-Improve-display-modes-handling.patch +++ /dev/null @@ -1,715 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Wed, 27 Mar 2024 20:36:15 +0200 -Subject: [WIP] dt-bindings: display: rockchip-drm: Add optional clocks - property - -Allow using the clock provided by HDMI0 PHY PLL to improve HDMI output -support on RK3588 SoC. - -Signed-off-by: Cristian Ciocaltea ---- - Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml -index 111111111111..222222222222 100644 ---- a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml -+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml -@@ -28,6 +28,14 @@ properties: - of vop devices. vop definitions as defined in - Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml - -+ clocks: -+ maxItems: 1 -+ description: Optional clock provided by HDMI0 PLL -+ -+ clock-names: -+ items: -+ - const: hdmi0_phy_pll -+ - required: - - compatible - - ports --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Fri, 3 Nov 2023 19:58:02 +0200 -Subject: [WIP] drm/rockchip: vop2: Improve display modes handling on rk3588 - -The initial vop2 support for rk3588 in mainline is not able to handle -all display modes supported by connected displays, e.g. -2560x1440-75.00Hz, 2048x1152-60.00Hz, 1024x768-60.00Hz. - -Additionally, it doesn't cope with non-integer refresh rates like 59.94, -29.97, 23.98, etc. - -Improve HDMI0 clocking in order to support the additional display modes. - -Fixes: 5a028e8f062f ("drm/rockchip: vop2: Add support for rk3588") -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 553 +++++++++- - 1 file changed, 552 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -5,6 +5,8 @@ - */ - #include - #include -+#include -+#include - #include - #include - #include -@@ -212,6 +214,10 @@ struct vop2 { - struct clk *hclk; - struct clk *aclk; - struct clk *pclk; -+ // [CC:] hack to support additional display modes -+ struct clk *hdmi0_phy_pll; -+ /* list_head of internal clk */ -+ struct list_head clk_list_head; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; -@@ -220,6 +226,19 @@ struct vop2 { - struct vop2_win win[]; - }; - -+struct vop2_clk { -+ struct vop2 *vop2; -+ struct list_head list; -+ unsigned long rate; -+ struct clk_hw hw; -+ struct clk_divider div; -+ int div_val; -+ u8 parent_index; -+}; -+ -+#define to_vop2_clk(_hw) container_of(_hw, struct vop2_clk, hw) -+#define VOP2_MAX_DCLK_RATE 600000 /* kHz */ -+ - #define vop2_output_if_is_hdmi(x) ((x) == ROCKCHIP_VOP2_EP_HDMI0 || \ - (x) == ROCKCHIP_VOP2_EP_HDMI1) - -@@ -1476,9 +1495,30 @@ static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) - { -+ struct vop2_video_port *vp = to_vop2_video_port(crtc); -+ struct drm_connector *connector; -+ struct drm_connector_list_iter conn_iter; -+ struct drm_crtc_state *new_crtc_state = container_of(mode, struct drm_crtc_state, mode); - drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | - CRTC_STEREO_DOUBLE); - -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) -+ adj_mode->crtc_clock *= 2; -+ -+ drm_connector_list_iter_begin(crtc->dev, &conn_iter); -+ drm_for_each_connector_iter(connector, &conn_iter) { -+ if ((new_crtc_state->connector_mask & drm_connector_mask(connector)) && -+ ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || -+ (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))) { -+ drm_connector_list_iter_end(&conn_iter); -+ return true; -+ } -+ } -+ drm_connector_list_iter_end(&conn_iter); -+ -+ if (adj_mode->crtc_clock <= VOP2_MAX_DCLK_RATE) -+ adj_mode->crtc_clock = DIV_ROUND_UP(clk_round_rate(vp->dclk, -+ adj_mode->crtc_clock * 1000), 1000); - return true; - } - -@@ -1663,6 +1703,31 @@ static unsigned long rk3588_calc_dclk(unsigned long child_clk, unsigned long max - return 0; - } - -+static struct vop2_clk *vop2_clk_get(struct vop2 *vop2, const char *name); -+ -+static int vop2_cru_set_rate(struct vop2_clk *if_pixclk, struct vop2_clk *if_dclk) -+{ -+ int ret = 0; -+ -+ if (if_pixclk) { -+ ret = clk_set_rate(if_pixclk->hw.clk, if_pixclk->rate); -+ if (ret < 0) { -+ DRM_DEV_ERROR(if_pixclk->vop2->dev, "set %s to %ld failed: %d\n", -+ clk_hw_get_name(&if_pixclk->hw), if_pixclk->rate, ret); -+ return ret; -+ } -+ } -+ -+ if (if_dclk) { -+ ret = clk_set_rate(if_dclk->hw.clk, if_dclk->rate); -+ if (ret < 0) -+ DRM_DEV_ERROR(if_dclk->vop2->dev, "set %s to %ld failed %d\n", -+ clk_hw_get_name(&if_dclk->hw), if_dclk->rate, ret); -+ } -+ -+ return ret; -+} -+ - /* - * 4 pixclk/cycle on rk3588 - * RGB/eDP/HDMI: if_pixclk >= dclk_core -@@ -1686,6 +1751,72 @@ static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id, - int K = 1; - - if (vop2_output_if_is_hdmi(id)) { -+ if (vop2->data->soc_id == 3588 && id == ROCKCHIP_VOP2_EP_HDMI0 && -+ vop2->hdmi0_phy_pll) { -+ const char *clk_src_name = "hdmi_edp0_clk_src"; -+ const char *clk_parent_name = "dclk"; -+ const char *pixclk_name = "hdmi_edp0_pixclk"; -+ const char *dclk_name = "hdmi_edp0_dclk"; -+ struct vop2_clk *if_clk_src, *if_clk_parent, *if_pixclk, *if_dclk, *dclk, *dclk_core, *dclk_out; -+ char clk_name[32]; -+ int ret; -+ -+ if_clk_src = vop2_clk_get(vop2, clk_src_name); -+ snprintf(clk_name, sizeof(clk_name), "%s%d", clk_parent_name, vp->id); -+ if_clk_parent = vop2_clk_get(vop2, clk_name); -+ if_pixclk = vop2_clk_get(vop2, pixclk_name); -+ if_dclk = vop2_clk_get(vop2, dclk_name); -+ if (!if_pixclk || !if_clk_parent) { -+ DRM_DEV_ERROR(vop2->dev, "failed to get connector interface clk\n"); -+ return -ENODEV; -+ } -+ -+ ret = clk_set_parent(if_clk_src->hw.clk, if_clk_parent->hw.clk); -+ if (ret < 0) { -+ DRM_DEV_ERROR(vop2->dev, "failed to set parent(%s) for %s: %d\n", -+ __clk_get_name(if_clk_parent->hw.clk), -+ __clk_get_name(if_clk_src->hw.clk), ret); -+ return ret; -+ } -+ -+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420) -+ K = 2; -+ -+ if_pixclk->rate = (dclk_core_rate << 1) / K; -+ if_dclk->rate = dclk_core_rate / K; -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk_core%d", vp->id); -+ dclk_core = vop2_clk_get(vop2, clk_name); -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk_out%d", vp->id); -+ dclk_out = vop2_clk_get(vop2, clk_name); -+ -+ snprintf(clk_name, sizeof(clk_name), "dclk%d", vp->id); -+ dclk = vop2_clk_get(vop2, clk_name); -+ if (v_pixclk <= (VOP2_MAX_DCLK_RATE * 1000)) { -+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420) -+ v_pixclk = v_pixclk >> 1; -+ } else { -+ v_pixclk = v_pixclk >> 2; -+ } -+ clk_set_rate(dclk->hw.clk, v_pixclk); -+ -+ if (dclk_core_rate > if_pixclk->rate) { -+ clk_set_rate(dclk_core->hw.clk, dclk_core_rate); -+ ret = vop2_cru_set_rate(if_pixclk, if_dclk); -+ } else { -+ ret = vop2_cru_set_rate(if_pixclk, if_dclk); -+ clk_set_rate(dclk_core->hw.clk, dclk_core_rate); -+ } -+ -+ *dclk_core_div = dclk_core->div_val; -+ *dclk_out_div = dclk_out->div_val; -+ *if_pixclk_div = if_pixclk->div_val; -+ *if_dclk_div = if_dclk->div_val; -+ -+ return dclk->rate; -+ } -+ - /* - * K = 2: dclk_core = if_pixclk_rate > if_dclk_rate - * K = 1: dclk_core = hdmie_edp_dclk > if_pixclk_rate -@@ -1917,6 +2048,22 @@ static int us_to_vertical_line(struct drm_display_mode *mode, int us) - return us * mode->clock / mode->htotal / 1000; - } - -+// [CC:] rework virtual clock -+static struct vop2_clk *vop2_clk_get(struct vop2 *vop2, const char *name) -+{ -+ struct vop2_clk *clk, *n; -+ -+ if (!name) -+ return NULL; -+ -+ list_for_each_entry_safe(clk, n, &vop2->clk_list_head, list) { -+ if (!strcmp(clk_hw_get_name(&clk->hw), name)) -+ return clk; -+ } -+ -+ return NULL; -+} -+ - static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) - { -@@ -1944,6 +2091,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - u32 val, polflags; - int ret; - struct drm_encoder *encoder; -+ char clk_name[32]; -+ struct vop2_clk *dclk; - - drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n", - hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p", -@@ -2044,11 +2193,38 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) { - dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV; -- clock *= 2; -+ // [CC:] done via mode_fixup -+ // clock *= 2; - } - - vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0); - -+ snprintf(clk_name, sizeof(clk_name), "dclk%d", vp->id); -+ dclk = vop2_clk_get(vop2, clk_name); -+ if (dclk) { -+ /* -+ * use HDMI_PHY_PLL as dclk source under 4K@60 if it is available, -+ * otherwise use system cru as dclk source. -+ */ -+ drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { -+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); -+ -+ // [CC:] Using PHY PLL to handle all display modes -+ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { -+ clk_get_rate(vop2->hdmi0_phy_pll); -+ -+ if (mode->crtc_clock <= VOP2_MAX_DCLK_RATE) { -+ ret = clk_set_parent(vp->dclk, vop2->hdmi0_phy_pll); -+ if (ret < 0) -+ DRM_WARN("failed to set clock parent for %s\n", -+ __clk_get_name(vp->dclk)); -+ } -+ -+ clock = dclk->rate; -+ } -+ } -+ } -+ - clk_set_rate(vp->dclk, clock); - - vop2_post_config(crtc); -@@ -2504,7 +2680,43 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, - spin_unlock_irq(&crtc->dev->event_lock); - } - -+static enum drm_mode_status -+vop2_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) -+{ -+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); -+ struct vop2_video_port *vp = to_vop2_video_port(crtc); -+ struct vop2 *vop2 = vp->vop2; -+ const struct vop2_data *vop2_data = vop2->data; -+ const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; -+ int request_clock = mode->clock; -+ int clock; -+ -+ if (mode->hdisplay > vp_data->max_output.width) -+ return MODE_BAD_HVALUE; -+ -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) -+ request_clock *= 2; -+ -+ if (request_clock <= VOP2_MAX_DCLK_RATE) { -+ clock = request_clock; -+ } else { -+ request_clock = request_clock >> 2; -+ clock = clk_round_rate(vp->dclk, request_clock * 1000) / 1000; -+ } -+ -+ /* -+ * Hdmi or DisplayPort request a Accurate clock. -+ */ -+ if (vcstate->output_type == DRM_MODE_CONNECTOR_HDMIA || -+ vcstate->output_type == DRM_MODE_CONNECTOR_DisplayPort) -+ if (clock != request_clock) -+ return MODE_CLOCK_RANGE; -+ -+ return MODE_OK; -+} -+ - static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { -+ .mode_valid = vop2_crtc_mode_valid, - .mode_fixup = vop2_crtc_mode_fixup, - .atomic_check = vop2_crtc_atomic_check, - .atomic_begin = vop2_crtc_atomic_begin, -@@ -3074,6 +3286,336 @@ static const struct regmap_config vop2_regmap_config = { - .cache_type = REGCACHE_MAPLE, - }; - -+/* -+ * BEGIN virtual clock -+ */ -+#define PLL_RATE_MIN 30000000 -+ -+#define cru_dbg(format, ...) do { \ -+ if (cru_debug) \ -+ pr_info("%s: " format, __func__, ## __VA_ARGS__); \ -+ } while (0) -+ -+#define PNAME(x) static const char *const x[] -+ -+enum vop_clk_branch_type { -+ branch_mux, -+ branch_divider, -+ branch_factor, -+ branch_virtual, -+}; -+ -+#define VIR(cname) \ -+ { \ -+ .branch_type = branch_virtual, \ -+ .name = cname, \ -+ } -+ -+ -+#define MUX(cname, pnames, f) \ -+ { \ -+ .branch_type = branch_mux, \ -+ .name = cname, \ -+ .parent_names = pnames, \ -+ .num_parents = ARRAY_SIZE(pnames), \ -+ .flags = f, \ -+ } -+ -+#define FACTOR(cname, pname, f) \ -+ { \ -+ .branch_type = branch_factor, \ -+ .name = cname, \ -+ .parent_names = (const char *[]){ pname }, \ -+ .num_parents = 1, \ -+ .flags = f, \ -+ } -+ -+#define DIV(cname, pname, f, w) \ -+ { \ -+ .branch_type = branch_divider, \ -+ .name = cname, \ -+ .parent_names = (const char *[]){ pname }, \ -+ .num_parents = 1, \ -+ .flags = f, \ -+ .div_width = w, \ -+ } -+ -+struct vop2_clk_branch { -+ enum vop_clk_branch_type branch_type; -+ const char *name; -+ const char *const *parent_names; -+ u8 num_parents; -+ unsigned long flags; -+ u8 div_shift; -+ u8 div_width; -+ u8 div_flags; -+}; -+ -+PNAME(mux_port0_dclk_src_p) = { "dclk0", "dclk1" }; -+PNAME(mux_port2_dclk_src_p) = { "dclk2", "dclk1" }; -+PNAME(mux_dp_pixclk_p) = { "dclk_out0", "dclk_out1", "dclk_out2" }; -+PNAME(mux_hdmi_edp_clk_src_p) = { "dclk0", "dclk1", "dclk2" }; -+PNAME(mux_mipi_clk_src_p) = { "dclk_out1", "dclk_out2", "dclk_out3" }; -+PNAME(mux_dsc_8k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" }; -+PNAME(mux_dsc_4k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" }; -+ -+/* -+ * We only use this clk driver calculate the div -+ * of dclk_core/dclk_out/if_pixclk/if_dclk and -+ * the rate of the dclk from the soc. -+ * -+ * We don't touch the cru in the vop here, as -+ * these registers has special read andy write -+ * limits. -+ */ -+static struct vop2_clk_branch rk3588_vop_clk_branches[] = { -+ VIR("dclk0"), -+ VIR("dclk1"), -+ VIR("dclk2"), -+ VIR("dclk3"), -+ -+ MUX("port0_dclk_src", mux_port0_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dclk_core0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ FACTOR("port1_dclk_src", "dclk1", CLK_SET_RATE_PARENT), -+ DIV("dclk_core1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ MUX("port2_dclk_src", mux_port2_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dclk_core2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ FACTOR("port3_dclk_src", "dclk3", CLK_SET_RATE_PARENT), -+ DIV("dclk_core3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2), -+ DIV("dclk_out3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2), -+ -+ MUX("dp0_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ MUX("dp1_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ -+ MUX("hdmi_edp0_clk_src", mux_hdmi_edp_clk_src_p, -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("hdmi_edp0_dclk", "hdmi_edp0_clk_src", 0, 2), -+ DIV("hdmi_edp0_pixclk", "hdmi_edp0_clk_src", CLK_SET_RATE_PARENT, 1), -+ -+ MUX("hdmi_edp1_clk_src", mux_hdmi_edp_clk_src_p, -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("hdmi_edp1_dclk", "hdmi_edp1_clk_src", 0, 2), -+ DIV("hdmi_edp1_pixclk", "hdmi_edp1_clk_src", CLK_SET_RATE_PARENT, 1), -+ -+ MUX("mipi0_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("mipi0_pixclk", "mipi0_clk_src", CLK_SET_RATE_PARENT, 2), -+ -+ MUX("mipi1_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("mipi1_pixclk", "mipi1_clk_src", CLK_SET_RATE_PARENT, 2), -+ -+ FACTOR("rgb_pixclk", "port3_dclk_src", CLK_SET_RATE_PARENT), -+ -+ MUX("dsc_8k_txp_clk_src", mux_dsc_8k_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dsc_8k_txp_clk", "dsc_8k_txp_clk_src", 0, 2), -+ DIV("dsc_8k_pxl_clk", "dsc_8k_txp_clk_src", 0, 2), -+ DIV("dsc_8k_cds_clk", "dsc_8k_txp_clk_src", 0, 2), -+ -+ MUX("dsc_4k_txp_clk_src", mux_dsc_4k_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), -+ DIV("dsc_4k_txp_clk", "dsc_4k_txp_clk_src", 0, 2), -+ DIV("dsc_4k_pxl_clk", "dsc_4k_txp_clk_src", 0, 2), -+ DIV("dsc_4k_cds_clk", "dsc_4k_txp_clk_src", 0, 2), -+}; -+ -+static unsigned long clk_virtual_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ return (unsigned long)vop2_clk->rate; -+} -+ -+static long clk_virtual_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ vop2_clk->rate = rate; -+ -+ return rate; -+} -+ -+static int clk_virtual_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ return 0; -+} -+ -+const struct clk_ops clk_virtual_ops = { -+ .round_rate = clk_virtual_round_rate, -+ .set_rate = clk_virtual_set_rate, -+ .recalc_rate = clk_virtual_recalc_rate, -+}; -+ -+static u8 vop2_mux_get_parent(struct clk_hw *hw) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ // cru_dbg("%s index: %d\n", clk_hw_get_name(hw), vop2_clk->parent_index); -+ return vop2_clk->parent_index; -+} -+ -+static int vop2_mux_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ vop2_clk->parent_index = index; -+ -+ // cru_dbg("%s index: %d\n", clk_hw_get_name(hw), index); -+ return 0; -+} -+ -+static int vop2_clk_mux_determine_rate(struct clk_hw *hw, -+ struct clk_rate_request *req) -+{ -+ // cru_dbg("%s %ld(min: %ld max: %ld)\n", -+ // clk_hw_get_name(hw), req->rate, req->min_rate, req->max_rate); -+ return __clk_mux_determine_rate(hw, req); -+} -+ -+static const struct clk_ops vop2_mux_clk_ops = { -+ .get_parent = vop2_mux_get_parent, -+ .set_parent = vop2_mux_set_parent, -+ .determine_rate = vop2_clk_mux_determine_rate, -+}; -+ -+#define div_mask(width) ((1 << (width)) - 1) -+ -+static int vop2_div_get_val(unsigned long rate, unsigned long parent_rate) -+{ -+ unsigned int div, value; -+ -+ div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ -+ value = ilog2(div); -+ -+ return value; -+} -+ -+static unsigned long vop2_clk_div_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ unsigned long rate; -+ unsigned int div; -+ -+ div = 1 << vop2_clk->div_val; -+ rate = parent_rate / div; -+ -+ // cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, parent_rate); -+ return rate; -+} -+ -+static long vop2_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ -+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { -+ if (*prate < rate) -+ *prate = rate; -+ if ((*prate >> vop2_clk->div.width) > rate) -+ *prate = rate; -+ -+ if ((*prate % rate)) -+ *prate = rate; -+ -+ /* SOC PLL can't output a too low pll freq */ -+ if (*prate < PLL_RATE_MIN) -+ *prate = rate << vop2_clk->div.width; -+ } -+ -+ // cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, *prate); -+ return rate; -+} -+ -+static int vop2_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) -+{ -+ struct vop2_clk *vop2_clk = to_vop2_clk(hw); -+ int div_val; -+ -+ div_val = vop2_div_get_val(rate, parent_rate); -+ vop2_clk->div_val = div_val; -+ -+ // cru_dbg("%s prate: %ld rate: %ld div_val: %d\n", -+ // clk_hw_get_name(hw), parent_rate, rate, div_val); -+ return 0; -+} -+ -+static const struct clk_ops vop2_div_clk_ops = { -+ .recalc_rate = vop2_clk_div_recalc_rate, -+ .round_rate = vop2_clk_div_round_rate, -+ .set_rate = vop2_clk_div_set_rate, -+}; -+ -+static struct clk *vop2_clk_register(struct vop2 *vop2, struct vop2_clk_branch *branch) -+{ -+ struct clk_init_data init = {}; -+ struct vop2_clk *vop2_clk; -+ struct clk *clk; -+ -+ vop2_clk = devm_kzalloc(vop2->dev, sizeof(*vop2_clk), GFP_KERNEL); -+ if (!vop2_clk) -+ return ERR_PTR(-ENOMEM); -+ -+ vop2_clk->vop2 = vop2; -+ vop2_clk->hw.init = &init; -+ vop2_clk->div.shift = branch->div_shift; -+ vop2_clk->div.width = branch->div_width; -+ -+ init.name = branch->name; -+ init.flags = branch->flags; -+ init.num_parents = branch->num_parents; -+ init.parent_names = branch->parent_names; -+ if (branch->branch_type == branch_divider) { -+ init.ops = &vop2_div_clk_ops; -+ } else if (branch->branch_type == branch_virtual) { -+ init.ops = &clk_virtual_ops; -+ init.num_parents = 0; -+ init.parent_names = NULL; -+ } else { -+ init.ops = &vop2_mux_clk_ops; -+ } -+ -+ clk = devm_clk_register(vop2->dev, &vop2_clk->hw); -+ if (!IS_ERR(clk)) -+ list_add_tail(&vop2_clk->list, &vop2->clk_list_head); -+ else -+ DRM_DEV_ERROR(vop2->dev, "Register %s failed\n", branch->name); -+ -+ return clk; -+} -+ -+static int vop2_clk_init(struct vop2 *vop2) -+{ -+ struct vop2_clk_branch *branch = rk3588_vop_clk_branches; -+ unsigned int nr_clk = ARRAY_SIZE(rk3588_vop_clk_branches); -+ unsigned int idx; -+ struct vop2_clk *clk, *n; -+ -+ INIT_LIST_HEAD(&vop2->clk_list_head); -+ -+ if (vop2->data->soc_id < 3588 || vop2->hdmi0_phy_pll == NULL) -+ return 0; -+ -+ list_for_each_entry_safe(clk, n, &vop2->clk_list_head, list) { -+ list_del(&clk->list); -+ } -+ -+ for (idx = 0; idx < nr_clk; idx++, branch++) -+ vop2_clk_register(vop2, branch); -+ -+ return 0; -+} -+/* -+ * END virtual clock -+ */ -+ - static int vop2_bind(struct device *dev, struct device *master, void *data) - { - struct platform_device *pdev = to_platform_device(dev); -@@ -3167,6 +3709,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->pclk); - } - -+ vop2->hdmi0_phy_pll = devm_clk_get_optional(vop2->drm->dev, "hdmi0_phy_pll"); -+ if (IS_ERR(vop2->hdmi0_phy_pll)) { -+ DRM_DEV_ERROR(vop2->dev, "failed to get hdmi0_phy_pll source\n"); -+ return PTR_ERR(vop2->hdmi0_phy_pll); -+ } -+ - vop2->irq = platform_get_irq(pdev, 0); - if (vop2->irq < 0) { - drm_err(vop2->drm, "cannot find irq for vop2\n"); -@@ -3183,6 +3731,9 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - if (ret) - return ret; - -+ // [CC:] rework virtual clock -+ vop2_clk_init(vop2); -+ - ret = vop2_find_rgb_encoder(vop2); - if (ret >= 0) { - vop2->rgb = rockchip_rgb_init(dev, &vop2->vps[ret].crtc, --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/general-fix-inno-usb2-phy-init.patch b/patch/kernel/archive/rockchip64-6.14/general-fix-inno-usb2-phy-init.patch deleted file mode 100644 index 6c608e4a69fd..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/general-fix-inno-usb2-phy-init.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paolo Sabatino -Date: Mon, 22 Aug 2022 20:51:22 +0000 -Subject: remove usb2phy extcon initialization causing kernel oops - ---- - drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c -index 111111111111..222222222222 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c -@@ -1323,11 +1323,6 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, - goto out; - } - -- if (!of_property_read_bool(rphy->dev->of_node, "extcon")) { -- /* do initial sync of usb state */ -- id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id); -- extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id); -- } - } - - out: --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-acodec-vendor-driver.patch b/patch/kernel/archive/rockchip64-6.14/rk3308-acodec-vendor-driver.patch deleted file mode 100644 index b532fa5a4077..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3308-acodec-vendor-driver.patch +++ /dev/null @@ -1,7158 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paolo Sabatino -Date: Fri, 20 Dec 2024 11:48:31 +0100 -Subject: revert rk3308 analog codec to vendor code - ---- - arch/arm64/boot/dts/rockchip/rk3308.dtsi | 7 +- - sound/soc/codecs/rk3308_codec.c | 5681 ++++++++-- - sound/soc/codecs/rk3308_codec.h | 892 +- - sound/soc/codecs/rk3308_codec_provider.h | 28 + - 4 files changed, 5665 insertions(+), 943 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi -@@ -836,11 +836,14 @@ codec: codec@ff560000 { - compatible = "rockchip,rk3308-codec"; - reg = <0x0 0xff560000 0x0 0x10000>; - rockchip,grf = <&grf>; -- clock-names = "mclk_tx", "mclk_rx", "hclk"; -+ rockchip,detect-grf = <&detect_grf>; -+ clock-names = "mclk_tx", "mclk_rx", "acodec"; - clocks = <&cru SCLK_I2S2_8CH_TX_OUT>, - <&cru SCLK_I2S2_8CH_RX_OUT>, - <&cru PCLK_ACODEC>; -- reset-names = "codec"; -+ interrupts = <&gic 114 IRQ_TYPE_LEVEL_HIGH>, -+ <&gic 115 IRQ_TYPE_LEVEL_HIGH>; -+ reset-names = "acodec-reset"; - resets = <&cru SRST_ACODEC_P>; - #sound-dai-cells = <0>; - status = "disabled"; -diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c -index 111111111111..222222222222 100644 ---- a/sound/soc/codecs/rk3308_codec.c -+++ b/sound/soc/codecs/rk3308_codec.c -@@ -1,9 +1,20 @@ --// SPDX-License-Identifier: GPL-2.0-only - /* -- * Rockchip RK3308 internal audio codec driver -+ * rk3308_codec.c -- RK3308 ALSA Soc Audio Driver - * - * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. -- * Copyright (c) 2024, Vivax-Metrotech Ltd -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * - */ - - #include -@@ -14,961 +25,5151 @@ - #include - #include - #include -+#include - #include -+#include - #include -+#include - #include --#include -+// #include -+#include - #include -+#include -+#include -+#include - #include - #include -+#include - #include - #include - - #include "rk3308_codec.h" -+#include "rk3308_codec_provider.h" - -+#if defined(CONFIG_DEBUG_FS) -+#include -+#include -+#include -+#endif -+ -+#define CODEC_DRV_NAME "rk3308-acodec" -+ -+#define ADC_GRP_SKIP_MAGIC 0x1001 - #define ADC_LR_GROUP_MAX 4 -+#define ADC_STABLE_MS 200 -+#define DEBUG_POP_ALWAYS 0 -+#define HPDET_POLL_MS 2000 -+#define NOT_USED 255 -+#define LOOPBACK_HANDLE_MS 100 -+#define PA_DRV_MS 5 - -+#define GRF_SOC_CON1 0x304 - #define GRF_CHIP_ID 0x800 -+#define GRF_I2S2_8CH_SDI_SFT 0 -+#define GRF_I2S3_4CH_SDI_SFT 8 -+#define GRF_I2S1_2CH_SDI_SFT 12 -+ -+#define GRF_I2S2_8CH_SDI_R_MSK(i, v) ((v >> (i * 2 + GRF_I2S2_8CH_SDI_SFT)) & 0x3) -+#define GRF_I2S2_8CH_SDI_W_MSK(i) (0x3 << (i * 2 + GRF_I2S2_8CH_SDI_SFT + 16)) -+#define GRF_I2S2_8CH_SDI(i, v) (((v & 0x3) << (i * 2 + GRF_I2S2_8CH_SDI_SFT)) |\ -+ GRF_I2S2_8CH_SDI_W_MSK(i)) -+ -+#define GRF_I2S3_4CH_SDI_W_MSK(i) (0x3 << (i * 2 + GRF_I2S3_4CH_SDI_SFT + 16)) -+#define GRF_I2S3_4CH_SDI(i, v) (((v & 0x3) << (i * 2 + GRF_I2S3_4CH_SDI_SFT)) |\ -+ GRF_I2S3_4CH_SDI_W_MSK(i)) -+ -+#define GRF_I2S1_2CH_SDI_W_MSK (0x3 << (GRF_I2S1_2CH_SDI_SFT + 16)) -+#define GRF_I2S1_2CH_SDI(v) (((v & 0x3) << GRF_I2S1_2CH_SDI_SFT) |\ -+ GRF_I2S1_2CH_SDI_W_MSK) -+ -+#define DETECT_GRF_ACODEC_HPDET_COUNTER 0x0030 -+#define DETECT_GRF_ACODEC_HPDET_CON 0x0034 -+#define DETECT_GRF_ACODEC_HPDET_STATUS 0x0038 -+#define DETECT_GRF_ACODEC_HPDET_STATUS_CLR 0x003c -+ -+/* 200ms based on pclk is 100MHz */ -+#define DEFAULT_HPDET_COUNT 20000000 -+#define HPDET_NEG_IRQ_SFT 1 -+#define HPDET_POS_IRQ_SFT 0 -+#define HPDET_BOTH_NEG_POS ((1 << HPDET_NEG_IRQ_SFT) |\ -+ (1 << HPDET_POS_IRQ_SFT)) -+ -+#define ACODEC_VERSION_A 0xa -+#define ACODEC_VERSION_B 0xb -+ -+enum { -+ ACODEC_TO_I2S2_8CH = 0, -+ ACODEC_TO_I2S3_4CH, -+ ACODEC_TO_I2S1_2CH, -+}; -+ -+enum { -+ ADC_GRP0_MICIN = 0, -+ ADC_GRP0_LINEIN -+}; -+ -+enum { -+ ADC_TYPE_NORMAL = 0, -+ ADC_TYPE_LOOPBACK, -+ ADC_TYPE_DBG, -+ ADC_TYPE_ALL, -+}; -+ -+enum { -+ DAC_LINEOUT = 0, -+ DAC_HPOUT = 1, -+ DAC_LINEOUT_HPOUT = 11, -+}; - - enum { -- ACODEC_VERSION_A = 'A', -- ACODEC_VERSION_B, -- ACODEC_VERSION_C, -+ EXT_MICBIAS_NONE = 0, -+ EXT_MICBIAS_FUNC1, /* enable external micbias via GPIO */ -+ EXT_MICBIAS_FUNC2, /* enable external micbias via regulator */ -+}; -+ -+enum { -+ PATH_IDLE = 0, -+ PATH_BUSY, -+}; -+ -+enum { -+ PM_NORMAL = 0, -+ PM_LLP_DOWN, /* light low power down */ -+ PM_LLP_UP, -+ PM_DLP_DOWN, /* deep low power down */ -+ PM_DLP_UP, -+ PM_DLP_DOWN2, -+ PM_DLP_UP2, - }; - - struct rk3308_codec_priv { -- const struct device *dev; -+ const struct device *plat_dev; -+ struct device dev; -+ struct reset_control *reset; - struct regmap *regmap; - struct regmap *grf; -- struct reset_control *reset; -- struct clk *hclk; -+ struct regmap *detect_grf; -+ struct clk *pclk; - struct clk *mclk_rx; - struct clk *mclk_tx; -+ struct gpio_desc *micbias_en_gpio; -+ struct gpio_desc *hp_ctl_gpio; -+ struct gpio_desc *spk_ctl_gpio; -+ struct gpio_desc *pa_drv_gpio; - struct snd_soc_component *component; -- unsigned char codec_ver; --}; -+ struct snd_soc_jack *hpdet_jack; -+ struct regulator *vcc_micbias; -+ u32 codec_ver; -+ -+ /* -+ * To select ADCs for groups: -+ * -+ * grp 0 -- select ADC1 / ADC2 -+ * grp 1 -- select ADC3 / ADC4 -+ * grp 2 -- select ADC5 / ADC6 -+ * grp 3 -- select ADC7 / ADC8 -+ */ -+ u32 used_adc_grps; -+ /* The ADC group which is used for loop back */ -+ u32 loopback_grp; -+ u32 cur_dbg_grp; -+ u32 en_always_grps[ADC_LR_GROUP_MAX]; -+ u32 en_always_grps_num; -+ u32 skip_grps[ADC_LR_GROUP_MAX]; -+ u32 i2s_sdis[ADC_LR_GROUP_MAX]; -+ u32 to_i2s_grps; -+ u32 delay_loopback_handle_ms; -+ u32 delay_start_play_ms; -+ u32 delay_pa_drv_ms; -+ u32 micbias_num; -+ u32 micbias_volt; -+ int which_i2s; -+ int irq; -+ int adc_grp0_using_linein; -+ int adc_zerocross; -+ /* 0: line out, 1: hp out, 11: lineout and hpout */ -+ int dac_output; -+ int dac_path_state; -+ -+ int ext_micbias; -+ int pm_state; -+ -+ /* AGC L/R Off/on */ -+ unsigned int agc_l[ADC_LR_GROUP_MAX]; -+ unsigned int agc_r[ADC_LR_GROUP_MAX]; - --static struct clk_bulk_data rk3308_codec_clocks[] = { -- { .id = "hclk" }, -- { .id = "mclk_rx" }, -- { .id = "mclk_tx" }, -+ /* AGC L/R Approximate Sample Rate */ -+ unsigned int agc_asr_l[ADC_LR_GROUP_MAX]; -+ unsigned int agc_asr_r[ADC_LR_GROUP_MAX]; -+ -+ /* ADC MIC Mute/Work */ -+ unsigned int mic_mute_l[ADC_LR_GROUP_MAX]; -+ unsigned int mic_mute_r[ADC_LR_GROUP_MAX]; -+ -+ /* For the high pass filter */ -+ unsigned int hpf_cutoff[ADC_LR_GROUP_MAX]; -+ -+ /* Only hpout do fade-in and fade-out */ -+ unsigned int hpout_l_dgain; -+ unsigned int hpout_r_dgain; -+ -+ bool adc_grps_endisable[ADC_LR_GROUP_MAX]; -+ bool dac_endisable; -+ bool enable_all_adcs; -+ bool enable_micbias; -+ bool micbias1; -+ bool micbias2; -+ bool hp_jack_reversed; -+ bool hp_plugged; -+ bool loopback_dacs_enabled; -+ bool no_deep_low_power; -+ bool no_hp_det; -+ struct delayed_work hpdet_work; -+ struct delayed_work loopback_work; -+ -+#if defined(CONFIG_DEBUG_FS) -+ struct dentry *dbg_codec; -+#endif - }; - --static const DECLARE_TLV_DB_SCALE(rk3308_codec_adc_alc_gain_tlv, -1800, 150, 0); --static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpout_gain_tlv, -3900, 150, 0); --static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv, -600, 600, 0); -+static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_gain_tlv, -+ -1800, 150, 2850); -+static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_max_gain_tlv, -+ -1350, 600, 2850); -+static const DECLARE_TLV_DB_SCALE(rk3308_codec_alc_agc_grp_min_gain_tlv, -+ -1800, 600, 2400); -+static const DECLARE_TLV_DB_SCALE(rk3308_codec_adc_alc_gain_tlv, -+ -1800, 150, 2850); -+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_lineout_gain_tlv, -+ -600, 150, 0); -+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpout_gain_tlv, -+ -3900, 150, 600); -+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv, -+ -600, 600, 0); -+ -+static const DECLARE_TLV_DB_RANGE(rk3308_codec_adc_mic_gain_tlv_a, -+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), -+ 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), -+); - --static const DECLARE_TLV_DB_RANGE(rk3308_codec_dac_lineout_gain_tlv, -- 0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0), -- 1, 1, TLV_DB_SCALE_ITEM(-300, 0, 0), -- 2, 2, TLV_DB_SCALE_ITEM(-150, 0, 0), -- 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0), -+static const DECLARE_TLV_DB_RANGE(rk3308_codec_adc_mic_gain_tlv_b, -+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), -+ 1, 1, TLV_DB_SCALE_ITEM(660, 0, 0), -+ 2, 2, TLV_DB_SCALE_ITEM(1300, 0, 0), -+ 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), - ); - --static const char * const rk3308_codec_hpf_cutoff_text[] = { -- "20 Hz", "245 Hz", "612 Hz" -+static bool handle_loopback(struct rk3308_codec_priv *rk3308); -+ -+static int check_micbias(int micbias); -+ -+static int rk3308_codec_micbias_enable(struct rk3308_codec_priv *rk3308, -+ int micbias); -+static int rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308); -+ -+static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_hpf_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_hpf_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_agc_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_agc_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_agc_asr_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_agc_asr_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_mic_mute_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_mic_mute_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_mic_gain_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_mic_gain_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_micbias_volts_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_main_micbias_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+static int rk3308_codec_main_micbias_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol); -+ -+static const char *offon_text[2] = { -+ [0] = "Off", -+ [1] = "On", -+}; -+ -+static const char *mute_text[2] = { -+ [0] = "Work", -+ [1] = "Mute", -+}; -+ -+/* ADC MICBIAS Volt */ -+#define MICBIAS_VOLT_NUM 8 -+ -+#define MICBIAS_VREFx0_5 0 -+#define MICBIAS_VREFx0_55 1 -+#define MICBIAS_VREFx0_6 2 -+#define MICBIAS_VREFx0_65 3 -+#define MICBIAS_VREFx0_7 4 -+#define MICBIAS_VREFx0_75 5 -+#define MICBIAS_VREFx0_8 6 -+#define MICBIAS_VREFx0_85 7 -+ -+static const char *micbias_volts_enum_array[MICBIAS_VOLT_NUM] = { -+ [MICBIAS_VREFx0_5] = "VREFx0_5", -+ [MICBIAS_VREFx0_55] = "VREFx0_55", -+ [MICBIAS_VREFx0_6] = "VREFx0_6", -+ [MICBIAS_VREFx0_65] = "VREFx0_65", -+ [MICBIAS_VREFx0_7] = "VREFx0_7", -+ [MICBIAS_VREFx0_75] = "VREFx0_75", -+ [MICBIAS_VREFx0_8] = "VREFx0_8", -+ [MICBIAS_VREFx0_85] = "VREFx0_85", -+}; -+ -+static const struct soc_enum rk3308_micbias_volts_enum_array[] = { -+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(micbias_volts_enum_array), micbias_volts_enum_array), -+}; -+ -+/* ADC MICBIAS1 and MICBIAS2 Main Switch */ -+static const struct soc_enum rk3308_main_micbias_enum_array[] = { -+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), -+}; -+ -+static const struct soc_enum rk3308_hpf_enum_array[] = { -+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(offon_text), offon_text), -+}; -+ -+/* ALC AGC Switch */ -+static const struct soc_enum rk3308_agc_enum_array[] = { -+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(1, 1, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(2, 1, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(offon_text), offon_text), -+ SOC_ENUM_SINGLE(3, 1, ARRAY_SIZE(offon_text), offon_text), -+}; -+ -+/* ADC MIC Mute/Work Switch */ -+static const struct soc_enum rk3308_mic_mute_enum_array[] = { -+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(mute_text), mute_text), -+ SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(mute_text), mute_text), -+ SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(mute_text), mute_text), -+ SOC_ENUM_SINGLE(1, 1, ARRAY_SIZE(mute_text), mute_text), -+ SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(mute_text), mute_text), -+ SOC_ENUM_SINGLE(2, 1, ARRAY_SIZE(mute_text), mute_text), -+ SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(mute_text), mute_text), -+ SOC_ENUM_SINGLE(3, 1, ARRAY_SIZE(mute_text), mute_text), -+}; -+ -+/* ALC AGC Approximate Sample Rate */ -+#define AGC_ASR_NUM 8 -+ -+#define AGC_ASR_96KHZ 0 -+#define AGC_ASR_48KHZ 1 -+#define AGC_ASR_44_1KHZ 2 -+#define AGC_ASR_32KHZ 3 -+#define AGC_ASR_24KHZ 4 -+#define AGC_ASR_16KHZ 5 -+#define AGC_ASR_12KHZ 6 -+#define AGC_ASR_8KHZ 7 -+ -+static const char *agc_asr_text[AGC_ASR_NUM] = { -+ [AGC_ASR_96KHZ] = "96KHz", -+ [AGC_ASR_48KHZ] = "48KHz", -+ [AGC_ASR_44_1KHZ] = "44.1KHz", -+ [AGC_ASR_32KHZ] = "32KHz", -+ [AGC_ASR_24KHZ] = "24KHz", -+ [AGC_ASR_16KHZ] = "16KHz", -+ [AGC_ASR_12KHZ] = "12KHz", -+ [AGC_ASR_8KHZ] = "8KHz", -+}; -+ -+static const struct soc_enum rk3308_agc_asr_enum_array[] = { -+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+ SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+ SOC_ENUM_SINGLE(1, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+ SOC_ENUM_SINGLE(1, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+ SOC_ENUM_SINGLE(2, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+ SOC_ENUM_SINGLE(2, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+ SOC_ENUM_SINGLE(3, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+ SOC_ENUM_SINGLE(3, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), -+}; -+ -+static const struct snd_kcontrol_new mic_gains_a[] = { -+ /* ADC MIC */ -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Left Volume", -+ RK3308_ADC_ANA_CON01(0), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Right Volume", -+ RK3308_ADC_ANA_CON01(0), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Left Volume", -+ RK3308_ADC_ANA_CON01(1), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Right Volume", -+ RK3308_ADC_ANA_CON01(1), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Left Volume", -+ RK3308_ADC_ANA_CON01(2), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Right Volume", -+ RK3308_ADC_ANA_CON01(2), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Left Volume", -+ RK3308_ADC_ANA_CON01(3), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Right Volume", -+ RK3308_ADC_ANA_CON01(3), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_a), -+}; -+ -+static const struct snd_kcontrol_new mic_gains_b[] = { -+ /* ADC MIC */ -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Left Volume", -+ RK3308_ADC_ANA_CON01(0), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 0 Right Volume", -+ RK3308_ADC_ANA_CON01(0), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Left Volume", -+ RK3308_ADC_ANA_CON01(1), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 1 Right Volume", -+ RK3308_ADC_ANA_CON01(1), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Left Volume", -+ RK3308_ADC_ANA_CON01(2), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 2 Right Volume", -+ RK3308_ADC_ANA_CON01(2), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Left Volume", -+ RK3308_ADC_ANA_CON01(3), -+ RK3308_ADC_CH1_MIC_GAIN_SFT, -+ RK3308_ADC_CH1_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), -+ SOC_SINGLE_EXT_TLV("ADC MIC Group 3 Right Volume", -+ RK3308_ADC_ANA_CON01(3), -+ RK3308_ADC_CH2_MIC_GAIN_SFT, -+ RK3308_ADC_CH2_MIC_GAIN_MAX, -+ 0, -+ rk3308_codec_mic_gain_get, -+ rk3308_codec_mic_gain_put, -+ rk3308_codec_adc_mic_gain_tlv_b), - }; - --static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum12, RK3308_ADC_DIG_CON04(0), 0, -- rk3308_codec_hpf_cutoff_text); --static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum34, RK3308_ADC_DIG_CON04(1), 0, -- rk3308_codec_hpf_cutoff_text); --static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum56, RK3308_ADC_DIG_CON04(2), 0, -- rk3308_codec_hpf_cutoff_text); --static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum78, RK3308_ADC_DIG_CON04(3), 0, -- rk3308_codec_hpf_cutoff_text); -- --static const struct snd_kcontrol_new rk3308_codec_controls[] = { -- /* Despite the register names, these set the gain when AGC is OFF */ -- SOC_SINGLE_RANGE_TLV("MIC1 Capture Volume", -+static const struct snd_kcontrol_new rk3308_codec_dapm_controls[] = { -+ /* ALC AGC Group */ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Left Volume", -+ RK3308_ALC_L_DIG_CON03(0), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Right Volume", -+ RK3308_ALC_R_DIG_CON03(0), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Left Volume", -+ RK3308_ALC_L_DIG_CON03(1), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Right Volume", -+ RK3308_ALC_R_DIG_CON03(1), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Left Volume", -+ RK3308_ALC_L_DIG_CON03(2), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Right Volume", -+ RK3308_ALC_R_DIG_CON03(2), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Left Volume", -+ RK3308_ALC_L_DIG_CON03(3), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Right Volume", -+ RK3308_ALC_R_DIG_CON03(3), -+ RK3308_AGC_PGA_GAIN_SFT, -+ RK3308_AGC_PGA_GAIN_MIN, -+ RK3308_AGC_PGA_GAIN_MAX, -+ 0, rk3308_codec_alc_agc_grp_gain_tlv), -+ -+ /* ALC AGC MAX */ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Left Max Volume", -+ RK3308_ALC_L_DIG_CON09(0), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Right Max Volume", -+ RK3308_ALC_R_DIG_CON09(0), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Left Max Volume", -+ RK3308_ALC_L_DIG_CON09(1), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Right Max Volume", -+ RK3308_ALC_R_DIG_CON09(1), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Left Max Volume", -+ RK3308_ALC_L_DIG_CON09(2), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Right Max Volume", -+ RK3308_ALC_R_DIG_CON09(2), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Left Max Volume", -+ RK3308_ALC_L_DIG_CON09(3), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Right Max Volume", -+ RK3308_ALC_R_DIG_CON09(3), -+ RK3308_AGC_MAX_GAIN_PGA_SFT, -+ RK3308_AGC_MAX_GAIN_PGA_MIN, -+ RK3308_AGC_MAX_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_max_gain_tlv), -+ -+ /* ALC AGC MIN */ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Left Min Volume", -+ RK3308_ALC_L_DIG_CON09(0), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 0 Right Min Volume", -+ RK3308_ALC_R_DIG_CON09(0), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Left Min Volume", -+ RK3308_ALC_L_DIG_CON09(1), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 1 Right Min Volume", -+ RK3308_ALC_R_DIG_CON09(1), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Left Min Volume", -+ RK3308_ALC_L_DIG_CON09(2), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 2 Right Min Volume", -+ RK3308_ALC_R_DIG_CON09(2), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Left Min Volume", -+ RK3308_ALC_L_DIG_CON09(3), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("ALC AGC Group 3 Right Min Volume", -+ RK3308_ALC_R_DIG_CON09(3), -+ RK3308_AGC_MIN_GAIN_PGA_SFT, -+ RK3308_AGC_MIN_GAIN_PGA_MIN, -+ RK3308_AGC_MIN_GAIN_PGA_MAX, -+ 0, rk3308_codec_alc_agc_grp_min_gain_tlv), -+ -+ /* ALC AGC Switch */ -+ SOC_ENUM_EXT("ALC AGC Group 0 Left Switch", rk3308_agc_enum_array[0], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ SOC_ENUM_EXT("ALC AGC Group 0 Right Switch", rk3308_agc_enum_array[1], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ SOC_ENUM_EXT("ALC AGC Group 1 Left Switch", rk3308_agc_enum_array[2], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ SOC_ENUM_EXT("ALC AGC Group 1 Right Switch", rk3308_agc_enum_array[3], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ SOC_ENUM_EXT("ALC AGC Group 2 Left Switch", rk3308_agc_enum_array[4], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ SOC_ENUM_EXT("ALC AGC Group 2 Right Switch", rk3308_agc_enum_array[5], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ SOC_ENUM_EXT("ALC AGC Group 3 Left Switch", rk3308_agc_enum_array[6], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ SOC_ENUM_EXT("ALC AGC Group 3 Right Switch", rk3308_agc_enum_array[7], -+ rk3308_codec_agc_get, rk3308_codec_agc_put), -+ -+ /* ALC AGC Approximate Sample Rate */ -+ SOC_ENUM_EXT("AGC Group 0 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[0], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ SOC_ENUM_EXT("AGC Group 0 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[1], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ SOC_ENUM_EXT("AGC Group 1 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[2], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ SOC_ENUM_EXT("AGC Group 1 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[3], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ SOC_ENUM_EXT("AGC Group 2 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[4], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ SOC_ENUM_EXT("AGC Group 2 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[5], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ SOC_ENUM_EXT("AGC Group 3 Left Approximate Sample Rate", rk3308_agc_asr_enum_array[6], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ SOC_ENUM_EXT("AGC Group 3 Right Approximate Sample Rate", rk3308_agc_asr_enum_array[7], -+ rk3308_codec_agc_asr_get, rk3308_codec_agc_asr_put), -+ -+ /* ADC MICBIAS Voltage */ -+ SOC_ENUM_EXT("ADC MICBIAS Voltage", rk3308_micbias_volts_enum_array[0], -+ rk3308_codec_micbias_volts_get, rk3308_codec_micbias_volts_put), -+ -+ /* ADC Main MICBIAS Switch */ -+ SOC_ENUM_EXT("ADC Main MICBIAS", rk3308_main_micbias_enum_array[0], -+ rk3308_codec_main_micbias_get, rk3308_codec_main_micbias_put), -+ -+ /* ADC MICBIAS1 and MICBIAS2 Switch */ -+ SOC_SINGLE("ADC MICBIAS1", RK3308_ADC_ANA_CON07(1), -+ RK3308_ADC_MIC_BIAS_BUF_SFT, 1, 0), -+ SOC_SINGLE("ADC MICBIAS2", RK3308_ADC_ANA_CON07(2), -+ RK3308_ADC_MIC_BIAS_BUF_SFT, 1, 0), -+ -+ /* ADC MIC Mute/Work Switch */ -+ SOC_ENUM_EXT("ADC MIC Group 0 Left Switch", rk3308_mic_mute_enum_array[0], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ SOC_ENUM_EXT("ADC MIC Group 0 Right Switch", rk3308_mic_mute_enum_array[1], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ SOC_ENUM_EXT("ADC MIC Group 1 Left Switch", rk3308_mic_mute_enum_array[2], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ SOC_ENUM_EXT("ADC MIC Group 1 Right Switch", rk3308_mic_mute_enum_array[3], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ SOC_ENUM_EXT("ADC MIC Group 2 Left Switch", rk3308_mic_mute_enum_array[4], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ SOC_ENUM_EXT("ADC MIC Group 2 Right Switch", rk3308_mic_mute_enum_array[5], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ SOC_ENUM_EXT("ADC MIC Group 3 Left Switch", rk3308_mic_mute_enum_array[6], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ SOC_ENUM_EXT("ADC MIC Group 3 Right Switch", rk3308_mic_mute_enum_array[7], -+ rk3308_codec_mic_mute_get, rk3308_codec_mic_mute_put), -+ -+ /* ADC ALC */ -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 0 Left Volume", - RK3308_ADC_ANA_CON03(0), - RK3308_ADC_CH1_ALC_GAIN_SFT, - RK3308_ADC_CH1_ALC_GAIN_MIN, - RK3308_ADC_CH1_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), -- SOC_SINGLE_RANGE_TLV("MIC2 Capture Volume", -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 0 Right Volume", - RK3308_ADC_ANA_CON04(0), - RK3308_ADC_CH2_ALC_GAIN_SFT, - RK3308_ADC_CH2_ALC_GAIN_MIN, - RK3308_ADC_CH2_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), -- SOC_SINGLE_RANGE_TLV("MIC3 Capture Volume", -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 1 Left Volume", - RK3308_ADC_ANA_CON03(1), - RK3308_ADC_CH1_ALC_GAIN_SFT, - RK3308_ADC_CH1_ALC_GAIN_MIN, - RK3308_ADC_CH1_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), -- SOC_SINGLE_RANGE_TLV("MIC4 Capture Volume", -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 1 Right Volume", - RK3308_ADC_ANA_CON04(1), - RK3308_ADC_CH2_ALC_GAIN_SFT, - RK3308_ADC_CH2_ALC_GAIN_MIN, - RK3308_ADC_CH2_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), -- SOC_SINGLE_RANGE_TLV("MIC5 Capture Volume", -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 2 Left Volume", - RK3308_ADC_ANA_CON03(2), - RK3308_ADC_CH1_ALC_GAIN_SFT, - RK3308_ADC_CH1_ALC_GAIN_MIN, - RK3308_ADC_CH1_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), -- SOC_SINGLE_RANGE_TLV("MIC6 Capture Volume", -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 2 Right Volume", - RK3308_ADC_ANA_CON04(2), - RK3308_ADC_CH2_ALC_GAIN_SFT, - RK3308_ADC_CH2_ALC_GAIN_MIN, - RK3308_ADC_CH2_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), -- SOC_SINGLE_RANGE_TLV("MIC7 Capture Volume", -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 3 Left Volume", - RK3308_ADC_ANA_CON03(3), - RK3308_ADC_CH1_ALC_GAIN_SFT, - RK3308_ADC_CH1_ALC_GAIN_MIN, - RK3308_ADC_CH1_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), -- SOC_SINGLE_RANGE_TLV("MIC8 Capture Volume", -+ SOC_SINGLE_RANGE_TLV("ADC ALC Group 3 Right Volume", - RK3308_ADC_ANA_CON04(3), - RK3308_ADC_CH2_ALC_GAIN_SFT, - RK3308_ADC_CH2_ALC_GAIN_MIN, - RK3308_ADC_CH2_ALC_GAIN_MAX, - 0, rk3308_codec_adc_alc_gain_tlv), - -- SOC_SINGLE("MIC1 Capture Switch", RK3308_ADC_ANA_CON00(0), 3, 1, 0), -- SOC_SINGLE("MIC2 Capture Switch", RK3308_ADC_ANA_CON00(0), 7, 1, 0), -- SOC_SINGLE("MIC3 Capture Switch", RK3308_ADC_ANA_CON00(1), 3, 1, 0), -- SOC_SINGLE("MIC4 Capture Switch", RK3308_ADC_ANA_CON00(1), 7, 1, 0), -- SOC_SINGLE("MIC5 Capture Switch", RK3308_ADC_ANA_CON00(2), 3, 1, 0), -- SOC_SINGLE("MIC6 Capture Switch", RK3308_ADC_ANA_CON00(2), 7, 1, 0), -- SOC_SINGLE("MIC7 Capture Switch", RK3308_ADC_ANA_CON00(3), 3, 1, 0), -- SOC_SINGLE("MIC8 Capture Switch", RK3308_ADC_ANA_CON00(3), 7, 1, 0), -- -- SOC_SINGLE("MIC12 HPF Capture Switch", RK3308_ADC_DIG_CON04(0), 2, 1, 1), -- SOC_SINGLE("MIC34 HPF Capture Switch", RK3308_ADC_DIG_CON04(1), 2, 1, 1), -- SOC_SINGLE("MIC56 HPF Capture Switch", RK3308_ADC_DIG_CON04(2), 2, 1, 1), -- SOC_SINGLE("MIC78 HPF Capture Switch", RK3308_ADC_DIG_CON04(3), 2, 1, 1), -- -- SOC_ENUM("MIC12 HPF Cutoff", rk3308_codec_hpf_cutoff_enum12), -- SOC_ENUM("MIC34 HPF Cutoff", rk3308_codec_hpf_cutoff_enum34), -- SOC_ENUM("MIC56 HPF Cutoff", rk3308_codec_hpf_cutoff_enum56), -- SOC_ENUM("MIC78 HPF Cutoff", rk3308_codec_hpf_cutoff_enum78), -- -- SOC_DOUBLE_TLV("Line Out Playback Volume", -+ /* ADC High Pass Filter */ -+ SOC_ENUM_EXT("ADC Group 0 HPF Cut-off", rk3308_hpf_enum_array[0], -+ rk3308_codec_hpf_get, rk3308_codec_hpf_put), -+ SOC_ENUM_EXT("ADC Group 1 HPF Cut-off", rk3308_hpf_enum_array[1], -+ rk3308_codec_hpf_get, rk3308_codec_hpf_put), -+ SOC_ENUM_EXT("ADC Group 2 HPF Cut-off", rk3308_hpf_enum_array[2], -+ rk3308_codec_hpf_get, rk3308_codec_hpf_put), -+ SOC_ENUM_EXT("ADC Group 3 HPF Cut-off", rk3308_hpf_enum_array[3], -+ rk3308_codec_hpf_get, rk3308_codec_hpf_put), -+ -+ /* DAC LINEOUT */ -+ SOC_SINGLE_TLV("DAC LINEOUT Left Volume", - RK3308_DAC_ANA_CON04, - RK3308_DAC_L_LINEOUT_GAIN_SFT, -+ RK3308_DAC_L_LINEOUT_GAIN_MAX, -+ 0, rk3308_codec_dac_lineout_gain_tlv), -+ SOC_SINGLE_TLV("DAC LINEOUT Right Volume", -+ RK3308_DAC_ANA_CON04, - RK3308_DAC_R_LINEOUT_GAIN_SFT, -- RK3308_DAC_x_LINEOUT_GAIN_MAX, -+ RK3308_DAC_R_LINEOUT_GAIN_MAX, - 0, rk3308_codec_dac_lineout_gain_tlv), -- SOC_DOUBLE("Line Out Playback Switch", -- RK3308_DAC_ANA_CON04, -- RK3308_DAC_L_LINEOUT_MUTE_SFT, -- RK3308_DAC_R_LINEOUT_MUTE_SFT, 1, 0), -- SOC_DOUBLE_R_TLV("Headphone Playback Volume", -- RK3308_DAC_ANA_CON05, -- RK3308_DAC_ANA_CON06, -- RK3308_DAC_x_HPOUT_GAIN_SFT, -- RK3308_DAC_x_HPOUT_GAIN_MAX, -- 0, rk3308_codec_dac_hpout_gain_tlv), -- SOC_DOUBLE("Headphone Playback Switch", -- RK3308_DAC_ANA_CON03, -- RK3308_DAC_L_HPOUT_MUTE_SFT, -- RK3308_DAC_R_HPOUT_MUTE_SFT, 1, 0), -- SOC_DOUBLE_RANGE_TLV("DAC HPMIX Playback Volume", -+ -+ /* DAC HPOUT */ -+ SOC_SINGLE_EXT_TLV("DAC HPOUT Left Volume", -+ RK3308_DAC_ANA_CON05, -+ RK3308_DAC_L_HPOUT_GAIN_SFT, -+ RK3308_DAC_L_HPOUT_GAIN_MAX, -+ 0, -+ rk3308_codec_hpout_l_get_tlv, -+ rk3308_codec_hpout_l_put_tlv, -+ rk3308_codec_dac_hpout_gain_tlv), -+ SOC_SINGLE_EXT_TLV("DAC HPOUT Right Volume", -+ RK3308_DAC_ANA_CON06, -+ RK3308_DAC_R_HPOUT_GAIN_SFT, -+ RK3308_DAC_R_HPOUT_GAIN_MAX, -+ 0, -+ rk3308_codec_hpout_r_get_tlv, -+ rk3308_codec_hpout_r_put_tlv, -+ rk3308_codec_dac_hpout_gain_tlv), -+ -+ /* DAC HPMIX */ -+ SOC_SINGLE_RANGE_TLV("DAC HPMIX Left Volume", - RK3308_DAC_ANA_CON12, - RK3308_DAC_L_HPMIX_GAIN_SFT, -+ RK3308_DAC_L_HPMIX_GAIN_MIN, -+ RK3308_DAC_L_HPMIX_GAIN_MAX, -+ 0, rk3308_codec_dac_hpmix_gain_tlv), -+ SOC_SINGLE_RANGE_TLV("DAC HPMIX Right Volume", -+ RK3308_DAC_ANA_CON12, - RK3308_DAC_R_HPMIX_GAIN_SFT, -- 1, 2, 0, rk3308_codec_dac_hpmix_gain_tlv), -+ RK3308_DAC_R_HPMIX_GAIN_MIN, -+ RK3308_DAC_R_HPMIX_GAIN_MAX, -+ 0, rk3308_codec_dac_hpmix_gain_tlv), - }; - --static int rk3308_codec_pop_sound_set(struct snd_soc_dapm_widget *w, -- struct snd_kcontrol *kcontrol, -- int event) -+static int rk3308_codec_agc_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) - { -- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -- unsigned int val = (event == SND_SOC_DAPM_POST_PMU) ? -- RK3308_DAC_HPOUT_POP_SOUND_x_WORK : -- RK3308_DAC_HPOUT_POP_SOUND_x_INIT; -- unsigned int mask = RK3308_DAC_HPOUT_POP_SOUND_x_MSK; -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - -- regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -- mask << w->shift, val << w->shift); -- -- return 0; --} -- --static const struct snd_soc_dapm_widget rk3308_codec_dapm_widgets[] = { -- SND_SOC_DAPM_INPUT("MIC1"), -- SND_SOC_DAPM_INPUT("MIC2"), -- SND_SOC_DAPM_INPUT("MIC3"), -- SND_SOC_DAPM_INPUT("MIC4"), -- SND_SOC_DAPM_INPUT("MIC5"), -- SND_SOC_DAPM_INPUT("MIC6"), -- SND_SOC_DAPM_INPUT("MIC7"), -- SND_SOC_DAPM_INPUT("MIC8"), -- -- SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN12", RK3308_ADC_ANA_CON06(0), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN34", RK3308_ADC_ANA_CON06(1), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN56", RK3308_ADC_ANA_CON06(2), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN78", RK3308_ADC_ANA_CON06(3), 0, 0, NULL, 0), -- -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_EN", RK3308_ADC_ANA_CON00(0), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_EN", RK3308_ADC_ANA_CON00(0), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_EN", RK3308_ADC_ANA_CON00(1), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_EN", RK3308_ADC_ANA_CON00(1), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_EN", RK3308_ADC_ANA_CON00(2), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_EN", RK3308_ADC_ANA_CON00(2), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_EN", RK3308_ADC_ANA_CON00(3), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_EN", RK3308_ADC_ANA_CON00(3), 5, 1, 1, 0), -- -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_WORK", RK3308_ADC_ANA_CON00(0), 2, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_WORK", RK3308_ADC_ANA_CON00(0), 6, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_WORK", RK3308_ADC_ANA_CON00(1), 2, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_WORK", RK3308_ADC_ANA_CON00(1), 6, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_WORK", RK3308_ADC_ANA_CON00(2), 2, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_WORK", RK3308_ADC_ANA_CON00(2), 6, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_WORK", RK3308_ADC_ANA_CON00(3), 2, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_WORK", RK3308_ADC_ANA_CON00(3), 6, 1, 1, 0), -- -- /* -- * In theory MIC1 and MIC2 can switch to LINE IN, but this is not -- * supported so all we can do is enabling the MIC input. -- */ -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH1_IN_SEL", RK3308_ADC_ANA_CON07(0), 4, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH2_IN_SEL", RK3308_ADC_ANA_CON07(0), 6, 1, 1, 0), -- -- SND_SOC_DAPM_SUPPLY("ADC1_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC2_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC3_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC4_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC5_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC6_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC7_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC8_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 4, 0, NULL, 0), -- -- SND_SOC_DAPM_SUPPLY("ADC_MCLK_GATE", RK3308_GLB_CON, 5, 1, NULL, 0), -- -- SND_SOC_DAPM_SUPPLY("ADC1_CLK_EN", RK3308_ADC_ANA_CON05(0), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC2_CLK_EN", RK3308_ADC_ANA_CON05(0), 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC3_CLK_EN", RK3308_ADC_ANA_CON05(1), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC4_CLK_EN", RK3308_ADC_ANA_CON05(1), 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC5_CLK_EN", RK3308_ADC_ANA_CON05(2), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC6_CLK_EN", RK3308_ADC_ANA_CON05(2), 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC7_CLK_EN", RK3308_ADC_ANA_CON05(3), 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("ADC8_CLK_EN", RK3308_ADC_ANA_CON05(3), 4, 0, NULL, 0), -- -- /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */ -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_EN", RK3308_ADC_ANA_CON02(0), 0, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_EN", RK3308_ADC_ANA_CON02(0), 4, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_EN", RK3308_ADC_ANA_CON02(1), 0, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_EN", RK3308_ADC_ANA_CON02(1), 4, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_EN", RK3308_ADC_ANA_CON02(2), 0, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_EN", RK3308_ADC_ANA_CON02(2), 4, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_EN", RK3308_ADC_ANA_CON02(3), 0, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_EN", RK3308_ADC_ANA_CON02(3), 4, 1, 1, 0), -- -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC1_EN", RK3308_ADC_ANA_CON05(0), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC2_EN", RK3308_ADC_ANA_CON05(0), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC3_EN", RK3308_ADC_ANA_CON05(1), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC4_EN", RK3308_ADC_ANA_CON05(1), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC5_EN", RK3308_ADC_ANA_CON05(2), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC6_EN", RK3308_ADC_ANA_CON05(2), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC7_EN", RK3308_ADC_ANA_CON05(3), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC8_EN", RK3308_ADC_ANA_CON05(3), 5, 1, 1, 0), -- -- SND_SOC_DAPM_ADC("ADC1_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 2, 0), -- SND_SOC_DAPM_ADC("ADC2_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 6, 0), -- SND_SOC_DAPM_ADC("ADC3_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 2, 0), -- SND_SOC_DAPM_ADC("ADC4_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 6, 0), -- SND_SOC_DAPM_ADC("ADC5_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 2, 0), -- SND_SOC_DAPM_ADC("ADC6_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 6, 0), -- SND_SOC_DAPM_ADC("ADC7_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 2, 0), -- SND_SOC_DAPM_ADC("ADC8_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 6, 0), -- -- /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */ -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_WORK", RK3308_ADC_ANA_CON02(0), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_WORK", RK3308_ADC_ANA_CON02(0), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_WORK", RK3308_ADC_ANA_CON02(1), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_WORK", RK3308_ADC_ANA_CON02(1), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_WORK", RK3308_ADC_ANA_CON02(2), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_WORK", RK3308_ADC_ANA_CON02(2), 5, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_WORK", RK3308_ADC_ANA_CON02(3), 1, 1, 1, 0), -- SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_WORK", RK3308_ADC_ANA_CON02(3), 5, 1, 1, 0), -- -- SND_SOC_DAPM_SUPPLY("MICBIAS Current", RK3308_ADC_ANA_CON08(0), 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("MICBIAS1", RK3308_ADC_ANA_CON07(1), 3, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("MICBIAS2", RK3308_ADC_ANA_CON07(2), 3, 0, NULL, 0), -- -- SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_EN", RK3308_DAC_ANA_CON13, 0, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_EN", RK3308_DAC_ANA_CON13, 4, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_WORK", RK3308_DAC_ANA_CON13, 1, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_WORK", RK3308_DAC_ANA_CON13, 5, 0, NULL, 0), -- /* HPMIX is not actually acting as a mixer as the only supported input is I2S */ -- SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_SEL", RK3308_DAC_ANA_CON12, 2, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_SEL", RK3308_DAC_ANA_CON12, 6, 0, NULL, 0), -- SND_SOC_DAPM_MIXER("DAC HPMIX Left", RK3308_DAC_ANA_CON13, 2, 0, NULL, 0), -- SND_SOC_DAPM_MIXER("DAC HPMIX Right", RK3308_DAC_ANA_CON13, 6, 0, NULL, 0), -- -- SND_SOC_DAPM_SUPPLY("DAC_MCLK_GATE", RK3308_GLB_CON, 4, 1, NULL, 0), -- -- SND_SOC_DAPM_SUPPLY("DAC_CURRENT_EN", RK3308_DAC_ANA_CON00, 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("DAC_L_REF_EN", RK3308_DAC_ANA_CON02, 0, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("DAC_R_REF_EN", RK3308_DAC_ANA_CON02, 4, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("DAC_L_CLK_EN", RK3308_DAC_ANA_CON02, 1, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("DAC_R_CLK_EN", RK3308_DAC_ANA_CON02, 5, 0, NULL, 0), -- SND_SOC_DAPM_DAC("DAC_L_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 3, 0), -- SND_SOC_DAPM_DAC("DAC_R_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 7, 0), -- -- SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_L", RK3308_DAC_ANA_CON01, 2, 0, NULL, 0), -- SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_R", RK3308_DAC_ANA_CON01, 6, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_L", SND_SOC_NOPM, 0, 0, NULL, 0, -- rk3308_codec_pop_sound_set, -- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -- SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_R", SND_SOC_NOPM, 4, 0, NULL, 0, -- rk3308_codec_pop_sound_set, -- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -- SND_SOC_DAPM_OUT_DRV("L_HPOUT_EN", RK3308_DAC_ANA_CON03, 1, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("R_HPOUT_EN", RK3308_DAC_ANA_CON03, 5, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("L_HPOUT_WORK", RK3308_DAC_ANA_CON03, 2, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("R_HPOUT_WORK", RK3308_DAC_ANA_CON03, 6, 0, NULL, 0), -- SND_SOC_DAPM_OUTPUT("HPOUT_L"), -- SND_SOC_DAPM_OUTPUT("HPOUT_R"), -- -- SND_SOC_DAPM_OUT_DRV("L_LINEOUT_EN", RK3308_DAC_ANA_CON04, 0, 0, NULL, 0), -- SND_SOC_DAPM_OUT_DRV("R_LINEOUT_EN", RK3308_DAC_ANA_CON04, 4, 0, NULL, 0), -- SND_SOC_DAPM_OUTPUT("LINEOUT_L"), -- SND_SOC_DAPM_OUTPUT("LINEOUT_R"), --}; -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); -+ return -EINVAL; -+ } - --static const struct snd_soc_dapm_route rk3308_codec_dapm_routes[] = { -- { "MICBIAS1", NULL, "MICBIAS Current" }, -- { "MICBIAS2", NULL, "MICBIAS Current" }, -- -- { "MIC1_EN", NULL, "MIC1" }, -- { "MIC2_EN", NULL, "MIC2" }, -- { "MIC3_EN", NULL, "MIC3" }, -- { "MIC4_EN", NULL, "MIC4" }, -- { "MIC5_EN", NULL, "MIC5" }, -- { "MIC6_EN", NULL, "MIC6" }, -- { "MIC7_EN", NULL, "MIC7" }, -- { "MIC8_EN", NULL, "MIC8" }, -- -- { "MIC1_WORK", NULL, "MIC1_EN" }, -- { "MIC2_WORK", NULL, "MIC2_EN" }, -- { "MIC3_WORK", NULL, "MIC3_EN" }, -- { "MIC4_WORK", NULL, "MIC4_EN" }, -- { "MIC5_WORK", NULL, "MIC5_EN" }, -- { "MIC6_WORK", NULL, "MIC6_EN" }, -- { "MIC7_WORK", NULL, "MIC7_EN" }, -- { "MIC8_WORK", NULL, "MIC8_EN" }, -- -- { "CH1_IN_SEL", NULL, "MIC1_WORK" }, -- { "CH2_IN_SEL", NULL, "MIC2_WORK" }, -- -- { "ALC1_EN", NULL, "CH1_IN_SEL" }, -- { "ALC2_EN", NULL, "CH2_IN_SEL" }, -- { "ALC3_EN", NULL, "MIC3_WORK" }, -- { "ALC4_EN", NULL, "MIC4_WORK" }, -- { "ALC5_EN", NULL, "MIC5_WORK" }, -- { "ALC6_EN", NULL, "MIC6_WORK" }, -- { "ALC7_EN", NULL, "MIC7_WORK" }, -- { "ALC8_EN", NULL, "MIC8_WORK" }, -- -- { "ADC1_EN", NULL, "ALC1_EN" }, -- { "ADC2_EN", NULL, "ALC2_EN" }, -- { "ADC3_EN", NULL, "ALC3_EN" }, -- { "ADC4_EN", NULL, "ALC4_EN" }, -- { "ADC5_EN", NULL, "ALC5_EN" }, -- { "ADC6_EN", NULL, "ALC6_EN" }, -- { "ADC7_EN", NULL, "ALC7_EN" }, -- { "ADC8_EN", NULL, "ALC8_EN" }, -- -- { "ADC1_WORK", NULL, "ADC1_EN" }, -- { "ADC2_WORK", NULL, "ADC2_EN" }, -- { "ADC3_WORK", NULL, "ADC3_EN" }, -- { "ADC4_WORK", NULL, "ADC4_EN" }, -- { "ADC5_WORK", NULL, "ADC5_EN" }, -- { "ADC6_WORK", NULL, "ADC6_EN" }, -- { "ADC7_WORK", NULL, "ADC7_EN" }, -- { "ADC8_WORK", NULL, "ADC8_EN" }, -- -- { "ADC1_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" }, -- { "ADC2_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" }, -- { "ADC3_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" }, -- { "ADC4_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" }, -- { "ADC5_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" }, -- { "ADC6_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" }, -- { "ADC7_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" }, -- { "ADC8_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" }, -- -- { "ADC1_WORK", NULL, "ADC1_BUF_REF_EN" }, -- { "ADC2_WORK", NULL, "ADC2_BUF_REF_EN" }, -- { "ADC3_WORK", NULL, "ADC3_BUF_REF_EN" }, -- { "ADC4_WORK", NULL, "ADC4_BUF_REF_EN" }, -- { "ADC5_WORK", NULL, "ADC5_BUF_REF_EN" }, -- { "ADC6_WORK", NULL, "ADC6_BUF_REF_EN" }, -- { "ADC7_WORK", NULL, "ADC7_BUF_REF_EN" }, -- { "ADC8_WORK", NULL, "ADC8_BUF_REF_EN" }, -- -- { "ADC1_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- { "ADC2_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- { "ADC3_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- { "ADC4_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- { "ADC5_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- { "ADC6_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- { "ADC7_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- { "ADC8_CLK_EN", NULL, "ADC_MCLK_GATE" }, -- -- { "ADC1_WORK", NULL, "ADC1_CLK_EN" }, -- { "ADC2_WORK", NULL, "ADC2_CLK_EN" }, -- { "ADC3_WORK", NULL, "ADC3_CLK_EN" }, -- { "ADC4_WORK", NULL, "ADC4_CLK_EN" }, -- { "ADC5_WORK", NULL, "ADC5_CLK_EN" }, -- { "ADC6_WORK", NULL, "ADC6_CLK_EN" }, -- { "ADC7_WORK", NULL, "ADC7_CLK_EN" }, -- { "ADC8_WORK", NULL, "ADC8_CLK_EN" }, -- -- { "ALC1_WORK", NULL, "ADC1_WORK" }, -- { "ALC2_WORK", NULL, "ADC2_WORK" }, -- { "ALC3_WORK", NULL, "ADC3_WORK" }, -- { "ALC4_WORK", NULL, "ADC4_WORK" }, -- { "ALC5_WORK", NULL, "ADC5_WORK" }, -- { "ALC6_WORK", NULL, "ADC6_WORK" }, -- { "ALC7_WORK", NULL, "ADC7_WORK" }, -- { "ALC8_WORK", NULL, "ADC8_WORK" }, -- -- { "HiFi Capture", NULL, "ALC1_WORK" }, -- { "HiFi Capture", NULL, "ALC2_WORK" }, -- { "HiFi Capture", NULL, "ALC3_WORK" }, -- { "HiFi Capture", NULL, "ALC4_WORK" }, -- { "HiFi Capture", NULL, "ALC5_WORK" }, -- { "HiFi Capture", NULL, "ALC6_WORK" }, -- { "HiFi Capture", NULL, "ALC7_WORK" }, -- { "HiFi Capture", NULL, "ALC8_WORK" }, -- -- { "DAC_L_HPMIX_EN", NULL, "HiFi Playback" }, -- { "DAC_R_HPMIX_EN", NULL, "HiFi Playback" }, -- { "DAC_L_HPMIX_WORK", NULL, "DAC_L_HPMIX_EN" }, -- { "DAC_R_HPMIX_WORK", NULL, "DAC_R_HPMIX_EN" }, -- { "DAC HPMIX Left", NULL, "DAC_L_HPMIX_WORK" }, -- { "DAC HPMIX Right", NULL, "DAC_R_HPMIX_WORK" }, -- -- { "DAC_L_DAC_WORK", NULL, "DAC HPMIX Left" }, -- { "DAC_R_DAC_WORK", NULL, "DAC HPMIX Right" }, -- -- { "DAC_L_REF_EN", NULL, "DAC_CURRENT_EN" }, -- { "DAC_R_REF_EN", NULL, "DAC_CURRENT_EN" }, -- { "DAC_L_CLK_EN", NULL, "DAC_L_REF_EN" }, -- { "DAC_R_CLK_EN", NULL, "DAC_R_REF_EN" }, -- { "DAC_L_CLK_EN", NULL, "DAC_MCLK_GATE" }, -- { "DAC_R_CLK_EN", NULL, "DAC_MCLK_GATE" }, -- { "DAC_L_DAC_WORK", NULL, "DAC_L_CLK_EN" }, -- { "DAC_R_DAC_WORK", NULL, "DAC_R_CLK_EN" }, -- { "DAC_L_HPMIX_SEL", NULL, "DAC_L_DAC_WORK" }, -- { "DAC_R_HPMIX_SEL", NULL, "DAC_R_DAC_WORK" }, -- -- { "HPOUT_L", NULL, "DAC_BUF_REF_L" }, -- { "HPOUT_R", NULL, "DAC_BUF_REF_R" }, -- { "L_HPOUT_EN", NULL, "DAC_L_HPMIX_SEL" }, -- { "R_HPOUT_EN", NULL, "DAC_R_HPMIX_SEL" }, -- { "L_HPOUT_WORK", NULL, "L_HPOUT_EN" }, -- { "R_HPOUT_WORK", NULL, "R_HPOUT_EN" }, -- { "HPOUT_POP_SOUND_L", NULL, "L_HPOUT_WORK" }, -- { "HPOUT_POP_SOUND_R", NULL, "R_HPOUT_WORK" }, -- { "HPOUT_L", NULL, "HPOUT_POP_SOUND_L" }, -- { "HPOUT_R", NULL, "HPOUT_POP_SOUND_R" }, -- -- { "L_LINEOUT_EN", NULL, "DAC_L_HPMIX_SEL" }, -- { "R_LINEOUT_EN", NULL, "DAC_R_HPMIX_SEL" }, -- { "LINEOUT_L", NULL, "L_LINEOUT_EN" }, -- { "LINEOUT_R", NULL, "R_LINEOUT_EN" }, --}; -+ if (e->shift_l) -+ ucontrol->value.integer.value[0] = rk3308->agc_r[e->reg]; -+ else -+ ucontrol->value.integer.value[0] = rk3308->agc_l[e->reg]; -+ -+ return 0; -+} - --static int rk3308_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, -- unsigned int fmt) -+static int rk3308_codec_agc_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) - { -- struct snd_soc_component *component = codec_dai->component; -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -- const unsigned int inv_bits = fmt & SND_SOC_DAIFMT_INV_MASK; -- const bool inv_bitclk = -- (inv_bits & SND_SOC_DAIFMT_IB_IF) || -- (inv_bits & SND_SOC_DAIFMT_IB_NF); -- const bool inv_frmclk = -- (inv_bits & SND_SOC_DAIFMT_IB_IF) || -- (inv_bits & SND_SOC_DAIFMT_NB_IF); -- const unsigned int dac_master_bits = rk3308->codec_ver < ACODEC_VERSION_C ? -- RK3308_DAC_IO_MODE_MASTER | RK3308_DAC_MODE_MASTER : -- RK3308BS_DAC_IO_MODE_MASTER | RK3308BS_DAC_MODE_MASTER; -- unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; -- bool is_master = false; -- int grp; -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int value = ucontrol->value.integer.value[0]; -+ int grp = e->reg; - -- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -- case SND_SOC_DAIFMT_CBC_CFC: -- break; -- case SND_SOC_DAIFMT_CBP_CFP: -- adc_aif2 |= RK3308_ADC_IO_MODE_MASTER; -- adc_aif2 |= RK3308_ADC_MODE_MASTER; -- dac_aif2 |= dac_master_bits; -- is_master = true; -- break; -- default: -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); - return -EINVAL; - } - -- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -- case SND_SOC_DAIFMT_DSP_A: -- adc_aif1 |= RK3308_ADC_I2S_MODE_PCM; -- dac_aif1 |= RK3308_DAC_I2S_MODE_PCM; -- break; -- case SND_SOC_DAIFMT_I2S: -- adc_aif1 |= RK3308_ADC_I2S_MODE_I2S; -- dac_aif1 |= RK3308_DAC_I2S_MODE_I2S; -- break; -- case SND_SOC_DAIFMT_RIGHT_J: -- adc_aif1 |= RK3308_ADC_I2S_MODE_RJ; -- dac_aif1 |= RK3308_DAC_I2S_MODE_RJ; -- break; -- case SND_SOC_DAIFMT_LEFT_J: -- adc_aif1 |= RK3308_ADC_I2S_MODE_LJ; -- dac_aif1 |= RK3308_DAC_I2S_MODE_LJ; -- break; -- default: -- return -EINVAL; -- } -+ if (value) { -+ /* ALC AGC On */ -+ if (e->shift_l) { -+ /* ALC AGC Right On */ -+ regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), -+ RK3308_AGC_FUNC_SEL_MSK, -+ RK3308_AGC_FUNC_SEL_EN); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), -+ RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK, -+ RK3308_ADC_ALCR_CON_GAIN_PGAR_EN); - -- if (inv_bitclk) { -- adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL; -- dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL; -- } -+ rk3308->agc_r[e->reg] = 1; -+ } else { -+ /* ALC AGC Left On */ -+ regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), -+ RK3308_AGC_FUNC_SEL_MSK, -+ RK3308_AGC_FUNC_SEL_EN); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), -+ RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK, -+ RK3308_ADC_ALCL_CON_GAIN_PGAL_EN); - -- if (inv_frmclk) { -- adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL; -- dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL; -- } -+ rk3308->agc_l[e->reg] = 1; -+ } -+ } else { -+ /* ALC AGC Off */ -+ if (e->shift_l) { -+ /* ALC AGC Right Off */ -+ regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), -+ RK3308_AGC_FUNC_SEL_MSK, -+ RK3308_AGC_FUNC_SEL_DIS); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), -+ RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK, -+ RK3308_ADC_ALCR_CON_GAIN_PGAR_DIS); - -- /* -- * Hold ADC Digital registers start at master mode -- * -- * There are 8 ADCs which use the same internal SCLK and LRCK for -- * master mode. We need to make sure that they are in effect at the -- * same time, otherwise they will cause abnormal clocks. -- */ -- if (is_master) -- regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK); -+ rk3308->agc_r[e->reg] = 0; -+ } else { -+ /* ALC AGC Left Off */ -+ regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), -+ RK3308_AGC_FUNC_SEL_MSK, -+ RK3308_AGC_FUNC_SEL_DIS); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON11(grp), -+ RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK, -+ RK3308_ADC_ALCL_CON_GAIN_PGAL_DIS); - -- for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { -- regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), -- RK3308_ADC_I2S_LRC_POL_REVERSAL | -- RK3308_ADC_I2S_MODE_MSK, -- adc_aif1); -- regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), -- RK3308_ADC_IO_MODE_MASTER | -- RK3308_ADC_MODE_MASTER | -- RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL, -- adc_aif2); -+ rk3308->agc_l[e->reg] = 0; -+ } - } - -- /* Hold ADC Digital registers end at master mode */ -- if (is_master) -- regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK); -- -- regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, -- RK3308_DAC_I2S_LRC_POL_REVERSAL | -- RK3308_DAC_I2S_MODE_MSK, -- dac_aif1); -- regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, -- dac_master_bits | RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL, -- dac_aif2); -- - return 0; - } - --static int rk3308_codec_dac_dig_config(struct rk3308_codec_priv *rk3308, -- struct snd_pcm_hw_params *params) -+static int rk3308_codec_agc_asr_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) - { -- unsigned int dac_aif1 = 0; -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int value; -+ int grp = e->reg; - -- switch (params_format(params)) { -- case SNDRV_PCM_FORMAT_S16_LE: -- dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_16BITS; -- break; -- case SNDRV_PCM_FORMAT_S20_3LE: -- dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_20BITS; -- break; -- case SNDRV_PCM_FORMAT_S24_LE: -- dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_24BITS; -- break; -- case SNDRV_PCM_FORMAT_S32_LE: -- dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_32BITS; -- break; -- default: -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); - return -EINVAL; - } - -- regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, -- RK3308_DAC_I2S_VALID_LEN_MSK, dac_aif1); -- regmap_set_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, RK3308_DAC_I2S_WORK); -+ if (e->shift_l) { -+ regmap_read(rk3308->regmap, RK3308_ALC_R_DIG_CON04(grp), &value); -+ rk3308->agc_asr_r[e->reg] = value >> RK3308_AGC_APPROX_RATE_SFT; -+ ucontrol->value.integer.value[0] = rk3308->agc_asr_r[e->reg]; -+ } else { -+ regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON04(grp), &value); -+ rk3308->agc_asr_l[e->reg] = value >> RK3308_AGC_APPROX_RATE_SFT; -+ ucontrol->value.integer.value[0] = rk3308->agc_asr_l[e->reg]; -+ } - - return 0; - } - --static int rk3308_codec_adc_dig_config(struct rk3308_codec_priv *rk3308, -- struct snd_pcm_hw_params *params) -+static int rk3308_codec_agc_asr_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) - { -- unsigned int adc_aif1 = 0; -- /* -- * grp 0 = ADC1 and ADC2 -- * grp 1 = ADC3 and ADC4 -- * grp 2 = ADC5 and ADC6 -- * grp 3 = ADC7 and ADC8 -- */ -- u32 used_adc_grps; -- int grp; -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int value; -+ int grp = e->reg; - -- switch (params_channels(params)) { -- case 1: -- adc_aif1 |= RK3308_ADC_I2S_MONO; -- used_adc_grps = 1; -- break; -- case 2: -- case 4: -- case 6: -- case 8: -- used_adc_grps = params_channels(params) / 2; -- break; -- default: -- dev_err(rk3308->dev, "Invalid channel number %d\n", params_channels(params)); -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); - return -EINVAL; - } - -- switch (params_format(params)) { -- case SNDRV_PCM_FORMAT_S16_LE: -- adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_16BITS; -- break; -- case SNDRV_PCM_FORMAT_S20_3LE: -- adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_20BITS; -- break; -- case SNDRV_PCM_FORMAT_S24_LE: -- adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_24BITS; -- break; -- case SNDRV_PCM_FORMAT_S32_LE: -- adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_32BITS; -- break; -- default: -+ value = ucontrol->value.integer.value[0] << RK3308_AGC_APPROX_RATE_SFT; -+ -+ if (e->shift_l) { -+ /* ALC AGC Right Approximate Sample Rate */ -+ regmap_update_bits(rk3308->regmap, RK3308_ALC_R_DIG_CON04(grp), -+ RK3308_AGC_APPROX_RATE_MSK, -+ value); -+ rk3308->agc_asr_r[e->reg] = ucontrol->value.integer.value[0]; -+ } else { -+ /* ALC AGC Left Approximate Sample Rate */ -+ regmap_update_bits(rk3308->regmap, RK3308_ALC_L_DIG_CON04(grp), -+ RK3308_AGC_APPROX_RATE_MSK, -+ value); -+ rk3308->agc_asr_l[e->reg] = ucontrol->value.integer.value[0]; -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_mic_mute_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int value; -+ int grp = e->reg; -+ -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); - return -EINVAL; - } - -- for (grp = 0; grp < used_adc_grps; grp++) { -- regmap_update_bits(rk3308->regmap, -- RK3308_ADC_DIG_CON03(grp), -- RK3308_ADC_L_CH_BIST_MSK | RK3308_ADC_R_CH_BIST_MSK, -- RK3308_ADC_L_CH_NORMAL_LEFT | RK3308_ADC_R_CH_NORMAL_RIGHT); -- regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), -- RK3308_ADC_I2S_VALID_LEN_MSK | RK3308_ADC_I2S_MONO, adc_aif1); -- regmap_set_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), RK3308_ADC_I2S_WORK); -+ if (e->shift_l) { -+ /* ADC MIC Right Mute/Work Infos */ -+ regmap_read(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), &value); -+ rk3308->mic_mute_r[e->reg] = (value & RK3308_ADC_R_CH_BIST_SINE) >> -+ RK3308_ADC_R_CH_BIST_SFT; -+ ucontrol->value.integer.value[0] = rk3308->mic_mute_r[e->reg]; -+ } else { -+ /* ADC MIC Left Mute/Work Infos */ -+ regmap_read(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), &value); -+ rk3308->mic_mute_l[e->reg] = (value & RK3308_ADC_L_CH_BIST_SINE) >> -+ RK3308_ADC_L_CH_BIST_SFT; -+ ucontrol->value.integer.value[0] = rk3308->mic_mute_l[e->reg]; - } - - return 0; - } - --static int rk3308_codec_hw_params(struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params, -- struct snd_soc_dai *dai) -+static int rk3308_codec_mic_mute_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) - { -- struct snd_soc_component *component = dai->component; -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int value; -+ int grp = e->reg; - -- return (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? -- rk3308_codec_dac_dig_config(rk3308, params) : -- rk3308_codec_adc_dig_config(rk3308, params); --} -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); -+ return -EINVAL; -+ } - --static const struct snd_soc_dai_ops rk3308_codec_dai_ops = { -- .hw_params = rk3308_codec_hw_params, -- .set_fmt = rk3308_codec_set_dai_fmt, --}; -+ if (e->shift_l) { -+ /* ADC MIC Right Mute/Work Configuration */ -+ value = ucontrol->value.integer.value[0] << RK3308_ADC_R_CH_BIST_SFT; -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_R_CH_BIST_SINE, -+ value); -+ rk3308->mic_mute_r[e->reg] = ucontrol->value.integer.value[0]; -+ } else { -+ /* ADC MIC Left Mute/Work Configuration */ -+ value = ucontrol->value.integer.value[0] << RK3308_ADC_L_CH_BIST_SFT; -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_L_CH_BIST_SINE, -+ value); -+ rk3308->mic_mute_l[e->reg] = ucontrol->value.integer.value[0]; -+ } - --static struct snd_soc_dai_driver rk3308_codec_dai_driver = { -- .name = "rk3308-hifi", -- .playback = { -- .stream_name = "HiFi Playback", -- .channels_min = 2, -- .channels_max = 2, -- .rates = SNDRV_PCM_RATE_8000_192000, -- .formats = (SNDRV_PCM_FMTBIT_S16_LE | -- SNDRV_PCM_FMTBIT_S20_3LE | -- SNDRV_PCM_FMTBIT_S24_LE | -- SNDRV_PCM_FMTBIT_S32_LE), -- }, -- .capture = { -- .stream_name = "HiFi Capture", -- .channels_min = 1, -- .channels_max = 8, -- .rates = SNDRV_PCM_RATE_8000_192000, -- .formats = (SNDRV_PCM_FMTBIT_S16_LE | -- SNDRV_PCM_FMTBIT_S20_3LE | -- SNDRV_PCM_FMTBIT_S24_LE | -- SNDRV_PCM_FMTBIT_S32_LE), -- }, -- .ops = &rk3308_codec_dai_ops, --}; -+ return 0; -+} - --static void rk3308_codec_reset(struct snd_soc_component *component) -+static int rk3308_codec_micbias_volts_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) - { -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); - -- reset_control_assert(rk3308->reset); -- usleep_range(10000, 11000); /* estimated value */ -- reset_control_deassert(rk3308->reset); -+ ucontrol->value.integer.value[0] = rk3308->micbias_volt; - -- regmap_write(rk3308->regmap, RK3308_GLB_CON, 0x00); -- usleep_range(10000, 11000); /* estimated value */ -- regmap_write(rk3308->regmap, RK3308_GLB_CON, -- RK3308_SYS_WORK | -- RK3308_DAC_DIG_WORK | -- RK3308_ADC_DIG_WORK); -+ return 0; - } - --/* -- * Initialize register whose default after HW reset is problematic or which -- * are never modified. -- */ --static int rk3308_codec_initialize(struct rk3308_codec_priv *rk3308) -+static int rk3308_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) - { -- int grp; -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ unsigned int volt = ucontrol->value.integer.value[0]; -+ int ret; - -- /* -- * Init ADC digital vol to 0 dB (reset value is 0xff, undocumented). -- * Range: -97dB ~ +32dB. -- */ -- if (rk3308->codec_ver == ACODEC_VERSION_C) { -- for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { -- regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON05(grp), -- RK3308_ADC_DIG_VOL_CON_x_0DB); -- regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON06(grp), -- RK3308_ADC_DIG_VOL_CON_x_0DB); -- } -+ ret = check_micbias(volt); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, "The invalid micbias volt: %d\n", -+ volt); -+ return ret; - } - -- /* set HPMIX default gains (reset value is 0, which is illegal) */ -- regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, -- RK3308_DAC_L_HPMIX_GAIN_MSK | -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), -+ RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK, -+ volt); -+ -+ rk3308->micbias_volt = volt; -+ -+ return 0; -+} -+ -+static int rk3308_codec_main_micbias_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ ucontrol->value.integer.value[0] = rk3308->enable_micbias; -+ -+ return 0; -+} -+ -+static int rk3308_codec_main_micbias_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ unsigned int on = ucontrol->value.integer.value[0]; -+ -+ if (on) { -+ if (!rk3308->enable_micbias) -+ rk3308_codec_micbias_enable(rk3308, rk3308->micbias_volt); -+ } else { -+ if (rk3308->enable_micbias) -+ rk3308_codec_micbias_disable(rk3308); -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_mic_gain_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ return snd_soc_get_volsw_range(kcontrol, ucontrol); -+} -+ -+static int rk3308_codec_mic_gain_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ unsigned int gain = ucontrol->value.integer.value[0]; -+ -+ if (gain > RK3308_ADC_CH1_MIC_GAIN_MAX) { -+ dev_err(rk3308->plat_dev, "%s: invalid mic gain: %d\n", -+ __func__, gain); -+ return -EINVAL; -+ } -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_A) { -+ /* -+ * From the TRM, there are only suupport 0dB(gain==0) and -+ * 20dB(gain==3) on the codec version A. -+ */ -+ if (!(gain == 0 || gain == RK3308_ADC_CH1_MIC_GAIN_MAX)) { -+ dev_err(rk3308->plat_dev, -+ "version A doesn't supported: %d, expect: 0,%d\n", -+ gain, RK3308_ADC_CH1_MIC_GAIN_MAX); -+ return 0; -+ } -+ } -+ -+ return snd_soc_put_volsw_range(kcontrol, ucontrol); -+} -+ -+static int rk3308_codec_hpf_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int value; -+ -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); -+ return -EINVAL; -+ } -+ -+ regmap_read(rk3308->regmap, RK3308_ADC_DIG_CON04(e->reg), &value); -+ if (value & RK3308_ADC_HPF_PATH_MSK) -+ rk3308->hpf_cutoff[e->reg] = 0; -+ else -+ rk3308->hpf_cutoff[e->reg] = 1; -+ -+ ucontrol->value.integer.value[0] = rk3308->hpf_cutoff[e->reg]; -+ -+ return 0; -+} -+ -+static int rk3308_codec_hpf_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int value = ucontrol->value.integer.value[0]; -+ -+ if (e->reg < 0 || e->reg > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "%s: Invalid ADC grp: %d\n", __func__, e->reg); -+ return -EINVAL; -+ } -+ -+ if (value) { -+ /* Enable high pass filter for ADCs */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON04(e->reg), -+ RK3308_ADC_HPF_PATH_MSK, -+ RK3308_ADC_HPF_PATH_EN); -+ } else { -+ /* Disable high pass filter for ADCs. */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON04(e->reg), -+ RK3308_ADC_HPF_PATH_MSK, -+ RK3308_ADC_HPF_PATH_DIS); -+ } -+ -+ rk3308->hpf_cutoff[e->reg] = value; -+ -+ return 0; -+} -+ -+static int rk3308_codec_hpout_l_get_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ return snd_soc_get_volsw_range(kcontrol, ucontrol); -+} -+ -+static int rk3308_codec_hpout_l_put_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ unsigned int dgain = ucontrol->value.integer.value[0]; -+ -+ if (dgain > RK3308_DAC_L_HPOUT_GAIN_MAX) { -+ dev_err(rk3308->plat_dev, "%s: invalid l_dgain: %d\n", -+ __func__, dgain); -+ return -EINVAL; -+ } -+ -+ rk3308->hpout_l_dgain = dgain; -+ -+ return snd_soc_put_volsw_range(kcontrol, ucontrol); -+} -+ -+static int rk3308_codec_hpout_r_get_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ return snd_soc_get_volsw_range(kcontrol, ucontrol); -+} -+ -+static int rk3308_codec_hpout_r_put_tlv(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ unsigned int dgain = ucontrol->value.integer.value[0]; -+ -+ if (dgain > RK3308_DAC_R_HPOUT_GAIN_MAX) { -+ dev_err(rk3308->plat_dev, "%s: invalid r_dgain: %d\n", -+ __func__, dgain); -+ return -EINVAL; -+ } -+ -+ rk3308->hpout_r_dgain = dgain; -+ -+ return snd_soc_put_volsw_range(kcontrol, ucontrol); -+} -+ -+static u32 to_mapped_grp(struct rk3308_codec_priv *rk3308, int idx) -+{ -+ return rk3308->i2s_sdis[idx]; -+} -+ -+static bool adc_for_each_grp(struct rk3308_codec_priv *rk3308, -+ int type, int idx, u32 *grp) -+{ -+ if (type == ADC_TYPE_NORMAL) { -+ u32 mapped_grp = to_mapped_grp(rk3308, idx); -+ int max_grps; -+ -+ if (rk3308->enable_all_adcs) -+ max_grps = ADC_LR_GROUP_MAX; -+ else -+ max_grps = rk3308->used_adc_grps; -+ -+ if (idx >= max_grps) -+ return false; -+ -+ if ((!rk3308->loopback_dacs_enabled) && -+ handle_loopback(rk3308) && -+ rk3308->loopback_grp == mapped_grp) { -+ /* -+ * Ths loopback DACs are closed, and specify the -+ * loopback ADCs. -+ */ -+ *grp = ADC_GRP_SKIP_MAGIC; -+ } else if (rk3308->en_always_grps_num && -+ rk3308->skip_grps[mapped_grp]) { -+ /* To set the skip flag if the ADC GRP is enabled. */ -+ *grp = ADC_GRP_SKIP_MAGIC; -+ } else { -+ *grp = mapped_grp; -+ } -+ -+ dev_dbg(rk3308->plat_dev, -+ "ADC_TYPE_NORMAL, idx: %d, mapped_grp: %d, get grp: %d,\n", -+ idx, mapped_grp, *grp); -+ } else if (type == ADC_TYPE_ALL) { -+ if (idx >= ADC_LR_GROUP_MAX) -+ return false; -+ -+ *grp = idx; -+ dev_dbg(rk3308->plat_dev, -+ "ADC_TYPE_ALL, idx: %d, get grp: %d\n", -+ idx, *grp); -+ } else if (type == ADC_TYPE_DBG) { -+ if (idx >= ADC_LR_GROUP_MAX) -+ return false; -+ -+ if (idx == (int)rk3308->cur_dbg_grp) -+ *grp = idx; -+ else -+ *grp = ADC_GRP_SKIP_MAGIC; -+ -+ dev_dbg(rk3308->plat_dev, -+ "ADC_TYPE_DBG, idx: %d, get grp: %d\n", -+ idx, *grp); -+ } else { -+ if (idx >= 1) -+ return false; -+ -+ *grp = rk3308->loopback_grp; -+ dev_dbg(rk3308->plat_dev, -+ "ADC_TYPE_LOOPBACK, idx: %d, get grp: %d\n", -+ idx, *grp); -+ } -+ -+ return true; -+} -+ -+static int rk3308_codec_get_dac_path_state(struct rk3308_codec_priv *rk3308) -+{ -+ return rk3308->dac_path_state; -+} -+ -+static void rk3308_codec_set_dac_path_state(struct rk3308_codec_priv *rk3308, -+ int state) -+{ -+ rk3308->dac_path_state = state; -+} -+ -+static void rk3308_headphone_ctl(struct rk3308_codec_priv *rk3308, int on) -+{ -+ if (rk3308->hp_ctl_gpio) -+ gpiod_direction_output(rk3308->hp_ctl_gpio, on); -+} -+ -+static void rk3308_speaker_ctl(struct rk3308_codec_priv *rk3308, int on) -+{ -+ if (on) { -+ if (rk3308->pa_drv_gpio) { -+ gpiod_direction_output(rk3308->pa_drv_gpio, on); -+ msleep(rk3308->delay_pa_drv_ms); -+ } -+ -+ if (rk3308->spk_ctl_gpio) -+ gpiod_direction_output(rk3308->spk_ctl_gpio, on); -+ } else { -+ if (rk3308->spk_ctl_gpio) -+ gpiod_direction_output(rk3308->spk_ctl_gpio, on); -+ -+ if (rk3308->pa_drv_gpio) { -+ msleep(rk3308->delay_pa_drv_ms); -+ gpiod_direction_output(rk3308->pa_drv_gpio, on); -+ } -+ } -+} -+ -+static int rk3308_codec_reset(struct snd_soc_component *component) -+{ -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ reset_control_assert(rk3308->reset); -+ usleep_range(2000, 2500); /* estimated value */ -+ reset_control_deassert(rk3308->reset); -+ -+ regmap_write(rk3308->regmap, RK3308_GLB_CON, 0x00); -+ usleep_range(200, 300); /* estimated value */ -+ regmap_write(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_SYS_WORK | -+ RK3308_DAC_DIG_WORK | -+ RK3308_ADC_DIG_WORK); -+ -+ return 0; -+} -+ -+static int rk3308_codec_adc_dig_reset(struct rk3308_codec_priv *rk3308) -+{ -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_ADC_DIG_WORK, -+ RK3308_ADC_DIG_RESET); -+ udelay(50); -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_ADC_DIG_WORK, -+ RK3308_ADC_DIG_WORK); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_dig_reset(struct rk3308_codec_priv *rk3308) -+{ -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_DAC_DIG_WORK, -+ RK3308_DAC_DIG_RESET); -+ udelay(50); -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_DAC_DIG_WORK, -+ RK3308_DAC_DIG_WORK); -+ -+ return 0; -+} -+ -+static int rk3308_set_bias_level(struct snd_soc_component *component, -+ enum snd_soc_bias_level level) -+{ -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ switch (level) { -+ case SND_SOC_BIAS_ON: -+ break; -+ case SND_SOC_BIAS_PREPARE: -+ break; -+ case SND_SOC_BIAS_STANDBY: -+ regcache_cache_only(rk3308->regmap, false); -+ regcache_sync(rk3308->regmap); -+ break; -+ case SND_SOC_BIAS_OFF: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int rk3308_set_dai_fmt(struct snd_soc_dai *dai, -+ unsigned int fmt) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; -+ int idx, grp, is_master; -+ int type = ADC_TYPE_ALL; -+ -+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBS_CFS: -+ adc_aif2 |= RK3308_ADC_IO_MODE_SLAVE; -+ adc_aif2 |= RK3308_ADC_MODE_SLAVE; -+ dac_aif2 |= RK3308_DAC_IO_MODE_SLAVE; -+ dac_aif2 |= RK3308_DAC_MODE_SLAVE; -+ is_master = 0; -+ break; -+ case SND_SOC_DAIFMT_CBM_CFM: -+ adc_aif2 |= RK3308_ADC_IO_MODE_MASTER; -+ adc_aif2 |= RK3308_ADC_MODE_MASTER; -+ dac_aif2 |= RK3308_DAC_IO_MODE_MASTER; -+ dac_aif2 |= RK3308_DAC_MODE_MASTER; -+ is_master = 1; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_DSP_A: -+ adc_aif1 |= RK3308_ADC_I2S_MODE_PCM; -+ dac_aif1 |= RK3308_DAC_I2S_MODE_PCM; -+ break; -+ case SND_SOC_DAIFMT_I2S: -+ adc_aif1 |= RK3308_ADC_I2S_MODE_I2S; -+ dac_aif1 |= RK3308_DAC_I2S_MODE_I2S; -+ break; -+ case SND_SOC_DAIFMT_RIGHT_J: -+ adc_aif1 |= RK3308_ADC_I2S_MODE_RJ; -+ dac_aif1 |= RK3308_DAC_I2S_MODE_RJ; -+ break; -+ case SND_SOC_DAIFMT_LEFT_J: -+ adc_aif1 |= RK3308_ADC_I2S_MODE_LJ; -+ dac_aif1 |= RK3308_DAC_I2S_MODE_LJ; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { -+ case SND_SOC_DAIFMT_NB_NF: -+ adc_aif1 |= RK3308_ADC_I2S_LRC_POL_NORMAL; -+ adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_NORMAL; -+ dac_aif1 |= RK3308_DAC_I2S_LRC_POL_NORMAL; -+ dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_NORMAL; -+ break; -+ case SND_SOC_DAIFMT_IB_IF: -+ adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL; -+ adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL; -+ dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL; -+ dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL; -+ break; -+ case SND_SOC_DAIFMT_IB_NF: -+ adc_aif1 |= RK3308_ADC_I2S_LRC_POL_NORMAL; -+ adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL; -+ dac_aif1 |= RK3308_DAC_I2S_LRC_POL_NORMAL; -+ dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL; -+ break; -+ case SND_SOC_DAIFMT_NB_IF: -+ adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL; -+ adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_NORMAL; -+ dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL; -+ dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_NORMAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* -+ * Hold ADC Digital registers start at master mode -+ * -+ * There are 8 ADCs and use the same SCLK and LRCK internal for master -+ * mode, We need to make sure that they are in effect at the same time, -+ * otherwise they will cause the abnormal clocks. -+ */ -+ if (is_master) -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_ADC_DIG_WORK, -+ RK3308_ADC_DIG_RESET); -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), -+ RK3308_ADC_I2S_LRC_POL_MSK | -+ RK3308_ADC_I2S_MODE_MSK, -+ adc_aif1); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), -+ RK3308_ADC_IO_MODE_MSK | -+ RK3308_ADC_MODE_MSK | -+ RK3308_ADC_I2S_BIT_CLK_POL_MSK, -+ adc_aif2); -+ } -+ -+ /* Hold ADC Digital registers end at master mode */ -+ if (is_master) -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_ADC_DIG_WORK, -+ RK3308_ADC_DIG_WORK); -+ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, -+ RK3308_DAC_I2S_LRC_POL_MSK | -+ RK3308_DAC_I2S_MODE_MSK, -+ dac_aif1); -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, -+ RK3308_DAC_IO_MODE_MSK | -+ RK3308_DAC_MODE_MSK | -+ RK3308_DAC_I2S_BIT_CLK_POL_MSK, -+ dac_aif2); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_dig_config(struct rk3308_codec_priv *rk3308, -+ struct snd_pcm_hw_params *params) -+{ -+ unsigned int dac_aif1 = 0, dac_aif2 = 0; -+ -+ /* Clear the status of DAC DIG Digital reigisters */ -+ rk3308_codec_dac_dig_reset(rk3308); -+ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S16_LE: -+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_16BITS; -+ break; -+ case SNDRV_PCM_FORMAT_S20_3LE: -+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_20BITS; -+ break; -+ case SNDRV_PCM_FORMAT_S24_LE: -+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_24BITS; -+ break; -+ case SNDRV_PCM_FORMAT_S32_LE: -+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_32BITS; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ dac_aif1 |= RK3308_DAC_I2S_LR_NORMAL; -+ dac_aif2 |= RK3308_DAC_I2S_WORK; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01, -+ RK3308_DAC_I2S_VALID_LEN_MSK | -+ RK3308_DAC_I2S_LR_MSK, -+ dac_aif1); -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, -+ RK3308_DAC_I2S_MSK, -+ dac_aif2); -+ -+ return 0; -+} -+ -+static int rk3308_codec_adc_dig_config(struct rk3308_codec_priv *rk3308, -+ struct snd_pcm_hw_params *params) -+{ -+ unsigned int adc_aif1 = 0, adc_aif2 = 0; -+ int type = ADC_TYPE_NORMAL; -+ int idx, grp; -+ -+ /* Clear the status of ADC DIG Digital reigisters */ -+ rk3308_codec_adc_dig_reset(rk3308); -+ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S16_LE: -+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_16BITS; -+ break; -+ case SNDRV_PCM_FORMAT_S20_3LE: -+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_20BITS; -+ break; -+ case SNDRV_PCM_FORMAT_S24_LE: -+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_24BITS; -+ break; -+ case SNDRV_PCM_FORMAT_S32_LE: -+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_32BITS; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ switch (params_channels(params)) { -+ case 1: -+ adc_aif1 |= RK3308_ADC_I2S_MONO; -+ break; -+ case 2: -+ case 4: -+ case 6: -+ case 8: -+ adc_aif1 |= RK3308_ADC_I2S_STEREO; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ adc_aif1 |= RK3308_ADC_I2S_LR_NORMAL; -+ adc_aif2 |= RK3308_ADC_I2S_WORK; -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp), -+ RK3308_ADC_I2S_VALID_LEN_MSK | -+ RK3308_ADC_I2S_LR_MSK | -+ RK3308_ADC_I2S_TYPE_MSK, -+ adc_aif1); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), -+ RK3308_ADC_I2S_MSK, -+ adc_aif2); -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_update_adc_grps(struct rk3308_codec_priv *rk3308, -+ struct snd_pcm_hw_params *params) -+{ -+ switch (params_channels(params)) { -+ case 1: -+ rk3308->used_adc_grps = 1; -+ break; -+ case 2: -+ case 4: -+ case 6: -+ case 8: -+ rk3308->used_adc_grps = params_channels(params) / 2; -+ break; -+ default: -+ dev_err(rk3308->plat_dev, "Invalid channels: %d\n", -+ params_channels(params)); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int rk3308_mute_stream(struct snd_soc_dai *dai, int mute, int stream) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ int dgain; -+ -+ if (mute) { -+ for (dgain = 0x2; dgain <= 0x7; dgain++) { -+ /* -+ * Keep the max -> min digital CIC interpolation -+ * filter gain step by step. -+ * -+ * loud: 0x2; whisper: 0x7 -+ */ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_DAC_DIG_CON04, -+ RK3308_DAC_CIC_IF_GAIN_MSK, -+ dgain); -+ usleep_range(200, 300); /* estimated value */ -+ } -+ -+#if !DEBUG_POP_ALWAYS -+ rk3308_headphone_ctl(rk3308, 0); -+ rk3308_speaker_ctl(rk3308, 0); -+#endif -+ } else { -+#if !DEBUG_POP_ALWAYS -+ if (rk3308->dac_output == DAC_LINEOUT) -+ rk3308_speaker_ctl(rk3308, 1); -+ else if (rk3308->dac_output == DAC_HPOUT) -+ rk3308_headphone_ctl(rk3308, 1); -+ -+ if (rk3308->delay_start_play_ms) -+ msleep(rk3308->delay_start_play_ms); -+#endif -+ for (dgain = 0x7; dgain >= 0x2; dgain--) { -+ /* -+ * Keep the min -> max digital CIC interpolation -+ * filter gain step by step -+ * -+ * loud: 0x2; whisper: 0x7 -+ */ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_DAC_DIG_CON04, -+ RK3308_DAC_CIC_IF_GAIN_MSK, -+ dgain); -+ usleep_range(200, 300); /* estimated value */ -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_digital_fadein(struct rk3308_codec_priv *rk3308) -+{ -+ unsigned int dgain, dgain_ref; -+ -+ if (rk3308->hpout_l_dgain != rk3308->hpout_r_dgain) { -+ pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n", -+ rk3308->hpout_l_dgain, rk3308->hpout_r_dgain); -+ dgain_ref = min(rk3308->hpout_l_dgain, rk3308->hpout_r_dgain); -+ } else { -+ dgain_ref = rk3308->hpout_l_dgain; -+ } -+ -+ /* -+ * We'd better change the gain of the left and right channels -+ * at the same time to avoid different listening -+ */ -+ for (dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39; -+ dgain <= dgain_ref; dgain++) { -+ /* Step 02 decrease dgains for de-pop */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, -+ RK3308_DAC_L_HPOUT_GAIN_MSK, -+ dgain); -+ -+ /* Step 02 decrease dgains for de-pop */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, -+ RK3308_DAC_R_HPOUT_GAIN_MSK, -+ dgain); -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_digital_fadeout(struct rk3308_codec_priv *rk3308) -+{ -+ unsigned int l_dgain, r_dgain; -+ -+ /* -+ * Note. In the step2, adjusting the register step by step to -+ * the appropriate value and taking 20ms as time step -+ */ -+ regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON05, &l_dgain); -+ l_dgain &= RK3308_DAC_L_HPOUT_GAIN_MSK; -+ -+ regmap_read(rk3308->regmap, RK3308_DAC_ANA_CON06, &r_dgain); -+ r_dgain &= RK3308_DAC_R_HPOUT_GAIN_MSK; -+ -+ if (l_dgain != r_dgain) { -+ pr_warn("HPOUT l_dgain: 0x%x != r_dgain: 0x%x\n", -+ l_dgain, r_dgain); -+ l_dgain = min(l_dgain, r_dgain); -+ } -+ -+ /* -+ * We'd better change the gain of the left and right channels -+ * at the same time to avoid different listening -+ */ -+ while (l_dgain >= RK3308_DAC_L_HPOUT_GAIN_NDB_39) { -+ /* Step 02 decrease dgains for de-pop */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, -+ RK3308_DAC_L_HPOUT_GAIN_MSK, -+ l_dgain); -+ -+ /* Step 02 decrease dgains for de-pop */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, -+ RK3308_DAC_R_HPOUT_GAIN_MSK, -+ l_dgain); -+ -+ usleep_range(200, 300); /* estimated value */ -+ -+ if (l_dgain == RK3308_DAC_L_HPOUT_GAIN_NDB_39) -+ break; -+ -+ l_dgain--; -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_lineout_enable(struct rk3308_codec_priv *rk3308) -+{ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* Step 04 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, -+ RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_L_SEL_DC_FROM_INTERNAL | -+ RK3308_DAC_R_SEL_DC_FROM_INTERNAL); -+ } -+ -+ /* Step 07 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_EN | -+ RK3308_DAC_R_LINEOUT_EN, -+ RK3308_DAC_L_LINEOUT_EN | -+ RK3308_DAC_R_LINEOUT_EN); -+ -+ udelay(20); -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* Step 10 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, -+ RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL | -+ RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL); -+ -+ udelay(20); -+ } -+ -+ /* Step 19 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_UNMUTE | -+ RK3308_DAC_R_LINEOUT_UNMUTE, -+ RK3308_DAC_L_LINEOUT_UNMUTE | -+ RK3308_DAC_R_LINEOUT_UNMUTE); -+ udelay(20); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_lineout_disable(struct rk3308_codec_priv *rk3308) -+{ -+ /* Step 08 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_UNMUTE | -+ RK3308_DAC_R_LINEOUT_UNMUTE, -+ RK3308_DAC_L_LINEOUT_MUTE | -+ RK3308_DAC_R_LINEOUT_MUTE); -+ -+ /* Step 09 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_EN | -+ RK3308_DAC_R_LINEOUT_EN, -+ RK3308_DAC_L_LINEOUT_DIS | -+ RK3308_DAC_R_LINEOUT_DIS); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_hpout_enable(struct rk3308_codec_priv *rk3308) -+{ -+ /* Step 03 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_HPOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_HPOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_HPOUT_POP_SOUND_L_WORK | -+ RK3308_DAC_HPOUT_POP_SOUND_R_WORK); -+ -+ udelay(20); -+ -+ /* Step 07 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_EN | -+ RK3308_DAC_R_HPOUT_EN, -+ RK3308_DAC_L_HPOUT_EN | -+ RK3308_DAC_R_HPOUT_EN); -+ -+ udelay(20); -+ -+ /* Step 08 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_WORK | -+ RK3308_DAC_R_HPOUT_WORK, -+ RK3308_DAC_L_HPOUT_WORK | -+ RK3308_DAC_R_HPOUT_WORK); -+ -+ udelay(20); -+ -+ /* Step 16 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_UNMUTE | -+ RK3308_DAC_R_HPOUT_UNMUTE, -+ RK3308_DAC_L_HPOUT_UNMUTE | -+ RK3308_DAC_R_HPOUT_UNMUTE); -+ -+ udelay(20); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_hpout_disable(struct rk3308_codec_priv *rk3308) -+{ -+ /* Step 03 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_HPOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_HPOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_HPOUT_POP_SOUND_L_INIT | -+ RK3308_DAC_HPOUT_POP_SOUND_R_INIT); -+ -+ /* Step 07 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_EN | -+ RK3308_DAC_R_HPOUT_EN, -+ RK3308_DAC_L_HPOUT_DIS | -+ RK3308_DAC_R_HPOUT_DIS); -+ -+ /* Step 08 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_WORK | -+ RK3308_DAC_R_HPOUT_WORK, -+ RK3308_DAC_L_HPOUT_INIT | -+ RK3308_DAC_R_HPOUT_INIT); -+ -+ /* Step 16 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_UNMUTE | -+ RK3308_DAC_R_HPOUT_UNMUTE, -+ RK3308_DAC_L_HPOUT_MUTE | -+ RK3308_DAC_R_HPOUT_MUTE); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_switch(struct rk3308_codec_priv *rk3308, -+ int dac_output) -+{ int ret = 0; -+ -+ if (rk3308->dac_output == dac_output) { -+ dev_info(rk3308->plat_dev, -+ "Don't need to change dac_output: %d\n", dac_output); -+ goto out; -+ } -+ -+ switch (dac_output) { -+ case DAC_LINEOUT: -+ case DAC_HPOUT: -+ case DAC_LINEOUT_HPOUT: -+ break; -+ default: -+ dev_err(rk3308->plat_dev, "Unknown value: %d\n", dac_output); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ if (rk3308_codec_get_dac_path_state(rk3308) == PATH_BUSY) { -+ /* -+ * We can only switch the audio path to LINEOUT or HPOUT on -+ * codec during playbacking, otherwise, just update the -+ * dac_output flag. -+ */ -+ switch (dac_output) { -+ case DAC_LINEOUT: -+ rk3308_headphone_ctl(rk3308, 0); -+ rk3308_speaker_ctl(rk3308, 1); -+ rk3308_codec_dac_hpout_disable(rk3308); -+ rk3308_codec_dac_lineout_enable(rk3308); -+ break; -+ case DAC_HPOUT: -+ rk3308_speaker_ctl(rk3308, 0); -+ rk3308_headphone_ctl(rk3308, 1); -+ rk3308_codec_dac_lineout_disable(rk3308); -+ rk3308_codec_dac_hpout_enable(rk3308); -+ break; -+ case DAC_LINEOUT_HPOUT: -+ rk3308_speaker_ctl(rk3308, 1); -+ rk3308_headphone_ctl(rk3308, 1); -+ rk3308_codec_dac_lineout_enable(rk3308); -+ rk3308_codec_dac_hpout_enable(rk3308); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ rk3308->dac_output = dac_output; -+out: -+ dev_dbg(rk3308->plat_dev, "switch dac_output to: %d\n", -+ rk3308->dac_output); -+ -+ return ret; -+} -+ -+static int rk3308_codec_dac_enable(struct rk3308_codec_priv *rk3308) -+{ -+ /* -+ * Note1. If the ACODEC_DAC_ANA_CON12[6] or ACODEC_DAC_ANA_CON12[2] -+ * is set to 0x1, ignoring the step9~12. -+ */ -+ -+ /* -+ * Note2. If the ACODEC_ DAC_ANA_CON12[7] or ACODEC_DAC_ANA_CON12[3] -+ * is set to 0x1, the ADC0 or ADC1 should be enabled firstly, and -+ * please refer to Enable ADC Configuration Standard Usage Flow(expect -+ * step7~step9,step14). -+ */ -+ -+ /* -+ * Note3. If no opening the line out, ignoring the step6, step17 and -+ * step19. -+ */ -+ -+ /* -+ * Note4. If no opening the headphone out, ignoring the step3,step7~8, -+ * step16 and step18. -+ */ -+ -+ /* -+ * Note5. In the step18, adjust the register step by step to the -+ * appropriate value and taking 10ms as one time step -+ */ -+ -+ /* -+ * 1. Set the ACODEC_DAC_ANA_CON0[0] to 0x1, to enable the current -+ * source of DAC -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, -+ RK3308_DAC_CURRENT_MSK, -+ RK3308_DAC_CURRENT_EN); -+ -+ udelay(20); -+ -+ /* -+ * 2. Set the ACODEC_DAC_ANA_CON1[6] and ACODEC_DAC_ANA_CON1[2] to 0x1, -+ * to enable the reference voltage buffer -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_BUF_REF_L_MSK | -+ RK3308_DAC_BUF_REF_R_MSK, -+ RK3308_DAC_BUF_REF_L_EN | -+ RK3308_DAC_BUF_REF_R_EN); -+ -+ /* Waiting the stable reference voltage */ -+ mdelay(1); -+ -+ if (rk3308->dac_output == DAC_HPOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT) { -+ /* Step 03 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_HPOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_HPOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_HPOUT_POP_SOUND_L_WORK | -+ RK3308_DAC_HPOUT_POP_SOUND_R_WORK); -+ -+ udelay(20); -+ } -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B && -+ (rk3308->dac_output == DAC_LINEOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT)) { -+ /* Step 04 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, -+ RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_L_SEL_DC_FROM_INTERNAL | -+ RK3308_DAC_R_SEL_DC_FROM_INTERNAL); -+ -+ udelay(20); -+ } -+ -+ /* Step 05 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, -+ RK3308_DAC_L_HPMIX_EN | -+ RK3308_DAC_R_HPMIX_EN, -+ RK3308_DAC_L_HPMIX_EN | -+ RK3308_DAC_R_HPMIX_EN); -+ -+ /* Waiting the stable HPMIX */ -+ mdelay(1); -+ -+ /* Step 06. Reset HPMIX and recover HPMIX gains */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, -+ RK3308_DAC_L_HPMIX_WORK | -+ RK3308_DAC_R_HPMIX_WORK, -+ RK3308_DAC_L_HPMIX_INIT | -+ RK3308_DAC_R_HPMIX_INIT); -+ udelay(50); -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, -+ RK3308_DAC_L_HPMIX_WORK | -+ RK3308_DAC_R_HPMIX_WORK, -+ RK3308_DAC_L_HPMIX_WORK | -+ RK3308_DAC_R_HPMIX_WORK); -+ -+ udelay(20); -+ -+ if (rk3308->dac_output == DAC_LINEOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT) { -+ /* Step 07 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_EN | -+ RK3308_DAC_R_LINEOUT_EN, -+ RK3308_DAC_L_LINEOUT_EN | -+ RK3308_DAC_R_LINEOUT_EN); -+ -+ udelay(20); -+ } -+ -+ if (rk3308->dac_output == DAC_HPOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT) { -+ /* Step 08 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_EN | -+ RK3308_DAC_R_HPOUT_EN, -+ RK3308_DAC_L_HPOUT_EN | -+ RK3308_DAC_R_HPOUT_EN); -+ -+ udelay(20); -+ -+ /* Step 09 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_WORK | -+ RK3308_DAC_R_HPOUT_WORK, -+ RK3308_DAC_L_HPOUT_WORK | -+ RK3308_DAC_R_HPOUT_WORK); -+ -+ udelay(20); -+ } -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* Step 10 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, -+ RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL | -+ RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL); -+ -+ udelay(20); -+ } -+ -+ /* Step 11 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_REF_EN | -+ RK3308_DAC_R_REF_EN, -+ RK3308_DAC_L_REF_EN | -+ RK3308_DAC_R_REF_EN); -+ -+ udelay(20); -+ -+ /* Step 12 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_CLK_EN | -+ RK3308_DAC_R_CLK_EN, -+ RK3308_DAC_L_CLK_EN | -+ RK3308_DAC_R_CLK_EN); -+ -+ udelay(20); -+ -+ /* Step 13 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_DAC_EN | -+ RK3308_DAC_R_DAC_EN, -+ RK3308_DAC_L_DAC_EN | -+ RK3308_DAC_R_DAC_EN); -+ -+ udelay(20); -+ -+ /* Step 14 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_DAC_WORK | -+ RK3308_DAC_R_DAC_WORK, -+ RK3308_DAC_L_DAC_WORK | -+ RK3308_DAC_R_DAC_WORK); -+ -+ udelay(20); -+ -+ /* Step 15 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, -+ RK3308_DAC_L_HPMIX_SEL_MSK | -+ RK3308_DAC_R_HPMIX_SEL_MSK, -+ RK3308_DAC_L_HPMIX_I2S | -+ RK3308_DAC_R_HPMIX_I2S); -+ -+ udelay(20); -+ -+ /* Step 16 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, -+ RK3308_DAC_L_HPMIX_UNMUTE | -+ RK3308_DAC_R_HPMIX_UNMUTE, -+ RK3308_DAC_L_HPMIX_UNMUTE | -+ RK3308_DAC_R_HPMIX_UNMUTE); -+ -+ udelay(20); -+ -+ /* Step 17: Put configuration HPMIX Gain to DAPM */ -+ -+ if (rk3308->dac_output == DAC_HPOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT) { -+ /* Step 18 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_UNMUTE | -+ RK3308_DAC_R_HPOUT_UNMUTE, -+ RK3308_DAC_L_HPOUT_UNMUTE | -+ RK3308_DAC_R_HPOUT_UNMUTE); -+ -+ udelay(20); -+ } -+ -+ if (rk3308->dac_output == DAC_LINEOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT) { -+ /* Step 19 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_UNMUTE | -+ RK3308_DAC_R_LINEOUT_UNMUTE, -+ RK3308_DAC_L_LINEOUT_UNMUTE | -+ RK3308_DAC_R_LINEOUT_UNMUTE); -+ udelay(20); -+ } -+ -+ /* Step 20, put configuration HPOUT gain to DAPM control */ -+ /* Step 21, put configuration LINEOUT gain to DAPM control */ -+ -+ if (rk3308->dac_output == DAC_HPOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT) { -+ /* Just for HPOUT */ -+ rk3308_codec_digital_fadein(rk3308); -+ } -+ -+ rk3308->dac_endisable = true; -+ -+ /* TODO: TRY TO TEST DRIVE STRENGTH */ -+ -+ return 0; -+} -+ -+static int rk3308_codec_dac_disable(struct rk3308_codec_priv *rk3308) -+{ -+ /* -+ * Step 00 skipped. Keep the DAC channel work and input the mute signal. -+ */ -+ -+ /* Step 01 skipped. May set the min gain for LINEOUT. */ -+ -+ /* Step 02 skipped. May set the min gain for HPOUT. */ -+ -+ if (rk3308->dac_output == DAC_HPOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT) { -+ /* Just for HPOUT */ -+ rk3308_codec_digital_fadeout(rk3308); -+ } -+ -+ /* Step 03 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, -+ RK3308_DAC_L_HPMIX_UNMUTE | -+ RK3308_DAC_R_HPMIX_UNMUTE, -+ RK3308_DAC_L_HPMIX_UNMUTE | -+ RK3308_DAC_R_HPMIX_UNMUTE); -+ -+ /* Step 04 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, -+ RK3308_DAC_L_HPMIX_SEL_MSK | -+ RK3308_DAC_R_HPMIX_SEL_MSK, -+ RK3308_DAC_L_HPMIX_NONE | -+ RK3308_DAC_R_HPMIX_NONE); -+ /* Step 05 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_UNMUTE | -+ RK3308_DAC_R_HPOUT_UNMUTE, -+ RK3308_DAC_L_HPOUT_MUTE | -+ RK3308_DAC_R_HPOUT_MUTE); -+ -+ /* Step 06 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_DAC_WORK | -+ RK3308_DAC_R_DAC_WORK, -+ RK3308_DAC_L_DAC_INIT | -+ RK3308_DAC_R_DAC_INIT); -+ -+ /* Step 07 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_EN | -+ RK3308_DAC_R_HPOUT_EN, -+ RK3308_DAC_L_HPOUT_DIS | -+ RK3308_DAC_R_HPOUT_DIS); -+ -+ /* Step 08 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_UNMUTE | -+ RK3308_DAC_R_LINEOUT_UNMUTE, -+ RK3308_DAC_L_LINEOUT_MUTE | -+ RK3308_DAC_R_LINEOUT_MUTE); -+ -+ /* Step 09 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_EN | -+ RK3308_DAC_R_LINEOUT_EN, -+ RK3308_DAC_L_LINEOUT_DIS | -+ RK3308_DAC_R_LINEOUT_DIS); -+ -+ /* Step 10 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, -+ RK3308_DAC_L_HPMIX_EN | -+ RK3308_DAC_R_HPMIX_EN, -+ RK3308_DAC_L_HPMIX_DIS | -+ RK3308_DAC_R_HPMIX_DIS); -+ -+ /* Step 11 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_DAC_EN | -+ RK3308_DAC_R_DAC_EN, -+ RK3308_DAC_L_DAC_DIS | -+ RK3308_DAC_R_DAC_DIS); -+ -+ /* Step 12 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_CLK_EN | -+ RK3308_DAC_R_CLK_EN, -+ RK3308_DAC_L_CLK_DIS | -+ RK3308_DAC_R_CLK_DIS); -+ -+ /* Step 13 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -+ RK3308_DAC_L_REF_EN | -+ RK3308_DAC_R_REF_EN, -+ RK3308_DAC_L_REF_DIS | -+ RK3308_DAC_R_REF_DIS); -+ -+ /* Step 14 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_HPOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_HPOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_HPOUT_POP_SOUND_L_INIT | -+ RK3308_DAC_HPOUT_POP_SOUND_R_INIT); -+ -+ /* Step 15 */ -+ if (rk3308->codec_ver == ACODEC_VERSION_B && -+ (rk3308->dac_output == DAC_LINEOUT || -+ rk3308->dac_output == DAC_LINEOUT_HPOUT)) { -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, -+ RK3308_DAC_LINEOUT_POP_SOUND_L_MSK | -+ RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_L_SEL_DC_FROM_VCM | -+ RK3308_DAC_R_SEL_DC_FROM_VCM); -+ } -+ -+ /* Step 16 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_BUF_REF_L_EN | -+ RK3308_DAC_BUF_REF_R_EN, -+ RK3308_DAC_BUF_REF_L_DIS | -+ RK3308_DAC_BUF_REF_R_DIS); -+ -+ /* Step 17 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, -+ RK3308_DAC_CURRENT_EN, -+ RK3308_DAC_CURRENT_DIS); -+ -+ /* Step 18 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON03, -+ RK3308_DAC_L_HPOUT_WORK | -+ RK3308_DAC_R_HPOUT_WORK, -+ RK3308_DAC_L_HPOUT_INIT | -+ RK3308_DAC_R_HPOUT_INIT); -+ -+ /* Step 19 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON13, -+ RK3308_DAC_L_HPMIX_WORK | -+ RK3308_DAC_R_HPMIX_WORK, -+ RK3308_DAC_L_HPMIX_WORK | -+ RK3308_DAC_R_HPMIX_WORK); -+ -+ /* Step 20 skipped, may set the min gain for HPOUT. */ -+ -+ /* -+ * Note2. If the ACODEC_DAC_ANA_CON12[7] or ACODEC_DAC_ANA_CON12[3] -+ * is set to 0x1, add the steps from the section Disable ADC -+ * Configuration Standard Usage Flow after complete the step 19 -+ * -+ * IF USING LINE-IN -+ * rk3308_codec_adc_ana_disable(rk3308, type); -+ */ -+ -+ rk3308->dac_endisable = false; -+ -+ return 0; -+} -+ -+static int rk3308_codec_power_on(struct rk3308_codec_priv *rk3308) -+{ -+ unsigned int v; -+ -+ /* 0. Supply the power of digital part and reset the Audio Codec */ -+ /* Do nothing */ -+ -+ /* -+ * 1. Configure ACODEC_DAC_ANA_CON1[1:0] and ACODEC_DAC_ANA_CON1[5:4] -+ * to 0x1, to setup dc voltage of the DAC channel output. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_HPOUT_POP_SOUND_L_MSK, -+ RK3308_DAC_HPOUT_POP_SOUND_L_INIT); -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01, -+ RK3308_DAC_HPOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_HPOUT_POP_SOUND_R_INIT); -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* -+ * 2. Configure ACODEC_DAC_ANA_CON15[1:0] and -+ * ACODEC_DAC_ANA_CON15[5:4] to 0x1, to setup dc voltage of -+ * the DAC channel output. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, -+ RK3308_DAC_LINEOUT_POP_SOUND_L_MSK, -+ RK3308_DAC_L_SEL_DC_FROM_VCM); -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON15, -+ RK3308_DAC_LINEOUT_POP_SOUND_R_MSK, -+ RK3308_DAC_R_SEL_DC_FROM_VCM); -+ } -+ -+ /* -+ * 3. Configure the register ACODEC_ADC_ANA_CON10[3:0] to 7’b000_0001. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_CURRENT_CHARGE_MSK, -+ RK3308_ADC_SEL_I(0x1)); -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* -+ * 4. Configure the register ACODEC_ADC_ANA_CON14[3:0] to -+ * 4’b0001. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, -+ RK3308_DAC_CURRENT_CHARGE_MSK, -+ RK3308_DAC_SEL_I(0x1)); -+ } -+ -+ /* 5. Supply the power of the analog part(AVDD,AVDDRV) */ -+ -+ /* -+ * 6. Configure the register ACODEC_ADC_ANA_CON10[7] to 0x1 to setup -+ * reference voltage -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_REF_EN, RK3308_ADC_REF_EN); -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* -+ * 7. Configure the register ACODEC_ADC_ANA_CON14[4] to 0x1 to -+ * setup reference voltage -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, -+ RK3308_DAC_VCM_LINEOUT_EN, -+ RK3308_DAC_VCM_LINEOUT_EN); -+ } -+ -+ /* -+ * 8. Change the register ACODEC_ADC_ANA_CON10[6:0] from the 0x1 to -+ * 0x7f step by step or configure the ACODEC_ADC_ANA_CON10[6:0] to -+ * 0x7f directly. Here the slot time of the step is 200us. -+ */ -+ for (v = 0x1; v <= 0x7f; v++) { -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_CURRENT_CHARGE_MSK, -+ v); -+ udelay(200); -+ } -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* -+ * 9. Change the register ACODEC_ADC_ANA_CON14[3:0] from the 0x1 -+ * to 0xf step by step or configure the -+ * ACODEC_ADC_ANA_CON14[3:0] to 0xf directly. Here the slot -+ * time of the step is 200us. -+ */ -+ for (v = 0x1; v <= 0xf; v++) { -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, -+ RK3308_DAC_CURRENT_CHARGE_MSK, -+ v); -+ udelay(200); -+ } -+ } -+ -+ /* 10. Wait until the voltage of VCM keeps stable at the AVDD/2 */ -+ msleep(20); /* estimated value */ -+ -+ /* -+ * 11. Configure the register ACODEC_ADC_ANA_CON10[6:0] to the -+ * appropriate value(expect 0x0) for reducing power. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_CURRENT_CHARGE_MSK, 0x7c); -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* -+ * 12. Configure the register ACODEC_DAC_ANA_CON14[6:0] to the -+ * appropriate value(expect 0x0) for reducing power. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, -+ RK3308_DAC_CURRENT_CHARGE_MSK, 0xf); -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_power_off(struct rk3308_codec_priv *rk3308) -+{ -+ unsigned int v; -+ -+ /* -+ * 0. Keep the power on and disable the DAC and ADC path according to -+ * the section power on configuration standard usage flow. -+ */ -+ -+ /* -+ * 1. Configure the register ACODEC_ADC_ANA_CON10[6:0] to 7’b000_0001. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_CURRENT_CHARGE_MSK, -+ RK3308_ADC_SEL_I(0x1)); -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* -+ * 2. Configure the register ACODEC_DAC_ANA_CON14[3:0] to -+ * 4’b0001. -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, -+ RK3308_DAC_CURRENT_CHARGE_MSK, -+ RK3308_DAC_SEL_I(0x1)); -+ } -+ -+ /* 3. Configure the register ACODEC_ADC_ANA_CON10[7] to 0x0 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_REF_EN, -+ RK3308_ADC_REF_DIS); -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* 4. Configure the register ACODEC_DAC_ANA_CON14[7] to 0x0 */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON14, -+ RK3308_DAC_VCM_LINEOUT_EN, -+ RK3308_DAC_VCM_LINEOUT_DIS); -+ } -+ -+ /* -+ * 5. Change the register ACODEC_ADC_ANA_CON10[6:0] from the 0x1 to 0x7f -+ * step by step or configure the ACODEC_ADC_ANA_CON10[6:0] to 0x7f -+ * directly. Here the slot time of the step is 200us. -+ */ -+ for (v = 0x1; v <= 0x7f; v++) { -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_CURRENT_CHARGE_MSK, -+ v); -+ udelay(200); -+ } -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* -+ * 6. Change the register ACODEC_DAC_ANA_CON14[3:0] from the 0x1 -+ * to 0xf step by step or configure the -+ * ACODEC_DAC_ANA_CON14[3:0] to 0xf directly. Here the slot -+ * time of the step is 200us. -+ */ -+ for (v = 0x1; v <= 0x7f; v++) { -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_ANA_CON10(0), -+ RK3308_ADC_CURRENT_CHARGE_MSK, -+ v); -+ udelay(200); -+ } -+ } -+ -+ /* 7. Wait until the voltage of VCM keeps stable at the AGND */ -+ msleep(20); /* estimated value */ -+ -+ /* 8. Power off the analog power supply */ -+ /* 9. Power off the digital power supply */ -+ -+ /* Do something via hardware */ -+ -+ return 0; -+} -+ -+static int rk3308_codec_headset_detect_enable(struct rk3308_codec_priv *rk3308) -+{ -+ /* -+ * Set ACODEC_DAC_ANA_CON0[1] to 0x1, to enable the headset insert -+ * detection -+ * -+ * Note. When the voltage of PAD HPDET> 8*AVDD/9, the output value of -+ * the pin_hpdet will be set to 0x1 and assert a interrupt -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, -+ RK3308_DAC_HEADPHONE_DET_MSK, -+ RK3308_DAC_HEADPHONE_DET_EN); -+ -+ return 0; -+} -+ -+static int rk3308_codec_headset_detect_disable(struct rk3308_codec_priv *rk3308) -+{ -+ /* -+ * Set ACODEC_DAC_ANA_CON0[1] to 0x0, to disable the headset insert -+ * detection -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON00, -+ RK3308_DAC_HEADPHONE_DET_MSK, -+ RK3308_DAC_HEADPHONE_DET_DIS); -+ -+ return 0; -+} -+ -+static int rk3308_codec_check_i2s_sdis(struct rk3308_codec_priv *rk3308, -+ int num) -+{ -+ int i, j, ret = 0; -+ -+ switch (num) { -+ case 1: -+ rk3308->which_i2s = ACODEC_TO_I2S1_2CH; -+ break; -+ case 2: -+ rk3308->which_i2s = ACODEC_TO_I2S3_4CH; -+ break; -+ case 4: -+ rk3308->which_i2s = ACODEC_TO_I2S2_8CH; -+ break; -+ default: -+ dev_err(rk3308->plat_dev, "Invalid i2s sdis num: %d\n", num); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ for (i = 0; i < num; i++) { -+ if (rk3308->i2s_sdis[i] > ADC_LR_GROUP_MAX - 1) { -+ dev_err(rk3308->plat_dev, -+ "i2s_sdis[%d]: %d is overflow\n", -+ i, rk3308->i2s_sdis[i]); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ for (j = 0; j < num; j++) { -+ if (i == j) -+ continue; -+ -+ if (rk3308->i2s_sdis[i] == rk3308->i2s_sdis[j]) { -+ dev_err(rk3308->plat_dev, -+ "Invalid i2s_sdis: [%d]%d == [%d]%d\n", -+ i, rk3308->i2s_sdis[i], -+ j, rk3308->i2s_sdis[j]); -+ ret = -EINVAL; -+ goto err; -+ } -+ } -+ } -+ -+err: -+ return ret; -+} -+ -+static int rk3308_codec_adc_grps_route_config(struct rk3308_codec_priv *rk3308) -+{ -+ int idx = 0; -+ -+ if (rk3308->which_i2s == ACODEC_TO_I2S2_8CH) { -+ for (idx = 0; idx < rk3308->to_i2s_grps; idx++) { -+ regmap_write(rk3308->grf, GRF_SOC_CON1, -+ GRF_I2S2_8CH_SDI(idx, rk3308->i2s_sdis[idx])); -+ } -+ } else if (rk3308->which_i2s == ACODEC_TO_I2S3_4CH) { -+ for (idx = 0; idx < rk3308->to_i2s_grps; idx++) { -+ regmap_write(rk3308->grf, GRF_SOC_CON1, -+ GRF_I2S3_4CH_SDI(idx, rk3308->i2s_sdis[idx])); -+ } -+ } else if (rk3308->which_i2s == ACODEC_TO_I2S1_2CH) { -+ regmap_write(rk3308->grf, GRF_SOC_CON1, -+ GRF_I2S1_2CH_SDI(rk3308->i2s_sdis[idx])); -+ } -+ -+ return 0; -+} -+ -+/* Put default one-to-one mapping */ -+static int rk3308_codec_adc_grps_route_default(struct rk3308_codec_priv *rk3308) -+{ -+ unsigned int idx; -+ -+ /* -+ * The GRF values may be kept the previous status after hot reboot, -+ * if the property 'rockchip,adc-grps-route' is not set, we need to -+ * recover default the order of sdi/sdo for i2s2_8ch/i2s3_8ch/i2s1_2ch. -+ */ -+ regmap_write(rk3308->grf, GRF_SOC_CON1, -+ GRF_I2S1_2CH_SDI(0)); -+ -+ for (idx = 0; idx < 2; idx++) { -+ regmap_write(rk3308->grf, GRF_SOC_CON1, -+ GRF_I2S3_4CH_SDI(idx, idx)); -+ } -+ -+ /* Using i2s2_8ch by default. */ -+ rk3308->which_i2s = ACODEC_TO_I2S2_8CH; -+ rk3308->to_i2s_grps = ADC_LR_GROUP_MAX; -+ -+ for (idx = 0; idx < ADC_LR_GROUP_MAX; idx++) { -+ rk3308->i2s_sdis[idx] = idx; -+ regmap_write(rk3308->grf, GRF_SOC_CON1, -+ GRF_I2S2_8CH_SDI(idx, idx)); -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_adc_grps_route(struct rk3308_codec_priv *rk3308, -+ struct device_node *np) -+{ -+ int num, ret; -+ -+ num = of_count_phandle_with_args(np, "rockchip,adc-grps-route", NULL); -+ if (num < 0) { -+ if (num == -ENOENT) { -+ /* Not use 'rockchip,adc-grps-route' property here */ -+ rk3308_codec_adc_grps_route_default(rk3308); -+ ret = 0; -+ } else { -+ dev_err(rk3308->plat_dev, -+ "Failed to read 'rockchip,adc-grps-route' num: %d\n", -+ num); -+ ret = num; -+ } -+ return ret; -+ } -+ -+ ret = of_property_read_u32_array(np, "rockchip,adc-grps-route", -+ rk3308->i2s_sdis, num); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to read 'rockchip,adc-grps-route': %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = rk3308_codec_check_i2s_sdis(rk3308, num); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to check i2s_sdis: %d\n", ret); -+ return ret; -+ } -+ -+ rk3308->to_i2s_grps = num; -+ -+ rk3308_codec_adc_grps_route_config(rk3308); -+ -+ return 0; -+} -+ -+static int check_micbias(int micbias) -+{ -+ switch (micbias) { -+ case RK3308_ADC_MICBIAS_VOLT_0_85: -+ case RK3308_ADC_MICBIAS_VOLT_0_8: -+ case RK3308_ADC_MICBIAS_VOLT_0_75: -+ case RK3308_ADC_MICBIAS_VOLT_0_7: -+ case RK3308_ADC_MICBIAS_VOLT_0_65: -+ case RK3308_ADC_MICBIAS_VOLT_0_6: -+ case RK3308_ADC_MICBIAS_VOLT_0_55: -+ case RK3308_ADC_MICBIAS_VOLT_0_5: -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static bool handle_loopback(struct rk3308_codec_priv *rk3308) -+{ -+ /* The version B doesn't need to handle loopback. */ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) -+ return false; -+ -+ switch (rk3308->loopback_grp) { -+ case 0: -+ case 1: -+ case 2: -+ case 3: -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool has_en_always_grps(struct rk3308_codec_priv *rk3308) -+{ -+ int idx; -+ -+ if (rk3308->en_always_grps_num) { -+ for (idx = 0; idx < ADC_LR_GROUP_MAX; idx++) { -+ if (rk3308->en_always_grps[idx] >= 0 && -+ rk3308->en_always_grps[idx] <= ADC_LR_GROUP_MAX - 1) -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static int rk3308_codec_micbias_enable(struct rk3308_codec_priv *rk3308, -+ int micbias) -+{ -+ int ret; -+ -+ if (rk3308->ext_micbias != EXT_MICBIAS_NONE) -+ return 0; -+ -+ /* 0. Power up the ACODEC and keep the AVDDH stable */ -+ -+ /* Step 1. Configure ACODEC_ADC_ANA_CON7[2:0] to the certain value */ -+ ret = check_micbias(micbias); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, "This is an invalid micbias: %d\n", -+ micbias); -+ return ret; -+ } -+ -+ /* -+ * Note: Only the reg (ADC_ANA_CON7+0x0)[2:0] represent the level range -+ * control signal of MICBIAS voltage -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), -+ RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK, -+ micbias); -+ -+ /* Step 2. Wait until the VCMH keep stable */ -+ msleep(20); /* estimated value */ -+ -+ /* -+ * Step 3. Configure ACODEC_ADC_ANA_CON8[4] to 0x1 -+ * -+ * Note: Only the reg (ADC_ANA_CON8+0x0)[4] represent the enable -+ * signal of current source for MICBIAS -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0), -+ RK3308_ADC_MICBIAS_CURRENT_MSK, -+ RK3308_ADC_MICBIAS_CURRENT_EN); -+ -+ /* -+ * Step 4. Configure the (ADC_ANA_CON7+0x40)[3] or -+ * (ADC_ANA_CON7+0x80)[3] to 0x1. -+ * -+ * (ADC_ANA_CON7+0x40)[3] used to control the MICBIAS1, and -+ * (ADC_ANA_CON7+0x80)[3] used to control the MICBIAS2 -+ */ -+ if (rk3308->micbias1) -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(1), -+ RK3308_ADC_MIC_BIAS_BUF_EN, -+ RK3308_ADC_MIC_BIAS_BUF_EN); -+ -+ if (rk3308->micbias2) -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(2), -+ RK3308_ADC_MIC_BIAS_BUF_EN, -+ RK3308_ADC_MIC_BIAS_BUF_EN); -+ -+ /* waiting micbias stabled*/ -+ mdelay(50); -+ -+ rk3308->enable_micbias = true; -+ -+ return 0; -+} -+ -+static int rk3308_codec_micbias_disable(struct rk3308_codec_priv *rk3308) -+{ -+ if (rk3308->ext_micbias != EXT_MICBIAS_NONE) -+ return 0; -+ -+ /* Step 0. Enable the MICBIAS and keep the Audio Codec stable */ -+ /* Do nothing */ -+ -+ /* -+ * Step 1. Configure the (ADC_ANA_CON7+0x40)[3] or -+ * (ADC_ANA_CON7+0x80)[3] to 0x0 -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(1), -+ RK3308_ADC_MIC_BIAS_BUF_EN, -+ RK3308_ADC_MIC_BIAS_BUF_DIS); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(2), -+ RK3308_ADC_MIC_BIAS_BUF_EN, -+ RK3308_ADC_MIC_BIAS_BUF_DIS); -+ -+ /* -+ * Step 2. Configure ACODEC_ADC_ANA_CON8[4] to 0x0 -+ * -+ * Note: Only the reg (ADC_ANA_CON8+0x0)[4] represent the enable -+ * signal of current source for MICBIAS -+ */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON08(0), -+ RK3308_ADC_MICBIAS_CURRENT_MSK, -+ RK3308_ADC_MICBIAS_CURRENT_DIS); -+ -+ rk3308->enable_micbias = false; -+ -+ return 0; -+} -+ -+static int rk3308_codec_adc_reinit_mics(struct rk3308_codec_priv *rk3308, -+ int type) -+{ -+ int idx, grp; -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 1 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_ADC_WORK | -+ RK3308_ADC_CH2_ADC_WORK, -+ RK3308_ADC_CH1_ADC_INIT | -+ RK3308_ADC_CH2_ADC_INIT); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 2 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ALC_WORK | -+ RK3308_ADC_CH2_ALC_WORK, -+ RK3308_ADC_CH1_ALC_INIT | -+ RK3308_ADC_CH2_ALC_INIT); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 3 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_MIC_WORK | -+ RK3308_ADC_CH2_MIC_WORK, -+ RK3308_ADC_CH1_MIC_INIT | -+ RK3308_ADC_CH2_MIC_INIT); -+ } -+ -+ usleep_range(200, 250); /* estimated value */ -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 1 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_ADC_WORK | -+ RK3308_ADC_CH2_ADC_WORK, -+ RK3308_ADC_CH1_ADC_WORK | -+ RK3308_ADC_CH2_ADC_WORK); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 2 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ALC_WORK | -+ RK3308_ADC_CH2_ALC_WORK, -+ RK3308_ADC_CH1_ALC_WORK | -+ RK3308_ADC_CH2_ALC_WORK); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 3 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_MIC_WORK | -+ RK3308_ADC_CH2_MIC_WORK, -+ RK3308_ADC_CH1_MIC_WORK | -+ RK3308_ADC_CH2_MIC_WORK); -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_adc_ana_enable(struct rk3308_codec_priv *rk3308, -+ int type) -+{ -+ unsigned int agc_func_en; -+ int idx, grp; -+ -+ /* -+ * 1. Set the ACODEC_ADC_ANA_CON7[7:6] and ACODEC_ADC_ANA_CON7[5:4], -+ * to select the line-in or microphone as input of ADC -+ * -+ * Note1. Please ignore the step1 for enabling ADC3, ADC4, ADC5, -+ * ADC6, ADC7, and ADC8 -+ */ -+ if (rk3308->adc_grp0_using_linein) { -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), -+ RK3308_ADC_CH1_IN_SEL_MSK | -+ RK3308_ADC_CH2_IN_SEL_MSK, -+ RK3308_ADC_CH1_IN_LINEIN | -+ RK3308_ADC_CH2_IN_LINEIN); -+ -+ /* Keep other ADCs as MIC-IN */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ /* The groups without line-in are >= 1 */ -+ if (grp < 1 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_ANA_CON07(grp), -+ RK3308_ADC_CH1_IN_SEL_MSK | -+ RK3308_ADC_CH2_IN_SEL_MSK, -+ RK3308_ADC_CH1_IN_MIC | -+ RK3308_ADC_CH2_IN_MIC); -+ } -+ } else { -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_ANA_CON07(grp), -+ RK3308_ADC_CH1_IN_SEL_MSK | -+ RK3308_ADC_CH2_IN_SEL_MSK, -+ RK3308_ADC_CH1_IN_MIC | -+ RK3308_ADC_CH2_IN_MIC); -+ } -+ } -+ -+ /* -+ * 2. Set ACODEC_ADC_ANA_CON0[7] and [3] to 0x1, to end the mute station -+ * of ADC, to enable the MIC module, to enable the reference voltage -+ * buffer, and to end the initialization of MIC -+ */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_MIC_UNMUTE | -+ RK3308_ADC_CH2_MIC_UNMUTE, -+ RK3308_ADC_CH1_MIC_UNMUTE | -+ RK3308_ADC_CH2_MIC_UNMUTE); -+ } -+ -+ /* -+ * 3. Set ACODEC_ADC_ANA_CON6[0] to 0x1, to enable the current source -+ * of audio -+ */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp), -+ RK3308_ADC_CURRENT_MSK, -+ RK3308_ADC_CURRENT_EN); -+ } -+ -+ /* -+ * This is mainly used for BIST mode that wait ADCs are stable. -+ * -+ * By tested results, the type delay is >40us, but we need to leave -+ * enough delay margin. -+ */ -+ usleep_range(400, 500); -+ -+ /* vendor step 4*/ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_BUF_REF_EN | -+ RK3308_ADC_CH2_BUF_REF_EN, -+ RK3308_ADC_CH1_BUF_REF_EN | -+ RK3308_ADC_CH2_BUF_REF_EN); -+ } -+ -+ /* vendor step 5 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_MIC_EN | -+ RK3308_ADC_CH2_MIC_EN, -+ RK3308_ADC_CH1_MIC_EN | -+ RK3308_ADC_CH2_MIC_EN); -+ } -+ -+ /* vendor step 6 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ALC_EN | -+ RK3308_ADC_CH2_ALC_EN, -+ RK3308_ADC_CH1_ALC_EN | -+ RK3308_ADC_CH2_ALC_EN); -+ } -+ -+ /* vendor step 7 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_CLK_EN | -+ RK3308_ADC_CH2_CLK_EN, -+ RK3308_ADC_CH1_CLK_EN | -+ RK3308_ADC_CH2_CLK_EN); -+ } -+ -+ /* vendor step 8 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_ADC_EN | -+ RK3308_ADC_CH2_ADC_EN, -+ RK3308_ADC_CH1_ADC_EN | -+ RK3308_ADC_CH2_ADC_EN); -+ } -+ -+ /* vendor step 9 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_ADC_WORK | -+ RK3308_ADC_CH2_ADC_WORK, -+ RK3308_ADC_CH1_ADC_WORK | -+ RK3308_ADC_CH2_ADC_WORK); -+ } -+ -+ /* vendor step 10 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ALC_WORK | -+ RK3308_ADC_CH2_ALC_WORK, -+ RK3308_ADC_CH1_ALC_WORK | -+ RK3308_ADC_CH2_ALC_WORK); -+ } -+ -+ /* vendor step 11 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_MIC_WORK | -+ RK3308_ADC_CH2_MIC_WORK, -+ RK3308_ADC_CH1_MIC_WORK | -+ RK3308_ADC_CH2_MIC_WORK); -+ } -+ -+ /* vendor step 12 */ -+ -+ /* vendor step 13 */ -+ -+ /* vendor step 14 */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_read(rk3308->regmap, RK3308_ALC_L_DIG_CON09(grp), -+ &agc_func_en); -+ if (rk3308->adc_zerocross || -+ agc_func_en & RK3308_AGC_FUNC_SEL_EN) { -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ZEROCROSS_DET_EN, -+ RK3308_ADC_CH1_ZEROCROSS_DET_EN); -+ } -+ regmap_read(rk3308->regmap, RK3308_ALC_R_DIG_CON09(grp), -+ &agc_func_en); -+ if (rk3308->adc_zerocross || -+ agc_func_en & RK3308_AGC_FUNC_SEL_EN) { -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH2_ZEROCROSS_DET_EN, -+ RK3308_ADC_CH2_ZEROCROSS_DET_EN); -+ } -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ rk3308->adc_grps_endisable[grp] = true; -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_adc_ana_disable(struct rk3308_codec_priv *rk3308, -+ int type) -+{ -+ int idx, grp; -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 1 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ZEROCROSS_DET_EN | -+ RK3308_ADC_CH2_ZEROCROSS_DET_EN, -+ RK3308_ADC_CH1_ZEROCROSS_DET_DIS | -+ RK3308_ADC_CH2_ZEROCROSS_DET_DIS); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 2 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_ADC_EN | -+ RK3308_ADC_CH2_ADC_EN, -+ RK3308_ADC_CH1_ADC_DIS | -+ RK3308_ADC_CH2_ADC_DIS); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 3 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_CLK_EN | -+ RK3308_ADC_CH2_CLK_EN, -+ RK3308_ADC_CH1_CLK_DIS | -+ RK3308_ADC_CH2_CLK_DIS); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 4 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ALC_EN | -+ RK3308_ADC_CH2_ALC_EN, -+ RK3308_ADC_CH1_ALC_DIS | -+ RK3308_ADC_CH2_ALC_DIS); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 5 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_MIC_EN | -+ RK3308_ADC_CH2_MIC_EN, -+ RK3308_ADC_CH1_MIC_DIS | -+ RK3308_ADC_CH2_MIC_DIS); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 6 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_BUF_REF_EN | -+ RK3308_ADC_CH2_BUF_REF_EN, -+ RK3308_ADC_CH1_BUF_REF_DIS | -+ RK3308_ADC_CH2_BUF_REF_DIS); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 7 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON06(grp), -+ RK3308_ADC_CURRENT_MSK, -+ RK3308_ADC_CURRENT_DIS); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 8 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON05(grp), -+ RK3308_ADC_CH1_ADC_WORK | -+ RK3308_ADC_CH2_ADC_WORK, -+ RK3308_ADC_CH1_ADC_INIT | -+ RK3308_ADC_CH2_ADC_INIT); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 9 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -+ RK3308_ADC_CH1_ALC_WORK | -+ RK3308_ADC_CH2_ALC_WORK, -+ RK3308_ADC_CH1_ALC_INIT | -+ RK3308_ADC_CH2_ALC_INIT); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ /* vendor step 10 */ -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON00(grp), -+ RK3308_ADC_CH1_MIC_WORK | -+ RK3308_ADC_CH2_MIC_WORK, -+ RK3308_ADC_CH1_MIC_INIT | -+ RK3308_ADC_CH2_MIC_INIT); -+ } -+ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ rk3308->adc_grps_endisable[grp] = false; -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_open_capture(struct rk3308_codec_priv *rk3308) -+{ -+ int idx, grp = 0; -+ int type = ADC_TYPE_NORMAL; -+ -+ rk3308_codec_adc_ana_enable(rk3308, type); -+ rk3308_codec_adc_reinit_mics(rk3308, type); -+ -+ if (rk3308->adc_grp0_using_linein) { -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(0), -+ RK3308_ADC_L_CH_BIST_MSK, -+ RK3308_ADC_L_CH_NORMAL_RIGHT); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON03(0), -+ RK3308_ADC_R_CH_BIST_MSK, -+ RK3308_ADC_R_CH_NORMAL_LEFT); -+ } else { -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (handle_loopback(rk3308) && -+ idx == rk3308->loopback_grp && -+ grp == ADC_GRP_SKIP_MAGIC) { -+ /* -+ * Switch to dummy BIST mode (BIST keep reset -+ * now) to keep the zero input data in I2S bus. -+ * -+ * It may cause the glitch if we hold the ADC -+ * digtital i2s module in codec. -+ * -+ * Then, the grp which is set from loopback_grp. -+ */ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(rk3308->loopback_grp), -+ RK3308_ADC_L_CH_BIST_MSK, -+ RK3308_ADC_L_CH_BIST_SINE); -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(rk3308->loopback_grp), -+ RK3308_ADC_R_CH_BIST_MSK, -+ RK3308_ADC_R_CH_BIST_SINE); -+ } else { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_L_CH_BIST_MSK, -+ RK3308_ADC_L_CH_NORMAL_LEFT); -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_R_CH_BIST_MSK, -+ RK3308_ADC_R_CH_NORMAL_RIGHT); -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static void rk3308_codec_adc_mclk_disable(struct rk3308_codec_priv *rk3308) -+{ -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_ADC_MCLK_MSK, -+ RK3308_ADC_MCLK_DIS); -+} -+ -+static void rk3308_codec_adc_mclk_enable(struct rk3308_codec_priv *rk3308) -+{ -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_ADC_MCLK_MSK, -+ RK3308_ADC_MCLK_EN); -+ udelay(20); -+} -+ -+static void rk3308_codec_dac_mclk_disable(struct rk3308_codec_priv *rk3308) -+{ -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_DAC_MCLK_MSK, -+ RK3308_DAC_MCLK_DIS); -+} -+ -+static void rk3308_codec_dac_mclk_enable(struct rk3308_codec_priv *rk3308) -+{ -+ regmap_update_bits(rk3308->regmap, RK3308_GLB_CON, -+ RK3308_DAC_MCLK_MSK, -+ RK3308_DAC_MCLK_EN); -+ udelay(20); -+} -+ -+static int rk3308_codec_open_dbg_capture(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_adc_ana_enable(rk3308, ADC_TYPE_DBG); -+ -+ return 0; -+} -+ -+static int rk3308_codec_close_dbg_capture(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_DBG); -+ -+ return 0; -+} -+ -+static int rk3308_codec_close_all_capture(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_ALL); -+ -+ return 0; -+} -+ -+static int rk3308_codec_close_capture(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_NORMAL); -+ -+ return 0; -+} -+ -+static int rk3308_codec_open_playback(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_dac_enable(rk3308); -+ -+ return 0; -+} -+ -+static int rk3308_codec_close_playback(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_dac_disable(rk3308); -+ -+ return 0; -+} -+ -+static int rk3308_codec_llp_down(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_adc_mclk_disable(rk3308); -+ rk3308_codec_dac_mclk_disable(rk3308); -+ -+ return 0; -+} -+ -+static int rk3308_codec_llp_up(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_adc_mclk_enable(rk3308); -+ rk3308_codec_dac_mclk_enable(rk3308); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dlp_down(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_micbias_disable(rk3308); -+ rk3308_codec_power_off(rk3308); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dlp_up(struct rk3308_codec_priv *rk3308) -+{ -+ rk3308_codec_power_on(rk3308); -+ rk3308_codec_micbias_enable(rk3308, rk3308->micbias_volt); -+ -+ return 0; -+} -+ -+/* Just used for debug and trace power state */ -+static void rk3308_codec_set_pm_state(struct rk3308_codec_priv *rk3308, -+ int pm_state) -+{ -+ int ret; -+ -+ switch (pm_state) { -+ case PM_LLP_DOWN: -+ rk3308_codec_llp_down(rk3308); -+ break; -+ case PM_LLP_UP: -+ rk3308_codec_llp_up(rk3308); -+ break; -+ case PM_DLP_DOWN: -+ rk3308_codec_dlp_down(rk3308); -+ break; -+ case PM_DLP_UP: -+ rk3308_codec_dlp_up(rk3308); -+ break; -+ case PM_DLP_DOWN2: -+ clk_disable_unprepare(rk3308->mclk_rx); -+ clk_disable_unprepare(rk3308->mclk_tx); -+ clk_disable_unprepare(rk3308->pclk); -+ break; -+ case PM_DLP_UP2: -+ ret = clk_prepare_enable(rk3308->pclk); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to enable acodec pclk: %d\n", ret); -+ goto err; -+ } -+ -+ ret = clk_prepare_enable(rk3308->mclk_rx); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to enable i2s mclk_rx: %d\n", ret); -+ goto err; -+ } -+ -+ ret = clk_prepare_enable(rk3308->mclk_tx); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to enable i2s mclk_tx: %d\n", ret); -+ goto err; -+ } -+ break; -+ default: -+ dev_err(rk3308->plat_dev, "Invalid pm_state: %d\n", pm_state); -+ goto err; -+ } -+ -+ rk3308->pm_state = pm_state; -+ -+err: -+ return; -+} -+ -+static void rk3308_codec_update_adcs_status(struct rk3308_codec_priv *rk3308, -+ int state) -+{ -+ int idx, grp; -+ -+ /* Update skip_grps flags if the ADCs need to be enabled always. */ -+ if (state == PATH_BUSY) { -+ for (idx = 0; idx < rk3308->used_adc_grps; idx++) { -+ u32 mapped_grp = to_mapped_grp(rk3308, idx); -+ -+ for (grp = 0; grp < rk3308->en_always_grps_num; grp++) { -+ u32 en_always_grp = rk3308->en_always_grps[grp]; -+ -+ if (mapped_grp == en_always_grp) -+ rk3308->skip_grps[en_always_grp] = 1; -+ } -+ } -+ } -+} -+ -+static int rk3308_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct snd_pcm_str *playback_str = -+ &substream->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; -+ int type = ADC_TYPE_LOOPBACK; -+ int idx, grp; -+ int ret; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ /* DAC only supports 2 channels */ -+ rk3308_codec_dac_mclk_enable(rk3308); -+ rk3308_codec_open_playback(rk3308); -+ rk3308_codec_dac_dig_config(rk3308, params); -+ rk3308_codec_set_dac_path_state(rk3308, PATH_BUSY); -+ } else { -+ if (rk3308->micbias_num && -+ !rk3308->enable_micbias) -+ rk3308_codec_micbias_enable(rk3308, rk3308->micbias_volt); -+ -+ rk3308_codec_adc_mclk_enable(rk3308); -+ ret = rk3308_codec_update_adc_grps(rk3308, params); -+ if (ret < 0) -+ return ret; -+ -+ if (handle_loopback(rk3308)) { -+ if (rk3308->micbias_num && -+ (params_channels(params) == 2) && -+ to_mapped_grp(rk3308, 0) == rk3308->loopback_grp) -+ rk3308_codec_micbias_disable(rk3308); -+ -+ /* Check the DACs are opened */ -+ if (playback_str->substream_opened) { -+ rk3308->loopback_dacs_enabled = true; -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_L_CH_BIST_MSK, -+ RK3308_ADC_L_CH_NORMAL_LEFT); -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_R_CH_BIST_MSK, -+ RK3308_ADC_R_CH_NORMAL_RIGHT); -+ } -+ } else { -+ rk3308->loopback_dacs_enabled = false; -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_L_CH_BIST_MSK, -+ RK3308_ADC_L_CH_BIST_SINE); -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_R_CH_BIST_MSK, -+ RK3308_ADC_R_CH_BIST_SINE); -+ } -+ } -+ } -+ -+ rk3308_codec_open_capture(rk3308); -+ rk3308_codec_adc_dig_config(rk3308, params); -+ rk3308_codec_update_adcs_status(rk3308, PATH_BUSY); -+ } -+ -+ return 0; -+} -+ -+static int rk3308_pcm_trigger(struct snd_pcm_substream *substream, -+ int cmd, struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ int type = ADC_TYPE_LOOPBACK; -+ int idx, grp; -+ -+ if (handle_loopback(rk3308) && -+ rk3308->dac_output == DAC_LINEOUT && -+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if (cmd == SNDRV_PCM_TRIGGER_START) { -+ struct snd_pcm_str *capture_str = -+ &substream->pcm->streams[SNDRV_PCM_STREAM_CAPTURE]; -+ -+ if (capture_str->substream_opened) -+ queue_delayed_work(system_power_efficient_wq, -+ &rk3308->loopback_work, -+ msecs_to_jiffies(rk3308->delay_loopback_handle_ms)); -+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { -+ /* -+ * Switch to dummy bist mode to kick the glitch during disable -+ * ADCs and keep zero input data -+ */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_L_CH_BIST_MSK, -+ RK3308_ADC_L_CH_BIST_SINE); -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_R_CH_BIST_MSK, -+ RK3308_ADC_R_CH_BIST_SINE); -+ } -+ rk3308_codec_adc_ana_disable(rk3308, ADC_TYPE_LOOPBACK); -+ } -+ } -+ -+ return 0; -+} -+ -+static void rk3308_pcm_shutdown(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ rk3308_codec_close_playback(rk3308); -+ rk3308_codec_dac_mclk_disable(rk3308); -+ regcache_cache_only(rk3308->regmap, false); -+ regcache_sync(rk3308->regmap); -+ rk3308_codec_set_dac_path_state(rk3308, PATH_IDLE); -+ } else { -+ rk3308_codec_close_capture(rk3308); -+ if (!has_en_always_grps(rk3308)) { -+ rk3308_codec_adc_mclk_disable(rk3308); -+ rk3308_codec_update_adcs_status(rk3308, PATH_IDLE); -+ if (rk3308->micbias_num && -+ rk3308->enable_micbias) -+ rk3308_codec_micbias_disable(rk3308); -+ } -+ -+ regcache_cache_only(rk3308->regmap, false); -+ regcache_sync(rk3308->regmap); -+ } -+} -+ -+static struct snd_soc_dai_ops rk3308_dai_ops = { -+ .hw_params = rk3308_hw_params, -+ .set_fmt = rk3308_set_dai_fmt, -+ .mute_stream = rk3308_mute_stream, -+ .trigger = rk3308_pcm_trigger, -+ .shutdown = rk3308_pcm_shutdown, -+}; -+ -+static struct snd_soc_dai_driver rk3308_dai[] = { -+ { -+ .name = "rk3308-hifi", -+ .id = RK3308_HIFI, -+ .playback = { -+ .stream_name = "HiFi Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_192000, -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S20_3LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE), -+ }, -+ .capture = { -+ .stream_name = "HiFi Capture", -+ .channels_min = 1, -+ .channels_max = 8, -+ .rates = SNDRV_PCM_RATE_8000_192000, -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S20_3LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE), -+ }, -+ .ops = &rk3308_dai_ops, -+ }, -+}; -+ -+static int rk3308_suspend(struct snd_soc_component *component) -+{ -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ if (rk3308->no_deep_low_power) -+ goto out; -+ -+ rk3308_codec_dlp_down(rk3308); -+ clk_disable_unprepare(rk3308->mclk_rx); -+ clk_disable_unprepare(rk3308->mclk_tx); -+ clk_disable_unprepare(rk3308->pclk); -+ -+out: -+ rk3308_set_bias_level(component, SND_SOC_BIAS_OFF); -+ return 0; -+} -+ -+static int rk3308_resume(struct snd_soc_component *component) -+{ -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ int ret = 0; -+ -+ if (rk3308->no_deep_low_power) -+ goto out; -+ -+ ret = clk_prepare_enable(rk3308->pclk); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to enable acodec pclk: %d\n", ret); -+ goto out; -+ } -+ -+ ret = clk_prepare_enable(rk3308->mclk_rx); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to enable i2s mclk_rx: %d\n", ret); -+ goto out; -+ } -+ -+ ret = clk_prepare_enable(rk3308->mclk_tx); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to enable i2s mclk_tx: %d\n", ret); -+ goto out; -+ } -+ -+ rk3308_codec_dlp_up(rk3308); -+out: -+ rk3308_set_bias_level(component, SND_SOC_BIAS_STANDBY); -+ return ret; -+} -+ -+static int rk3308_codec_default_gains(struct rk3308_codec_priv *rk3308) -+{ -+ int grp; -+ -+ /* Prepare ADC gains */ -+ /* vendor step 12, set MIC PGA default gains */ -+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON01(grp), -+ RK3308_ADC_CH1_MIC_GAIN_MSK | -+ RK3308_ADC_CH2_MIC_GAIN_MSK, -+ RK3308_ADC_CH1_MIC_GAIN_0DB | -+ RK3308_ADC_CH2_MIC_GAIN_0DB); -+ } -+ -+ /* vendor step 13, set ALC default gains */ -+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON03(grp), -+ RK3308_ADC_CH1_ALC_GAIN_MSK, -+ RK3308_ADC_CH1_ALC_GAIN_0DB); -+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON04(grp), -+ RK3308_ADC_CH2_ALC_GAIN_MSK, -+ RK3308_ADC_CH2_ALC_GAIN_0DB); -+ } -+ -+ /* Prepare DAC gains */ -+ /* Step 15, set HPMIX default gains */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12, -+ RK3308_DAC_L_HPMIX_GAIN_MSK | - RK3308_DAC_R_HPMIX_GAIN_MSK, - RK3308_DAC_L_HPMIX_GAIN_NDB_6 | - RK3308_DAC_R_HPMIX_GAIN_NDB_6); - -- /* recover DAC digital gain to 0 dB (reset value is 0xff, undocumented) */ -- if (rk3308->codec_ver == ACODEC_VERSION_C) -- regmap_write(rk3308->regmap, RK3308_DAC_DIG_CON04, -- RK3308BS_DAC_DIG_GAIN_0DB); -+ /* Step 18, set HPOUT default gains */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON05, -+ RK3308_DAC_L_HPOUT_GAIN_MSK, -+ RK3308_DAC_L_HPOUT_GAIN_NDB_39); -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON06, -+ RK3308_DAC_R_HPOUT_GAIN_MSK, -+ RK3308_DAC_R_HPOUT_GAIN_NDB_39); -+ -+ /* Using the same gain to HPOUT LR channels */ -+ rk3308->hpout_l_dgain = RK3308_DAC_L_HPOUT_GAIN_NDB_39; -+ -+ /* Step 19, set LINEOUT default gains */ -+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON04, -+ RK3308_DAC_L_LINEOUT_GAIN_MSK | -+ RK3308_DAC_R_LINEOUT_GAIN_MSK, -+ RK3308_DAC_L_LINEOUT_GAIN_NDB_6 | -+ RK3308_DAC_R_LINEOUT_GAIN_NDB_6); -+ -+ return 0; -+} -+ -+static int rk3308_codec_setup_en_always_adcs(struct rk3308_codec_priv *rk3308, -+ struct device_node *np) -+{ -+ int num, ret; -+ -+ num = of_count_phandle_with_args(np, "rockchip,en-always-grps", NULL); -+ if (num < 0) { -+ if (num == -ENOENT) { -+ /* -+ * If there is note use 'rockchip,en-always-grps' -+ * property, return 0 is also right. -+ */ -+ ret = 0; -+ } else { -+ dev_err(rk3308->plat_dev, -+ "Failed to read 'rockchip,adc-grps-route' num: %d\n", -+ num); -+ ret = num; -+ } -+ -+ rk3308->en_always_grps_num = 0; -+ return ret; -+ } -+ -+ rk3308->en_always_grps_num = num; -+ -+ ret = of_property_read_u32_array(np, "rockchip,en-always-grps", -+ rk3308->en_always_grps, num); -+ if (ret < 0) { -+ dev_err(rk3308->plat_dev, -+ "Failed to read 'rockchip,en-always-grps': %d\n", -+ ret); -+ return ret; -+ } -+ -+ /* Clear all of skip_grps flags. */ -+ for (num = 0; num < ADC_LR_GROUP_MAX; num++) -+ rk3308->skip_grps[num] = 0; -+ -+ /* The loopback grp should not be enabled always. */ -+ for (num = 0; num < rk3308->en_always_grps_num; num++) { -+ if (rk3308->en_always_grps[num] == rk3308->loopback_grp) { -+ dev_err(rk3308->plat_dev, -+ "loopback_grp: %d should not be enabled always!\n", -+ rk3308->loopback_grp); -+ ret = -EINVAL; -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_dapm_mic_gains(struct rk3308_codec_priv *rk3308) -+{ -+ int ret; -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ ret = snd_soc_add_component_controls(rk3308->component, -+ mic_gains_b, -+ ARRAY_SIZE(mic_gains_b)); -+ if (ret) { -+ dev_err(rk3308->plat_dev, -+ "%s: add mic_gains_b failed: %d\n", -+ __func__, ret); -+ return ret; -+ } -+ } else { -+ ret = snd_soc_add_component_controls(rk3308->component, -+ mic_gains_a, -+ ARRAY_SIZE(mic_gains_a)); -+ if (ret) { -+ dev_err(rk3308->plat_dev, -+ "%s: add mic_gains_a failed: %d\n", -+ __func__, ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int rk3308_codec_check_micbias(struct rk3308_codec_priv *rk3308, -+ struct device_node *np) -+{ -+ struct device *dev = (struct device *)rk3308->plat_dev; -+ int num = 0, ret; -+ -+ /* Check internal micbias */ -+ rk3308->micbias1 = -+ of_property_read_bool(np, "rockchip,micbias1"); -+ if (rk3308->micbias1) -+ num++; -+ -+ rk3308->micbias2 = -+ of_property_read_bool(np, "rockchip,micbias2"); -+ if (rk3308->micbias2) -+ num++; -+ -+ rk3308->micbias_volt = RK3308_ADC_MICBIAS_VOLT_0_85; /* by default */ -+ rk3308->micbias_num = num; -+ -+ /* Check external micbias */ -+ rk3308->ext_micbias = EXT_MICBIAS_NONE; -+ -+ rk3308->micbias_en_gpio = devm_gpiod_get_optional(dev, -+ "micbias-en", -+ GPIOD_IN); -+ if (!rk3308->micbias_en_gpio) { -+ dev_info(dev, "Don't need micbias-en gpio\n"); -+ } else if (IS_ERR(rk3308->micbias_en_gpio)) { -+ ret = PTR_ERR(rk3308->micbias_en_gpio); -+ dev_err(dev, "Unable to claim gpio micbias-en\n"); -+ return ret; -+ } else if (gpiod_get_value(rk3308->micbias_en_gpio)) { -+ rk3308->ext_micbias = EXT_MICBIAS_FUNC1; -+ } -+ -+ rk3308->vcc_micbias = devm_regulator_get_optional(dev, -+ "vmicbias"); -+ if (IS_ERR(rk3308->vcc_micbias)) { -+ if (PTR_ERR(rk3308->vcc_micbias) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ dev_info(dev, "no vmicbias regulator found\n"); -+ } else { -+ ret = regulator_enable(rk3308->vcc_micbias); -+ if (ret) { -+ dev_err(dev, "Can't enable vmicbias: %d\n", ret); -+ return ret; -+ } -+ rk3308->ext_micbias = EXT_MICBIAS_FUNC2; -+ } -+ -+ dev_info(dev, "Check ext_micbias: %d\n", rk3308->ext_micbias); -+ -+ return 0; -+} -+ -+static int rk3308_codec_dapm_controls_prepare(struct rk3308_codec_priv *rk3308) -+{ -+ int grp; -+ -+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) { -+ rk3308->hpf_cutoff[grp] = 0; -+ rk3308->agc_l[grp] = 0; -+ rk3308->agc_r[grp] = 0; -+ rk3308->agc_asr_l[grp] = AGC_ASR_96KHZ; -+ rk3308->agc_asr_r[grp] = AGC_ASR_96KHZ; -+ } -+ -+ rk3308_codec_dapm_mic_gains(rk3308); -+ -+ return 0; -+} -+ -+static int rk3308_codec_prepare(struct rk3308_codec_priv *rk3308) -+{ -+ /* Clear registers for ADC and DAC */ -+ rk3308_codec_close_playback(rk3308); -+ rk3308_codec_close_all_capture(rk3308); -+ rk3308_codec_default_gains(rk3308); -+ rk3308_codec_llp_down(rk3308); -+ rk3308_codec_dapm_controls_prepare(rk3308); -+ -+ return 0; -+} -+ -+static int rk3308_probe(struct snd_soc_component *component) -+{ -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ int ext_micbias; -+ -+ rk3308->component = component; -+ rk3308_codec_set_dac_path_state(rk3308, PATH_IDLE); -+ -+ rk3308_codec_reset(component); -+ rk3308_codec_power_on(rk3308); -+ -+ /* From vendor recommend, disable micbias at first. */ -+ ext_micbias = rk3308->ext_micbias; -+ rk3308->ext_micbias = EXT_MICBIAS_NONE; -+ rk3308_codec_micbias_disable(rk3308); -+ rk3308->ext_micbias = ext_micbias; -+ -+ rk3308_codec_prepare(rk3308); -+ if (!rk3308->no_hp_det) -+ rk3308_codec_headset_detect_enable(rk3308); -+ -+ regcache_cache_only(rk3308->regmap, false); -+ regcache_sync(rk3308->regmap); -+ -+ return 0; -+} -+ -+static void rk3308_remove(struct snd_soc_component *component) -+{ -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ rk3308_headphone_ctl(rk3308, 0); -+ rk3308_speaker_ctl(rk3308, 0); -+ if (!rk3308->no_hp_det) -+ rk3308_codec_headset_detect_disable(rk3308); -+ rk3308_codec_micbias_disable(rk3308); -+ rk3308_codec_power_off(rk3308); -+ -+ rk3308_codec_set_dac_path_state(rk3308, PATH_IDLE); -+ -+ regcache_cache_only(rk3308->regmap, false); -+ regcache_sync(rk3308->regmap); -+ -+ return; -+} -+ -+static const struct snd_soc_component_driver soc_codec_dev_rk3308_component = { -+ .probe = rk3308_probe, -+ .remove = rk3308_remove, -+ .resume = rk3308_resume, -+ .suspend = rk3308_suspend, -+ .set_bias_level = rk3308_set_bias_level, -+ .controls = rk3308_codec_dapm_controls, -+ .num_controls = ARRAY_SIZE(rk3308_codec_dapm_controls), -+ // .dapm_widgets = rk3308_dapm_widgets, -+ // .num_dapm_widgets = ARRAY_SIZE(rk3308_dapm_widgets), -+ // .dapm_routes = rk3308_dapm_routes, -+ // .num_dapm_routes = ARRAY_SIZE(rk3308_dapm_routes), -+ // .suspend_bias_off = 1, -+ // .idle_bias_on = 1, -+ // .use_pmdown_time = 1, -+ .endianness = 1, -+ .legacy_dai_naming = 1, -+}; -+ -+static const struct reg_default rk3308_codec_reg_defaults[] = { -+ { RK3308_GLB_CON, 0x07 }, -+}; -+ -+static bool rk3308_codec_write_read_reg(struct device *dev, unsigned int reg) -+{ -+ /* All registers can be read / write */ -+ return true; -+} -+ -+static bool rk3308_codec_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ return true; -+} -+ -+static void rk3308_codec_hpdetect_work(struct work_struct *work) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(work, struct rk3308_codec_priv, hpdet_work.work); -+ unsigned int val; -+ int need_poll = 0, need_irq = 0; -+ int need_report = 0, report_type = 0; -+ int dac_output = DAC_LINEOUT; -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ /* Check headphone plugged/unplugged directly. */ -+ regmap_read(rk3308->detect_grf, -+ DETECT_GRF_ACODEC_HPDET_STATUS, &val); -+ regmap_write(rk3308->detect_grf, -+ DETECT_GRF_ACODEC_HPDET_STATUS_CLR, val); -+ -+ if (rk3308->hp_jack_reversed) { -+ switch (val) { -+ case 0x0: -+ case 0x2: -+ dac_output = DAC_HPOUT; -+ report_type = SND_JACK_HEADPHONE; -+ break; -+ default: -+ break; -+ } -+ } else { -+ switch (val) { -+ case 0x1: -+ dac_output = DAC_HPOUT; -+ report_type = SND_JACK_HEADPHONE; -+ break; -+ default: -+ /* Includes val == 2 or others. */ -+ break; -+ } -+ } -+ -+ rk3308_codec_dac_switch(rk3308, dac_output); -+ if (rk3308->hpdet_jack) -+ snd_soc_jack_report(rk3308->hpdet_jack, -+ report_type, -+ SND_JACK_HEADPHONE); -+ -+ enable_irq(rk3308->irq); -+ -+ return; -+ } -+ -+ /* Check headphone unplugged via poll. */ -+ regmap_read(rk3308->regmap, RK3308_DAC_DIG_CON14, &val); -+ -+ if (rk3308->hp_jack_reversed) { -+ if (!val) { -+ rk3308->hp_plugged = true; -+ report_type = SND_JACK_HEADPHONE; -+ -+ need_report = 1; -+ need_irq = 1; -+ } else { -+ if (rk3308->hp_plugged) { -+ rk3308->hp_plugged = false; -+ need_report = 1; -+ } -+ need_poll = 1; -+ } -+ } else { -+ if (!val) { -+ rk3308->hp_plugged = false; -+ -+ need_report = 1; -+ need_irq = 1; -+ } else { -+ if (!rk3308->hp_plugged) { -+ rk3308->hp_plugged = true; -+ report_type = SND_JACK_HEADPHONE; -+ need_report = 1; -+ } -+ need_poll = 1; -+ } -+ } -+ -+ if (need_poll) -+ queue_delayed_work(system_power_efficient_wq, -+ &rk3308->hpdet_work, -+ msecs_to_jiffies(HPDET_POLL_MS)); -+ -+ if (need_report) { -+ if (report_type) -+ dac_output = DAC_HPOUT; -+ -+ rk3308_codec_dac_switch(rk3308, dac_output); -+ -+ if (rk3308->hpdet_jack) -+ snd_soc_jack_report(rk3308->hpdet_jack, -+ report_type, -+ SND_JACK_HEADPHONE); -+ } -+ -+ if (need_irq) -+ enable_irq(rk3308->irq); -+} -+ -+static void rk3308_codec_loopback_work(struct work_struct *work) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(work, struct rk3308_codec_priv, loopback_work.work); -+ int type = ADC_TYPE_LOOPBACK; -+ int idx, grp; -+ -+ /* Prepare loopback ADCs */ -+ rk3308_codec_adc_ana_enable(rk3308, type); -+ -+ /* Waiting ADCs are stable */ -+ msleep(ADC_STABLE_MS); -+ -+ /* Recover normal mode after enable ADCs */ -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) { -+ if (grp < 0 || grp > ADC_LR_GROUP_MAX - 1) -+ continue; -+ -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_L_CH_BIST_MSK, -+ RK3308_ADC_L_CH_NORMAL_LEFT); -+ regmap_update_bits(rk3308->regmap, -+ RK3308_ADC_DIG_CON03(grp), -+ RK3308_ADC_R_CH_BIST_MSK, -+ RK3308_ADC_R_CH_NORMAL_RIGHT); -+ } -+} -+ -+static irqreturn_t rk3308_codec_hpdet_isr(int irq, void *data) -+{ -+ struct rk3308_codec_priv *rk3308 = data; -+ -+ /* -+ * For the high level irq trigger, disable irq and avoid a lot of -+ * repeated irq handlers entry. -+ */ -+ disable_irq_nosync(rk3308->irq); -+ queue_delayed_work(system_power_efficient_wq, -+ &rk3308->hpdet_work, msecs_to_jiffies(10)); -+ -+ return IRQ_HANDLED; -+} -+ -+void (*rk3308_codec_set_jack_detect_cb)(struct snd_soc_component *component, -+ struct snd_soc_jack *hpdet_jack); -+EXPORT_SYMBOL_GPL(rk3308_codec_set_jack_detect_cb); -+ -+static void rk3308_codec_set_jack_detect(struct snd_soc_component *component, -+ struct snd_soc_jack *hpdet_jack) -+{ -+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ -+ rk3308->hpdet_jack = hpdet_jack; -+ -+ /* To detect jack once during startup */ -+ disable_irq_nosync(rk3308->irq); -+ queue_delayed_work(system_power_efficient_wq, -+ &rk3308->hpdet_work, msecs_to_jiffies(10)); -+ -+ dev_info(rk3308->plat_dev, "%s: Request detect hp jack once\n", -+ __func__); -+} -+ -+static const struct regmap_config rk3308_codec_regmap_config = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .max_register = RK3308_DAC_ANA_CON15, -+ .writeable_reg = rk3308_codec_write_read_reg, -+ .readable_reg = rk3308_codec_write_read_reg, -+ .volatile_reg = rk3308_codec_volatile_reg, -+ .reg_defaults = rk3308_codec_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(rk3308_codec_reg_defaults), -+ .cache_type = REGCACHE_FLAT, -+}; -+ -+static ssize_t pm_state_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ -+ return sprintf(buf, "pm_state: %d\n", rk3308->pm_state); -+} - -- /* -- * Unconditionally enable zero-cross detection (needed for AGC, -- * harmless without AGC) -- */ -- for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) -- regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp), -- RK3308_ADC_CH1_ZEROCROSS_DET_EN | -- RK3308_ADC_CH2_ZEROCROSS_DET_EN); -+static ssize_t pm_state_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ unsigned long pm_state; -+ int ret = kstrtoul(buf, 10, &pm_state); - -- return 0; -+ if (ret < 0) { -+ dev_err(dev, "Invalid pm_state: %ld, ret: %d\n", -+ pm_state, ret); -+ return -EINVAL; -+ } -+ -+ rk3308_codec_set_pm_state(rk3308, pm_state); -+ -+ dev_info(dev, "Store pm_state: %d\n", rk3308->pm_state); -+ -+ return count; - } - --static int rk3308_codec_probe(struct snd_soc_component *component) -+static ssize_t adc_grps_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) - { -- struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ u32 grp; -+ int type = ADC_TYPE_NORMAL, count = 0; -+ int idx; - -- rk3308->component = component; -+ count += sprintf(buf + count, "current used adc_grps:\n"); -+ count += sprintf(buf + count, "- normal:"); -+ for (idx = 0; adc_for_each_grp(rk3308, type, idx, &grp); idx++) -+ count += sprintf(buf + count, " %d", grp); -+ count += sprintf(buf + count, "\n"); -+ count += sprintf(buf + count, "- loopback: %d\n", -+ rk3308->loopback_grp); - -- rk3308_codec_reset(component); -- rk3308_codec_initialize(rk3308); -+ return count; -+} - -- return 0; -+static ssize_t adc_grps_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ char adc_type; -+ int grps, ret; -+ -+ ret = sscanf(buf, "%c,%d", &adc_type, &grps); -+ if (ret != 2) { -+ dev_err(rk3308->plat_dev, "%s sscanf failed: %d\n", -+ __func__, ret); -+ return -EFAULT; -+ } -+ -+ if (adc_type == 'n') -+ rk3308->used_adc_grps = grps; -+ else if (adc_type == 'l') -+ rk3308->loopback_grp = grps; -+ -+ return count; - } - --static int rk3308_codec_set_bias_level(struct snd_soc_component *component, -- enum snd_soc_bias_level level) -+static ssize_t adc_grps_route_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) - { -- struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component); -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ char which_i2s[32] = {0}; -+ int count = 0; -+ u32 grp; - -- switch (level) { -- case SND_SOC_BIAS_ON: -+ switch (rk3308->which_i2s) { -+ case ACODEC_TO_I2S1_2CH: -+ strcpy(which_i2s, "i2s1_2ch"); - break; -- case SND_SOC_BIAS_PREPARE: -+ case ACODEC_TO_I2S3_4CH: -+ strcpy(which_i2s, "i2s3_4ch"); - break; -- case SND_SOC_BIAS_STANDBY: -- if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_OFF) -- break; -+ default: -+ strcpy(which_i2s, "i2s2_8ch"); -+ break; -+ } - -- /* Sequence from TRM Section 8.6.3 "Power Up" */ -- regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -- RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN); -- regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -- RK3308_ADC_CURRENT_CHARGE_MSK, 1); -- regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -- RK3308_ADC_REF_EN); -- regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -- RK3308_ADC_CURRENT_CHARGE_MSK, 0x7f); -- msleep(20); /* estimated value */ -+ count += sprintf(buf + count, "%s from acodec route mapping:\n", -+ which_i2s); -+ for (grp = 0; grp < rk3308->to_i2s_grps; grp++) { -+ count += sprintf(buf + count, "* sdi_%d <-- sdo_%d\n", -+ grp, rk3308->i2s_sdis[grp]); -+ } -+ -+ return count; -+} -+ -+static ssize_t adc_grps_route_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ int which_i2s, idx, i2s_sdis[ADC_LR_GROUP_MAX]; -+ int ret; -+ -+ ret = sscanf(buf, "%d,%d,%d,%d,%d", &which_i2s, -+ &i2s_sdis[0], &i2s_sdis[1], &i2s_sdis[2], &i2s_sdis[3]); -+ if (ret != 5) { -+ dev_err(rk3308->plat_dev, "%s sscanf failed: %d\n", -+ __func__, ret); -+ goto err; -+ } -+ -+ if (which_i2s < ACODEC_TO_I2S2_8CH || -+ which_i2s > ACODEC_TO_I2S1_2CH) { -+ dev_err(rk3308->plat_dev, "Invalid i2s type: %d\n", which_i2s); -+ goto err; -+ } -+ -+ rk3308->which_i2s = which_i2s; -+ -+ switch (rk3308->which_i2s) { -+ case ACODEC_TO_I2S1_2CH: -+ rk3308->to_i2s_grps = 1; - break; -- case SND_SOC_BIAS_OFF: -- /* Sequence from TRM Section 8.6.4 "Power Down" */ -- regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -- RK3308_ADC_CURRENT_CHARGE_MSK, 1); -- regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0), -- RK3308_ADC_REF_EN); -- regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02, -- RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN); -- msleep(20); /* estimated value */ -+ case ACODEC_TO_I2S3_4CH: -+ rk3308->to_i2s_grps = 2; -+ break; -+ default: -+ rk3308->to_i2s_grps = 4; - break; - } -- return 0; -+ -+ for (idx = 0; idx < rk3308->to_i2s_grps; idx++) -+ rk3308->i2s_sdis[idx] = i2s_sdis[idx]; -+ -+ rk3308_codec_adc_grps_route_config(rk3308); -+ -+err: -+ return count; - } - --static const struct snd_soc_component_driver rk3308_codec_component_driver = { -- .probe = rk3308_codec_probe, -- .set_bias_level = rk3308_codec_set_bias_level, -- .controls = rk3308_codec_controls, -- .num_controls = ARRAY_SIZE(rk3308_codec_controls), -- .dapm_widgets = rk3308_codec_dapm_widgets, -- .num_dapm_widgets = ARRAY_SIZE(rk3308_codec_dapm_widgets), -- .dapm_routes = rk3308_codec_dapm_routes, -- .num_dapm_routes = ARRAY_SIZE(rk3308_codec_dapm_routes), --}; -+static ssize_t adc_grp0_in_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); - --static const struct regmap_config rk3308_codec_regmap_config = { -- .reg_bits = 32, -- .reg_stride = 4, -- .val_bits = 32, -- .max_register = RK3308_DAC_ANA_CON15, --}; -+ return sprintf(buf, "adc ch0 using: %s\n", -+ rk3308->adc_grp0_using_linein ? "line in" : "mic in"); -+} - --static int rk3308_codec_get_version(struct rk3308_codec_priv *rk3308) -+static ssize_t adc_grp0_in_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) - { -- unsigned int chip_id; -- int err; -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ unsigned long using_linein; -+ int ret = kstrtoul(buf, 10, &using_linein); - -- err = regmap_read(rk3308->grf, GRF_CHIP_ID, &chip_id); -- if (err) -- return err; -+ if (ret < 0 || using_linein > 1) { -+ dev_err(dev, "Invalid input status: %ld, ret: %d\n", -+ using_linein, ret); -+ return -EINVAL; -+ } - -- switch (chip_id) { -- case 3306: -- rk3308->codec_ver = ACODEC_VERSION_A; -+ rk3308->adc_grp0_using_linein = using_linein; -+ -+ dev_info(dev, "store using_linein: %d\n", -+ rk3308->adc_grp0_using_linein); -+ -+ return count; -+} -+ -+static ssize_t adc_zerocross_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ -+ return sprintf(buf, "adc zerocross: %s\n", -+ rk3308->adc_zerocross ? "enabled" : "disabled"); -+} -+ -+static ssize_t adc_zerocross_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ unsigned long zerocross; -+ int ret = kstrtoul(buf, 10, &zerocross); -+ -+ if (ret < 0 || zerocross > 1) { -+ dev_err(dev, "Invalid zerocross: %ld, ret: %d\n", -+ zerocross, ret); -+ return -EINVAL; -+ } -+ -+ rk3308->adc_zerocross = zerocross; -+ -+ dev_info(dev, "store adc zerocross: %d\n", rk3308->adc_zerocross); -+ -+ return count; -+} -+ -+static ssize_t adc_grps_endisable_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ int count = 0, i; -+ -+ count += sprintf(buf + count, "enabled adc grps:"); -+ for (i = 0; i < ADC_LR_GROUP_MAX; i++) -+ count += sprintf(buf + count, "%d ", -+ rk3308->adc_grps_endisable[i]); -+ -+ count += sprintf(buf + count, "\n"); -+ return count; -+} -+ -+static ssize_t adc_grps_endisable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ int grp, endisable, ret; -+ -+ ret = sscanf(buf, "%d,%d", &grp, &endisable); -+ if (ret != 2) { -+ dev_err(rk3308->plat_dev, "%s sscanf failed: %d\n", -+ __func__, ret); -+ return -EFAULT; -+ } -+ -+ rk3308->cur_dbg_grp = grp; -+ -+ if (endisable) -+ rk3308_codec_open_dbg_capture(rk3308); -+ else -+ rk3308_codec_close_dbg_capture(rk3308); -+ -+ dev_info(dev, "ADC grp %d endisable: %d\n", grp, endisable); -+ -+ return count; -+} -+ -+static ssize_t dac_endisable_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ -+ return sprintf(buf, "%d\n", rk3308->dac_endisable); -+} -+ -+static ssize_t dac_endisable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ unsigned long endisable; -+ int ret = kstrtoul(buf, 10, &endisable); -+ -+ if (ret < 0) { -+ dev_err(dev, "Invalid endisable: %ld, ret: %d\n", -+ endisable, ret); -+ return -EINVAL; -+ } -+ -+ if (endisable) -+ rk3308_codec_open_playback(rk3308); -+ else -+ rk3308_codec_close_playback(rk3308); -+ -+ dev_info(dev, "DAC endisable: %ld\n", endisable); -+ -+ return count; -+} -+ -+static ssize_t dac_output_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ ssize_t ret = 0; -+ -+ switch (rk3308->dac_output) { -+ case DAC_LINEOUT: -+ ret = sprintf(buf, "dac path: %s\n", "line out"); - break; -- case 0x3308: -- rk3308->codec_ver = ACODEC_VERSION_B; -- return dev_err_probe(rk3308->dev, -EINVAL, "Chip version B not supported\n"); -- case 0x3308c: -- rk3308->codec_ver = ACODEC_VERSION_C; -+ case DAC_HPOUT: -+ ret = sprintf(buf, "dac path: %s\n", "hp out"); -+ break; -+ case DAC_LINEOUT_HPOUT: -+ ret = sprintf(buf, "dac path: %s\n", -+ "both line out and hp out"); - break; - default: -- return dev_err_probe(rk3308->dev, -EINVAL, "Unknown chip_id: 0x%x\n", chip_id); -+ pr_err("Invalid dac path: %d ?\n", rk3308->dac_output); -+ break; -+ } -+ -+ return ret; -+} -+ -+static ssize_t dac_output_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ unsigned long dac_output; -+ int ret = kstrtoul(buf, 10, &dac_output); -+ -+ if (ret < 0) { -+ dev_err(dev, "Invalid input status: %ld, ret: %d\n", -+ dac_output, ret); -+ return -EINVAL; -+ } -+ -+ rk3308_codec_dac_switch(rk3308, dac_output); -+ -+ dev_info(dev, "Store dac_output: %d\n", rk3308->dac_output); -+ -+ return count; -+} -+ -+static ssize_t enable_all_adcs_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ -+ return sprintf(buf, "%d\n", rk3308->enable_all_adcs); -+} -+ -+static ssize_t enable_all_adcs_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ container_of(dev, struct rk3308_codec_priv, dev); -+ unsigned long enable; -+ int ret = kstrtoul(buf, 10, &enable); -+ -+ if (ret < 0) { -+ dev_err(dev, "Invalid enable value: %ld, ret: %d\n", -+ enable, ret); -+ return -EINVAL; -+ } -+ -+ rk3308->enable_all_adcs = enable; -+ -+ return count; -+} -+ -+static const struct device_attribute acodec_attrs[] = { -+ __ATTR_RW(adc_grps), -+ __ATTR_RW(adc_grps_endisable), -+ __ATTR_RW(adc_grps_route), -+ __ATTR_RW(adc_grp0_in), -+ __ATTR_RW(adc_zerocross), -+ __ATTR_RW(dac_endisable), -+ __ATTR_RW(dac_output), -+ __ATTR_RW(enable_all_adcs), -+ __ATTR_RW(pm_state), -+}; -+ -+static void rk3308_codec_device_release(struct device *dev) -+{ -+ /* Do nothing */ -+} -+ -+static int rk3308_codec_sysfs_init(struct platform_device *pdev, -+ struct rk3308_codec_priv *rk3308) -+{ -+ struct device *dev = &rk3308->dev; -+ int i; -+ -+ dev->release = rk3308_codec_device_release; -+ dev->parent = &pdev->dev; -+ set_dev_node(dev, dev_to_node(&pdev->dev)); -+ dev_set_name(dev, "rk3308-acodec-dev"); -+ -+ if (device_register(dev)) { -+ dev_err(&pdev->dev, -+ "Register 'rk3308-acodec-dev' failed\n"); -+ dev->parent = NULL; -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(acodec_attrs); i++) { -+ if (device_create_file(dev, &acodec_attrs[i])) { -+ dev_err(&pdev->dev, -+ "Create 'rk3308-acodec-dev' attr failed\n"); -+ device_unregister(dev); -+ return -ENOMEM; -+ } - } - -- dev_info(rk3308->dev, "Found codec version %c\n", rk3308->codec_ver); - return 0; - } - --static int rk3308_codec_set_micbias_level(struct rk3308_codec_priv *rk3308) -+#if defined(CONFIG_DEBUG_FS) -+static int rk3308_codec_debugfs_reg_show(struct seq_file *s, void *v) - { -- struct device_node *np = rk3308->dev->of_node; -- u32 percent; -- u32 mult; -- int err; -+ struct rk3308_codec_priv *rk3308 = s->private; -+ unsigned int i; -+ unsigned int val; - -- err = of_property_read_u32(np, "rockchip,micbias-avdd-percent", &percent); -- if (err == -EINVAL) -- return 0; -- if (err) -- return dev_err_probe(rk3308->dev, err, -- "Error reading 'rockchip,micbias-avdd-percent'\n"); -+ for (i = RK3308_GLB_CON; i <= RK3308_DAC_ANA_CON13; i += 4) { -+ regmap_read(rk3308->regmap, i, &val); -+ if (!(i % 16)) -+ seq_printf(s, "\nR:%04x: ", i); -+ seq_printf(s, "%08x ", val); -+ } - -- /* Convert percent to register value, linerarly (50% -> 0, 5% step = +1) */ -- mult = (percent - 50) / 5; -+ seq_puts(s, "\n"); - -- /* Check range and that the percent was an exact value allowed */ -- if (mult > RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX || mult * 5 + 50 != percent) -- return dev_err_probe(rk3308->dev, -EINVAL, -- "Invalid value %u for 'rockchip,micbias-avdd-percent'\n", -- percent); -+ return 0; -+} - -- regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0), -- RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK, -- mult << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT); -+static ssize_t rk3308_codec_debugfs_reg_operate(struct file *file, -+ const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ ((struct seq_file *)file->private_data)->private; -+ unsigned int reg, val; -+ char op; -+ char kbuf[32]; -+ int ret; - -+ if (count >= sizeof(kbuf)) -+ return -EINVAL; -+ -+ if (copy_from_user(kbuf, buf, count)) -+ return -EFAULT; -+ kbuf[count] = '\0'; -+ -+ ret = sscanf(kbuf, "%c,%x,%x", &op, ®, &val); -+ if (ret != 3) { -+ pr_err("sscanf failed: %d\n", ret); -+ return -EFAULT; -+ } -+ -+ if (op == 'w') { -+ pr_info("Write reg: 0x%04x with val: 0x%08x\n", reg, val); -+ regmap_write(rk3308->regmap, reg, val); -+ regcache_cache_only(rk3308->regmap, false); -+ regcache_sync(rk3308->regmap); -+ pr_info("Read back reg: 0x%04x with val: 0x%08x\n", reg, val); -+ } else if (op == 'r') { -+ regmap_read(rk3308->regmap, reg, &val); -+ pr_info("Read reg: 0x%04x with val: 0x%08x\n", reg, val); -+ } else { -+ pr_err("This is an invalid operation: %c\n", op); -+ } -+ -+ return count; -+} -+ -+static int rk3308_codec_debugfs_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, -+ rk3308_codec_debugfs_reg_show, inode->i_private); -+} -+ -+static const struct file_operations rk3308_codec_reg_debugfs_fops = { -+ .owner = THIS_MODULE, -+ .open = rk3308_codec_debugfs_open, -+ .read = seq_read, -+ .write = rk3308_codec_debugfs_reg_operate, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+#endif /* CONFIG_DEBUG_FS */ -+ -+static int rk3308_codec_get_version(struct rk3308_codec_priv *rk3308) -+{ -+ unsigned int chip_id; -+ -+ regmap_read(rk3308->grf, GRF_CHIP_ID, &chip_id); -+ switch (chip_id) { -+ case 3306: -+ rk3308->codec_ver = ACODEC_VERSION_A; -+ break; -+ case 0x3308: -+ rk3308->codec_ver = ACODEC_VERSION_B; -+ break; -+ default: -+ pr_err("Unknown chip_id: %d / 0x%x\n", chip_id, chip_id); -+ return -EFAULT; -+ } -+ -+ pr_info("The acodec version is: %x\n", rk3308->codec_ver); - return 0; - } - --static int rk3308_codec_platform_probe(struct platform_device *pdev) -+static int rk3308_platform_probe(struct platform_device *pdev) - { - struct device_node *np = pdev->dev.of_node; -- struct device *dev = &pdev->dev; - struct rk3308_codec_priv *rk3308; -+ struct resource *res; - void __iomem *base; -- int err; -+ int ret; - - rk3308 = devm_kzalloc(&pdev->dev, sizeof(*rk3308), GFP_KERNEL); - if (!rk3308) - return -ENOMEM; - -- rk3308->dev = dev; -- - rk3308->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); -- if (IS_ERR(rk3308->grf)) -- return dev_err_probe(dev, PTR_ERR(rk3308->grf), "Error getting GRF\n"); -+ if (IS_ERR(rk3308->grf)) { -+ dev_err(&pdev->dev, -+ "Missing 'rockchip,grf' property\n"); -+ return PTR_ERR(rk3308->grf); -+ } -+ -+ ret = rk3308_codec_sysfs_init(pdev, rk3308); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Sysfs init failed\n"); -+ return ret; -+ } - -- rk3308->reset = devm_reset_control_get_optional_exclusive(dev, "codec"); -- if (IS_ERR(rk3308->reset)) -- return dev_err_probe(dev, PTR_ERR(rk3308->reset), "Failed to get reset control\n"); -+#if defined(CONFIG_DEBUG_FS) -+ rk3308->dbg_codec = debugfs_create_dir(CODEC_DRV_NAME, NULL); -+ if (IS_ERR(rk3308->dbg_codec)) -+ dev_err(&pdev->dev, -+ "Failed to create debugfs dir for rk3308!\n"); -+ else -+ debugfs_create_file("reg", 0644, rk3308->dbg_codec, -+ rk3308, &rk3308_codec_reg_debugfs_fops); -+#endif -+ rk3308->plat_dev = &pdev->dev; - -- err = devm_clk_bulk_get(dev, ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks); -- if (err) -- return dev_err_probe(dev, err, "Failed to get clocks\n"); -+ rk3308->reset = devm_reset_control_get(&pdev->dev, "acodec-reset"); -+ if (IS_ERR(rk3308->reset)) { -+ ret = PTR_ERR(rk3308->reset); -+ if (ret != -ENOENT) -+ return ret; - -- err = clk_bulk_prepare_enable(ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks); -- if (err) -- return dev_err_probe(dev, err, "Failed to enable clocks\n"); -+ dev_dbg(&pdev->dev, "No reset control found\n"); -+ rk3308->reset = NULL; -+ } -+ -+ rk3308->hp_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, "hp-ctl", -+ GPIOD_OUT_LOW); -+ if (!rk3308->hp_ctl_gpio) { -+ dev_info(&pdev->dev, "Don't need hp-ctl gpio\n"); -+ } else if (IS_ERR(rk3308->hp_ctl_gpio)) { -+ ret = PTR_ERR(rk3308->hp_ctl_gpio); -+ dev_err(&pdev->dev, "Unable to claim gpio hp-ctl\n"); -+ return ret; -+ } -+ -+ rk3308->spk_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, "spk-ctl", -+ GPIOD_OUT_LOW); -+ -+ if (!rk3308->spk_ctl_gpio) { -+ dev_info(&pdev->dev, "Don't need spk-ctl gpio\n"); -+ } else if (IS_ERR(rk3308->spk_ctl_gpio)) { -+ ret = PTR_ERR(rk3308->spk_ctl_gpio); -+ dev_err(&pdev->dev, "Unable to claim gpio spk-ctl\n"); -+ return ret; -+ } -+ -+ rk3308->pa_drv_gpio = devm_gpiod_get_optional(&pdev->dev, "pa-drv", -+ GPIOD_OUT_LOW); -+ -+ if (!rk3308->pa_drv_gpio) { -+ dev_info(&pdev->dev, "Don't need pa-drv gpio\n"); -+ } else if (IS_ERR(rk3308->pa_drv_gpio)) { -+ ret = PTR_ERR(rk3308->pa_drv_gpio); -+ dev_err(&pdev->dev, "Unable to claim gpio pa-drv\n"); -+ return ret; -+ } -+ -+ if (rk3308->pa_drv_gpio) { -+ rk3308->delay_pa_drv_ms = PA_DRV_MS; -+ ret = of_property_read_u32(np, "rockchip,delay-pa-drv-ms", -+ &rk3308->delay_pa_drv_ms); -+ } -+ -+#if DEBUG_POP_ALWAYS -+ dev_info(&pdev->dev, "Enable all ctl gpios always for debugging pop\n"); -+ rk3308_headphone_ctl(rk3308, 1); -+ rk3308_speaker_ctl(rk3308, 1); -+#else -+ dev_info(&pdev->dev, "De-pop as much as possible\n"); -+ rk3308_headphone_ctl(rk3308, 0); -+ rk3308_speaker_ctl(rk3308, 0); -+#endif -+ -+ rk3308->pclk = devm_clk_get(&pdev->dev, "acodec"); -+ if (IS_ERR(rk3308->pclk)) { -+ dev_err(&pdev->dev, "Can't get acodec pclk\n"); -+ return PTR_ERR(rk3308->pclk); -+ } -+ -+ rk3308->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx"); -+ if (IS_ERR(rk3308->mclk_rx)) { -+ dev_err(&pdev->dev, "Can't get acodec mclk_rx\n"); -+ return PTR_ERR(rk3308->mclk_rx); -+ } -+ -+ rk3308->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx"); -+ if (IS_ERR(rk3308->mclk_tx)) { -+ dev_err(&pdev->dev, "Can't get acodec mclk_tx\n"); -+ return PTR_ERR(rk3308->mclk_tx); -+ } -+ -+ ret = clk_prepare_enable(rk3308->pclk); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to enable acodec pclk: %d\n", ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(rk3308->mclk_rx); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to enable i2s mclk_rx: %d\n", ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(rk3308->mclk_tx); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to enable i2s mclk_tx: %d\n", ret); -+ return ret; -+ } -+ -+ rk3308_codec_check_micbias(rk3308, np); -+ -+ rk3308->enable_all_adcs = -+ of_property_read_bool(np, "rockchip,enable-all-adcs"); -+ -+ rk3308->hp_jack_reversed = -+ of_property_read_bool(np, "rockchip,hp-jack-reversed"); -+ -+ rk3308->no_deep_low_power = -+ of_property_read_bool(np, "rockchip,no-deep-low-power"); -+ -+ rk3308->no_hp_det = -+ of_property_read_bool(np, "rockchip,no-hp-det"); -+ -+ rk3308->delay_loopback_handle_ms = LOOPBACK_HANDLE_MS; -+ ret = of_property_read_u32(np, "rockchip,delay-loopback-handle-ms", -+ &rk3308->delay_loopback_handle_ms); -+ -+ rk3308->delay_start_play_ms = 0; -+ ret = of_property_read_u32(np, "rockchip,delay-start-play-ms", -+ &rk3308->delay_start_play_ms); -+ -+ rk3308->loopback_grp = NOT_USED; -+ ret = of_property_read_u32(np, "rockchip,loopback-grp", -+ &rk3308->loopback_grp); -+ /* -+ * If there is no loopback on some board, the -EINVAL indicates that -+ * we don't need add the node, and it is not an error. -+ */ -+ if (ret < 0 && ret != -EINVAL) { -+ dev_err(&pdev->dev, "Failed to read loopback property: %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = rk3308_codec_adc_grps_route(rk3308, np); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to route ADC groups: %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = rk3308_codec_setup_en_always_adcs(rk3308, np); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to setup enabled always ADCs: %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = rk3308_codec_get_version(rk3308); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to get acodec version: %d\n", -+ ret); -+ return ret; -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) { -+ ret = PTR_ERR(base); -+ dev_err(&pdev->dev, "Failed to ioremap resource\n"); -+ goto failed; -+ } -+ -+ rk3308->regmap = devm_regmap_init_mmio(&pdev->dev, base, -+ &rk3308_codec_regmap_config); -+ if (IS_ERR(rk3308->regmap)) { -+ ret = PTR_ERR(rk3308->regmap); -+ dev_err(&pdev->dev, "Failed to regmap mmio\n"); -+ goto failed; -+ } -+ -+ if (!rk3308->no_hp_det) { -+ int index = 0; -+ -+ if (rk3308->codec_ver == ACODEC_VERSION_B) -+ index = 1; -+ -+ rk3308->irq = platform_get_irq(pdev, index); -+ if (rk3308->irq < 0) { -+ dev_err(&pdev->dev, "Can not get codec irq\n"); -+ goto failed; -+ } -+ -+ INIT_DELAYED_WORK(&rk3308->hpdet_work, rk3308_codec_hpdetect_work); -+ -+ ret = devm_request_irq(&pdev->dev, rk3308->irq, -+ rk3308_codec_hpdet_isr, -+ 0, -+ "acodec-hpdet", -+ rk3308); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to request IRQ: %d\n", ret); -+ goto failed; -+ } - -- err = rk3308_codec_get_version(rk3308); -- if (err) -- return err; -+ if (rk3308->codec_ver == ACODEC_VERSION_B) { -+ rk3308->detect_grf = -+ syscon_regmap_lookup_by_phandle(np, "rockchip,detect-grf"); -+ if (IS_ERR(rk3308->detect_grf)) { -+ dev_err(&pdev->dev, -+ "Missing 'rockchip,detect-grf' property\n"); -+ return PTR_ERR(rk3308->detect_grf); -+ } -+ -+ /* Configure filter count and enable hpdet irq. */ -+ regmap_write(rk3308->detect_grf, -+ DETECT_GRF_ACODEC_HPDET_COUNTER, -+ DEFAULT_HPDET_COUNT); -+ regmap_write(rk3308->detect_grf, -+ DETECT_GRF_ACODEC_HPDET_CON, -+ (HPDET_BOTH_NEG_POS << 16) | -+ HPDET_BOTH_NEG_POS); -+ } -+ -+ rk3308_codec_set_jack_detect_cb = rk3308_codec_set_jack_detect; -+ } - -- base = devm_platform_ioremap_resource(pdev, 0); -- if (IS_ERR(base)) -- return PTR_ERR(base); -+ if (rk3308->codec_ver == ACODEC_VERSION_A) -+ INIT_DELAYED_WORK(&rk3308->loopback_work, -+ rk3308_codec_loopback_work); - -- rk3308->regmap = devm_regmap_init_mmio(dev, base, &rk3308_codec_regmap_config); -- if (IS_ERR(rk3308->regmap)) -- return dev_err_probe(dev, PTR_ERR(rk3308->regmap), -- "Failed to init regmap\n"); -+ rk3308->adc_grp0_using_linein = ADC_GRP0_MICIN; -+ rk3308->dac_output = DAC_LINEOUT; -+ rk3308->adc_zerocross = 1; -+ rk3308->pm_state = PM_NORMAL; - - platform_set_drvdata(pdev, rk3308); - -- err = rk3308_codec_set_micbias_level(rk3308); -- if (err) -- return err; -+ ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk3308_component, -+ rk3308_dai, ARRAY_SIZE(rk3308_dai)); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Failed to register component: %d\n", ret); -+ goto failed; -+ } - -- err = devm_snd_soc_register_component(dev, &rk3308_codec_component_driver, -- &rk3308_codec_dai_driver, 1); -- if (err) -- return dev_err_probe(dev, err, "Failed to register codec\n"); -+ return ret; - -- return 0; -+failed: -+ clk_disable_unprepare(rk3308->mclk_rx); -+ clk_disable_unprepare(rk3308->mclk_tx); -+ clk_disable_unprepare(rk3308->pclk); -+ device_unregister(&rk3308->dev); -+ -+ return ret; -+} -+ -+static void rk3308_platform_remove(struct platform_device *pdev) -+{ -+ struct rk3308_codec_priv *rk3308 = -+ (struct rk3308_codec_priv *)platform_get_drvdata(pdev); -+ -+ clk_disable_unprepare(rk3308->mclk_rx); -+ clk_disable_unprepare(rk3308->mclk_tx); -+ clk_disable_unprepare(rk3308->pclk); -+ device_unregister(&rk3308->dev); -+ -+ return; - } - --static const struct of_device_id __maybe_unused rk3308_codec_of_match[] = { -+static const struct of_device_id rk3308codec_of_match[] = { - { .compatible = "rockchip,rk3308-codec", }, - {}, - }; --MODULE_DEVICE_TABLE(of, rk3308_codec_of_match); -+MODULE_DEVICE_TABLE(of, rk3308codec_of_match); - - static struct platform_driver rk3308_codec_driver = { - .driver = { -- .name = "rk3308-acodec", -- .of_match_table = rk3308_codec_of_match, -+ .name = CODEC_DRV_NAME, -+ .of_match_table = of_match_ptr(rk3308codec_of_match), - }, -- .probe = rk3308_codec_platform_probe, -+ .probe = rk3308_platform_probe, -+ .remove = rk3308_platform_remove, - }; - module_platform_driver(rk3308_codec_driver); - - MODULE_AUTHOR("Xing Zheng "); --MODULE_AUTHOR("Luca Ceresoli "); - MODULE_DESCRIPTION("ASoC RK3308 Codec Driver"); --MODULE_LICENSE("GPL"); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/rk3308_codec.h b/sound/soc/codecs/rk3308_codec.h -index 111111111111..222222222222 100644 ---- a/sound/soc/codecs/rk3308_codec.h -+++ b/sound/soc/codecs/rk3308_codec.h -@@ -1,15 +1,114 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ - /* -- * Rockchip RK3308 internal audio codec driver -- register definitions -+ * rk3308_codec.h -- RK3308 ALSA Soc Audio Driver - * - * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. -- * Copyright (c) 2022, Vivax-Metrotech Ltd -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * - */ - - #ifndef __RK3308_CODEC_H__ - #define __RK3308_CODEC_H__ - --#define RK3308_GLB_CON 0x00 -+#define ACODEC_RESET_CTL 0x00 /* REG 0x00 */ -+ -+/* ADC DIGITAL REGISTERS */ -+#define ACODEC_ADC_I2S_CTL0 0x04 /* REG 0x01 */ -+#define ACODEC_ADC_I2S_CTL1 0x08 /* REG 0x02 */ -+#define ACODEC_ADC_BIST_MODE_SEL 0x0c /* REG 0x03 */ -+#define ACODEC_ADC_HPF_PATH 0x10 /* REG 0x04 */ -+/* Resevred REG 0x05 ~ 0x06 */ -+#define ACODEC_ADC_DATA_PATH 0x1c /* REG 0x07 */ -+/* Resevred REG 0x08 ~ 0x0f */ -+ -+/* REG 0x10 ~ 0x1c are used to configure AGC of Left channel (ALC1) */ -+#define ACODEC_ADC_PGA_AGC_L_CTL0 0x40 /* REG 0x10 */ -+#define ACODEC_ADC_PGA_AGC_L_CTL1 0x44 /* REG 0x11 */ -+#define ACODEC_ADC_PGA_AGC_L_CTL2 0x48 /* REG 0x12 */ -+#define ACODEC_ADC_PGA_AGC_L_CTL3 0x4c /* REG 0x13 */ -+#define ACODEC_ADC_PGA_AGC_L_CTL4 0x50 /* REG 0x14 */ -+#define ACODEC_ADC_PGA_AGC_L_LO_MAX 0x54 /* REG 0x15 */ -+#define ACODEC_ADC_PGA_AGC_L_HI_MAX 0x58 /* REG 0x16 */ -+#define ACODEC_ADC_PGA_AGC_L_LO_MIN 0x5c /* REG 0x17 */ -+#define ACODEC_ADC_PGA_AGC_L_HI_MIN 0x60 /* REG 0x18 */ -+#define ACODEC_ADC_PGA_AGC_L_CTL5 0x64 /* REG 0x19 */ -+/* Resevred REG 0x1a ~ 0x1b */ -+#define ACODEC_ADC_AGC_L_RO_GAIN 0x70 /* REG 0x1c */ -+ -+/* REG 0x20 ~ 0x2c are used to configure AGC of Right channel (ALC2) */ -+#define ACODEC_ADC_PGA_AGC_R_CTL0 0x80 /* REG 0x20 */ -+#define ACODEC_ADC_PGA_AGC_R_CTL1 0x84 /* REG 0x21 */ -+#define ACODEC_ADC_PGA_AGC_R_CTL2 0x88 /* REG 0x22 */ -+#define ACODEC_ADC_PGA_AGC_R_CTL3 0x8c /* REG 0x23 */ -+#define ACODEC_ADC_PGA_AGC_R_CTL4 0x90 /* REG 0x24 */ -+#define ACODEC_ADC_PGA_AGC_R_LO_MAX 0x94 /* REG 0x25 */ -+#define ACODEC_ADC_PGA_AGC_R_HI_MAX 0x98 /* REG 0x26 */ -+#define ACODEC_ADC_PGA_AGC_R_LO_MIN 0x9c /* REG 0x27 */ -+#define ACODEC_ADC_PGA_AGC_R_HI_MIN 0xa0 /* REG 0x28 */ -+#define ACODEC_ADC_PGA_AGC_R_CTL5 0xa4 /* REG 0x29 */ -+/* Resevred REG 0x2a ~ 0x2b */ -+#define ACODEC_ADC_AGC_R_RO_GAIN 0xb0 /* REG 0x2c */ -+ -+/* DAC DIGITAL REGISTERS */ -+#define ACODEC_DAC_I2S_CTL0 0x04 /* REG 0x01 */ -+#define ACODEC_DAC_I2S_CTL1 0x08 /* REG 0x02 */ -+#define ACODEC_DAC_BIST_MODE_SEL 0x0c /* REG 0x03 */ -+#define ACODEC_DAC_DIGITAL_GAIN 0x10 /* REG 0x04 */ -+#define ACODEC_DAC_DATA_SEL 0x14 /* REG 0x05 */ -+/* Resevred REG 0x06 ~ 0x09 */ -+#define ACODEC_DAC_DATA_HI 0x28 /* REG 0x0a */ -+#define ACODEC_DAC_DATA_LO 0x2c /* REG 0x0b */ -+/* Resevred REG 0x0c */ -+#define ACODEC_DAC_HPDET_DELAYTIME 0x34 /* REG 0x0d */ -+#define ACODEC_DAC_HPDET_STATUS 0x38 /* REG 0x0e, Read-only */ -+/* Resevred REG 0x0f */ -+ -+/* ADC ANALOG REGISTERS */ -+#define ACODEC_ADC_ANA_MIC_CTL 0x00 /* REG 0x00 */ -+#define ACODEC_ADC_ANA_MIC_GAIN 0x04 /* REG 0x01 */ -+#define ACODEC_ADC_ANA_ALC_CTL 0x08 /* REG 0x02 */ -+#define ACODEC_ADC_ANA_ALC_GAIN1 0x0c /* REG 0x03 */ -+#define ACODEC_ADC_ANA_ALC_GAIN2 0x10 /* REG 0x04 */ -+#define ACODEC_ADC_ANA_CTL0 0x14 /* REG 0x05 */ -+#define ACODEC_ADC_ANA_CTL1 0x18 /* REG 0x06 */ -+#define ACODEC_ADC_ANA_CTL2 0x1c /* REG 0x07 */ -+#define ACODEC_ADC_ANA_CTL3 0x20 /* REG 0x08 */ -+/* Resevred REG 0x09 */ -+#define ACODEC_ADC_ANA_CTL4 0x28 /* REG 0x0a */ -+#define ACODEC_ADC_ANA_ALC_PGA 0x2c /* REG 0x0b */ -+/* Resevred REG 0x0c ~ 0x0f */ -+ -+/* DAC ANALOG REGISTERS */ -+#define ACODEC_DAC_ANA_CTL0 0x00 /* REG 0x00 */ -+#define ACODEC_DAC_ANA_POP_VOLT 0x04 /* REG 0x01 */ -+#define ACODEC_DAC_ANA_CTL1 0x08 /* REG 0x02 */ -+#define ACODEC_DAC_ANA_HPOUT 0x0c /* REG 0x03 */ -+#define ACODEC_DAC_ANA_LINEOUT 0x10 /* REG 0x04 */ -+#define ACODEC_DAC_ANA_L_HPOUT_GAIN 0x14 /* REG 0x05 */ -+#define ACODEC_DAC_ANA_R_HPOUT_GAIN 0x18 /* REG 0x06 */ -+#define ACODEC_DAC_ANA_DRV_HPOUT 0x1c /* REG 0x07 */ -+#define ACODEC_DAC_ANA_DRV_LINEOUT 0x20 /* REG 0x08 */ -+/* Resevred REG 0x07 ~ 0x0b */ -+#define ACODEC_DAC_ANA_HPMIX_CTL0 0x30 /* REG 0x0c */ -+#define ACODEC_DAC_ANA_HPMIX_CTL1 0x34 /* REG 0x0d */ -+#define ACODEC_DAC_ANA_LINEOUT_CTL0 0x38 /* REG 0x0e */ -+#define ACODEC_DAC_ANA_LINEOUT_CTL1 0x3c /* REG 0x0f */ -+ -+/* -+ * These registers are referenced by codec driver -+ */ -+ -+#define RK3308_GLB_CON ACODEC_RESET_CTL - - /* ADC DIGITAL REGISTERS */ - -@@ -21,51 +120,50 @@ - * CH2: left_2(ADC5) and right_2(ADC6) - * CH3: left_3(ADC7) and right_3(ADC8) - */ --#define RK3308_ADC_DIG_OFFSET(ch) (((ch) & 0x3) * 0xc0 + 0x0) -- --#define RK3308_ADC_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x04) --#define RK3308_ADC_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x08) --#define RK3308_ADC_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x0c) --#define RK3308_ADC_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x10) --#define RK3308_ADC_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x14) // ver.C only --#define RK3308_ADC_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x18) // ver.C only --#define RK3308_ADC_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x1c) -- --#define RK3308_ALC_L_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x40) --#define RK3308_ALC_L_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x44) --#define RK3308_ALC_L_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x48) --#define RK3308_ALC_L_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x4c) --#define RK3308_ALC_L_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x50) --#define RK3308_ALC_L_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x54) --#define RK3308_ALC_L_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x58) --#define RK3308_ALC_L_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x5c) --#define RK3308_ALC_L_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x60) --#define RK3308_ALC_L_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x64) --#define RK3308_ALC_L_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x70) -- --#define RK3308_ALC_R_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x80) --#define RK3308_ALC_R_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x84) --#define RK3308_ALC_R_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x88) --#define RK3308_ALC_R_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x8c) --#define RK3308_ALC_R_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x90) --#define RK3308_ALC_R_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x94) --#define RK3308_ALC_R_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x98) --#define RK3308_ALC_R_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x9c) --#define RK3308_ALC_R_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa0) --#define RK3308_ALC_R_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa4) --#define RK3308_ALC_R_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xb0) -+#define RK3308_ADC_DIG_OFFSET(ch) ((ch & 0x3) * 0xc0 + 0x0) -+ -+#define RK3308_ADC_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_I2S_CTL0) -+#define RK3308_ADC_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_I2S_CTL1) -+#define RK3308_ADC_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_BIST_MODE_SEL) -+#define RK3308_ADC_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_HPF_PATH) -+#define RK3308_ADC_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_DATA_PATH) -+ -+#define RK3308_ALC_L_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL0) -+#define RK3308_ALC_L_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL1) -+#define RK3308_ALC_L_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL2) -+#define RK3308_ALC_L_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL3) -+#define RK3308_ALC_L_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL4) -+#define RK3308_ALC_L_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_LO_MAX) -+#define RK3308_ALC_L_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_HI_MAX) -+#define RK3308_ALC_L_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_LO_MIN) -+#define RK3308_ALC_L_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_HI_MIN) -+#define RK3308_ALC_L_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_L_CTL5) -+#define RK3308_ALC_L_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_AGC_L_RO_GAIN) -+ -+#define RK3308_ALC_R_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL0) -+#define RK3308_ALC_R_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL1) -+#define RK3308_ALC_R_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL2) -+#define RK3308_ALC_R_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL3) -+#define RK3308_ALC_R_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL4) -+#define RK3308_ALC_R_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_LO_MAX) -+#define RK3308_ALC_R_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_HI_MAX) -+#define RK3308_ALC_R_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_LO_MIN) -+#define RK3308_ALC_R_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_HI_MIN) -+#define RK3308_ALC_R_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_PGA_AGC_R_CTL5) -+#define RK3308_ALC_R_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET(ch) + ACODEC_ADC_AGC_R_RO_GAIN) - - /* DAC DIGITAL REGISTERS */ - #define RK3308_DAC_DIG_OFFSET 0x300 --#define RK3308_DAC_DIG_CON01 (RK3308_DAC_DIG_OFFSET + 0x04) --#define RK3308_DAC_DIG_CON02 (RK3308_DAC_DIG_OFFSET + 0x08) --#define RK3308_DAC_DIG_CON03 (RK3308_DAC_DIG_OFFSET + 0x0c) --#define RK3308_DAC_DIG_CON04 (RK3308_DAC_DIG_OFFSET + 0x10) --#define RK3308_DAC_DIG_CON05 (RK3308_DAC_DIG_OFFSET + 0x14) --#define RK3308_DAC_DIG_CON10 (RK3308_DAC_DIG_OFFSET + 0x28) --#define RK3308_DAC_DIG_CON11 (RK3308_DAC_DIG_OFFSET + 0x2c) --#define RK3308_DAC_DIG_CON13 (RK3308_DAC_DIG_OFFSET + 0x34) --#define RK3308_DAC_DIG_CON14 (RK3308_DAC_DIG_OFFSET + 0x38) -+ -+#define RK3308_DAC_DIG_CON01 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_I2S_CTL0) -+#define RK3308_DAC_DIG_CON02 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_I2S_CTL1) -+#define RK3308_DAC_DIG_CON03 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_BIST_MODE_SEL) -+#define RK3308_DAC_DIG_CON04 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DIGITAL_GAIN) -+#define RK3308_DAC_DIG_CON05 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DATA_SEL) -+#define RK3308_DAC_DIG_CON10 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DATA_HI) -+#define RK3308_DAC_DIG_CON11 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_DATA_LO) -+#define RK3308_DAC_DIG_CON13 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_HPDET_DELAYTIME) -+#define RK3308_DAC_DIG_CON14 (RK3308_DAC_DIG_OFFSET + ACODEC_DAC_HPDET_STATUS) - - /* ADC ANALOG REGISTERS */ - /* -@@ -76,50 +174,63 @@ - * CH2: left_2(ADC5) and right_2(ADC6) - * CH3: left_3(ADC7) and right_3(ADC8) - */ --#define RK3308_ADC_ANA_OFFSET(ch) (((ch) & 0x3) * 0x40 + 0x340) --#define RK3308_ADC_ANA_CON00(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x00) --#define RK3308_ADC_ANA_CON01(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x04) --#define RK3308_ADC_ANA_CON02(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x08) --#define RK3308_ADC_ANA_CON03(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x0c) --#define RK3308_ADC_ANA_CON04(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x10) --#define RK3308_ADC_ANA_CON05(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x14) --#define RK3308_ADC_ANA_CON06(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x18) --#define RK3308_ADC_ANA_CON07(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x1c) --#define RK3308_ADC_ANA_CON08(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x20) --#define RK3308_ADC_ANA_CON10(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x28) --#define RK3308_ADC_ANA_CON11(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x2c) -+#define RK3308_ADC_ANA_OFFSET(ch) ((ch & 0x3) * 0x40 + 0x340) -+ -+#define RK3308_ADC_ANA_CON00(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_MIC_CTL) -+#define RK3308_ADC_ANA_CON01(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_MIC_GAIN) -+#define RK3308_ADC_ANA_CON02(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_CTL) -+#define RK3308_ADC_ANA_CON03(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_GAIN1) -+#define RK3308_ADC_ANA_CON04(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_GAIN2) -+#define RK3308_ADC_ANA_CON05(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL0) -+#define RK3308_ADC_ANA_CON06(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL1) -+#define RK3308_ADC_ANA_CON07(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL2) -+#define RK3308_ADC_ANA_CON08(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL3) -+#define RK3308_ADC_ANA_CON10(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_CTL4) -+#define RK3308_ADC_ANA_CON11(ch) (RK3308_ADC_ANA_OFFSET(ch) + ACODEC_ADC_ANA_ALC_PGA) - - /* DAC ANALOG REGISTERS */ - #define RK3308_DAC_ANA_OFFSET 0x440 --#define RK3308_DAC_ANA_CON00 (RK3308_DAC_ANA_OFFSET + 0x00) --#define RK3308_DAC_ANA_CON01 (RK3308_DAC_ANA_OFFSET + 0x04) --#define RK3308_DAC_ANA_CON02 (RK3308_DAC_ANA_OFFSET + 0x08) --#define RK3308_DAC_ANA_CON03 (RK3308_DAC_ANA_OFFSET + 0x0c) --#define RK3308_DAC_ANA_CON04 (RK3308_DAC_ANA_OFFSET + 0x10) --#define RK3308_DAC_ANA_CON05 (RK3308_DAC_ANA_OFFSET + 0x14) --#define RK3308_DAC_ANA_CON06 (RK3308_DAC_ANA_OFFSET + 0x18) --#define RK3308_DAC_ANA_CON07 (RK3308_DAC_ANA_OFFSET + 0x1c) --#define RK3308_DAC_ANA_CON08 (RK3308_DAC_ANA_OFFSET + 0x20) --#define RK3308_DAC_ANA_CON12 (RK3308_DAC_ANA_OFFSET + 0x30) --#define RK3308_DAC_ANA_CON13 (RK3308_DAC_ANA_OFFSET + 0x34) --#define RK3308_DAC_ANA_CON14 (RK3308_DAC_ANA_OFFSET + 0x38) --#define RK3308_DAC_ANA_CON15 (RK3308_DAC_ANA_OFFSET + 0x3c) -+#define RK3308_DAC_ANA_CON00 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_CTL0) -+#define RK3308_DAC_ANA_CON01 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_POP_VOLT) -+#define RK3308_DAC_ANA_CON02 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_CTL1) -+#define RK3308_DAC_ANA_CON03 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_HPOUT) -+#define RK3308_DAC_ANA_CON04 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_LINEOUT) -+#define RK3308_DAC_ANA_CON05 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_L_HPOUT_GAIN) -+#define RK3308_DAC_ANA_CON06 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_R_HPOUT_GAIN) -+#define RK3308_DAC_ANA_CON07 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_DRV_HPOUT) -+#define RK3308_DAC_ANA_CON08 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_DRV_LINEOUT) -+#define RK3308_DAC_ANA_CON12 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_HPMIX_CTL0) -+#define RK3308_DAC_ANA_CON13 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_HPMIX_CTL1) -+#define RK3308_DAC_ANA_CON14 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_LINEOUT_CTL0) -+#define RK3308_DAC_ANA_CON15 (RK3308_DAC_ANA_OFFSET + ACODEC_DAC_ANA_LINEOUT_CTL1) - - /* - * These are the bits for registers - */ - - /* RK3308_GLB_CON - REG: 0x0000 */ --#define RK3308_ADC_BIST_WORK BIT(7) --#define RK3308_DAC_BIST_WORK BIT(6) --#define RK3308_ADC_MCLK_GATING BIT(5) --#define RK3308_DAC_MCLK_GATING BIT(4) --#define RK3308_ADC_DIG_WORK BIT(2) --#define RK3308_DAC_DIG_WORK BIT(1) --#define RK3308_SYS_WORK BIT(0) -+#define RK3308_ADC_BIST_WORK (1 << 7) -+#define RK3308_ADC_BIST_RESET (0 << 7) -+#define RK3308_DAC_BIST_WORK (1 << 6) -+#define RK3308_DAC_BIST_RESET (0 << 6) -+#define RK3308_ADC_MCLK_MSK (1 << 5) -+#define RK3308_ADC_MCLK_DIS (1 << 5) -+#define RK3308_ADC_MCLK_EN (0 << 5) -+#define RK3308_DAC_MCLK_MSK (1 << 4) -+#define RK3308_DAC_MCLK_DIS (1 << 4) -+#define RK3308_DAC_MCLK_EN (0 << 4) -+#define RK3308_CODEC_RST_MSK (0x7 << 0) -+#define RK3308_ADC_DIG_WORK (1 << 2) -+#define RK3308_ADC_DIG_RESET (0 << 2) -+#define RK3308_DAC_DIG_WORK (1 << 1) -+#define RK3308_DAC_DIG_RESET (0 << 1) -+#define RK3308_SYS_WORK (1 << 0) -+#define RK3308_SYS_RESET (0 << 0) - - /* RK3308_ADC_DIG_CON01 - REG: 0x0004 */ --#define RK3308_ADC_I2S_LRC_POL_REVERSAL BIT(7) -+#define RK3308_ADC_I2S_LRC_POL_MSK (1 << 0) -+#define RK3308_ADC_I2S_LRC_POL_REVERSAL (1 << 0) -+#define RK3308_ADC_I2S_LRC_POL_NORMAL (0 << 0) - #define RK3308_ADC_I2S_VALID_LEN_SFT 5 - #define RK3308_ADC_I2S_VALID_LEN_MSK (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT) - #define RK3308_ADC_I2S_VALID_LEN_32BITS (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT) -@@ -132,20 +243,32 @@ - #define RK3308_ADC_I2S_MODE_I2S (0x2 << RK3308_ADC_I2S_MODE_SFT) - #define RK3308_ADC_I2S_MODE_LJ (0x1 << RK3308_ADC_I2S_MODE_SFT) - #define RK3308_ADC_I2S_MODE_RJ (0x0 << RK3308_ADC_I2S_MODE_SFT) --#define RK3308_ADC_I2S_LR_SWAP BIT(1) --#define RK3308_ADC_I2S_MONO BIT(0) -+#define RK3308_ADC_I2S_LR_MSK (1 << 1) -+#define RK3308_ADC_I2S_LR_SWAP (1 << 1) -+#define RK3308_ADC_I2S_LR_NORMAL (0 << 1) -+#define RK3308_ADC_I2S_TYPE_MSK (1 << 0) -+#define RK3308_ADC_I2S_MONO (1 << 0) -+#define RK3308_ADC_I2S_STEREO (0 << 0) - - /* RK3308_ADC_DIG_CON02 - REG: 0x0008 */ --#define RK3308_ADC_IO_MODE_MASTER BIT(5) --#define RK3308_ADC_MODE_MASTER BIT(4) -+#define RK3308_ADC_IO_MODE_MSK (1 << 5) -+#define RK3308_ADC_IO_MODE_MASTER (1 << 5) -+#define RK3308_ADC_IO_MODE_SLAVE (0 << 5) -+#define RK3308_ADC_MODE_MSK (1 << 4) -+#define RK3308_ADC_MODE_MASTER (1 << 4) -+#define RK3308_ADC_MODE_SLAVE (0 << 4) - #define RK3308_ADC_I2S_FRAME_LEN_SFT 2 - #define RK3308_ADC_I2S_FRAME_LEN_MSK (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT) - #define RK3308_ADC_I2S_FRAME_32BITS (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT) - #define RK3308_ADC_I2S_FRAME_24BITS (0x2 << RK3308_ADC_I2S_FRAME_LEN_SFT) - #define RK3308_ADC_I2S_FRAME_20BITS (0x1 << RK3308_ADC_I2S_FRAME_LEN_SFT) - #define RK3308_ADC_I2S_FRAME_16BITS (0x0 << RK3308_ADC_I2S_FRAME_LEN_SFT) --#define RK3308_ADC_I2S_WORK BIT(1) --#define RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL BIT(0) -+#define RK3308_ADC_I2S_MSK (0x1 << 1) -+#define RK3308_ADC_I2S_WORK (0x1 << 1) -+#define RK3308_ADC_I2S_RESET (0x0 << 1) -+#define RK3308_ADC_I2S_BIT_CLK_POL_MSK (0x1 << 0) -+#define RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) -+#define RK3308_ADC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) - - /* RK3308_ADC_DIG_CON03 - REG: 0x000c */ - #define RK3308_ADC_L_CH_BIST_SFT 2 -@@ -162,7 +285,10 @@ - #define RK3308_ADC_R_CH_NORMAL_RIGHT (0x0 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */ - - /* RK3308_ADC_DIG_CON04 - REG: 0x0010 */ --#define RK3308_ADC_HPF_PATH_DIS BIT(2) -+#define RK3308_ADC_HPF_PATH_SFT 2 -+#define RK3308_ADC_HPF_PATH_MSK (1 << RK3308_ADC_HPF_PATH_SFT) -+#define RK3308_ADC_HPF_PATH_DIS (1 << RK3308_ADC_HPF_PATH_SFT) -+#define RK3308_ADC_HPF_PATH_EN (0 << RK3308_ADC_HPF_PATH_SFT) - #define RK3308_ADC_HPF_CUTOFF_SFT 0 - #define RK3308_ADC_HPF_CUTOFF_MSK (0x3 << RK3308_ADC_HPF_CUTOFF_SFT) - #define RK3308_ADC_HPF_CUTOFF_612HZ (0x2 << RK3308_ADC_HPF_CUTOFF_SFT) -@@ -171,15 +297,20 @@ - - /* RK3308_ADC_DIG_CON07 - REG: 0x001c */ - #define RK3308_ADCL_DATA_SFT 4 -+#define RK3308_ADCL_DATA(x) (x << RK3308_ADCL_DATA_SFT) - #define RK3308_ADCR_DATA_SFT 2 --#define RK3308_ADCL_DATA_SEL_ADCL BIT(1) --#define RK3308_ADCR_DATA_SEL_ADCR BIT(0) -+#define RK3308_ADCR_DATA(x) (x << RK3308_ADCR_DATA_SFT) -+#define RK3308_ADCL_DATA_SEL_ADCL (0x1 << 1) -+#define RK3308_ADCL_DATA_SEL_NORMAL (0x0 << 1) -+#define RK3308_ADCR_DATA_SEL_ADCR (0x1 << 0) -+#define RK3308_ADCR_DATA_SEL_NORMAL (0x0 << 0) - - /* - * RK3308_ALC_L_DIG_CON00 - REG: 0x0040 + ch * 0xc0 - * RK3308_ALC_R_DIG_CON00 - REG: 0x0080 + ch * 0xc0 - */ --#define RK3308_GAIN_ATTACK_JACK BIT(6) -+#define RK3308_GAIN_ATTACK_JACK (0x1 << 6) -+#define RK3308_GAIN_ATTACK_NORMAL (0x0 << 6) - #define RK3308_CTRL_GEN_SFT 4 - #define RK3308_CTRL_GEN_MSK (0x3 << RK3308_ALC_CTRL_GEN_SFT) - #define RK3308_CTRL_GEN_JACK3 (0x3 << RK3308_ALC_CTRL_GEN_SFT) -@@ -205,36 +336,145 @@ - * RK3308_ALC_R_DIG_CON01 - REG: 0x0084 + ch * 0xc0 - */ - #define RK3308_AGC_DECAY_TIME_SFT 4 -+/* Normal mode (reg_agc_mode = 0) */ -+#define RK3308_AGC_DECAY_NORMAL_MSK (0xf << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_512MS (0xa << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_256MS (0x9 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_128MS (0x8 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_64MS (0x7 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_32MS (0x6 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_16MS (0x5 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_8MS (0x4 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_4MS (0x3 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_2MS (0x2 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_1MS (0x1 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_NORMAL_0MS (0x0 << RK3308_AGC_DECAY_TIME_SFT) -+/* Limiter mode (reg_agc_mode = 1) */ -+#define RK3308_AGC_DECAY_LIMITER_MSK (0xf << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_128MS (0xa << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_64MS (0x9 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_32MS (0x8 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_16MS (0x7 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_8MS (0x6 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_4MS (0x5 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_2MS (0x4 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_1MS (0x3 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_500US (0x2 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_250US (0x1 << RK3308_AGC_DECAY_TIME_SFT) -+#define RK3308_AGC_DECAY_LIMITER_125US (0x0 << RK3308_AGC_DECAY_TIME_SFT) -+ - #define RK3308_AGC_ATTACK_TIME_SFT 0 -+/* Normal mode (reg_agc_mode = 0) */ -+#define RK3308_AGC_ATTACK_NORMAL_MSK (0xf << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_128MS (0xa << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_64MS (0x9 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_32MS (0x8 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_16MS (0x7 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_8MS (0x6 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_4MS (0x5 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_2MS (0x4 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_1MS (0x3 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_500US (0x2 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_250US (0x1 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_NORMAL_125US (0x0 << RK3308_AGC_ATTACK_TIME_SFT) -+/* Limiter mode (reg_agc_mode = 1) */ -+#define RK3308_AGC_ATTACK_LIMITER_MSK (0xf << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_32MS (0xa << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_16MS (0x9 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_8MS (0x8 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_4MS (0x7 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_2MS (0x6 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_1MS (0x5 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_500US (0x4 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_250US (0x3 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_125US (0x2 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_64US (0x1 << RK3308_AGC_ATTACK_TIME_SFT) -+#define RK3308_AGC_ATTACK_LIMITER_32US (0x0 << RK3308_AGC_ATTACK_TIME_SFT) - - /* - * RK3308_ALC_L_DIG_CON02 - REG: 0x0048 + ch * 0xc0 - * RK3308_ALC_R_DIG_CON02 - REG: 0x0088 + ch * 0xc0 - */ --#define RK3308_AGC_MODE_LIMITER BIT(7) --#define RK3308_AGC_ZERO_CRO_EN BIT(6) --#define RK3308_AGC_AMP_RECOVER_GAIN BIT(5) --#define RK3308_AGC_FAST_DEC_EN BIT(4) --#define RK3308_AGC_NOISE_GATE_EN BIT(3) -+#define RK3308_AGC_MODE_LIMITER (0x1 << 7) -+#define RK3308_AGC_MODE_NORMAL (0x0 << 7) -+#define RK3308_AGC_ZERO_CRO_EN (0x1 << 6) -+#define RK3308_AGC_ZERO_CRO_DIS (0x0 << 6) -+#define RK3308_AGC_AMP_RECOVER_GAIN (0x1 << 5) -+#define RK3308_AGC_AMP_RECOVER_LVOL (0x0 << 5) -+#define RK3308_AGC_FAST_DEC_EN (0x1 << 4) -+#define RK3308_AGC_FAST_DEC_DIS (0x0 << 4) -+#define RK3308_AGC_NOISE_GATE_EN (0x1 << 3) -+#define RK3308_AGC_NOISE_GATE_DIS (0x0 << 3) - #define RK3308_AGC_NOISE_GATE_THRESH_SFT 0 - #define RK3308_AGC_NOISE_GATE_THRESH_MSK (0x7 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N81DB (0x7 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N75DB (0x6 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N69DB (0x5 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N63DB (0x4 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N57DB (0x3 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N51DB (0x2 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N45DB (0x1 << RK3308_AGC_NOISE_GATE_THRESH_SFT) -+#define RK3308_AGC_NOISE_GATE_THRESH_N39DB (0x0 << RK3308_AGC_NOISE_GATE_THRESH_SFT) - - /* - * RK3308_ALC_L_DIG_CON03 - REG: 0x004c + ch * 0xc0 - * RK3308_ALC_R_DIG_CON03 - REG: 0x008c + ch * 0xc0 - */ --#define RK3308_AGC_PGA_ZERO_CRO_EN BIT(5) -+#define RK3308_AGC_PGA_ZERO_CRO_EN (0x1 << 5) -+#define RK3308_AGC_PGA_ZERO_CRO_DIS (0x0 << 5) - #define RK3308_AGC_PGA_GAIN_MAX 0x1f - #define RK3308_AGC_PGA_GAIN_MIN 0 - #define RK3308_AGC_PGA_GAIN_SFT 0 -+#define RK3308_AGC_PGA_GAIN_MSK (0x1f << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_28_5 (0x1f << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_27 (0x1e << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_25_5 (0x1d << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_24 (0x1c << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_22_5 (0x1b << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_21 (0x1a << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_19_5 (0x19 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_18 (0x18 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_16_5 (0x17 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_15 (0x16 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_13_5 (0x15 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_12 (0x14 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_10_5 (0x13 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_9 (0x12 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_7_5 (0x11 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_6 (0x10 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_4_5 (0x0f << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_3 (0x0e << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_PDB_1_5 (0x0d << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_0DB (0x0c << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_1_5 (0x0b << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_3 (0x0a << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_4_5 (0x09 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_6 (0x08 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_7_5 (0x07 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_9 (0x06 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_10_5 (0x05 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_12 (0x04 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_13_5 (0x03 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_15 (0x02 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_16_5 (0x01 << RK3308_AGC_PGA_GAIN_SFT) -+#define RK3308_AGC_PGA_GAIN_NDB_18 (0x00 << RK3308_AGC_PGA_GAIN_SFT) - - /* - * RK3308_ALC_L_DIG_CON04 - REG: 0x0050 + ch * 0xc0 - * RK3308_ALC_R_DIG_CON04 - REG: 0x0090 + ch * 0xc0 - */ --#define RK3308_AGC_SLOW_CLK_EN BIT(3) -+#define RK3308_AGC_SLOW_CLK_EN (0x1 << 3) -+#define RK3308_AGC_SLOW_CLK_DIS (0x0 << 3) - #define RK3308_AGC_APPROX_RATE_SFT 0 - #define RK3308_AGC_APPROX_RATE_MSK (0x7 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_8K (0x7 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_12K (0x6 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_16K (0x5 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_24K (0x4 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_32K (0x3 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_44_1K (0x2 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_48K (0x1 << RK3308_AGC_APPROX_RATE_SFT) -+#define RK3308_AGC_APPROX_RATE_96K (0x0 << RK3308_AGC_APPROX_RATE_SFT) - - /* - * RK3308_ALC_L_DIG_CON05 - REG: 0x0054 + ch * 0xc0 -@@ -264,15 +504,33 @@ - * RK3308_ALC_L_DIG_CON09 - REG: 0x0064 + ch * 0xc0 - * RK3308_ALC_R_DIG_CON09 - REG: 0x00a4 + ch * 0xc0 - */ --#define RK3308_AGC_FUNC_SEL BIT(6) -+#define RK3308_AGC_FUNC_SEL_MSK (0x1 << 6) -+#define RK3308_AGC_FUNC_SEL_EN (0x1 << 6) -+#define RK3308_AGC_FUNC_SEL_DIS (0x0 << 6) - #define RK3308_AGC_MAX_GAIN_PGA_MAX 0x7 - #define RK3308_AGC_MAX_GAIN_PGA_MIN 0 - #define RK3308_AGC_MAX_GAIN_PGA_SFT 3 - #define RK3308_AGC_MAX_GAIN_PGA_MSK (0x7 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_PDB_28_5 (0x7 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_PDB_22_5 (0x6 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_PDB_16_5 (0x5 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_PDB_10_5 (0x4 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_PDB_4_5 (0x3 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_NDB_1_5 (0x2 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_NDB_7_5 (0x1 << RK3308_AGC_MAX_GAIN_PGA_SFT) -+#define RK3308_AGC_MAX_GAIN_PGA_NDB_13_5 (0x0 << RK3308_AGC_MAX_GAIN_PGA_SFT) - #define RK3308_AGC_MIN_GAIN_PGA_MAX 0x7 - #define RK3308_AGC_MIN_GAIN_PGA_MIN 0 - #define RK3308_AGC_MIN_GAIN_PGA_SFT 0 - #define RK3308_AGC_MIN_GAIN_PGA_MSK (0x7 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_PDB_24 (0x7 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_PDB_18 (0x6 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_PDB_12 (0x5 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_PDB_6 (0x4 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_0DB (0x3 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_NDB_6 (0x2 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_NDB_12 (0x1 << RK3308_AGC_MIN_GAIN_PGA_SFT) -+#define RK3308_AGC_MIN_GAIN_PGA_NDB_18 (0x0 << RK3308_AGC_MIN_GAIN_PGA_SFT) - - /* - * RK3308_ALC_L_DIG_CON12 - REG: 0x0068 + ch * 0xc0 -@@ -281,7 +539,9 @@ - #define RK3308_AGC_GAIN_MSK 0x1f - - /* RK3308_DAC_DIG_CON01 - REG: 0x0304 */ --#define RK3308_DAC_I2S_LRC_POL_REVERSAL BIT(7) -+#define RK3308_DAC_I2S_LRC_POL_MSK (0x1 << 7) -+#define RK3308_DAC_I2S_LRC_POL_REVERSAL (0x1 << 7) -+#define RK3308_DAC_I2S_LRC_POL_NORMAL (0x0 << 7) - #define RK3308_DAC_I2S_VALID_LEN_SFT 5 - #define RK3308_DAC_I2S_VALID_LEN_MSK (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT) - #define RK3308_DAC_I2S_VALID_LEN_32BITS (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT) -@@ -294,21 +554,29 @@ - #define RK3308_DAC_I2S_MODE_I2S (0x2 << RK3308_DAC_I2S_MODE_SFT) - #define RK3308_DAC_I2S_MODE_LJ (0x1 << RK3308_DAC_I2S_MODE_SFT) - #define RK3308_DAC_I2S_MODE_RJ (0x0 << RK3308_DAC_I2S_MODE_SFT) --#define RK3308_DAC_I2S_LR_SWAP BIT(2) -+#define RK3308_DAC_I2S_LR_MSK (0x1 << 2) -+#define RK3308_DAC_I2S_LR_SWAP (0x1 << 2) -+#define RK3308_DAC_I2S_LR_NORMAL (0x0 << 2) - - /* RK3308_DAC_DIG_CON02 - REG: 0x0308 */ --#define RK3308BS_DAC_IO_MODE_MASTER BIT(7) --#define RK3308BS_DAC_MODE_MASTER BIT(6) --#define RK3308_DAC_IO_MODE_MASTER BIT(5) --#define RK3308_DAC_MODE_MASTER BIT(4) -+#define RK3308_DAC_IO_MODE_MSK (0x1 << 5) -+#define RK3308_DAC_IO_MODE_MASTER (0x1 << 5) -+#define RK3308_DAC_IO_MODE_SLAVE (0x0 << 5) -+#define RK3308_DAC_MODE_MSK (0x1 << 4) -+#define RK3308_DAC_MODE_MASTER (0x1 << 4) -+#define RK3308_DAC_MODE_SLAVE (0x0 << 4) - #define RK3308_DAC_I2S_FRAME_LEN_SFT 2 - #define RK3308_DAC_I2S_FRAME_LEN_MSK (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT) - #define RK3308_DAC_I2S_FRAME_32BITS (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT) - #define RK3308_DAC_I2S_FRAME_24BITS (0x2 << RK3308_DAC_I2S_FRAME_LEN_SFT) - #define RK3308_DAC_I2S_FRAME_20BITS (0x1 << RK3308_DAC_I2S_FRAME_LEN_SFT) - #define RK3308_DAC_I2S_FRAME_16BITS (0x0 << RK3308_DAC_I2S_FRAME_LEN_SFT) --#define RK3308_DAC_I2S_WORK BIT(1) --#define RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL BIT(0) -+#define RK3308_DAC_I2S_MSK (0x1 << 1) -+#define RK3308_DAC_I2S_WORK (0x1 << 1) -+#define RK3308_DAC_I2S_RESET (0x0 << 1) -+#define RK3308_DAC_I2S_BIT_CLK_POL_MSK (0x1 << 0) -+#define RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) -+#define RK3308_DAC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) - - /* RK3308_DAC_DIG_CON03 - REG: 0x030C */ - #define RK3308_DAC_L_CH_BIST_SFT 2 -@@ -325,62 +593,64 @@ - #define RK3308_DAC_R_CH_BIST_RIGHT (0x0 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */ - - /* RK3308_DAC_DIG_CON04 - REG: 0x0310 */ --/* Versions up to B: */ - #define RK3308_DAC_MODULATOR_GAIN_SFT 4 - #define RK3308_DAC_MODULATOR_GAIN_MSK (0x7 << RK3308_DAC_MODULATOR_GAIN_SFT) -+#define RK3308_DAC_MODULATOR_GAIN_4_8DB (0x5 << RK3308_DAC_MODULATOR_GAIN_SFT) -+#define RK3308_DAC_MODULATOR_GAIN_4_2DB (0x4 << RK3308_DAC_MODULATOR_GAIN_SFT) -+#define RK3308_DAC_MODULATOR_GAIN_3_5DB (0x3 << RK3308_DAC_MODULATOR_GAIN_SFT) -+#define RK3308_DAC_MODULATOR_GAIN_2_8DB (0x2 << RK3308_DAC_MODULATOR_GAIN_SFT) -+#define RK3308_DAC_MODULATOR_GAIN_2DB (0x1 << RK3308_DAC_MODULATOR_GAIN_SFT) -+#define RK3308_DAC_MODULATOR_GAIN_0DB (0x0 << RK3308_DAC_MODULATOR_GAIN_SFT) - #define RK3308_DAC_CIC_IF_GAIN_SFT 0 - #define RK3308_DAC_CIC_IF_GAIN_MSK (0x7 << RK3308_DAC_CIC_IF_GAIN_SFT) --/* Version C: */ --#define RK3308BS_DAC_DIG_GAIN_SFT 0 --#define RK3308BS_DAC_DIG_GAIN_MSK (0xff << RK3308BS_DAC_DIG_GAIN_SFT) --#define RK3308BS_DAC_DIG_GAIN_0DB (0xed << RK3308BS_DAC_DIG_GAIN_SFT) -- --/* RK3308BS_ADC_DIG_CON05..06 (Version C only) */ --#define RK3308_ADC_DIG_VOL_CON_x_SFT 0 --#define RK3308_ADC_DIG_VOL_CON_x_MSK (0xff << RK3308_ADC_DIG_VOL_CON_x_SFT) --#define RK3308_ADC_DIG_VOL_CON_x_0DB (0xc2 << RK3308_ADC_DIG_VOL_CON_x_SFT) - - /* RK3308_DAC_DIG_CON05 - REG: 0x0314 */ --#define RK3308_DAC_L_REG_CTL_INDATA BIT(2) --#define RK3308_DAC_R_REG_CTL_INDATA BIT(1) -+#define RK3308_DAC_L_REG_CTL_INDATA (0x1 << 2) -+#define RK3308_DAC_L_NORMAL_DATA (0x0 << 2) -+#define RK3308_DAC_R_REG_CTL_INDATA (0x1 << 1) -+#define RK3308_DAC_R_NORMAL_DATA (0x0 << 1) - - /* RK3308_DAC_DIG_CON10 - REG: 0x0328 */ --#define RK3308_DAC_DATA_HI4(x) ((x) & 0xf) -+#define RK3308_DAC_DATA_HI4(x) (x & 0xf) /* Need to RK3308_DAC_x_REG_CTL_INDATA */ - - /* RK3308_DAC_DIG_CON11 - REG: 0x032c */ --#define RK3308_DAC_DATA_LO8(x) ((x) & 0xff) -+#define RK3308_DAC_DATA_LO8(x) (x & 0xff) /* Need to RK3308_DAC_x_REG_CTL_INDATA */ - - /* RK3308_ADC_ANA_CON00 - REG: 0x0340 */ - #define RK3308_ADC_CH1_CH2_MIC_ALL_MSK (0xff << 0) - #define RK3308_ADC_CH1_CH2_MIC_ALL 0xff --#define RK3308_ADC_CH2_MIC_UNMUTE BIT(7) --#define RK3308_ADC_CH2_MIC_WORK BIT(6) --#define RK3308_ADC_CH2_MIC_EN BIT(5) --#define RK3308_ADC_CH2_BUF_REF_EN BIT(4) --#define RK3308_ADC_CH1_MIC_UNMUTE BIT(3) --#define RK3308_ADC_CH1_MIC_WORK BIT(2) --#define RK3308_ADC_CH1_MIC_EN BIT(1) --#define RK3308_ADC_CH1_BUF_REF_EN BIT(0) -+#define RK3308_ADC_CH2_MIC_UNMUTE (0x1 << 7) -+#define RK3308_ADC_CH2_MIC_MUTE (0x0 << 7) -+#define RK3308_ADC_CH2_MIC_WORK (0x1 << 6) -+#define RK3308_ADC_CH2_MIC_INIT (0x0 << 6) -+#define RK3308_ADC_CH2_MIC_EN (0x1 << 5) -+#define RK3308_ADC_CH2_MIC_DIS (0x0 << 5) -+#define RK3308_ADC_CH2_BUF_REF_EN (0x1 << 4) -+#define RK3308_ADC_CH2_BUF_REF_DIS (0x0 << 4) -+#define RK3308_ADC_CH1_MIC_UNMUTE (0x1 << 3) -+#define RK3308_ADC_CH1_MIC_MUTE (0x0 << 3) -+#define RK3308_ADC_CH1_MIC_WORK (0x1 << 2) -+#define RK3308_ADC_CH1_MIC_INIT (0x0 << 2) -+#define RK3308_ADC_CH1_MIC_EN (0x1 << 1) -+#define RK3308_ADC_CH1_MIC_DIS (0x0 << 1) -+#define RK3308_ADC_CH1_BUF_REF_EN (0x1 << 0) -+#define RK3308_ADC_CH1_BUF_REF_DIS (0x0 << 0) - - /* RK3308_ADC_ANA_CON01 - REG: 0x0344 - * - * The PGA of MIC-INs: -- * - HW version A: -- * 0x0 - MIC1~MIC8 0 dB (recommended when ADC used as loopback) -- * 0x3 - MIC1~MIC8 20 dB (recommended when ADC used as MIC input) -- * - HW version B: -- * 0x0 - MIC1~MIC8 0 dB -- * 0x1 - MIC1~MIC8 6.6 dB -- * 0x2 - MIC1~MIC8 13 dB -- * 0x3 - MIC1~MIC8 20 dB -+ * 0x0 - MIC1~MIC8 0dB -+ * 0x1 - MIC1~MIC8 6.6dB -+ * 0x2 - MIC1~MIC8 13dB -+ * 0x3 - MIC1~MIC8 20dB - */ - #define RK3308_ADC_CH2_MIC_GAIN_MAX 0x3 - #define RK3308_ADC_CH2_MIC_GAIN_MIN 0 - #define RK3308_ADC_CH2_MIC_GAIN_SFT 4 - #define RK3308_ADC_CH2_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT) - #define RK3308_ADC_CH2_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT) --#define RK3308_ADC_CH2_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH2_MIC_GAIN_SFT) --#define RK3308_ADC_CH2_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH2_MIC_GAIN_SFT) -+#define RK3308_ADC_CH2_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH2_MIC_GAIN_SFT) /* TRM: only used for version B */ -+#define RK3308_ADC_CH2_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH2_MIC_GAIN_SFT) /* TRM: only used for version B */ - #define RK3308_ADC_CH2_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH2_MIC_GAIN_SFT) - - #define RK3308_ADC_CH1_MIC_GAIN_MAX 0x3 -@@ -388,42 +658,124 @@ - #define RK3308_ADC_CH1_MIC_GAIN_SFT 0 - #define RK3308_ADC_CH1_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT) - #define RK3308_ADC_CH1_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT) --#define RK3308_ADC_CH1_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH1_MIC_GAIN_SFT) --#define RK3308_ADC_CH1_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH1_MIC_GAIN_SFT) -+#define RK3308_ADC_CH1_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH1_MIC_GAIN_SFT) /* TRM: only used for version B */ -+#define RK3308_ADC_CH1_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH1_MIC_GAIN_SFT) /* TRM: only used for version B */ - #define RK3308_ADC_CH1_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH1_MIC_GAIN_SFT) - - /* RK3308_ADC_ANA_CON02 - REG: 0x0348 */ --#define RK3308_ADC_CH2_ZEROCROSS_DET_EN BIT(6) --#define RK3308_ADC_CH2_ALC_WORK BIT(5) --#define RK3308_ADC_CH2_ALC_EN BIT(4) --#define RK3308_ADC_CH1_ZEROCROSS_DET_EN BIT(2) --#define RK3308_ADC_CH1_ALC_WORK BIT(1) --#define RK3308_ADC_CH1_ALC_EN BIT(0) -+#define RK3308_ADC_CH2_ALC_ZC_MSK (0x7 << 4) -+#define RK3308_ADC_CH2_ZEROCROSS_DET_EN (0x1 << 6) -+#define RK3308_ADC_CH2_ZEROCROSS_DET_DIS (0x0 << 6) -+#define RK3308_ADC_CH2_ALC_WORK (0x1 << 5) -+#define RK3308_ADC_CH2_ALC_INIT (0x0 << 5) -+#define RK3308_ADC_CH2_ALC_EN (0x1 << 4) -+#define RK3308_ADC_CH2_ALC_DIS (0x0 << 4) -+ -+#define RK3308_ADC_CH1_ALC_ZC_MSK (0x7 << 0) -+#define RK3308_ADC_CH1_ZEROCROSS_DET_EN (0x1 << 2) -+#define RK3308_ADC_CH1_ZEROCROSS_DET_DIS (0x0 << 2) -+#define RK3308_ADC_CH1_ALC_WORK (0x1 << 1) -+#define RK3308_ADC_CH1_ALC_INIT (0x0 << 1) -+#define RK3308_ADC_CH1_ALC_EN (0x1 << 0) -+#define RK3308_ADC_CH1_ALC_DIS (0x0 << 0) - - /* RK3308_ADC_ANA_CON03 - REG: 0x034c */ - #define RK3308_ADC_CH1_ALC_GAIN_MAX 0x1f - #define RK3308_ADC_CH1_ALC_GAIN_MIN 0 - #define RK3308_ADC_CH1_ALC_GAIN_SFT 0 - #define RK3308_ADC_CH1_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_28_5 (0x1f << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_27 (0x1e << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_25_5 (0x1d << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_24 (0x1c << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_22_5 (0x1b << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_21 (0x1a << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_19_5 (0x19 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_18 (0x18 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_16_5 (0x17 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_15 (0x16 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_13_5 (0x15 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_12 (0x14 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_10_5 (0x13 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_9 (0x12 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_7_5 (0x11 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_6 (0x10 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_4_5 (0x0f << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_3 (0x0e << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_PDB_1_5 (0x0d << RK3308_ADC_CH1_ALC_GAIN_SFT) - #define RK3308_ADC_CH1_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_1_5 (0x0b << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_3 (0x0a << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_4_5 (0x09 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_6 (0x08 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_7_5 (0x07 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_9 (0x06 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_10_5 (0x05 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_12 (0x04 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_13_5 (0x03 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_15 (0x02 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_16_5 (0x01 << RK3308_ADC_CH1_ALC_GAIN_SFT) -+#define RK3308_ADC_CH1_ALC_GAIN_NDB_18 (0x00 << RK3308_ADC_CH1_ALC_GAIN_SFT) - - /* RK3308_ADC_ANA_CON04 - REG: 0x0350 */ - #define RK3308_ADC_CH2_ALC_GAIN_MAX 0x1f - #define RK3308_ADC_CH2_ALC_GAIN_MIN 0 - #define RK3308_ADC_CH2_ALC_GAIN_SFT 0 - #define RK3308_ADC_CH2_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_28_5 (0x1f << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_27 (0x1e << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_25_5 (0x1d << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_24 (0x1c << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_22_5 (0x1b << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_21 (0x1a << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_19_5 (0x19 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_18 (0x18 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_16_5 (0x17 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_15 (0x16 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_13_5 (0x15 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_12 (0x14 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_10_5 (0x13 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_9 (0x12 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_7_5 (0x11 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_6 (0x10 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_4_5 (0x0f << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_3 (0x0e << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_PDB_1_5 (0x0d << RK3308_ADC_CH2_ALC_GAIN_SFT) - #define RK3308_ADC_CH2_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_1_5 (0x0b << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_3 (0x0a << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_4_5 (0x09 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_6 (0x08 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_7_5 (0x07 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_9 (0x06 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_10_5 (0x05 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_12 (0x04 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_13_5 (0x03 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_15 (0x02 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_16_5 (0x01 << RK3308_ADC_CH2_ALC_GAIN_SFT) -+#define RK3308_ADC_CH2_ALC_GAIN_NDB_18 (0x00 << RK3308_ADC_CH2_ALC_GAIN_SFT) - - /* RK3308_ADC_ANA_CON05 - REG: 0x0354 */ --#define RK3308_ADC_CH2_ADC_WORK BIT(6) --#define RK3308_ADC_CH2_ADC_EN BIT(5) --#define RK3308_ADC_CH2_CLK_EN BIT(4) --#define RK3308_ADC_CH1_ADC_WORK BIT(2) --#define RK3308_ADC_CH1_ADC_EN BIT(1) --#define RK3308_ADC_CH1_CLK_EN BIT(0) -+#define RK3308_ADC_CH2_ADC_CLK_MSK (0x7 << 4) -+#define RK3308_ADC_CH2_ADC_WORK (0x1 << 6) -+#define RK3308_ADC_CH2_ADC_INIT (0x0 << 6) -+#define RK3308_ADC_CH2_ADC_EN (0x1 << 5) -+#define RK3308_ADC_CH2_ADC_DIS (0x0 << 5) -+#define RK3308_ADC_CH2_CLK_EN (0x1 << 4) -+#define RK3308_ADC_CH2_CLK_DIS (0x0 << 4) -+ -+#define RK3308_ADC_CH1_ADC_CLK_MSK (0x7 << 0) -+#define RK3308_ADC_CH1_ADC_WORK (0x1 << 2) -+#define RK3308_ADC_CH1_ADC_INIT (0x0 << 2) -+#define RK3308_ADC_CH1_ADC_EN (0x1 << 1) -+#define RK3308_ADC_CH1_ADC_DIS (0x0 << 1) -+#define RK3308_ADC_CH1_CLK_EN (0x1 << 0) -+#define RK3308_ADC_CH1_CLK_DIS (0x0 << 0) - - /* RK3308_ADC_ANA_CON06 - REG: 0x0358 */ --#define RK3308_ADC_CURRENT_EN BIT(0) -+#define RK3308_ADC_CURRENT_MSK (0x1 << 0) -+#define RK3308_ADC_CURRENT_EN (0x1 << 0) -+#define RK3308_ADC_CURRENT_DIS (0x0 << 0) - - /* RK3308_ADC_ANA_CON07 - REG: 0x035c */ - /* Note: The register configuration is only valid for ADC2 */ -@@ -440,80 +792,201 @@ - #define RK3308_ADC_CH1_IN_LINEIN (0x2 << RK3308_ADC_CH1_IN_SEL_SFT) - #define RK3308_ADC_CH1_IN_MIC (0x1 << RK3308_ADC_CH1_IN_SEL_SFT) - #define RK3308_ADC_CH1_IN_NONE (0x0 << RK3308_ADC_CH1_IN_SEL_SFT) --#define RK3308_ADC_MIC_BIAS_BUF_EN BIT(3) --#define RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX 7 -+ -+#define RK3308_ADC_MIC_BIAS_BUF_SFT 3 -+#define RK3308_ADC_MIC_BIAS_BUF_EN (0x1 << RK3308_ADC_MIC_BIAS_BUF_SFT) -+#define RK3308_ADC_MIC_BIAS_BUF_DIS (0x0 << RK3308_ADC_MIC_BIAS_BUF_SFT) - #define RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT 0 - #define RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK (0x7 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+/* -+ * The follow MICBIAS_VOLTs are based on the external reference voltage(Vref). -+ * For example, the Vref == 3.3V, the MICBIAS_VOLT_0_85 is equal: -+ * 3.3V * 0.85 = 2.805V. -+ */ -+#define RK3308_ADC_MICBIAS_VOLT_0_85 (0x7 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+#define RK3308_ADC_MICBIAS_VOLT_0_8 (0x6 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+#define RK3308_ADC_MICBIAS_VOLT_0_75 (0x5 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+#define RK3308_ADC_MICBIAS_VOLT_0_7 (0x4 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+#define RK3308_ADC_MICBIAS_VOLT_0_65 (0x3 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+#define RK3308_ADC_MICBIAS_VOLT_0_6 (0x2 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+#define RK3308_ADC_MICBIAS_VOLT_0_55 (0x1 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) -+#define RK3308_ADC_MICBIAS_VOLT_0_5 (0x0 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT) - - /* RK3308_ADC_ANA_CON08 - REG: 0x0360 */ --#define RK3308_ADC_MICBIAS_CURRENT_EN BIT(4) -+#define RK3308_ADC_MICBIAS_CURRENT_MSK (0x1 << 4) -+#define RK3308_ADC_MICBIAS_CURRENT_EN (0x1 << 4) -+#define RK3308_ADC_MICBIAS_CURRENT_DIS (0x0 << 4) - - /* RK3308_ADC_ANA_CON10 - REG: 0x0368 */ --#define RK3308_ADC_REF_EN BIT(7) -+#define RK3308_ADC_REF_EN (0x1 << 7) -+#define RK3308_ADC_REF_DIS (0x0 << 7) - #define RK3308_ADC_CURRENT_CHARGE_SFT 0 - #define RK3308_ADC_CURRENT_CHARGE_MSK (0x7f << RK3308_ADC_CURRENT_CHARGE_SFT) -+/* -+ * 1: Choose the current I -+ * 0: Don't choose the current I -+ */ -+#define RK3308_ADC_SEL_I(x) (x & 0x7f) - - /* RK3308_ADC_ANA_CON11 - REG: 0x036c */ --#define RK3308_ADC_ALCR_CON_GAIN_PGAR_EN BIT(1) --#define RK3308_ADC_ALCL_CON_GAIN_PGAL_EN BIT(0) -+#define RK3308_ADC_ALCR_CON_GAIN_PGAR_MSK (0x1 << 1) -+#define RK3308_ADC_ALCR_CON_GAIN_PGAR_EN (0x1 << 1) -+#define RK3308_ADC_ALCR_CON_GAIN_PGAR_DIS (0x0 << 1) -+#define RK3308_ADC_ALCL_CON_GAIN_PGAL_MSK (0x1 << 0) -+#define RK3308_ADC_ALCL_CON_GAIN_PGAL_EN (0x1 << 0) -+#define RK3308_ADC_ALCL_CON_GAIN_PGAL_DIS (0x0 << 0) - - /* RK3308_DAC_ANA_CON00 - REG: 0x0440 */ --#define RK3308_DAC_HEADPHONE_DET_EN BIT(1) --#define RK3308_DAC_CURRENT_EN BIT(0) -+#define RK3308_DAC_HEADPHONE_DET_MSK (0x1 << 1) -+#define RK3308_DAC_HEADPHONE_DET_EN (0x1 << 1) -+#define RK3308_DAC_HEADPHONE_DET_DIS (0x0 << 1) -+#define RK3308_DAC_CURRENT_MSK (0x1 << 0) -+#define RK3308_DAC_CURRENT_EN (0x1 << 0) -+#define RK3308_DAC_CURRENT_DIS (0x0 << 0) - - /* RK3308_DAC_ANA_CON01 - REG: 0x0444 */ --#define RK3308_DAC_BUF_REF_R_EN BIT(6) --#define RK3308_DAC_BUF_REF_L_EN BIT(2) -+#define RK3308_DAC_BUF_REF_R_MSK (0x1 << 6) -+#define RK3308_DAC_BUF_REF_R_EN (0x1 << 6) -+#define RK3308_DAC_BUF_REF_R_DIS (0x0 << 6) - #define RK3308_DAC_HPOUT_POP_SOUND_R_SFT 4 -+#define RK3308_DAC_HPOUT_POP_SOUND_R_MSK (0x3 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT) -+#define RK3308_DAC_HPOUT_POP_SOUND_R_WORK (0x2 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT) -+#define RK3308_DAC_HPOUT_POP_SOUND_R_INIT (0x1 << RK3308_DAC_HPOUT_POP_SOUND_R_SFT) -+#define RK3308_DAC_BUF_REF_L_MSK (0x1 << 2) -+#define RK3308_DAC_BUF_REF_L_EN (0x1 << 2) -+#define RK3308_DAC_BUF_REF_L_DIS (0x0 << 2) - #define RK3308_DAC_HPOUT_POP_SOUND_L_SFT 0 --// unshifted values for both L and R: --#define RK3308_DAC_HPOUT_POP_SOUND_x_MSK 0x3 --#define RK3308_DAC_HPOUT_POP_SOUND_x_WORK 0x2 --#define RK3308_DAC_HPOUT_POP_SOUND_x_INIT 0x1 -+#define RK3308_DAC_HPOUT_POP_SOUND_L_MSK (0x3 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT) -+#define RK3308_DAC_HPOUT_POP_SOUND_L_WORK (0x2 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT) -+#define RK3308_DAC_HPOUT_POP_SOUND_L_INIT (0x1 << RK3308_DAC_HPOUT_POP_SOUND_L_SFT) - - /* RK3308_DAC_ANA_CON02 - REG: 0x0448 */ --#define RK3308_DAC_R_DAC_WORK BIT(7) --#define RK3308_DAC_R_DAC_EN BIT(6) --#define RK3308_DAC_R_CLK_EN BIT(5) --#define RK3308_DAC_R_REF_EN BIT(4) --#define RK3308_DAC_L_DAC_WORK BIT(3) --#define RK3308_DAC_L_DAC_EN BIT(2) --#define RK3308_DAC_L_CLK_EN BIT(1) --#define RK3308_DAC_L_REF_EN BIT(0) -+#define RK3308_DAC_R_DAC_WORK (0x1 << 7) -+#define RK3308_DAC_R_DAC_INIT (0x0 << 7) -+#define RK3308_DAC_R_DAC_EN (0x1 << 6) -+#define RK3308_DAC_R_DAC_DIS (0x0 << 6) -+#define RK3308_DAC_R_CLK_EN (0x1 << 5) -+#define RK3308_DAC_R_CLK_DIS (0x0 << 5) -+#define RK3308_DAC_R_REF_EN (0x1 << 4) -+#define RK3308_DAC_R_REF_DIS (0x0 << 4) -+#define RK3308_DAC_L_DAC_WORK (0x1 << 3) -+#define RK3308_DAC_L_DAC_INIT (0x0 << 3) -+#define RK3308_DAC_L_DAC_EN (0x1 << 2) -+#define RK3308_DAC_L_DAC_DIS (0x0 << 2) -+#define RK3308_DAC_L_CLK_EN (0x1 << 1) -+#define RK3308_DAC_L_CLK_DIS (0x0 << 1) -+#define RK3308_DAC_L_REF_EN (0x1 << 0) -+#define RK3308_DAC_L_REF_DIS (0x0 << 0) - - /* RK3308_DAC_ANA_CON03 - REG: 0x044c */ --#define RK3308_DAC_R_HPOUT_WORK BIT(6) --#define RK3308_DAC_R_HPOUT_EN BIT(5) --#define RK3308_DAC_R_HPOUT_MUTE_SFT 4 --#define RK3308_DAC_L_HPOUT_WORK BIT(2) --#define RK3308_DAC_L_HPOUT_EN BIT(1) --#define RK3308_DAC_L_HPOUT_MUTE_SFT 0 -+#define RK3308_DAC_R_HPOUT_WORK (0x1 << 6) -+#define RK3308_DAC_R_HPOUT_INIT (0x0 << 6) -+#define RK3308_DAC_R_HPOUT_EN (0x1 << 5) -+#define RK3308_DAC_R_HPOUT_DIS (0x0 << 5) -+#define RK3308_DAC_R_HPOUT_UNMUTE (0x1 << 4) -+#define RK3308_DAC_R_HPOUT_MUTE (0x0 << 4) -+#define RK3308_DAC_L_HPOUT_WORK (0x1 << 2) -+#define RK3308_DAC_L_HPOUT_INIT (0x0 << 2) -+#define RK3308_DAC_L_HPOUT_EN (0x1 << 1) -+#define RK3308_DAC_L_HPOUT_DIS (0x0 << 1) -+#define RK3308_DAC_L_HPOUT_UNMUTE (0x1 << 0) -+#define RK3308_DAC_L_HPOUT_MUTE (0x0 << 0) - - /* RK3308_DAC_ANA_CON04 - REG: 0x0450 */ --#define RK3308_DAC_x_LINEOUT_GAIN_MAX 0x3 -+#define RK3308_DAC_R_LINEOUT_GAIN_MAX 0x3 - #define RK3308_DAC_R_LINEOUT_GAIN_SFT 6 - #define RK3308_DAC_R_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT) - #define RK3308_DAC_R_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT) - #define RK3308_DAC_R_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_R_LINEOUT_GAIN_SFT) - #define RK3308_DAC_R_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_R_LINEOUT_GAIN_SFT) - #define RK3308_DAC_R_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_R_LINEOUT_GAIN_SFT) --#define RK3308_DAC_R_LINEOUT_MUTE_SFT 5 --#define RK3308_DAC_R_LINEOUT_EN BIT(4) -+#define RK3308_DAC_R_LINEOUT_UNMUTE (0x1 << 5) -+#define RK3308_DAC_R_LINEOUT_MUTE (0x0 << 5) -+#define RK3308_DAC_R_LINEOUT_EN (0x1 << 4) -+#define RK3308_DAC_R_LINEOUT_DIS (0x0 << 4) -+#define RK3308_DAC_L_LINEOUT_GAIN_MAX 0x3 - #define RK3308_DAC_L_LINEOUT_GAIN_SFT 2 - #define RK3308_DAC_L_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT) - #define RK3308_DAC_L_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT) - #define RK3308_DAC_L_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_L_LINEOUT_GAIN_SFT) - #define RK3308_DAC_L_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_L_LINEOUT_GAIN_SFT) - #define RK3308_DAC_L_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_L_LINEOUT_GAIN_SFT) --#define RK3308_DAC_L_LINEOUT_MUTE_SFT 1 --#define RK3308_DAC_L_LINEOUT_EN BIT(0) -+#define RK3308_DAC_L_LINEOUT_UNMUTE (0x1 << 1) -+#define RK3308_DAC_L_LINEOUT_MUTE (0x0 << 1) -+#define RK3308_DAC_L_LINEOUT_EN (0x1 << 0) -+#define RK3308_DAC_L_LINEOUT_DIS (0x0 << 0) - - /* RK3308_DAC_ANA_CON05 - REG: 0x0454, step is 1.5db */ -+#define RK3308_DAC_L_HPOUT_GAIN_MAX 0x1e -+#define RK3308_DAC_L_HPOUT_GAIN_SFT 0 -+#define RK3308_DAC_L_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_PDB_6 (0x1e << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_PDB_4_5 (0x1d << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_PDB_3 (0x1c << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_PDB_1_5 (0x1b << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_0DB (0x1a << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_1_5 (0x19 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_3 (0x18 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_4_5 (0x17 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_6 (0x16 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_7_5 (0x15 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_9 (0x14 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_10_5 (0x13 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_12 (0x12 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_13_5 (0x11 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_15 (0x10 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_16_5 (0x0f << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_18 (0x0e << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_19_5 (0x0d << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_21 (0x0c << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_22_5 (0x0b << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_24 (0x0a << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_25_5 (0x09 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_27 (0x08 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_28_5 (0x07 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_30 (0x06 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_31_5 (0x05 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_33 (0x04 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_34_5 (0x03 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_36 (0x02 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_37_5 (0x01 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+#define RK3308_DAC_L_HPOUT_GAIN_NDB_39 (0x00 << RK3308_DAC_L_HPOUT_GAIN_SFT) -+ - /* RK3308_DAC_ANA_CON06 - REG: 0x0458, step is 1.5db */ --#define RK3308_DAC_x_HPOUT_GAIN_MAX 0x1e --#define RK3308_DAC_x_HPOUT_GAIN_SFT 0 --#define RK3308_DAC_x_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_x_HPOUT_GAIN_SFT) --#define RK3308_DAC_x_HPOUT_GAIN_MIN (0x00 << RK3308_DAC_x_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_MAX 0x1e -+#define RK3308_DAC_R_HPOUT_GAIN_SFT 0 -+#define RK3308_DAC_R_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_PDB_6 (0x1e << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_PDB_4_5 (0x1d << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_PDB_3 (0x1c << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_PDB_1_5 (0x1b << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_0DB (0x1a << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_1_5 (0x19 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_3 (0x18 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_4_5 (0x17 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_6 (0x16 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_7_5 (0x15 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_9 (0x14 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_10_5 (0x13 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_12 (0x12 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_13_5 (0x11 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_15 (0x10 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_16_5 (0x0f << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_18 (0x0e << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_19_5 (0x0d << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_21 (0x0c << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_22_5 (0x0b << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_24 (0x0a << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_25_5 (0x09 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_27 (0x08 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_28_5 (0x07 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_30 (0x06 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_31_5 (0x05 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_33 (0x04 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_34_5 (0x03 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_36 (0x02 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_37_5 (0x01 << RK3308_DAC_R_HPOUT_GAIN_SFT) -+#define RK3308_DAC_R_HPOUT_GAIN_NDB_39 (0x00 << RK3308_DAC_R_HPOUT_GAIN_SFT) - - /* RK3308_DAC_ANA_CON07 - REG: 0x045c */ - #define RK3308_DAC_R_HPOUT_DRV_SFT 4 -@@ -534,36 +1007,51 @@ - #define RK3308_DAC_R_HPMIX_LINEIN (0x2 << RK3308_DAC_R_HPMIX_SEL_SFT) - #define RK3308_DAC_R_HPMIX_I2S (0x1 << RK3308_DAC_R_HPMIX_SEL_SFT) - #define RK3308_DAC_R_HPMIX_NONE (0x0 << RK3308_DAC_R_HPMIX_SEL_SFT) -+#define RK3308_DAC_R_HPMIX_GAIN_MIN 0x1 -+#define RK3308_DAC_R_HPMIX_GAIN_MAX 0x2 -+#define RK3308_DAC_R_HPMIX_GAIN_SFT 4 -+#define RK3308_DAC_R_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_R_HPMIX_GAIN_SFT) -+#define RK3308_DAC_R_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_R_HPMIX_GAIN_SFT) -+#define RK3308_DAC_R_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_R_HPMIX_GAIN_SFT) - #define RK3308_DAC_L_HPMIX_SEL_SFT 2 - #define RK3308_DAC_L_HPMIX_SEL_MSK (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT) - #define RK3308_DAC_L_HPMIX_LINEIN_I2S (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT) - #define RK3308_DAC_L_HPMIX_LINEIN (0x2 << RK3308_DAC_L_HPMIX_SEL_SFT) - #define RK3308_DAC_L_HPMIX_I2S (0x1 << RK3308_DAC_L_HPMIX_SEL_SFT) - #define RK3308_DAC_L_HPMIX_NONE (0x0 << RK3308_DAC_L_HPMIX_SEL_SFT) --#define RK3308_DAC_x_HPMIX_GAIN_MIN 0x1 /* 0x0 and 0x3 are reserved */ --#define RK3308_DAC_x_HPMIX_GAIN_MAX 0x2 --#define RK3308_DAC_R_HPMIX_GAIN_SFT 4 --#define RK3308_DAC_R_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_R_HPMIX_GAIN_SFT) --#define RK3308_DAC_R_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_R_HPMIX_GAIN_SFT) --#define RK3308_DAC_R_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_R_HPMIX_GAIN_SFT) -+#define RK3308_DAC_L_HPMIX_GAIN_MIN 0x1 -+#define RK3308_DAC_L_HPMIX_GAIN_MAX 0x2 - #define RK3308_DAC_L_HPMIX_GAIN_SFT 0 - #define RK3308_DAC_L_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_L_HPMIX_GAIN_SFT) - #define RK3308_DAC_L_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_L_HPMIX_GAIN_SFT) - #define RK3308_DAC_L_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_L_HPMIX_GAIN_SFT) - - /* RK3308_DAC_ANA_CON13 - REG: 0x0474 */ --#define RK3308_DAC_R_HPMIX_UNMUTE BIT(6) --#define RK3308_DAC_R_HPMIX_WORK BIT(5) --#define RK3308_DAC_R_HPMIX_EN BIT(4) --#define RK3308_DAC_L_HPMIX_UNMUTE BIT(2) --#define RK3308_DAC_L_HPMIX_WORK BIT(1) --#define RK3308_DAC_L_HPMIX_EN BIT(0) -+#define RK3308_DAC_R_HPMIX_UNMUTE (0x1 << 6) -+#define RK3308_DAC_R_HPMIX_MUTE (0x0 << 6) -+#define RK3308_DAC_R_HPMIX_WORK (0x1 << 5) -+#define RK3308_DAC_R_HPMIX_INIT (0x0 << 5) -+#define RK3308_DAC_R_HPMIX_EN (0x1 << 4) -+#define RK3308_DAC_R_HPMIX_DIS (0x0 << 4) -+#define RK3308_DAC_L_HPMIX_UNMUTE (0x1 << 2) -+#define RK3308_DAC_L_HPMIX_MUTE (0x0 << 2) -+#define RK3308_DAC_L_HPMIX_WORK (0x1 << 1) -+#define RK3308_DAC_L_HPMIX_INIT (0x0 << 1) -+#define RK3308_DAC_L_HPMIX_EN (0x1 << 0) -+#define RK3308_DAC_L_HPMIX_DIS (0x0 << 0) - - /* RK3308_DAC_ANA_CON14 - REG: 0x0478 */ - #define RK3308_DAC_VCM_LINEOUT_EN (0x1 << 4) -+#define RK3308_DAC_VCM_LINEOUT_DIS (0x0 << 4) - #define RK3308_DAC_CURRENT_CHARGE_SFT 0 - #define RK3308_DAC_CURRENT_CHARGE_MSK (0xf << RK3308_DAC_CURRENT_CHARGE_SFT) - -+/* -+ * 1: Choose the current I -+ * 0: Don't choose the current I -+ */ -+#define RK3308_DAC_SEL_I(x) (x & 0xf) -+ - /* RK3308_DAC_ANA_CON15 - REG: 0x047C */ - #define RK3308_DAC_LINEOUT_POP_SOUND_R_SFT 4 - #define RK3308_DAC_LINEOUT_POP_SOUND_R_MSK (0x3 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT) -@@ -576,4 +1064,6 @@ - #define RK3308_DAC_L_SEL_DC_FROM_VCM (0x1 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT) - #define RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL (0x0 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT) - -+#define RK3308_HIFI 0x0 -+ - #endif /* __RK3308_CODEC_H__ */ -diff --git a/sound/soc/codecs/rk3308_codec_provider.h b/sound/soc/codecs/rk3308_codec_provider.h -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/sound/soc/codecs/rk3308_codec_provider.h -@@ -0,0 +1,28 @@ -+/* -+ * rk3308_codec_provider.h -- RK3308 ALSA Soc Audio Driver -+ * -+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ */ -+ -+#ifndef __RK3308_CODEC_PROVIDER_H__ -+#define __RK3308_CODEC_PROVIDER_H__ -+ -+#ifdef CONFIG_SND_SOC_RK3308 -+extern void (*rk3308_codec_set_jack_detect_cb)(struct snd_soc_component *component, -+ struct snd_soc_jack *hpdet_jack); -+#endif -+ -+#endif /* __RK3308_CODEC_PROVIDER_H__ */ --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0113-add-synopsys-designware-hdmi-rx-controller.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0113-add-synopsys-designware-hdmi-rx-controller.patch deleted file mode 100644 index 23f04155b859..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0113-add-synopsys-designware-hdmi-rx-controller.patch +++ /dev/null @@ -1,4117 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Fri, 19 Jul 2024 18:10:30 +0530 -Subject: dt-bindings: media: Document bindings for HDMI RX Controller - -Document bindings for the Synopsys DesignWare HDMI RX Controller. - -Reviewed-by: Rob Herring -Reviewed-by: Dmitry Osipenko -Signed-off-by: Shreeya Patel -Reviewed-by: Sebastian Reichel -Reviewed-by: AngeloGioacchino Del Regno -Link: https://lore.kernel.org/r/20240719124032.26852-3-shreeya.patel@collabora.com -Signed-off-by: Sebastian Reichel ---- - Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml | 132 ++++++++++ - 1 file changed, 132 insertions(+) - -diff --git a/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml b/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml -@@ -0,0 +1,132 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+# Device Tree bindings for Synopsys DesignWare HDMI RX Controller -+ -+--- -+$id: http://devicetree.org/schemas/media/snps,dw-hdmi-rx.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Synopsys DesignWare HDMI RX Controller -+ -+maintainers: -+ - Shreeya Patel -+ -+description: -+ Synopsys DesignWare HDMI Input Controller preset on RK3588 SoCs -+ allowing devices to receive and decode high-resolution video streams -+ from external sources like media players, cameras, laptops, etc. -+ -+properties: -+ compatible: -+ items: -+ - const: rockchip,rk3588-hdmirx-ctrler -+ - const: snps,dw-hdmi-rx -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts: -+ maxItems: 3 -+ -+ interrupt-names: -+ items: -+ - const: cec -+ - const: hdmi -+ - const: dma -+ -+ clocks: -+ maxItems: 7 -+ -+ clock-names: -+ items: -+ - const: aclk -+ - const: audio -+ - const: cr_para -+ - const: pclk -+ - const: ref -+ - const: hclk_s_hdmirx -+ - const: hclk_vo1 -+ -+ power-domains: -+ maxItems: 1 -+ -+ resets: -+ maxItems: 4 -+ -+ reset-names: -+ items: -+ - const: axi -+ - const: apb -+ - const: ref -+ - const: biu -+ -+ memory-region: -+ maxItems: 1 -+ -+ hpd-gpios: -+ description: GPIO specifier for HPD. -+ maxItems: 1 -+ -+ rockchip,grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ The phandle of the syscon node for the general register file -+ containing HDMIRX PHY status bits. -+ -+ rockchip,vo1-grf: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ The phandle of the syscon node for the Video Output GRF register -+ to enable EDID transfer through SDAIN and SCLIN. -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - interrupt-names -+ - clocks -+ - clock-names -+ - power-domains -+ - resets -+ - pinctrl-0 -+ - hpd-gpios -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ #include -+ #include -+ #include -+ #include -+ #include -+ hdmi_receiver: hdmi-receiver@fdee0000 { -+ compatible = "rockchip,rk3588-hdmirx-ctrler", "snps,dw-hdmi-rx"; -+ reg = <0xfdee0000 0x6000>; -+ interrupts = , -+ , -+ ; -+ interrupt-names = "cec", "hdmi", "dma"; -+ clocks = <&cru ACLK_HDMIRX>, -+ <&cru CLK_HDMIRX_AUD>, -+ <&cru CLK_CR_PARA>, -+ <&cru PCLK_HDMIRX>, -+ <&cru CLK_HDMIRX_REF>, -+ <&cru PCLK_S_HDMIRX>, -+ <&cru HCLK_VO1>; -+ clock-names = "aclk", -+ "audio", -+ "cr_para", -+ "pclk", -+ "ref", -+ "hclk_s_hdmirx", -+ "hclk_vo1"; -+ power-domains = <&power RK3588_PD_VO1>; -+ resets = <&cru SRST_A_HDMIRX>, <&cru SRST_P_HDMIRX>, -+ <&cru SRST_HDMIRX_REF>, <&cru SRST_A_HDMIRX_BIU>; -+ reset-names = "axi", "apb", "ref", "biu"; -+ memory-region = <&hdmi_receiver_cma>; -+ pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_5v_detection>; -+ pinctrl-names = "default"; -+ hpd-gpios = <&gpio1 22 GPIO_ACTIVE_LOW>; -+ }; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Fri, 19 Jul 2024 18:10:31 +0530 -Subject: arm64: dts: rockchip: Add device tree support for HDMI RX Controller - -Add device tree support for Synopsys DesignWare HDMI RX -Controller. - -Reviewed-by: Dmitry Osipenko -Tested-by: Dmitry Osipenko -Co-developed-by: Dingxian Wen -Signed-off-by: Dingxian Wen -Signed-off-by: Shreeya Patel -Link: https://lore.kernel.org/r/20240719124032.26852-4-shreeya.patel@collabora.com -Signed-off-by: Sebastian Reichel ---- - arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi | 14 +++ - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 56 ++++++++++ - 2 files changed, 70 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi -@@ -594,6 +594,20 @@ hdmim0_tx1_hpd: hdmim0-tx1-hpd { - /* hdmim0_tx1_hpd */ - <1 RK_PA6 5 &pcfg_pull_none>; - }; -+ -+ /omit-if-no-ref/ -+ hdmim1_rx: hdmim1-rx { -+ rockchip,pins = -+ /* hdmim1_rx_cec */ -+ <3 RK_PD1 5 &pcfg_pull_none>, -+ /* hdmim1_rx_scl */ -+ <3 RK_PD2 5 &pcfg_pull_none_smt>, -+ /* hdmim1_rx_sda */ -+ <3 RK_PD3 5 &pcfg_pull_none_smt>, -+ /* hdmim1_rx_hpdin */ -+ <3 RK_PD4 5 &pcfg_pull_none>; -+ }; -+ - /omit-if-no-ref/ - hdmim1_rx_cec: hdmim1-rx-cec { - rockchip,pins = -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -7,6 +7,29 @@ - #include "rk3588-extra-pinctrl.dtsi" - - / { -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ /* -+ * The 4k HDMI capture controller works only with 32bit -+ * phys addresses and doesn't support IOMMU. HDMI RX CMA -+ * must be reserved below 4GB. -+ * The size of 160MB was determined as follows: -+ * (3840 * 2160 pixels) * (4 bytes/pixel) * (2 frames/buffer) / 10^6 = 66MB -+ * To ensure sufficient support for practical use-cases, -+ * we doubled the 66MB value. -+ */ -+ hdmi_receiver_cma: hdmi-receiver-cma { -+ compatible = "shared-dma-pool"; -+ alloc-ranges = <0x0 0x0 0x0 0xffffffff>; -+ size = <0x0 (160 * 0x100000)>; /* 160MiB */ -+ no-map; -+ status = "disabled"; -+ }; -+ }; -+ - usb_host1_xhci: usb@fc400000 { - compatible = "rockchip,rk3588-dwc3", "snps,dwc3"; - reg = <0x0 0xfc400000 0x0 0x400000>; -@@ -135,6 +158,39 @@ i2s10_8ch: i2s@fde00000 { - status = "disabled"; - }; - -+ hdmi_receiver: hdmi_receiver@fdee0000 { -+ compatible = "rockchip,rk3588-hdmirx-ctrler", "snps,dw-hdmi-rx"; -+ reg = <0x0 0xfdee0000 0x0 0x6000>; -+ power-domains = <&power RK3588_PD_VO1>; -+ rockchip,grf = <&sys_grf>; -+ rockchip,vo1-grf = <&vo1_grf>; -+ interrupts = , -+ , -+ ; -+ interrupt-names = "cec", "hdmi", "dma"; -+ clocks = <&cru ACLK_HDMIRX>, -+ <&cru CLK_HDMIRX_AUD>, -+ <&cru CLK_CR_PARA>, -+ <&cru PCLK_HDMIRX>, -+ <&cru CLK_HDMIRX_REF>, -+ <&cru PCLK_S_HDMIRX>, -+ <&cru HCLK_VO1>; -+ clock-names = "aclk", -+ "audio", -+ "cr_para", -+ "pclk", -+ "ref", -+ "hclk_s_hdmirx", -+ "hclk_vo1"; -+ resets = <&cru SRST_A_HDMIRX>, <&cru SRST_P_HDMIRX>, -+ <&cru SRST_HDMIRX_REF>, <&cru SRST_A_HDMIRX_BIU>; -+ reset-names = "axi", "apb", "ref", "biu"; -+ memory-region = <&hdmi_receiver_cma>; -+ pinctrl-0 = <&hdmim1_rx>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ }; -+ - pcie3x4: pcie@fe150000 { - compatible = "rockchip,rk3588-pcie", "rockchip,rk3568-pcie"; - #address-cells = <3>; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shreeya Patel -Date: Fri, 19 Jul 2024 18:10:32 +0530 -Subject: media: platform: synopsys: Add support for hdmi input driver - -Add initial support for the Synopsys DesignWare HDMI RX -Controller Driver used by Rockchip RK3588. The driver -supports: - - HDMI 1.4b and 2.0 modes (HDMI 4k@60Hz) - - RGB888, YUV422, YUV444 and YCC420 pixel formats - - CEC - - EDID configuration - -The hardware also has Audio and HDCP capabilities, but these are -not yet supported by the driver. - -Reviewed-by: Dmitry Osipenko -Tested-by: Dmitry Osipenko -Co-developed-by: Dingxian Wen -Signed-off-by: Dingxian Wen -Signed-off-by: Shreeya Patel -Link: https://lore.kernel.org/r/20240719124032.26852-5-shreeya.patel@collabora.com -Signed-off-by: Sebastian Reichel ---- - drivers/media/platform/Kconfig | 1 + - drivers/media/platform/Makefile | 1 + - drivers/media/platform/synopsys/Kconfig | 3 + - drivers/media/platform/synopsys/Makefile | 2 + - drivers/media/platform/synopsys/hdmirx/Kconfig | 27 + - drivers/media/platform/synopsys/hdmirx/Makefile | 4 + - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 2763 ++++++++++ - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h | 394 ++ - drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c | 285 + - drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h | 44 + - 10 files changed, 3524 insertions(+) - -diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/Kconfig -+++ b/drivers/media/platform/Kconfig -@@ -85,6 +85,7 @@ source "drivers/media/platform/rockchip/Kconfig" - source "drivers/media/platform/samsung/Kconfig" - source "drivers/media/platform/st/Kconfig" - source "drivers/media/platform/sunxi/Kconfig" -+source "drivers/media/platform/synopsys/Kconfig" - source "drivers/media/platform/ti/Kconfig" - source "drivers/media/platform/verisilicon/Kconfig" - source "drivers/media/platform/via/Kconfig" -diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/Makefile -+++ b/drivers/media/platform/Makefile -@@ -28,6 +28,7 @@ obj-y += rockchip/ - obj-y += samsung/ - obj-y += st/ - obj-y += sunxi/ -+obj-y += synopsys/ - obj-y += ti/ - obj-y += verisilicon/ - obj-y += via/ -diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/Kconfig -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ -+source "drivers/media/platform/synopsys/hdmirx/Kconfig" -diff --git a/drivers/media/platform/synopsys/Makefile b/drivers/media/platform/synopsys/Makefile -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/Makefile -@@ -0,0 +1,2 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+obj-y += hdmirx/ -diff --git a/drivers/media/platform/synopsys/hdmirx/Kconfig b/drivers/media/platform/synopsys/hdmirx/Kconfig -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/Kconfig -@@ -0,0 +1,27 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+config VIDEO_SYNOPSYS_HDMIRX -+ tristate "Synopsys DesignWare HDMI Receiver driver" -+ depends on VIDEO_DEV -+ depends on ARCH_ROCKCHIP -+ select MEDIA_CONTROLLER -+ select VIDEO_V4L2_SUBDEV_API -+ select VIDEOBUF2_DMA_CONTIG -+ select CEC_CORE -+ select CEC_NOTIFIER -+ select HDMI -+ help -+ Support for Synopsys HDMI HDMI RX Controller. -+ This driver supports HDMI 2.0 version. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called synopsys_hdmirx. -+ -+config HDMIRX_LOAD_DEFAULT_EDID -+ bool "Load default EDID" -+ depends on VIDEO_SYNOPSYS_HDMIRX -+ default "y" -+ help -+ Preload the default EDID (Extended Display Identification Data). -+ EDID contains information about the capabilities of the display, -+ such as supported resolutions, refresh rates, and audio formats. -diff --git a/drivers/media/platform/synopsys/hdmirx/Makefile b/drivers/media/platform/synopsys/hdmirx/Makefile -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/Makefile -@@ -0,0 +1,4 @@ -+# SPDX-License-Identifier: GPL-2.0 -+synopsys-hdmirx-objs := snps_hdmirx.o snps_hdmirx_cec.o -+ -+obj-$(CONFIG_VIDEO_SYNOPSYS_HDMIRX) += synopsys-hdmirx.o -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -0,0 +1,2763 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2024 Collabora, Ltd. -+ * Author: Shreeya Patel -+ * -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * Author: Dingxian Wen -+ */ -+ -+#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 "snps_hdmirx.h" -+#include "snps_hdmirx_cec.h" -+ -+static int debug; -+module_param(debug, int, 0644); -+MODULE_PARM_DESC(debug, "debug level (0-3)"); -+ -+#define EDID_NUM_BLOCKS_MAX 2 -+#define EDID_BLOCK_SIZE 128 -+#define HDMIRX_STORED_BIT_WIDTH 8 -+#define IREF_CLK_FREQ_HZ 428571429 -+#define MEMORY_ALIGN_ROUND_UP_BYTES 64 -+#define HDMIRX_PLANE_Y 0 -+#define HDMIRX_PLANE_CBCR 1 -+#define RK_IRQ_HDMIRX_HDMI 210 -+#define FILTER_FRAME_CNT 6 -+#define RK_SIP_FIQ_CTRL 0x82000024 -+#define SIP_WDT_CFG 0x82000026 -+#define DETECTION_THRESHOLD 7 -+ -+/* fiq control sub func */ -+enum { -+ RK_SIP_FIQ_CTRL_FIQ_EN = 1, -+ RK_SIP_FIQ_CTRL_FIQ_DIS, -+ RK_SIP_FIQ_CTRL_SET_AFF -+}; -+ -+/* SIP_WDT_CONFIG call types */ -+enum { -+ WDT_START = 0, -+ WDT_STOP = 1, -+ WDT_PING = 2, -+}; -+ -+enum hdmirx_pix_fmt { -+ HDMIRX_RGB888 = 0, -+ HDMIRX_YUV422 = 1, -+ HDMIRX_YUV444 = 2, -+ HDMIRX_YUV420 = 3, -+}; -+ -+enum ddr_store_fmt { -+ STORE_RGB888 = 0, -+ STORE_RGBA_ARGB, -+ STORE_YUV420_8BIT, -+ STORE_YUV420_10BIT, -+ STORE_YUV422_8BIT, -+ STORE_YUV422_10BIT, -+ STORE_YUV444_8BIT, -+ STORE_YUV420_16BIT = 8, -+ STORE_YUV422_16BIT = 9, -+}; -+ -+enum hdmirx_reg_attr { -+ HDMIRX_ATTR_RW = 0, -+ HDMIRX_ATTR_RO = 1, -+ HDMIRX_ATTR_WO = 2, -+ HDMIRX_ATTR_RE = 3, -+}; -+ -+enum { -+ HDMIRX_RST_A, -+ HDMIRX_RST_P, -+ HDMIRX_RST_REF, -+ HDMIRX_RST_BIU, -+ HDMIRX_NUM_RST, -+}; -+ -+static const char * const pix_fmt_str[] = { -+ "RGB888", -+ "YUV422", -+ "YUV444", -+ "YUV420", -+}; -+ -+struct hdmirx_buffer { -+ struct vb2_v4l2_buffer vb; -+ struct list_head queue; -+ u32 buff_addr[VIDEO_MAX_PLANES]; -+}; -+ -+struct hdmirx_stream { -+ struct snps_hdmirx_dev *hdmirx_dev; -+ struct video_device vdev; -+ struct vb2_queue buf_queue; -+ struct list_head buf_head; -+ struct hdmirx_buffer *curr_buf; -+ struct hdmirx_buffer *next_buf; -+ struct v4l2_pix_format_mplane pixm; -+ const struct v4l2_format_info *out_finfo; -+ struct mutex vlock; /* to lock resources associated with video buffer and video device */ -+ spinlock_t vbq_lock; /* to lock video buffer queue */ -+ bool stopping; -+ wait_queue_head_t wq_stopped; -+ u32 frame_idx; -+ u32 line_flag_int_cnt; -+ u32 irq_stat; -+}; -+ -+struct snps_hdmirx_dev { -+ struct device *dev; -+ struct device *codec_dev; -+ struct hdmirx_stream stream; -+ struct v4l2_device v4l2_dev; -+ struct v4l2_ctrl_handler hdl; -+ struct v4l2_ctrl *detect_tx_5v_ctrl; -+ struct v4l2_ctrl *rgb_range; -+ struct v4l2_dv_timings timings; -+ struct gpio_desc *detect_5v_gpio; -+ struct work_struct work_wdt_config; -+ struct delayed_work delayed_work_hotplug; -+ struct delayed_work delayed_work_res_change; -+ struct delayed_work delayed_work_heartbeat; -+ struct cec_notifier *cec_notifier; -+ struct hdmirx_cec *cec; -+ struct mutex stream_lock; /* to lock video stream capture */ -+ struct mutex work_lock; /* to lock the critical section of hotplug event */ -+ struct reset_control_bulk_data resets[HDMIRX_NUM_RST]; -+ struct clk_bulk_data *clks; -+ struct regmap *grf; -+ struct regmap *vo1_grf; -+ struct completion cr_write_done; -+ struct completion timer_base_lock; -+ struct completion avi_pkt_rcv; -+ enum hdmirx_pix_fmt pix_fmt; -+ void __iomem *regs; -+ int hdmi_irq; -+ int dma_irq; -+ int det_irq; -+ bool hpd_trigger_level; -+ bool tmds_clk_ratio; -+ bool is_dvi_mode; -+ bool got_timing; -+ u32 num_clks; -+ u32 edid_blocks_written; -+ u32 cur_vic; -+ u32 cur_fmt_fourcc; -+ u32 color_depth; -+ u8 edid[EDID_BLOCK_SIZE * 2]; -+ hdmi_codec_plugged_cb plugged_cb; -+ spinlock_t rst_lock; /* to lock register access */ -+}; -+ -+static u8 edid_init_data_340M[] = { -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, -+ 0x49, 0x70, 0x88, 0x35, 0x01, 0x00, 0x00, 0x00, -+ 0x2D, 0x1F, 0x01, 0x03, 0x80, 0x78, 0x44, 0x78, -+ 0x0A, 0xCF, 0x74, 0xA3, 0x57, 0x4C, 0xB0, 0x23, -+ 0x09, 0x48, 0x4C, 0x21, 0x08, 0x00, 0x61, 0x40, -+ 0x01, 0x01, 0x81, 0x00, 0x95, 0x00, 0xA9, 0xC0, -+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A, -+ 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, -+ 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, -+ 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, -+ 0x6E, 0x28, 0x55, 0x00, 0x20, 0xC2, 0x31, 0x00, -+ 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x52, -+ 0x4B, 0x2D, 0x55, 0x48, 0x44, 0x0A, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFD, -+ 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xA7, -+ -+ 0x02, 0x03, 0x2F, 0xD1, 0x51, 0x07, 0x16, 0x14, -+ 0x05, 0x01, 0x03, 0x12, 0x13, 0x84, 0x22, 0x1F, -+ 0x90, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x23, 0x09, -+ 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x67, 0x03, -+ 0x0C, 0x00, 0x30, 0x00, 0x10, 0x44, 0xE3, 0x05, -+ 0x03, 0x01, 0xE4, 0x0F, 0x00, 0x80, 0x01, 0x02, -+ 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, -+ 0x2C, 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, -+ 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, -+}; -+ -+static const struct v4l2_dv_timings cea640x480 = V4L2_DV_BT_CEA_640X480P59_94; -+ -+static const struct v4l2_dv_timings_cap hdmirx_timings_cap = { -+ .type = V4L2_DV_BT_656_1120, -+ .reserved = { 0 }, -+ V4L2_INIT_BT_TIMINGS(640, 4096, /* min/max width */ -+ 480, 2160, /* min/max height */ -+ 20000000, 600000000, /* min/max pixelclock */ -+ /* standards */ -+ V4L2_DV_BT_STD_CEA861, -+ /* capabilities */ -+ V4L2_DV_BT_CAP_PROGRESSIVE | -+ V4L2_DV_BT_CAP_INTERLACED) -+}; -+ -+static void hdmirx_writel(struct snps_hdmirx_dev *hdmirx_dev, int reg, u32 val) -+{ -+ unsigned long lock_flags = 0; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ writel(val, hdmirx_dev->regs + reg); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+} -+ -+static u32 hdmirx_readl(struct snps_hdmirx_dev *hdmirx_dev, int reg) -+{ -+ unsigned long lock_flags = 0; -+ u32 val; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ val = readl(hdmirx_dev->regs + reg); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+ return val; -+} -+ -+static void hdmirx_reset_dma(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ unsigned long lock_flags = 0; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ reset_control_reset(hdmirx_dev->resets[0].rstc); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+} -+ -+static void hdmirx_update_bits(struct snps_hdmirx_dev *hdmirx_dev, int reg, -+ u32 mask, u32 data) -+{ -+ unsigned long lock_flags = 0; -+ u32 val; -+ -+ spin_lock_irqsave(&hdmirx_dev->rst_lock, lock_flags); -+ val = readl(hdmirx_dev->regs + reg) & ~mask; -+ val |= (data & mask); -+ writel(val, hdmirx_dev->regs + reg); -+ spin_unlock_irqrestore(&hdmirx_dev->rst_lock, lock_flags); -+} -+ -+static int hdmirx_subscribe_event(struct v4l2_fh *fh, -+ const struct v4l2_event_subscription *sub) -+{ -+ switch (sub->type) { -+ case V4L2_EVENT_SOURCE_CHANGE: -+ if (fh->vdev->vfl_dir == VFL_DIR_RX) -+ return v4l2_src_change_event_subscribe(fh, sub); -+ break; -+ case V4L2_EVENT_CTRL: -+ return v4l2_ctrl_subscribe_event(fh, sub); -+ default: -+ break; -+ } -+ -+ return -EINVAL; -+} -+ -+static bool tx_5v_power_present(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ bool ret; -+ int val, i, cnt; -+ -+ cnt = 0; -+ for (i = 0; i < 10; i++) { -+ usleep_range(1000, 1100); -+ val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); -+ if (val > 0) -+ cnt++; -+ if (cnt >= DETECTION_THRESHOLD) -+ break; -+ } -+ -+ ret = (cnt >= DETECTION_THRESHOLD) ? true : false; -+ v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: %d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static bool signal_not_lock(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ u32 mu_status, dma_st10, cmu_st; -+ -+ mu_status = hdmirx_readl(hdmirx_dev, MAINUNIT_STATUS); -+ dma_st10 = hdmirx_readl(hdmirx_dev, DMA_STATUS10); -+ cmu_st = hdmirx_readl(hdmirx_dev, CMU_STATUS); -+ -+ if ((mu_status & TMDSVALID_STABLE_ST) && -+ (dma_st10 & HDMIRX_LOCK) && -+ (cmu_st & TMDSQPCLK_LOCKED_ST)) -+ return false; -+ -+ return true; -+} -+ -+static void hdmirx_get_colordepth(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 val, color_depth_reg; -+ -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); -+ color_depth_reg = (val & HDMIRX_COLOR_DEPTH_MASK) >> 3; -+ -+ switch (color_depth_reg) { -+ case 0x4: -+ hdmirx_dev->color_depth = 24; -+ break; -+ case 0x5: -+ hdmirx_dev->color_depth = 30; -+ break; -+ case 0x6: -+ hdmirx_dev->color_depth = 36; -+ break; -+ case 0x7: -+ hdmirx_dev->color_depth = 48; -+ break; -+ default: -+ hdmirx_dev->color_depth = 24; -+ break; -+ } -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: color_depth: %d, reg_val:%d\n", -+ __func__, hdmirx_dev->color_depth, color_depth_reg); -+} -+ -+static void hdmirx_get_pix_fmt(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 val; -+ -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); -+ hdmirx_dev->pix_fmt = val & HDMIRX_FORMAT_MASK; -+ -+ switch (hdmirx_dev->pix_fmt) { -+ case HDMIRX_RGB888: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; -+ break; -+ case HDMIRX_YUV422: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV16; -+ break; -+ case HDMIRX_YUV444: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV24; -+ break; -+ case HDMIRX_YUV420: -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV12; -+ break; -+ default: -+ v4l2_err(v4l2_dev, -+ "%s: err pix_fmt: %d, set RGB888 as default\n", -+ __func__, hdmirx_dev->pix_fmt); -+ hdmirx_dev->pix_fmt = HDMIRX_RGB888; -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; -+ break; -+ } -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s\n", __func__, -+ pix_fmt_str[hdmirx_dev->pix_fmt]); -+} -+ -+static void hdmirx_get_timings(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_bt_timings *bt, bool from_dma) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 hact, vact, htotal, vtotal, fps; -+ u32 hfp, hs, hbp, vfp, vs, vbp; -+ u32 val; -+ -+ if (from_dma) { -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS2); -+ hact = (val >> 16) & 0xffff; -+ vact = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS3); -+ htotal = (val >> 16) & 0xffff; -+ vtotal = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS4); -+ hs = (val >> 16) & 0xffff; -+ vs = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS5); -+ hbp = (val >> 16) & 0xffff; -+ vbp = val & 0xffff; -+ hfp = htotal - hact - hs - hbp; -+ vfp = vtotal - vact - vs - vbp; -+ } else { -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS1); -+ hs = (val >> 16) & 0xffff; -+ hfp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS2); -+ hbp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS3); -+ htotal = (val >> 16) & 0xffff; -+ hact = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS4); -+ vs = (val >> 16) & 0xffff; -+ vfp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS5); -+ vbp = val & 0xffff; -+ val = hdmirx_readl(hdmirx_dev, VMON_STATUS6); -+ vtotal = (val >> 16) & 0xffff; -+ vact = val & 0xffff; -+ if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) -+ hact *= 2; -+ } -+ if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) -+ htotal *= 2; -+ fps = (bt->pixelclock + (htotal * vtotal) / 2) / (htotal * vtotal); -+ if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) -+ fps *= 2; -+ bt->width = hact; -+ bt->height = vact; -+ bt->hfrontporch = hfp; -+ bt->hsync = hs; -+ bt->hbackporch = hbp; -+ bt->vfrontporch = vfp; -+ bt->vsync = vs; -+ bt->vbackporch = vbp; -+ -+ v4l2_dbg(1, debug, v4l2_dev, "get timings from %s\n", from_dma ? "dma" : "ctrl"); -+ v4l2_dbg(1, debug, v4l2_dev, "act:%ux%u, total:%ux%u, fps:%u, pixclk:%llu\n", -+ bt->width, bt->height, htotal, vtotal, fps, bt->pixelclock); -+ -+ v4l2_dbg(2, debug, v4l2_dev, "hfp:%u, hs:%u, hbp:%u, vfp:%u, vs:%u, vbp:%u\n", -+ bt->hfrontporch, bt->hsync, bt->hbackporch, -+ bt->vfrontporch, bt->vsync, bt->vbackporch); -+} -+ -+static bool hdmirx_check_timing_valid(struct v4l2_bt_timings *bt) -+{ -+ if (bt->width < 100 || bt->width > 5000 || -+ bt->height < 100 || bt->height > 5000) -+ return false; -+ -+ if (!bt->hsync || bt->hsync > 200 || -+ !bt->vsync || bt->vsync > 100) -+ return false; -+ -+ if (!bt->hbackporch || bt->hbackporch > 2000 || -+ !bt->vbackporch || bt->vbackporch > 2000) -+ return false; -+ -+ if (!bt->hfrontporch || bt->hfrontporch > 2000 || -+ !bt->vfrontporch || bt->vfrontporch > 2000) -+ return false; -+ -+ return true; -+} -+ -+static void hdmirx_get_avi_infoframe(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ union hdmi_infoframe frame = {}; -+ int err, i, b, itr = 0; -+ u8 aviif[3 + 7 * 4]; -+ u32 val; -+ -+ aviif[itr++] = HDMI_INFOFRAME_TYPE_AVI; -+ val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PH2_1); -+ aviif[itr++] = val & 0xff; -+ aviif[itr++] = (val >> 8) & 0xff; -+ -+ for (i = 0; i < 7; i++) { -+ val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PB3_0 + 4 * i); -+ -+ for (b = 0; b < 4; b++) -+ aviif[itr++] = (val >> (8 * b)) & 0xff; -+ } -+ -+ err = hdmi_infoframe_unpack(&frame, aviif, sizeof(aviif)); -+ if (err) { -+ v4l2_err(v4l2_dev, "failed to unpack AVI infoframe\n"); -+ return; -+ } -+ -+ v4l2_ctrl_s_ctrl(hdmirx_dev->rgb_range, frame.avi.quantization_range); -+} -+ -+/* -+ * When querying DV timings during preview, if the DMA's timing is stable, -+ * we retrieve the timings directly from the DMA. However, if the current -+ * resolution is negative, obtaining the timing from CTRL may require a -+ * change in the sync polarity, potentially leading to DMA errors. -+ */ -+static int hdmirx_get_detected_timings(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_dv_timings *timings, -+ bool from_dma) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_bt_timings *bt = &timings->bt; -+ u32 field_type, color_depth, deframer_st; -+ u32 val, tmdsqpclk_freq, pix_clk; -+ u64 tmp_data, tmds_clk; -+ -+ memset(timings, 0, sizeof(struct v4l2_dv_timings)); -+ timings->type = V4L2_DV_BT_656_1120; -+ -+ val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); -+ field_type = (val & HDMIRX_TYPE_MASK) >> 7; -+ hdmirx_get_pix_fmt(hdmirx_dev); -+ bt->interlaced = field_type & BIT(0) ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; -+ val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PB7_4); -+ hdmirx_dev->cur_vic = val | VIC_VAL_MASK; -+ hdmirx_get_colordepth(hdmirx_dev); -+ color_depth = hdmirx_dev->color_depth; -+ deframer_st = hdmirx_readl(hdmirx_dev, DEFRAMER_STATUS); -+ hdmirx_dev->is_dvi_mode = deframer_st & OPMODE_STS_MASK ? false : true; -+ tmdsqpclk_freq = hdmirx_readl(hdmirx_dev, CMU_TMDSQPCLK_FREQ); -+ tmds_clk = tmdsqpclk_freq * 4 * 1000; -+ tmp_data = tmds_clk * 24; -+ do_div(tmp_data, color_depth); -+ pix_clk = tmp_data; -+ bt->pixelclock = pix_clk; -+ -+ hdmirx_get_avi_infoframe(hdmirx_dev); -+ -+ hdmirx_get_timings(hdmirx_dev, bt, from_dma); -+ if (bt->interlaced == V4L2_DV_INTERLACED) { -+ bt->height *= 2; -+ bt->il_vsync = bt->vsync + 1; -+ } -+ -+ v4l2_dbg(2, debug, v4l2_dev, "tmds_clk:%llu\n", tmds_clk); -+ v4l2_dbg(1, debug, v4l2_dev, "interlace:%d, fmt:%d, vic:%d, color:%d, mode:%s\n", -+ bt->interlaced, hdmirx_dev->pix_fmt, -+ hdmirx_dev->cur_vic, hdmirx_dev->color_depth, -+ hdmirx_dev->is_dvi_mode ? "dvi" : "hdmi"); -+ v4l2_dbg(2, debug, v4l2_dev, "deframer_st:%#x\n", deframer_st); -+ -+ if (!hdmirx_check_timing_valid(bt)) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static bool port_no_link(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ return !tx_5v_power_present(hdmirx_dev); -+} -+ -+static int hdmirx_query_dv_timings(struct file *file, void *_fh, -+ struct v4l2_dv_timings *timings) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int ret; -+ -+ if (port_no_link(hdmirx_dev)) { -+ v4l2_err(v4l2_dev, "%s: port has no link\n", __func__); -+ return -ENOLINK; -+ } -+ -+ if (signal_not_lock(hdmirx_dev)) { -+ v4l2_err(v4l2_dev, "%s: signal is not locked\n", __func__); -+ return -ENOLCK; -+ } -+ -+ ret = hdmirx_get_detected_timings(hdmirx_dev, timings, true); -+ if (ret) -+ return ret; -+ -+ if (debug) -+ v4l2_print_dv_timings(hdmirx_dev->v4l2_dev.name, -+ "query_dv_timings: ", timings, false); -+ -+ if (!v4l2_valid_dv_timings(timings, &hdmirx_timings_cap, NULL, NULL)) { -+ v4l2_dbg(1, debug, v4l2_dev, "%s: timings out of range\n", __func__); -+ return -ERANGE; -+ } -+ -+ return 0; -+} -+ -+static void hdmirx_hpd_ctrl(struct snps_hdmirx_dev *hdmirx_dev, bool en) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: %sable, hpd_trigger_level:%d\n", -+ __func__, en ? "en" : "dis", -+ hdmirx_dev->hpd_trigger_level); -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, HPDLOW, en ? 0 : HPDLOW); -+ en = hdmirx_dev->hpd_trigger_level ? en : !en; -+ hdmirx_writel(hdmirx_dev, CORE_CONFIG, en); -+} -+ -+static int hdmirx_write_edid(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_edid *edid, bool hpd_up) -+{ -+ u32 edid_len = edid->blocks * EDID_BLOCK_SIZE; -+ char data[300]; -+ u32 i; -+ -+ memset(edid->reserved, 0, sizeof(edid->reserved)); -+ if (edid->pad) -+ return -EINVAL; -+ -+ if (edid->start_block) -+ return -EINVAL; -+ -+ if (edid->blocks > EDID_NUM_BLOCKS_MAX) { -+ edid->blocks = EDID_NUM_BLOCKS_MAX; -+ return -E2BIG; -+ } -+ -+ if (!edid->blocks) { -+ hdmirx_dev->edid_blocks_written = 0; -+ return 0; -+ } -+ -+ cec_s_phys_addr_from_edid(hdmirx_dev->cec->adap, -+ (const struct edid *)edid->edid); -+ -+ memset(&hdmirx_dev->edid, 0, sizeof(hdmirx_dev->edid)); -+ hdmirx_hpd_ctrl(hdmirx_dev, false); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, -+ EDID_READ_EN_MASK | -+ EDID_WRITE_EN_MASK | -+ EDID_SLAVE_ADDR_MASK, -+ EDID_READ_EN(0) | -+ EDID_WRITE_EN(1) | -+ EDID_SLAVE_ADDR(0x50)); -+ for (i = 0; i < edid_len; i++) -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG10, edid->edid[i]); -+ -+ /* read out for debug */ -+ if (debug >= 2) { -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, -+ EDID_READ_EN_MASK | -+ EDID_WRITE_EN_MASK, -+ EDID_READ_EN(1) | -+ EDID_WRITE_EN(0)); -+ edid_len = edid_len > sizeof(data) ? sizeof(data) : edid_len; -+ memset(data, 0, sizeof(data)); -+ for (i = 0; i < edid_len; i++) -+ data[i] = hdmirx_readl(hdmirx_dev, DMA_STATUS14); -+ -+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, data, -+ edid_len, false); -+ } -+ -+ /* -+ * You must set EDID_READ_EN & EDID_WRITE_EN bit to 0, -+ * when the read/write edid operation is completed.Otherwise, it -+ * will affect the reading and writing of other registers -+ */ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, -+ EDID_READ_EN_MASK | EDID_WRITE_EN_MASK, -+ EDID_READ_EN(0) | EDID_WRITE_EN(0)); -+ -+ hdmirx_dev->edid_blocks_written = edid->blocks; -+ memcpy(&hdmirx_dev->edid, edid->edid, edid->blocks * EDID_BLOCK_SIZE); -+ if (hpd_up) { -+ if (tx_5v_power_present(hdmirx_dev)) { -+ /* Add 100ms delay after updating the EDID as per HDMI specs */ -+ msleep(100); -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Before clearing interrupt, we need to read the interrupt status. -+ */ -+static inline void hdmirx_clear_interrupt(struct snps_hdmirx_dev *hdmirx_dev, -+ u32 reg, u32 val) -+{ -+ /* (interrupt status register) = (interrupt clear register) - 0x8 */ -+ hdmirx_readl(hdmirx_dev, reg - 0x8); -+ hdmirx_writel(hdmirx_dev, reg, val); -+} -+ -+static void hdmirx_interrupts_setup(struct snps_hdmirx_dev *hdmirx_dev, bool en) -+{ -+ v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: %sable\n", -+ __func__, en ? "en" : "dis"); -+ -+ /* Note: In DVI mode, it needs to be written twice to take effect. */ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); -+ -+ if (en) { -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, -+ TMDSQPCLK_OFF_CHG | TMDSQPCLK_LOCKED_CHG, -+ TMDSQPCLK_OFF_CHG | TMDSQPCLK_LOCKED_CHG); -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, -+ TMDSVALID_STABLE_CHG, TMDSVALID_STABLE_CHG); -+ hdmirx_update_bits(hdmirx_dev, AVPUNIT_0_INT_MASK_N, -+ CED_DYN_CNT_CH2_IRQ | -+ CED_DYN_CNT_CH1_IRQ | -+ CED_DYN_CNT_CH0_IRQ, -+ CED_DYN_CNT_CH2_IRQ | -+ CED_DYN_CNT_CH1_IRQ | -+ CED_DYN_CNT_CH0_IRQ); -+ } else { -+ hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_MASK_N, 0); -+ } -+} -+ -+static void hdmirx_plugout(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct arm_smccc_res res; -+ -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 0); -+ hdmirx_interrupts_setup(hdmirx_dev, false); -+ hdmirx_hpd_ctrl(hdmirx_dev, false); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, 0); -+ hdmirx_reset_dma(hdmirx_dev); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, HDMI_DISABLE | PHY_RESET | -+ PHY_PDDQ, HDMI_DISABLE); -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG0, 0x0); -+ cancel_delayed_work(&hdmirx_dev->delayed_work_res_change); -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_heartbeat); -+ flush_work(&hdmirx_dev->work_wdt_config); -+ arm_smccc_smc(SIP_WDT_CFG, WDT_STOP, 0, 0, 0, 0, 0, 0, &res); -+} -+ -+static int hdmirx_set_edid(struct file *file, void *fh, struct v4l2_edid *edid) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct arm_smccc_res res; -+ int ret; -+ -+ disable_irq(hdmirx_dev->hdmi_irq); -+ disable_irq(hdmirx_dev->dma_irq); -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_DIS, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ if (tx_5v_power_present(hdmirx_dev)) -+ hdmirx_plugout(hdmirx_dev); -+ ret = hdmirx_write_edid(hdmirx_dev, edid, false); -+ if (ret) -+ return ret; -+ -+ enable_irq(hdmirx_dev->hdmi_irq); -+ enable_irq(hdmirx_dev->dma_irq); -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_EN, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(500)); -+ return 0; -+} -+ -+static int hdmirx_get_edid(struct file *file, void *fh, struct v4l2_edid *edid) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ memset(edid->reserved, 0, sizeof(edid->reserved)); -+ -+ if (edid->pad) -+ return -EINVAL; -+ -+ if (!edid->start_block && !edid->blocks) { -+ edid->blocks = hdmirx_dev->edid_blocks_written; -+ return 0; -+ } -+ -+ if (!hdmirx_dev->edid_blocks_written) -+ return -ENODATA; -+ -+ if (edid->start_block >= hdmirx_dev->edid_blocks_written || !edid->blocks) -+ return -EINVAL; -+ -+ if (edid->start_block + edid->blocks > hdmirx_dev->edid_blocks_written) -+ edid->blocks = hdmirx_dev->edid_blocks_written - edid->start_block; -+ -+ memcpy(edid->edid, &hdmirx_dev->edid, edid->blocks * EDID_BLOCK_SIZE); -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: read EDID:\n", __func__); -+ if (debug > 0) -+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, -+ edid->edid, edid->blocks * EDID_BLOCK_SIZE, false); -+ -+ return 0; -+} -+ -+static int hdmirx_g_parm(struct file *file, void *priv, -+ struct v4l2_streamparm *parm) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_fract fps; -+ -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -+ return -EINVAL; -+ -+ fps = v4l2_calc_timeperframe(&hdmirx_dev->timings); -+ parm->parm.capture.timeperframe.numerator = fps.numerator; -+ parm->parm.capture.timeperframe.denominator = fps.denominator; -+ -+ return 0; -+} -+ -+static int hdmirx_dv_timings_cap(struct file *file, void *fh, -+ struct v4l2_dv_timings_cap *cap) -+{ -+ *cap = hdmirx_timings_cap; -+ return 0; -+} -+ -+static int hdmirx_enum_dv_timings(struct file *file, void *_fh, -+ struct v4l2_enum_dv_timings *timings) -+{ -+ return v4l2_enum_dv_timings_cap(timings, &hdmirx_timings_cap, NULL, NULL); -+} -+ -+static void hdmirx_scdc_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_update_bits(hdmirx_dev, I2C_SLAVE_CONFIG1, -+ I2C_SDA_OUT_HOLD_VALUE_QST_MASK | -+ I2C_SDA_IN_HOLD_VALUE_QST_MASK, -+ I2C_SDA_OUT_HOLD_VALUE_QST(0x80) | -+ I2C_SDA_IN_HOLD_VALUE_QST(0x15)); -+ hdmirx_update_bits(hdmirx_dev, SCDC_REGBANK_CONFIG0, -+ SCDC_SINKVERSION_QST_MASK, -+ SCDC_SINKVERSION_QST(1)); -+} -+ -+static int wait_reg_bit_status(struct snps_hdmirx_dev *hdmirx_dev, u32 reg, -+ u32 bit_mask, u32 expect_val, bool is_grf, -+ u32 ms) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 i, val; -+ -+ for (i = 0; i < ms; i++) { -+ if (is_grf) -+ regmap_read(hdmirx_dev->grf, reg, &val); -+ else -+ val = hdmirx_readl(hdmirx_dev, reg); -+ -+ if ((val & bit_mask) == expect_val) { -+ v4l2_dbg(2, debug, v4l2_dev, -+ "%s: i:%d, time: %dms\n", __func__, i, ms); -+ break; -+ } -+ usleep_range(1000, 1010); -+ } -+ -+ if (i == ms) -+ return -1; -+ -+ return 0; -+} -+ -+static int hdmirx_phy_register_write(struct snps_hdmirx_dev *hdmirx_dev, -+ u32 phy_reg, u32 val) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ -+ reinit_completion(&hdmirx_dev->cr_write_done); -+ /* clear irq status */ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ /* en irq */ -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, -+ PHYCREG_CR_WRITE_DONE, PHYCREG_CR_WRITE_DONE); -+ /* write phy reg addr */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG1, phy_reg); -+ /* write phy reg val */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG2, val); -+ /* config write enable */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONTROL, PHYCREG_CR_PARA_WRITE_P); -+ -+ if (!wait_for_completion_timeout(&hdmirx_dev->cr_write_done, -+ msecs_to_jiffies(20))) { -+ dev_err(dev, "%s wait cr write done failed\n", __func__); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static void hdmirx_tmds_clk_ratio_config(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 val; -+ -+ val = hdmirx_readl(hdmirx_dev, SCDC_REGBANK_STATUS1); -+ v4l2_dbg(3, debug, v4l2_dev, "%s: scdc_regbank_st:%#x\n", __func__, val); -+ hdmirx_dev->tmds_clk_ratio = (val & SCDC_TMDSBITCLKRATIO) > 0; -+ -+ if (hdmirx_dev->tmds_clk_ratio) { -+ v4l2_dbg(3, debug, v4l2_dev, "%s: HDMITX greater than 3.4Gbps\n", __func__); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, -+ TMDS_CLOCK_RATIO, TMDS_CLOCK_RATIO); -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, "%s: HDMITX less than 3.4Gbps\n", __func__); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, -+ TMDS_CLOCK_RATIO, 0); -+ } -+} -+ -+static void hdmirx_phy_config(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ -+ hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); -+ hdmirx_update_bits(hdmirx_dev, SCDC_INT_MASK_N, SCDCTMDSCCFG_CHG, -+ SCDCTMDSCCFG_CHG); -+ /* cr_para_clk 24M */ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, REFFREQ_SEL_MASK, REFFREQ_SEL(0)); -+ /* rx data width 40bit valid */ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, RXDATA_WIDTH, RXDATA_WIDTH); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET, PHY_RESET); -+ usleep_range(100, 110); -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET, 0); -+ usleep_range(100, 110); -+ /* select cr para interface */ -+ hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG0, 0x3); -+ -+ if (wait_reg_bit_status(hdmirx_dev, SYS_GRF_SOC_STATUS1, -+ HDMIRXPHY_SRAM_INIT_DONE, -+ HDMIRXPHY_SRAM_INIT_DONE, true, 10)) -+ dev_err(dev, "%s: phy SRAM init failed\n", __func__); -+ -+ regmap_write(hdmirx_dev->grf, SYS_GRF_SOC_CON1, -+ (HDMIRXPHY_SRAM_EXT_LD_DONE << 16) | -+ HDMIRXPHY_SRAM_EXT_LD_DONE); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 3); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 3); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 1); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); -+ hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); -+ -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG, -+ CDR_SETTING_BOUNDARY_3_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG, -+ CDR_SETTING_BOUNDARY_4_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG, -+ CDR_SETTING_BOUNDARY_5_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG, -+ CDR_SETTING_BOUNDARY_6_DEFAULT); -+ hdmirx_phy_register_write(hdmirx_dev, -+ HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG, -+ CDR_SETTING_BOUNDARY_7_DEFAULT); -+ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_PDDQ, 0); -+ if (wait_reg_bit_status(hdmirx_dev, PHY_STATUS, PDDQ_ACK, 0, false, 10)) -+ dev_err(dev, "%s: wait pddq ack failed\n", __func__); -+ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, HDMI_DISABLE, 0); -+ if (wait_reg_bit_status(hdmirx_dev, PHY_STATUS, HDMI_DISABLE_ACK, 0, -+ false, 50)) -+ dev_err(dev, "%s: wait hdmi disable ack failed\n", __func__); -+ -+ hdmirx_tmds_clk_ratio_config(hdmirx_dev); -+} -+ -+static void hdmirx_controller_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ -+ reinit_completion(&hdmirx_dev->timer_base_lock); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ /* en irq */ -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, -+ TIMER_BASE_LOCKED_IRQ, TIMER_BASE_LOCKED_IRQ); -+ /* write irefclk freq */ -+ hdmirx_writel(hdmirx_dev, GLOBAL_TIMER_REF_BASE, IREF_CLK_FREQ_HZ); -+ -+ if (!wait_for_completion_timeout(&hdmirx_dev->timer_base_lock, -+ msecs_to_jiffies(20))) -+ dev_err(dev, "%s wait timer base lock failed\n", __func__); -+ -+ hdmirx_update_bits(hdmirx_dev, CMU_CONFIG0, -+ TMDSQPCLK_STABLE_FREQ_MARGIN_MASK | -+ AUDCLK_STABLE_FREQ_MARGIN_MASK, -+ TMDSQPCLK_STABLE_FREQ_MARGIN(2) | -+ AUDCLK_STABLE_FREQ_MARGIN(1)); -+ hdmirx_update_bits(hdmirx_dev, DESCRAND_EN_CONTROL, -+ SCRAMB_EN_SEL_QST_MASK, SCRAMB_EN_SEL_QST(1)); -+ hdmirx_update_bits(hdmirx_dev, CED_CONFIG, -+ CED_VIDDATACHECKEN_QST | -+ CED_DATAISCHECKEN_QST | -+ CED_GBCHECKEN_QST | -+ CED_CTRLCHECKEN_QST | -+ CED_CHLOCKMAXER_QST_MASK, -+ CED_VIDDATACHECKEN_QST | -+ CED_GBCHECKEN_QST | -+ CED_CTRLCHECKEN_QST | -+ CED_CHLOCKMAXER_QST(0x10)); -+ hdmirx_update_bits(hdmirx_dev, DEFRAMER_CONFIG0, -+ VS_REMAPFILTER_EN_QST | VS_FILTER_ORDER_QST_MASK, -+ VS_REMAPFILTER_EN_QST | VS_FILTER_ORDER_QST(0x3)); -+} -+ -+static void hdmirx_set_negative_pol(struct snps_hdmirx_dev *hdmirx_dev, bool en) -+{ -+ if (en) { -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, -+ VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN, -+ VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN); -+ hdmirx_update_bits(hdmirx_dev, VIDEO_CONFIG2, -+ VPROC_VSYNC_POL_OVR_VALUE | -+ VPROC_VSYNC_POL_OVR_EN | -+ VPROC_HSYNC_POL_OVR_VALUE | -+ VPROC_HSYNC_POL_OVR_EN, -+ VPROC_VSYNC_POL_OVR_EN | -+ VPROC_HSYNC_POL_OVR_EN); -+ return; -+ } -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, -+ VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN, 0); -+ -+ hdmirx_update_bits(hdmirx_dev, VIDEO_CONFIG2, -+ VPROC_VSYNC_POL_OVR_VALUE | -+ VPROC_VSYNC_POL_OVR_EN | -+ VPROC_HSYNC_POL_OVR_VALUE | -+ VPROC_HSYNC_POL_OVR_EN, 0); -+} -+ -+static int hdmirx_try_to_get_timings(struct snps_hdmirx_dev *hdmirx_dev, -+ struct v4l2_dv_timings *timings, -+ int try_cnt) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int i, cnt = 0, fail_cnt = 0, ret = 0; -+ bool from_dma = false; -+ -+ hdmirx_set_negative_pol(hdmirx_dev, false); -+ for (i = 0; i < try_cnt; i++) { -+ ret = hdmirx_get_detected_timings(hdmirx_dev, timings, from_dma); -+ if (ret) { -+ cnt = 0; -+ fail_cnt++; -+ if (fail_cnt > 3) { -+ hdmirx_set_negative_pol(hdmirx_dev, true); -+ from_dma = true; -+ } -+ } else { -+ cnt++; -+ } -+ if (cnt >= 5) -+ break; -+ -+ usleep_range(10 * 1000, 10 * 1100); -+ } -+ -+ if (try_cnt > 8 && cnt < 5) -+ v4l2_dbg(1, debug, v4l2_dev, "%s: res not stable\n", __func__); -+ -+ return ret; -+} -+ -+static void hdmirx_format_change(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_dv_timings timings; -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ const struct v4l2_event ev_src_chg = { -+ .type = V4L2_EVENT_SOURCE_CHANGE, -+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, -+ }; -+ -+ if (hdmirx_try_to_get_timings(hdmirx_dev, &timings, 20)) { -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(20)); -+ return; -+ } -+ -+ hdmirx_dev->got_timing = true; -+ v4l2_dbg(1, debug, v4l2_dev, "%s: queue res_chg_event\n", __func__); -+ v4l2_event_queue(&stream->vdev, &ev_src_chg); -+} -+ -+static void hdmirx_set_ddr_store_fmt(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ enum ddr_store_fmt store_fmt; -+ u32 dma_cfg1; -+ -+ switch (hdmirx_dev->pix_fmt) { -+ case HDMIRX_RGB888: -+ store_fmt = STORE_RGB888; -+ break; -+ case HDMIRX_YUV444: -+ store_fmt = STORE_YUV444_8BIT; -+ break; -+ case HDMIRX_YUV422: -+ store_fmt = STORE_YUV422_8BIT; -+ break; -+ case HDMIRX_YUV420: -+ store_fmt = STORE_YUV420_8BIT; -+ break; -+ default: -+ store_fmt = STORE_RGB888; -+ break; -+ } -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG1, -+ DDR_STORE_FORMAT_MASK, DDR_STORE_FORMAT(store_fmt)); -+ dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1); -+ v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s, DMA_CONFIG1:%#x\n", -+ __func__, pix_fmt_str[hdmirx_dev->pix_fmt], dma_cfg1); -+} -+ -+static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 mu_status, scdc_status, dma_st10, cmu_st; -+ u32 i; -+ -+ for (i = 0; i < 300; i++) { -+ mu_status = hdmirx_readl(hdmirx_dev, MAINUNIT_STATUS); -+ scdc_status = hdmirx_readl(hdmirx_dev, SCDC_REGBANK_STATUS3); -+ dma_st10 = hdmirx_readl(hdmirx_dev, DMA_STATUS10); -+ cmu_st = hdmirx_readl(hdmirx_dev, CMU_STATUS); -+ -+ if ((mu_status & TMDSVALID_STABLE_ST) && -+ (dma_st10 & HDMIRX_LOCK) && -+ (cmu_st & TMDSQPCLK_LOCKED_ST)) -+ break; -+ -+ if (!tx_5v_power_present(hdmirx_dev)) { -+ v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); -+ return -1; -+ } -+ -+ hdmirx_tmds_clk_ratio_config(hdmirx_dev); -+ } -+ -+ if (i == 300) { -+ v4l2_err(v4l2_dev, "%s: signal not lock, tmds_clk_ratio:%d\n", -+ __func__, hdmirx_dev->tmds_clk_ratio); -+ v4l2_err(v4l2_dev, "%s: mu_st:%#x, scdc_st:%#x, dma_st10:%#x\n", -+ __func__, mu_status, scdc_status, dma_st10); -+ return -1; -+ } -+ -+ v4l2_info(v4l2_dev, "%s: signal lock ok, i:%d\n", __func__, i); -+ hdmirx_writel(hdmirx_dev, GLOBAL_SWRESET_REQUEST, DATAPATH_SWRESETREQ); -+ -+ reinit_completion(&hdmirx_dev->avi_pkt_rcv); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, -+ PKTDEC_AVIIF_RCV_IRQ, PKTDEC_AVIIF_RCV_IRQ); -+ -+ if (!wait_for_completion_timeout(&hdmirx_dev->avi_pkt_rcv, -+ msecs_to_jiffies(300))) { -+ v4l2_err(v4l2_dev, "%s wait avi_pkt_rcv failed\n", __func__); -+ hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, -+ PKTDEC_AVIIF_RCV_IRQ, 0); -+ } -+ -+ usleep_range(50 * 1000, 50 * 1010); -+ hdmirx_format_change(hdmirx_dev); -+ -+ return 0; -+} -+ -+static void hdmirx_dma_config(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_set_ddr_store_fmt(hdmirx_dev); -+ -+ /* Note: uv_swap, rb can not swap, doc err*/ -+ if (hdmirx_dev->cur_fmt_fourcc != V4L2_PIX_FMT_NV16) -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, RB_SWAP_EN, RB_SWAP_EN); -+ else -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, RB_SWAP_EN, 0); -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, -+ LOCK_FRAME_NUM_MASK, -+ LOCK_FRAME_NUM(2)); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG1, -+ UV_WID_MASK | Y_WID_MASK | ABANDON_EN, -+ UV_WID(1) | Y_WID(2) | ABANDON_EN); -+} -+ -+static void hdmirx_submodule_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ /* Note: if not config HDCP2_CONFIG, there will be some errors; */ -+ hdmirx_update_bits(hdmirx_dev, HDCP2_CONFIG, -+ HDCP2_SWITCH_OVR_VALUE | -+ HDCP2_SWITCH_OVR_EN, -+ HDCP2_SWITCH_OVR_EN); -+ hdmirx_scdc_init(hdmirx_dev); -+ hdmirx_controller_init(hdmirx_dev); -+} -+ -+static int hdmirx_enum_input(struct file *file, void *priv, -+ struct v4l2_input *input) -+{ -+ if (input->index > 0) -+ return -EINVAL; -+ -+ input->type = V4L2_INPUT_TYPE_CAMERA; -+ input->std = 0; -+ strscpy(input->name, "HDMI IN", sizeof(input->name)); -+ input->capabilities = V4L2_IN_CAP_DV_TIMINGS; -+ -+ return 0; -+} -+ -+static int hdmirx_get_input(struct file *file, void *priv, unsigned int *i) -+{ -+ *i = 0; -+ return 0; -+} -+ -+static int hdmirx_set_input(struct file *file, void *priv, unsigned int i) -+{ -+ if (i) -+ return -EINVAL; -+ return 0; -+} -+ -+static void hdmirx_set_fmt(struct hdmirx_stream *stream, -+ struct v4l2_pix_format_mplane *pixm, bool try) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_bt_timings *bt = &hdmirx_dev->timings.bt; -+ const struct v4l2_format_info *finfo; -+ unsigned int imagesize = 0; -+ int i; -+ -+ memset(&pixm->plane_fmt[0], 0, sizeof(struct v4l2_plane_pix_format)); -+ finfo = v4l2_format_info(pixm->pixelformat); -+ if (!finfo) { -+ finfo = v4l2_format_info(V4L2_PIX_FMT_BGR24); -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: set_fmt:%#x not supported, use def_fmt:%x\n", -+ __func__, pixm->pixelformat, finfo->format); -+ } -+ -+ if (!bt->width || !bt->height) -+ v4l2_dbg(1, debug, v4l2_dev, "%s: invalid resolution:%#xx%#x\n", -+ __func__, bt->width, bt->height); -+ -+ pixm->pixelformat = finfo->format; -+ pixm->width = bt->width; -+ pixm->height = bt->height; -+ pixm->num_planes = finfo->mem_planes; -+ pixm->quantization = V4L2_QUANTIZATION_DEFAULT; -+ pixm->colorspace = V4L2_COLORSPACE_SRGB; -+ pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; -+ -+ if (bt->interlaced == V4L2_DV_INTERLACED) -+ pixm->field = V4L2_FIELD_INTERLACED_TB; -+ else -+ pixm->field = V4L2_FIELD_NONE; -+ -+ memset(pixm->reserved, 0, sizeof(pixm->reserved)); -+ -+ v4l2_fill_pixfmt_mp(pixm, finfo->format, pixm->width, pixm->height); -+ -+ for (i = 0; i < pixm->num_planes; i++) { -+ struct v4l2_plane_pix_format *plane_fmt; -+ int width, height, bpl, size, bpp = 0; -+ -+ if (!i) { -+ width = pixm->width; -+ height = pixm->height; -+ } else { -+ width = pixm->width / finfo->hdiv; -+ height = pixm->height / finfo->vdiv; -+ } -+ -+ switch (finfo->format) { -+ case V4L2_PIX_FMT_NV24: -+ case V4L2_PIX_FMT_NV16: -+ case V4L2_PIX_FMT_NV12: -+ case V4L2_PIX_FMT_BGR24: -+ bpp = finfo->bpp[i]; -+ break; -+ default: -+ v4l2_dbg(1, debug, v4l2_dev, -+ "fourcc: %#x is not supported\n", -+ finfo->format); -+ break; -+ } -+ -+ bpl = ALIGN(width * bpp, MEMORY_ALIGN_ROUND_UP_BYTES); -+ size = bpl * height; -+ imagesize += size; -+ -+ if (finfo->mem_planes > i) { -+ /* Set bpl and size for each mplane */ -+ plane_fmt = pixm->plane_fmt + i; -+ plane_fmt->bytesperline = bpl; -+ plane_fmt->sizeimage = size; -+ } -+ -+ v4l2_dbg(1, debug, v4l2_dev, -+ "C-Plane %i size: %d, Total imagesize: %d\n", -+ i, size, imagesize); -+ } -+ -+ /* Convert to non-MPLANE format as we want to unify non-MPLANE and MPLANE */ -+ if (finfo->mem_planes == 1) -+ pixm->plane_fmt[0].sizeimage = imagesize; -+ -+ if (!try) { -+ stream->out_finfo = finfo; -+ stream->pixm = *pixm; -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: req(%d, %d), out(%d, %d), fmt:%#x\n", __func__, -+ pixm->width, pixm->height, stream->pixm.width, -+ stream->pixm.height, finfo->format); -+ } -+} -+ -+static int hdmirx_enum_fmt_vid_cap_mplane(struct file *file, void *priv, -+ struct v4l2_fmtdesc *f) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ -+ if (f->index >= 1) -+ return -EINVAL; -+ -+ f->pixelformat = hdmirx_dev->cur_fmt_fourcc; -+ -+ return 0; -+} -+ -+static int hdmirx_s_fmt_vid_cap_mplane(struct file *file, -+ void *priv, struct v4l2_format *f) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (vb2_is_busy(&stream->buf_queue)) { -+ v4l2_err(v4l2_dev, "%s: queue busy\n", __func__); -+ return -EBUSY; -+ } -+ -+ hdmirx_set_fmt(stream, &f->fmt.pix_mp, false); -+ -+ return 0; -+} -+ -+static int hdmirx_g_fmt_vid_cap_mplane(struct file *file, void *fh, -+ struct v4l2_format *f) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_pix_format_mplane pixm = {}; -+ -+ pixm.pixelformat = hdmirx_dev->cur_fmt_fourcc; -+ hdmirx_set_fmt(stream, &pixm, true); -+ f->fmt.pix_mp = pixm; -+ -+ return 0; -+} -+ -+static int hdmirx_g_dv_timings(struct file *file, void *_fh, -+ struct v4l2_dv_timings *timings) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 dma_cfg1; -+ -+ *timings = hdmirx_dev->timings; -+ dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1); -+ v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s, DMA_CONFIG1:%#x\n", -+ __func__, pix_fmt_str[hdmirx_dev->pix_fmt], dma_cfg1); -+ -+ return 0; -+} -+ -+static int hdmirx_s_dv_timings(struct file *file, void *_fh, -+ struct v4l2_dv_timings *timings) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (!timings) -+ return -EINVAL; -+ -+ if (debug) -+ v4l2_print_dv_timings(hdmirx_dev->v4l2_dev.name, -+ "s_dv_timings: ", timings, false); -+ -+ if (!v4l2_valid_dv_timings(timings, &hdmirx_timings_cap, NULL, NULL)) { -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: timings out of range\n", __func__); -+ return -ERANGE; -+ } -+ -+ /* Check if the timings are part of the CEA-861 timings. */ -+ v4l2_find_dv_timings_cap(timings, &hdmirx_timings_cap, 0, NULL, NULL); -+ -+ if (v4l2_match_dv_timings(&hdmirx_dev->timings, timings, 0, false)) { -+ v4l2_dbg(1, debug, v4l2_dev, "%s: no change\n", __func__); -+ return 0; -+ } -+ -+ /* -+ * Changing the timings implies a format change, which is not allowed -+ * while buffers for use with streaming have already been allocated. -+ */ -+ if (vb2_is_busy(&stream->buf_queue)) -+ return -EBUSY; -+ -+ hdmirx_dev->timings = *timings; -+ /* Update the internal format */ -+ hdmirx_set_fmt(stream, &stream->pixm, false); -+ -+ return 0; -+} -+ -+static int hdmirx_querycap(struct file *file, void *priv, -+ struct v4l2_capability *cap) -+{ -+ struct hdmirx_stream *stream = video_drvdata(file); -+ struct device *dev = stream->hdmirx_dev->dev; -+ -+ strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); -+ strscpy(cap->card, dev->driver->name, sizeof(cap->card)); -+ -+ return 0; -+} -+ -+static int hdmirx_queue_setup(struct vb2_queue *queue, -+ unsigned int *num_buffers, -+ unsigned int *num_planes, -+ unsigned int sizes[], -+ struct device *alloc_ctxs[]) -+{ -+ struct hdmirx_stream *stream = vb2_get_drv_priv(queue); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ const struct v4l2_pix_format_mplane *pixm = NULL; -+ const struct v4l2_format_info *out_finfo; -+ u32 i, height; -+ -+ pixm = &stream->pixm; -+ out_finfo = stream->out_finfo; -+ -+ if (!num_planes || !out_finfo) { -+ v4l2_err(v4l2_dev, "%s: out_fmt not set\n", __func__); -+ return -EINVAL; -+ } -+ -+ if (*num_planes) { -+ if (*num_planes != pixm->num_planes) -+ return -EINVAL; -+ -+ for (i = 0; i < *num_planes; i++) -+ if (sizes[i] < pixm->plane_fmt[i].sizeimage) -+ return -EINVAL; -+ return 0; -+ } -+ -+ *num_planes = out_finfo->mem_planes; -+ height = pixm->height; -+ -+ for (i = 0; i < out_finfo->mem_planes; i++) -+ sizes[i] = pixm->plane_fmt[i].sizeimage; -+ -+ v4l2_dbg(1, debug, v4l2_dev, "%s: count %d, size %d\n", -+ v4l2_type_names[queue->type], *num_buffers, sizes[0]); -+ -+ return 0; -+} -+ -+/* -+ * The vb2_buffer are stored in hdmirx_buffer, in order to unify -+ * mplane buffer and none-mplane buffer. -+ */ -+static void hdmirx_buf_queue(struct vb2_buffer *vb) -+{ -+ const struct v4l2_format_info *out_finfo; -+ struct vb2_v4l2_buffer *vbuf; -+ struct hdmirx_buffer *hdmirx_buf; -+ struct vb2_queue *queue; -+ struct hdmirx_stream *stream; -+ const struct v4l2_pix_format_mplane *pixm; -+ unsigned long lock_flags = 0; -+ int i; -+ -+ vbuf = to_vb2_v4l2_buffer(vb); -+ hdmirx_buf = container_of(vbuf, struct hdmirx_buffer, vb); -+ queue = vb->vb2_queue; -+ stream = vb2_get_drv_priv(queue); -+ pixm = &stream->pixm; -+ out_finfo = stream->out_finfo; -+ -+ memset(hdmirx_buf->buff_addr, 0, sizeof(hdmirx_buf->buff_addr)); -+ -+ /* -+ * If mplanes > 1, every c-plane has its own m-plane, -+ * otherwise, multiple c-planes are in the same m-plane -+ */ -+ for (i = 0; i < out_finfo->mem_planes; i++) -+ hdmirx_buf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); -+ -+ if (out_finfo->mem_planes == 1) { -+ if (out_finfo->comp_planes == 1) { -+ hdmirx_buf->buff_addr[HDMIRX_PLANE_CBCR] = -+ hdmirx_buf->buff_addr[HDMIRX_PLANE_Y]; -+ } else { -+ for (i = 0; i < out_finfo->comp_planes - 1; i++) -+ hdmirx_buf->buff_addr[i + 1] = -+ hdmirx_buf->buff_addr[i] + -+ pixm->plane_fmt[i].bytesperline * -+ pixm->height; -+ } -+ } -+ -+ spin_lock_irqsave(&stream->vbq_lock, lock_flags); -+ list_add_tail(&hdmirx_buf->queue, &stream->buf_head); -+ spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); -+} -+ -+static void return_all_buffers(struct hdmirx_stream *stream, -+ enum vb2_buffer_state state) -+{ -+ struct hdmirx_buffer *buf; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&stream->vbq_lock, flags); -+ if (stream->curr_buf) -+ list_add_tail(&stream->curr_buf->queue, &stream->buf_head); -+ if (stream->next_buf && stream->next_buf != stream->curr_buf) -+ list_add_tail(&stream->next_buf->queue, &stream->buf_head); -+ stream->curr_buf = NULL; -+ stream->next_buf = NULL; -+ -+ while (!list_empty(&stream->buf_head)) { -+ buf = list_first_entry(&stream->buf_head, -+ struct hdmirx_buffer, queue); -+ list_del(&buf->queue); -+ spin_unlock_irqrestore(&stream->vbq_lock, flags); -+ vb2_buffer_done(&buf->vb.vb2_buf, state); -+ spin_lock_irqsave(&stream->vbq_lock, flags); -+ } -+ spin_unlock_irqrestore(&stream->vbq_lock, flags); -+} -+ -+static void hdmirx_stop_streaming(struct vb2_queue *queue) -+{ -+ struct hdmirx_stream *stream = vb2_get_drv_priv(queue); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int ret; -+ -+ v4l2_info(v4l2_dev, "stream start stopping\n"); -+ mutex_lock(&hdmirx_dev->stream_lock); -+ WRITE_ONCE(stream->stopping, true); -+ -+ /* wait last irq to return the buffer */ -+ ret = wait_event_timeout(stream->wq_stopped, !stream->stopping, -+ msecs_to_jiffies(500)); -+ if (!ret) { -+ v4l2_err(v4l2_dev, "%s: timeout waiting last irq\n", -+ __func__); -+ WRITE_ONCE(stream->stopping, false); -+ } -+ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); -+ return_all_buffers(stream, VB2_BUF_STATE_ERROR); -+ mutex_unlock(&hdmirx_dev->stream_lock); -+ v4l2_info(v4l2_dev, "stream stopping finished\n"); -+} -+ -+static int hdmirx_start_streaming(struct vb2_queue *queue, unsigned int count) -+{ -+ struct hdmirx_stream *stream = vb2_get_drv_priv(queue); -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_dv_timings timings = hdmirx_dev->timings; -+ struct v4l2_bt_timings *bt = &timings.bt; -+ unsigned long lock_flags = 0; -+ int line_flag; -+ -+ if (!hdmirx_dev->got_timing) { -+ v4l2_dbg(1, debug, v4l2_dev, "timing is invalid\n"); -+ return 0; -+ } -+ -+ mutex_lock(&hdmirx_dev->stream_lock); -+ stream->frame_idx = 0; -+ stream->line_flag_int_cnt = 0; -+ stream->curr_buf = NULL; -+ stream->next_buf = NULL; -+ stream->irq_stat = 0; -+ queue->min_queued_buffers = 1; -+ -+ WRITE_ONCE(stream->stopping, false); -+ -+ spin_lock_irqsave(&stream->vbq_lock, lock_flags); -+ if (!stream->curr_buf) { -+ if (!list_empty(&stream->buf_head)) { -+ stream->curr_buf = list_first_entry(&stream->buf_head, -+ struct hdmirx_buffer, -+ queue); -+ list_del(&stream->curr_buf->queue); -+ } else { -+ stream->curr_buf = NULL; -+ } -+ } -+ spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); -+ -+ v4l2_dbg(2, debug, v4l2_dev, -+ "%s: start_stream cur_buf y_addr:%#x, uv_addr:%#x\n", -+ __func__, stream->curr_buf->buff_addr[HDMIRX_PLANE_Y], -+ stream->curr_buf->buff_addr[HDMIRX_PLANE_CBCR]); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG2, -+ stream->curr_buf->buff_addr[HDMIRX_PLANE_Y]); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG3, -+ stream->curr_buf->buff_addr[HDMIRX_PLANE_CBCR]); -+ -+ if (bt->height) { -+ if (bt->interlaced == V4L2_DV_INTERLACED) -+ line_flag = bt->height / 4; -+ else -+ line_flag = bt->height / 2; -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, -+ LINE_FLAG_NUM_MASK, -+ LINE_FLAG_NUM(line_flag)); -+ } else { -+ v4l2_err(v4l2_dev, "height err: %d\n", bt->height); -+ } -+ -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, CED_DYN_CONTROL, 0x1); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, HDMIRX_DMA_EN); -+ v4l2_dbg(1, debug, v4l2_dev, "%s: enable dma", __func__); -+ mutex_unlock(&hdmirx_dev->stream_lock); -+ -+ return 0; -+} -+ -+/* vb2 queue */ -+static const struct vb2_ops hdmirx_vb2_ops = { -+ .queue_setup = hdmirx_queue_setup, -+ .buf_queue = hdmirx_buf_queue, -+ .wait_prepare = vb2_ops_wait_prepare, -+ .wait_finish = vb2_ops_wait_finish, -+ .stop_streaming = hdmirx_stop_streaming, -+ .start_streaming = hdmirx_start_streaming, -+}; -+ -+static int hdmirx_init_vb2_queue(struct vb2_queue *q, -+ struct hdmirx_stream *stream, -+ enum v4l2_buf_type buf_type) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ -+ q->type = buf_type; -+ q->io_modes = VB2_MMAP | VB2_DMABUF; -+ q->drv_priv = stream; -+ q->ops = &hdmirx_vb2_ops; -+ q->mem_ops = &vb2_dma_contig_memops; -+ q->buf_struct_size = sizeof(struct hdmirx_buffer); -+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; -+ q->lock = &stream->vlock; -+ q->dev = hdmirx_dev->dev; -+ /* -+ * rk3588 doesn't use iommu and works only with dma buffers -+ * that are physically contiguous in memory. -+ */ -+ q->dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; -+ return vb2_queue_init(q); -+} -+ -+/* video device */ -+static const struct v4l2_ioctl_ops hdmirx_v4l2_ioctl_ops = { -+ .vidioc_querycap = hdmirx_querycap, -+ .vidioc_try_fmt_vid_cap_mplane = hdmirx_g_fmt_vid_cap_mplane, -+ .vidioc_s_fmt_vid_cap_mplane = hdmirx_s_fmt_vid_cap_mplane, -+ .vidioc_g_fmt_vid_cap_mplane = hdmirx_g_fmt_vid_cap_mplane, -+ .vidioc_enum_fmt_vid_cap = hdmirx_enum_fmt_vid_cap_mplane, -+ -+ .vidioc_s_dv_timings = hdmirx_s_dv_timings, -+ .vidioc_g_dv_timings = hdmirx_g_dv_timings, -+ .vidioc_enum_dv_timings = hdmirx_enum_dv_timings, -+ .vidioc_query_dv_timings = hdmirx_query_dv_timings, -+ .vidioc_dv_timings_cap = hdmirx_dv_timings_cap, -+ .vidioc_enum_input = hdmirx_enum_input, -+ .vidioc_g_input = hdmirx_get_input, -+ .vidioc_s_input = hdmirx_set_input, -+ .vidioc_g_edid = hdmirx_get_edid, -+ .vidioc_s_edid = hdmirx_set_edid, -+ .vidioc_g_parm = hdmirx_g_parm, -+ -+ .vidioc_reqbufs = vb2_ioctl_reqbufs, -+ .vidioc_querybuf = vb2_ioctl_querybuf, -+ .vidioc_create_bufs = vb2_ioctl_create_bufs, -+ .vidioc_qbuf = vb2_ioctl_qbuf, -+ .vidioc_expbuf = vb2_ioctl_expbuf, -+ .vidioc_dqbuf = vb2_ioctl_dqbuf, -+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, -+ .vidioc_streamon = vb2_ioctl_streamon, -+ .vidioc_streamoff = vb2_ioctl_streamoff, -+ -+ .vidioc_log_status = v4l2_ctrl_log_status, -+ .vidioc_subscribe_event = hdmirx_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -+}; -+ -+static const struct v4l2_file_operations hdmirx_fops = { -+ .owner = THIS_MODULE, -+ .open = v4l2_fh_open, -+ .release = vb2_fop_release, -+ .unlocked_ioctl = video_ioctl2, -+ .poll = vb2_fop_poll, -+ .mmap = vb2_fop_mmap, -+}; -+ -+static int hdmirx_register_stream_vdev(struct hdmirx_stream *stream) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct video_device *vdev = &stream->vdev; -+ int ret = 0; -+ -+ strscpy(vdev->name, "stream_hdmirx", sizeof(vdev->name)); -+ INIT_LIST_HEAD(&stream->buf_head); -+ spin_lock_init(&stream->vbq_lock); -+ mutex_init(&stream->vlock); -+ init_waitqueue_head(&stream->wq_stopped); -+ stream->curr_buf = NULL; -+ stream->next_buf = NULL; -+ -+ vdev->ioctl_ops = &hdmirx_v4l2_ioctl_ops; -+ vdev->release = video_device_release_empty; -+ vdev->fops = &hdmirx_fops; -+ vdev->minor = -1; -+ vdev->v4l2_dev = v4l2_dev; -+ vdev->lock = &stream->vlock; -+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | -+ V4L2_CAP_STREAMING; -+ video_set_drvdata(vdev, stream); -+ vdev->vfl_dir = VFL_DIR_RX; -+ -+ hdmirx_init_vb2_queue(&stream->buf_queue, stream, -+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); -+ vdev->queue = &stream->buf_queue; -+ -+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); -+ if (ret < 0) { -+ v4l2_err(v4l2_dev, "video_register_device failed: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void process_signal_change(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, 0); -+ hdmirx_reset_dma(hdmirx_dev); -+ hdmirx_dev->got_timing = false; -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_res_change, -+ msecs_to_jiffies(50)); -+} -+ -+static void avpunit_0_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (status & (CED_DYN_CNT_CH2_IRQ | -+ CED_DYN_CNT_CH1_IRQ | -+ CED_DYN_CNT_CH0_IRQ)) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: avp0_st:%#x\n", -+ __func__, status); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_FORCE, 0x0); -+} -+ -+static void avpunit_1_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ if (status & DEFRAMER_VSYNC_THR_REACHED_IRQ) { -+ v4l2_info(v4l2_dev, "Vertical Sync threshold reached interrupt %#x", status); -+ hdmirx_update_bits(hdmirx_dev, AVPUNIT_1_INT_MASK_N, -+ DEFRAMER_VSYNC_THR_REACHED_MASK_N, 0); -+ *handled = true; -+ } -+} -+ -+static void mainunit_0_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "mu0_st:%#x\n", status); -+ if (status & TIMER_BASE_LOCKED_IRQ) { -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, -+ TIMER_BASE_LOCKED_IRQ, 0); -+ complete(&hdmirx_dev->timer_base_lock); -+ *handled = true; -+ } -+ -+ if (status & TMDSQPCLK_OFF_CHG) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSQPCLK_OFF_CHG\n", __func__); -+ *handled = true; -+ } -+ -+ if (status & TMDSQPCLK_LOCKED_CHG) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSQPCLK_LOCKED_CHG\n", __func__); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_FORCE, 0x0); -+} -+ -+static void mainunit_2_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "mu2_st:%#x\n", status); -+ if (status & PHYCREG_CR_WRITE_DONE) { -+ hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, -+ PHYCREG_CR_WRITE_DONE, 0); -+ complete(&hdmirx_dev->cr_write_done); -+ *handled = true; -+ } -+ -+ if (status & TMDSVALID_STABLE_CHG) { -+ process_signal_change(hdmirx_dev); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSVALID_STABLE_CHG\n", __func__); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_FORCE, 0x0); -+} -+ -+static void pkt_2_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: pk2_st:%#x\n", __func__, status); -+ if (status & PKTDEC_AVIIF_RCV_IRQ) { -+ hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, -+ PKTDEC_AVIIF_RCV_IRQ, 0); -+ complete(&hdmirx_dev->avi_pkt_rcv); -+ v4l2_dbg(2, debug, v4l2_dev, "%s: AVIIF_RCV_IRQ\n", __func__); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); -+} -+ -+static void scdc_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ int status, bool *handled) -+{ -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: scdc_st:%#x\n", __func__, status); -+ if (status & SCDCTMDSCCFG_CHG) { -+ hdmirx_tmds_clk_ratio_config(hdmirx_dev); -+ *handled = true; -+ } -+ -+ hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); -+} -+ -+static irqreturn_t hdmirx_hdmi_irq_handler(int irq, void *dev_id) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_id; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct arm_smccc_res res; -+ u32 mu0_st, mu2_st, pk2_st, scdc_st, avp1_st, avp0_st; -+ u32 mu0_mask, mu2_mask, pk2_mask, scdc_mask, avp1_msk, avp0_msk; -+ bool handled = false; -+ -+ mu0_mask = hdmirx_readl(hdmirx_dev, MAINUNIT_0_INT_MASK_N); -+ mu2_mask = hdmirx_readl(hdmirx_dev, MAINUNIT_2_INT_MASK_N); -+ pk2_mask = hdmirx_readl(hdmirx_dev, PKT_2_INT_MASK_N); -+ scdc_mask = hdmirx_readl(hdmirx_dev, SCDC_INT_MASK_N); -+ mu0_st = hdmirx_readl(hdmirx_dev, MAINUNIT_0_INT_STATUS); -+ mu2_st = hdmirx_readl(hdmirx_dev, MAINUNIT_2_INT_STATUS); -+ pk2_st = hdmirx_readl(hdmirx_dev, PKT_2_INT_STATUS); -+ scdc_st = hdmirx_readl(hdmirx_dev, SCDC_INT_STATUS); -+ avp0_st = hdmirx_readl(hdmirx_dev, AVPUNIT_0_INT_STATUS); -+ avp1_st = hdmirx_readl(hdmirx_dev, AVPUNIT_1_INT_STATUS); -+ avp0_msk = hdmirx_readl(hdmirx_dev, AVPUNIT_0_INT_MASK_N); -+ avp1_msk = hdmirx_readl(hdmirx_dev, AVPUNIT_1_INT_MASK_N); -+ mu0_st &= mu0_mask; -+ mu2_st &= mu2_mask; -+ pk2_st &= pk2_mask; -+ avp1_st &= avp1_msk; -+ avp0_st &= avp0_msk; -+ scdc_st &= scdc_mask; -+ -+ if (avp0_st) -+ avpunit_0_int_handler(hdmirx_dev, avp0_st, &handled); -+ if (avp1_st) -+ avpunit_1_int_handler(hdmirx_dev, avp1_st, &handled); -+ if (mu0_st) -+ mainunit_0_int_handler(hdmirx_dev, mu0_st, &handled); -+ if (mu2_st) -+ mainunit_2_int_handler(hdmirx_dev, mu2_st, &handled); -+ if (pk2_st) -+ pkt_2_int_handler(hdmirx_dev, pk2_st, &handled); -+ if (scdc_st) -+ scdc_int_handler(hdmirx_dev, scdc_st, &handled); -+ -+ if (!handled) { -+ v4l2_dbg(2, debug, v4l2_dev, "%s: hdmi irq not handled", __func__); -+ v4l2_dbg(2, debug, v4l2_dev, -+ "avp0:%#x, avp1:%#x, mu0:%#x, mu2:%#x, pk2:%#x, scdc:%#x\n", -+ avp0_st, avp1_st, mu0_st, mu2_st, pk2_st, scdc_st); -+ } -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: en_fiq", __func__); -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_EN, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ return handled ? IRQ_HANDLED : IRQ_NONE; -+} -+ -+static void hdmirx_vb_done(struct hdmirx_stream *stream, -+ struct vb2_v4l2_buffer *vb_done) -+{ -+ const struct v4l2_format_info *finfo = stream->out_finfo; -+ u32 i; -+ -+ /* Dequeue a filled buffer */ -+ for (i = 0; i < finfo->mem_planes; i++) { -+ vb2_set_plane_payload(&vb_done->vb2_buf, i, -+ stream->pixm.plane_fmt[i].sizeimage); -+ } -+ -+ vb_done->vb2_buf.timestamp = ktime_get_ns(); -+ vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); -+} -+ -+static void dma_idle_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ bool *handled) -+{ -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_dv_timings timings = hdmirx_dev->timings; -+ struct v4l2_bt_timings *bt = &timings.bt; -+ struct vb2_v4l2_buffer *vb_done = NULL; -+ -+ if (!(stream->irq_stat) && !(stream->irq_stat & LINE_FLAG_INT_EN)) -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: last time have no line_flag_irq\n", __func__); -+ -+ if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) -+ goto DMA_IDLE_OUT; -+ -+ if (bt->interlaced != V4L2_DV_INTERLACED || -+ !(stream->line_flag_int_cnt % 2)) { -+ if (stream->next_buf) { -+ if (stream->curr_buf) -+ vb_done = &stream->curr_buf->vb; -+ -+ if (vb_done) { -+ vb_done->vb2_buf.timestamp = ktime_get_ns(); -+ vb_done->sequence = stream->frame_idx; -+ hdmirx_vb_done(stream, vb_done); -+ stream->frame_idx++; -+ if (stream->frame_idx == 30) -+ v4l2_info(v4l2_dev, "rcv frames\n"); -+ } -+ -+ stream->curr_buf = NULL; -+ if (stream->next_buf) { -+ stream->curr_buf = stream->next_buf; -+ stream->next_buf = NULL; -+ } -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, -+ "%s: next_buf NULL, skip vb_done\n", __func__); -+ } -+ } -+ -+DMA_IDLE_OUT: -+ *handled = true; -+} -+ -+static void line_flag_int_handler(struct snps_hdmirx_dev *hdmirx_dev, -+ bool *handled) -+{ -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ struct v4l2_dv_timings timings = hdmirx_dev->timings; -+ struct v4l2_bt_timings *bt = &timings.bt; -+ u32 dma_cfg6; -+ -+ stream->line_flag_int_cnt++; -+ if (!(stream->irq_stat) && !(stream->irq_stat & HDMIRX_DMA_IDLE_INT)) -+ v4l2_dbg(1, debug, v4l2_dev, -+ "%s: last have no dma_idle_irq\n", __func__); -+ dma_cfg6 = hdmirx_readl(hdmirx_dev, DMA_CONFIG6); -+ if (!(dma_cfg6 & HDMIRX_DMA_EN)) { -+ v4l2_dbg(2, debug, v4l2_dev, "%s: dma not on\n", __func__); -+ goto LINE_FLAG_OUT; -+ } -+ -+ if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) -+ goto LINE_FLAG_OUT; -+ -+ if (bt->interlaced != V4L2_DV_INTERLACED || -+ !(stream->line_flag_int_cnt % 2)) { -+ if (!stream->next_buf) { -+ spin_lock(&stream->vbq_lock); -+ if (!list_empty(&stream->buf_head)) { -+ stream->next_buf = list_first_entry(&stream->buf_head, -+ struct hdmirx_buffer, -+ queue); -+ list_del(&stream->next_buf->queue); -+ } else { -+ stream->next_buf = NULL; -+ } -+ spin_unlock(&stream->vbq_lock); -+ -+ if (stream->next_buf) { -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG2, -+ stream->next_buf->buff_addr[HDMIRX_PLANE_Y]); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG3, -+ stream->next_buf->buff_addr[HDMIRX_PLANE_CBCR]); -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, -+ "%s: no buffer is available\n", __func__); -+ } -+ } -+ } else { -+ v4l2_dbg(3, debug, v4l2_dev, "%s: interlace:%d, line_flag_int_cnt:%d\n", -+ __func__, bt->interlaced, stream->line_flag_int_cnt); -+ } -+ -+LINE_FLAG_OUT: -+ *handled = true; -+} -+ -+static irqreturn_t hdmirx_dma_irq_handler(int irq, void *dev_id) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_id; -+ struct hdmirx_stream *stream = &hdmirx_dev->stream; -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ u32 dma_stat1, dma_stat13; -+ bool handled = false; -+ -+ dma_stat1 = hdmirx_readl(hdmirx_dev, DMA_STATUS1); -+ dma_stat13 = hdmirx_readl(hdmirx_dev, DMA_STATUS13); -+ v4l2_dbg(3, debug, v4l2_dev, "dma_irq st1:%#x, st13:%d\n", -+ dma_stat1, dma_stat13); -+ -+ if (READ_ONCE(stream->stopping)) { -+ v4l2_dbg(1, debug, v4l2_dev, "%s: stop stream\n", __func__); -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); -+ hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, -+ LINE_FLAG_INT_EN | -+ HDMIRX_DMA_IDLE_INT | -+ HDMIRX_LOCK_DISABLE_INT | -+ LAST_FRAME_AXI_UNFINISH_INT_EN | -+ FIFO_OVERFLOW_INT_EN | -+ FIFO_UNDERFLOW_INT_EN | -+ HDMIRX_AXI_ERROR_INT_EN, 0); -+ WRITE_ONCE(stream->stopping, false); -+ wake_up(&stream->wq_stopped); -+ return IRQ_HANDLED; -+ } -+ -+ if (dma_stat1 & HDMIRX_DMA_IDLE_INT) -+ dma_idle_int_handler(hdmirx_dev, &handled); -+ -+ if (dma_stat1 & LINE_FLAG_INT_EN) -+ line_flag_int_handler(hdmirx_dev, &handled); -+ -+ if (!handled) -+ v4l2_dbg(3, debug, v4l2_dev, -+ "%s: dma irq not handled, dma_stat1:%#x\n", -+ __func__, dma_stat1); -+ -+ stream->irq_stat = dma_stat1; -+ hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); -+ -+ return IRQ_HANDLED; -+} -+ -+static void hdmirx_plugin(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct arm_smccc_res res; -+ int ret; -+ -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_heartbeat, -+ msecs_to_jiffies(10)); -+ arm_smccc_smc(SIP_WDT_CFG, WDT_START, 0, 0, 0, 0, 0, 0, &res); -+ hdmirx_submodule_init(hdmirx_dev); -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, -+ POWERPROVIDED); -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ hdmirx_phy_config(hdmirx_dev); -+ ret = hdmirx_wait_lock_and_get_timing(hdmirx_dev); -+ if (ret) { -+ hdmirx_plugout(hdmirx_dev); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(200)); -+ return; -+ } -+ hdmirx_dma_config(hdmirx_dev); -+ hdmirx_interrupts_setup(hdmirx_dev, true); -+} -+ -+static void hdmirx_delayed_work_hotplug(struct work_struct *work) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev; -+ bool plugin; -+ -+ hdmirx_dev = container_of(work, struct snps_hdmirx_dev, -+ delayed_work_hotplug.work); -+ -+ mutex_lock(&hdmirx_dev->work_lock); -+ hdmirx_dev->got_timing = false; -+ plugin = tx_5v_power_present(hdmirx_dev); -+ v4l2_ctrl_s_ctrl(hdmirx_dev->detect_tx_5v_ctrl, plugin); -+ v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: plugin:%d\n", -+ __func__, plugin); -+ -+ if (plugin) -+ hdmirx_plugin(hdmirx_dev); -+ else -+ hdmirx_plugout(hdmirx_dev); -+ -+ mutex_unlock(&hdmirx_dev->work_lock); -+} -+ -+static void hdmirx_delayed_work_res_change(struct work_struct *work) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev; -+ bool plugin; -+ -+ hdmirx_dev = container_of(work, struct snps_hdmirx_dev, -+ delayed_work_res_change.work); -+ -+ mutex_lock(&hdmirx_dev->work_lock); -+ plugin = tx_5v_power_present(hdmirx_dev); -+ v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: plugin:%d\n", -+ __func__, plugin); -+ if (plugin) { -+ hdmirx_interrupts_setup(hdmirx_dev, false); -+ hdmirx_submodule_init(hdmirx_dev); -+ hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, -+ POWERPROVIDED); -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ hdmirx_phy_config(hdmirx_dev); -+ -+ if (hdmirx_wait_lock_and_get_timing(hdmirx_dev)) { -+ hdmirx_plugout(hdmirx_dev); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(200)); -+ } else { -+ hdmirx_dma_config(hdmirx_dev); -+ hdmirx_interrupts_setup(hdmirx_dev, true); -+ } -+ } -+ mutex_unlock(&hdmirx_dev->work_lock); -+} -+ -+static void hdmirx_delayed_work_heartbeat(struct work_struct *work) -+{ -+ struct delayed_work *dwork = to_delayed_work(work); -+ struct snps_hdmirx_dev *hdmirx_dev = container_of(dwork, -+ struct snps_hdmirx_dev, -+ delayed_work_heartbeat); -+ -+ queue_work(system_highpri_wq, &hdmirx_dev->work_wdt_config); -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_heartbeat, HZ); -+} -+ -+static void hdmirx_work_wdt_config(struct work_struct *work) -+{ -+ struct arm_smccc_res res; -+ struct snps_hdmirx_dev *hdmirx_dev = container_of(work, -+ struct snps_hdmirx_dev, -+ work_wdt_config); -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ arm_smccc_smc(SIP_WDT_CFG, WDT_PING, 0, 0, 0, 0, 0, 0, &res); -+ v4l2_dbg(3, debug, v4l2_dev, "hb\n"); -+} -+ -+static irqreturn_t hdmirx_5v_det_irq_handler(int irq, void *dev_id) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_id; -+ u32 val; -+ -+ val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); -+ v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: 5v:%d\n", __func__, val); -+ -+ queue_delayed_work(system_unbound_wq, -+ &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(10)); -+ -+ return IRQ_HANDLED; -+} -+ -+static const struct hdmirx_cec_ops hdmirx_cec_ops = { -+ .write = hdmirx_writel, -+ .read = hdmirx_readl, -+}; -+ -+static int hdmirx_parse_dt(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ int ret; -+ -+ hdmirx_dev->num_clks = devm_clk_bulk_get_all(dev, &hdmirx_dev->clks); -+ if (hdmirx_dev->num_clks < 1) -+ return -ENODEV; -+ -+ hdmirx_dev->resets[HDMIRX_RST_A].id = "axi"; -+ hdmirx_dev->resets[HDMIRX_RST_P].id = "apb"; -+ hdmirx_dev->resets[HDMIRX_RST_REF].id = "ref"; -+ hdmirx_dev->resets[HDMIRX_RST_BIU].id = "biu"; -+ -+ ret = devm_reset_control_bulk_get_exclusive(dev, HDMIRX_NUM_RST, -+ hdmirx_dev->resets); -+ if (ret < 0) { -+ dev_err(dev, "failed to get reset controls\n"); -+ return ret; -+ } -+ -+ hdmirx_dev->detect_5v_gpio = -+ devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); -+ -+ if (IS_ERR(hdmirx_dev->detect_5v_gpio)) { -+ dev_err(dev, "failed to get hdmirx hot plug detection gpio\n"); -+ return PTR_ERR(hdmirx_dev->detect_5v_gpio); -+ } -+ -+ hdmirx_dev->grf = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "rockchip,grf"); -+ if (IS_ERR(hdmirx_dev->grf)) { -+ dev_err(dev, "failed to get rockchip,grf\n"); -+ return PTR_ERR(hdmirx_dev->grf); -+ } -+ -+ hdmirx_dev->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "rockchip,vo1-grf"); -+ if (IS_ERR(hdmirx_dev->vo1_grf)) { -+ dev_err(dev, "failed to get rockchip,vo1-grf\n"); -+ return PTR_ERR(hdmirx_dev->vo1_grf); -+ } -+ -+ hdmirx_dev->hpd_trigger_level = !device_property_read_bool(dev, "hpd-is-active-low"); -+ -+ ret = of_reserved_mem_device_init(dev); -+ if (ret) -+ dev_warn(dev, "No reserved memory for HDMIRX, use default CMA\n"); -+ -+ return 0; -+} -+ -+static void hdmirx_disable_all_interrupts(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_1_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, AVPUNIT_1_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, PKT_0_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, PKT_1_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, PKT_2_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, SCDC_INT_MASK_N, 0); -+ hdmirx_writel(hdmirx_dev, CEC_INT_MASK_N, 0); -+ -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_0_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, HDCP_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, HDCP_1_INT_CLEAR, 0xffffffff); -+ hdmirx_clear_interrupt(hdmirx_dev, CEC_INT_CLEAR, 0xffffffff); -+} -+ -+static int hdmirx_init(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET | PHY_PDDQ, 0); -+ -+ regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON2, -+ (HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) | -+ ((HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) << 16)); -+ /* -+ * Some interrupts are enabled by default, so we disable -+ * all interrupts and clear interrupts status first. -+ */ -+ hdmirx_disable_all_interrupts(hdmirx_dev); -+ -+ return 0; -+} -+ -+static void hdmirx_load_default_edid(struct snps_hdmirx_dev *hdmirx_dev) -+{ -+ int ret; -+ struct v4l2_edid def_edid; -+ -+ hdmirx_hpd_ctrl(hdmirx_dev, false); -+ -+ /* disable hpd and write edid */ -+ def_edid.pad = 0; -+ def_edid.start_block = 0; -+ def_edid.blocks = EDID_NUM_BLOCKS_MAX; -+ -+ if (IS_ENABLED(CONFIG_HDMIRX_LOAD_DEFAULT_EDID)) -+ def_edid.edid = edid_init_data_340M; -+ else -+ def_edid.edid = hdmirx_dev->edid; -+ -+ ret = hdmirx_write_edid(hdmirx_dev, &def_edid, true); -+ if (ret) -+ dev_err(hdmirx_dev->dev, "%s: write edid failed\n", __func__); -+} -+ -+static void hdmirx_disable_irq(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct arm_smccc_res res; -+ -+ disable_irq(hdmirx_dev->hdmi_irq); -+ disable_irq(hdmirx_dev->dma_irq); -+ disable_irq(hdmirx_dev->det_irq); -+ -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_DIS, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_hotplug); -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_res_change); -+ cancel_delayed_work_sync(&hdmirx_dev->delayed_work_heartbeat); -+ flush_work(&hdmirx_dev->work_wdt_config); -+ -+ arm_smccc_smc(SIP_WDT_CFG, WDT_STOP, 0, 0, 0, 0, 0, 0, &res); -+} -+ -+static int hdmirx_disable(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ -+ clk_bulk_disable_unprepare(hdmirx_dev->num_clks, hdmirx_dev->clks); -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: suspend\n", __func__); -+ -+ return pinctrl_pm_select_sleep_state(dev); -+} -+ -+static void hdmirx_enable_irq(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct arm_smccc_res res; -+ -+ enable_irq(hdmirx_dev->hdmi_irq); -+ enable_irq(hdmirx_dev->dma_irq); -+ enable_irq(hdmirx_dev->det_irq); -+ -+ arm_smccc_smc(RK_SIP_FIQ_CTRL, RK_SIP_FIQ_CTRL_FIQ_EN, -+ RK_IRQ_HDMIRX_HDMI, 0, 0, 0, 0, 0, &res); -+ -+ queue_delayed_work(system_unbound_wq, &hdmirx_dev->delayed_work_hotplug, -+ msecs_to_jiffies(20)); -+} -+ -+static int hdmirx_enable(struct device *dev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; -+ int ret; -+ -+ v4l2_dbg(2, debug, v4l2_dev, "%s: resume\n", __func__); -+ ret = pinctrl_pm_select_default_state(dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = clk_bulk_prepare_enable(hdmirx_dev->num_clks, hdmirx_dev->clks); -+ if (ret) { -+ dev_err(dev, "failed to enable hdmirx bulk clks: %d\n", ret); -+ return ret; -+ } -+ -+ reset_control_bulk_assert(HDMIRX_NUM_RST, hdmirx_dev->resets); -+ usleep_range(150, 160); -+ reset_control_bulk_deassert(HDMIRX_NUM_RST, hdmirx_dev->resets); -+ usleep_range(150, 160); -+ -+ return 0; -+} -+ -+static int hdmirx_suspend(struct device *dev) -+{ -+ hdmirx_disable_irq(dev); -+ -+ return hdmirx_disable(dev); -+} -+ -+static int hdmirx_resume(struct device *dev) -+{ -+ int ret = hdmirx_enable(dev); -+ -+ if (ret) -+ return ret; -+ -+ hdmirx_enable_irq(dev); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops snps_hdmirx_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(hdmirx_suspend, hdmirx_resume) -+}; -+ -+static int hdmirx_setup_irq(struct snps_hdmirx_dev *hdmirx_dev, -+ struct platform_device *pdev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ int ret, irq; -+ -+ irq = platform_get_irq_byname(pdev, "hdmi"); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get hdmi irq\n"); -+ return irq; -+ } -+ -+ irq_set_status_flags(irq, IRQ_NOAUTOEN); -+ -+ hdmirx_dev->hdmi_irq = irq; -+ ret = devm_request_irq(dev, irq, hdmirx_hdmi_irq_handler, 0, -+ "rk_hdmirx-hdmi", hdmirx_dev); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to request hdmi irq\n"); -+ return ret; -+ } -+ -+ irq = platform_get_irq_byname(pdev, "dma"); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get dma irq\n"); -+ return irq; -+ } -+ -+ irq_set_status_flags(irq, IRQ_NOAUTOEN); -+ -+ hdmirx_dev->dma_irq = irq; -+ ret = devm_request_threaded_irq(dev, irq, NULL, hdmirx_dma_irq_handler, -+ IRQF_ONESHOT, "rk_hdmirx-dma", -+ hdmirx_dev); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to request dma irq\n"); -+ return ret; -+ } -+ -+ irq = gpiod_to_irq(hdmirx_dev->detect_5v_gpio); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get hdmirx-5v irq\n"); -+ return irq; -+ } -+ -+ irq_set_status_flags(irq, IRQ_NOAUTOEN); -+ -+ hdmirx_dev->det_irq = irq; -+ ret = devm_request_irq(dev, irq, hdmirx_5v_det_irq_handler, -+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, -+ "rk_hdmirx-5v", hdmirx_dev); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to request hdmirx-5v irq\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int hdmirx_register_cec(struct snps_hdmirx_dev *hdmirx_dev, -+ struct platform_device *pdev) -+{ -+ struct device *dev = hdmirx_dev->dev; -+ struct hdmirx_cec_data cec_data; -+ int irq; -+ -+ irq = platform_get_irq_byname(pdev, "cec"); -+ if (irq < 0) { -+ dev_err_probe(dev, irq, "failed to get cec irq\n"); -+ return irq; -+ } -+ -+ hdmirx_dev->cec_notifier = cec_notifier_conn_register(dev, NULL, NULL); -+ if (!hdmirx_dev->cec_notifier) -+ return -EINVAL; -+ -+ cec_data.hdmirx = hdmirx_dev; -+ cec_data.dev = hdmirx_dev->dev; -+ cec_data.ops = &hdmirx_cec_ops; -+ cec_data.irq = irq; -+ -+ hdmirx_dev->cec = snps_hdmirx_cec_register(&cec_data); -+ if (!hdmirx_dev->cec) { -+ cec_notifier_conn_unregister(hdmirx_dev->cec_notifier); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int hdmirx_probe(struct platform_device *pdev) -+{ -+ struct snps_hdmirx_dev *hdmirx_dev; -+ struct device *dev = &pdev->dev; -+ struct v4l2_ctrl_handler *hdl; -+ struct hdmirx_stream *stream; -+ struct v4l2_device *v4l2_dev; -+ int ret; -+ -+ hdmirx_dev = devm_kzalloc(dev, sizeof(*hdmirx_dev), GFP_KERNEL); -+ if (!hdmirx_dev) -+ return -ENOMEM; -+ -+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); -+ if (ret) -+ return ret; -+ -+ hdmirx_dev->dev = dev; -+ dev_set_drvdata(dev, hdmirx_dev); -+ -+ ret = hdmirx_parse_dt(hdmirx_dev); -+ if (ret) -+ return ret; -+ -+ ret = hdmirx_setup_irq(hdmirx_dev, pdev); -+ if (ret) -+ return ret; -+ -+ hdmirx_dev->regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(hdmirx_dev->regs)) -+ return dev_err_probe(dev, PTR_ERR(hdmirx_dev->regs), -+ "failed to remap regs resource\n"); -+ -+ mutex_init(&hdmirx_dev->stream_lock); -+ mutex_init(&hdmirx_dev->work_lock); -+ spin_lock_init(&hdmirx_dev->rst_lock); -+ -+ init_completion(&hdmirx_dev->cr_write_done); -+ init_completion(&hdmirx_dev->timer_base_lock); -+ init_completion(&hdmirx_dev->avi_pkt_rcv); -+ -+ INIT_WORK(&hdmirx_dev->work_wdt_config, hdmirx_work_wdt_config); -+ INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_hotplug, -+ hdmirx_delayed_work_hotplug); -+ INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_res_change, -+ hdmirx_delayed_work_res_change); -+ INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_heartbeat, -+ hdmirx_delayed_work_heartbeat); -+ -+ hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; -+ hdmirx_dev->timings = cea640x480; -+ -+ hdmirx_enable(dev); -+ hdmirx_init(hdmirx_dev); -+ -+ v4l2_dev = &hdmirx_dev->v4l2_dev; -+ strscpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name)); -+ -+ hdl = &hdmirx_dev->hdl; -+ v4l2_ctrl_handler_init(hdl, 1); -+ -+ hdmirx_dev->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, -+ V4L2_CID_DV_RX_POWER_PRESENT, -+ 0, 1, 0, 0); -+ -+ hdmirx_dev->rgb_range = v4l2_ctrl_new_std_menu(hdl, 0, -+ V4L2_CID_DV_RX_RGB_RANGE, -+ V4L2_DV_RGB_RANGE_FULL, 0, -+ V4L2_DV_RGB_RANGE_AUTO); -+ -+ hdmirx_dev->rgb_range->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ -+ if (hdl->error) { -+ dev_err(dev, "v4l2 ctrl handler init failed\n"); -+ ret = hdl->error; -+ goto err_pm; -+ } -+ hdmirx_dev->v4l2_dev.ctrl_handler = hdl; -+ -+ ret = v4l2_device_register(dev, &hdmirx_dev->v4l2_dev); -+ if (ret < 0) { -+ dev_err(dev, "register v4l2 device failed\n"); -+ goto err_hdl; -+ } -+ -+ stream = &hdmirx_dev->stream; -+ stream->hdmirx_dev = hdmirx_dev; -+ ret = hdmirx_register_stream_vdev(stream); -+ if (ret < 0) { -+ dev_err(dev, "register video device failed\n"); -+ goto err_unreg_v4l2_dev; -+ } -+ -+ ret = hdmirx_register_cec(hdmirx_dev, pdev); -+ if (ret) -+ goto err_unreg_video_dev; -+ -+ hdmirx_load_default_edid(hdmirx_dev); -+ -+ hdmirx_enable_irq(dev); -+ -+ return 0; -+ -+err_unreg_video_dev: -+ video_unregister_device(&hdmirx_dev->stream.vdev); -+err_unreg_v4l2_dev: -+ v4l2_device_unregister(&hdmirx_dev->v4l2_dev); -+err_hdl: -+ v4l2_ctrl_handler_free(&hdmirx_dev->hdl); -+err_pm: -+ hdmirx_disable(dev); -+ -+ return ret; -+} -+ -+static void hdmirx_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); -+ -+ snps_hdmirx_cec_unregister(hdmirx_dev->cec); -+ cec_notifier_conn_unregister(hdmirx_dev->cec_notifier); -+ -+ hdmirx_disable_irq(dev); -+ -+ video_unregister_device(&hdmirx_dev->stream.vdev); -+ v4l2_ctrl_handler_free(&hdmirx_dev->hdl); -+ v4l2_device_unregister(&hdmirx_dev->v4l2_dev); -+ -+ hdmirx_disable(dev); -+ -+ reset_control_bulk_assert(HDMIRX_NUM_RST, hdmirx_dev->resets); -+ -+ of_reserved_mem_device_release(dev); -+} -+ -+static const struct of_device_id hdmirx_id[] = { -+ { .compatible = "rockchip,rk3588-hdmirx-ctrler" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, hdmirx_id); -+ -+static struct platform_driver hdmirx_driver = { -+ .probe = hdmirx_probe, -+ .remove = hdmirx_remove, -+ .driver = { -+ .name = "snps_hdmirx", -+ .of_match_table = hdmirx_id, -+ .pm = &snps_hdmirx_pm_ops, -+ } -+}; -+module_platform_driver(hdmirx_driver); -+ -+MODULE_DESCRIPTION("Rockchip HDMI Receiver Driver"); -+MODULE_AUTHOR("Dingxian Wen "); -+MODULE_AUTHOR("Shreeya Patel "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h -@@ -0,0 +1,394 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * -+ * Author: Dingxian Wen -+ */ -+ -+#ifndef DW_HDMIRX_H -+#define DW_HDMIRX_H -+ -+#include -+ -+#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) -+#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16)) -+ -+/* SYS_GRF */ -+#define SYS_GRF_SOC_CON1 0x0304 -+#define HDMIRXPHY_SRAM_EXT_LD_DONE BIT(1) -+#define HDMIRXPHY_SRAM_BYPASS BIT(0) -+#define SYS_GRF_SOC_STATUS1 0x0384 -+#define HDMIRXPHY_SRAM_INIT_DONE BIT(10) -+#define SYS_GRF_CHIP_ID 0x0600 -+ -+/* VO1_GRF */ -+#define VO1_GRF_VO1_CON2 0x0008 -+#define HDMIRX_SDAIN_MSK BIT(2) -+#define HDMIRX_SCLIN_MSK BIT(1) -+ -+/* HDMIRX PHY */ -+#define SUP_DIG_ANA_CREGS_SUP_ANA_NC 0x004f -+ -+#define LANE0_DIG_ASIC_RX_OVRD_OUT_0 0x100f -+#define LANE1_DIG_ASIC_RX_OVRD_OUT_0 0x110f -+#define LANE2_DIG_ASIC_RX_OVRD_OUT_0 0x120f -+#define LANE3_DIG_ASIC_RX_OVRD_OUT_0 0x130f -+#define ASIC_ACK_OVRD_EN BIT(1) -+#define ASIC_ACK BIT(0) -+ -+#define LANE0_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x104a -+#define LANE1_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x114a -+#define LANE2_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x124a -+#define LANE3_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x134a -+#define FREQ_TUNE_START_VAL_MASK GENMASK(9, 0) -+#define FREQ_TUNE_START_VAL(x) UPDATE(x, 9, 0) -+ -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_FSM_CONFIG 0x20c4 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_ADAPT_REF_FOM 0x20c7 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG 0x20e9 -+#define CDR_SETTING_BOUNDARY_3_DEFAULT 0x52da -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG 0x20ea -+#define CDR_SETTING_BOUNDARY_4_DEFAULT 0x43cd -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG 0x20eb -+#define CDR_SETTING_BOUNDARY_5_DEFAULT 0x35b3 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG 0x20fb -+#define CDR_SETTING_BOUNDARY_6_DEFAULT 0x2799 -+#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG 0x20fc -+#define CDR_SETTING_BOUNDARY_7_DEFAULT 0x1b65 -+ -+#define RAWLANE0_DIG_PCS_XF_RX_OVRD_OUT 0x300e -+#define RAWLANE1_DIG_PCS_XF_RX_OVRD_OUT 0x310e -+#define RAWLANE2_DIG_PCS_XF_RX_OVRD_OUT 0x320e -+#define RAWLANE3_DIG_PCS_XF_RX_OVRD_OUT 0x330e -+#define PCS_ACK_WRITE_SELECT BIT(14) -+#define PCS_EN_CTL BIT(1) -+#define PCS_ACK BIT(0) -+ -+#define RAWLANE0_DIG_AON_FAST_FLAGS 0x305c -+#define RAWLANE1_DIG_AON_FAST_FLAGS 0x315c -+#define RAWLANE2_DIG_AON_FAST_FLAGS 0x325c -+#define RAWLANE3_DIG_AON_FAST_FLAGS 0x335c -+ -+/* HDMIRX Ctrler */ -+#define GLOBAL_SWRESET_REQUEST 0x0020 -+#define DATAPATH_SWRESETREQ BIT(12) -+#define GLOBAL_SWENABLE 0x0024 -+#define PHYCTRL_ENABLE BIT(21) -+#define CEC_ENABLE BIT(16) -+#define TMDS_ENABLE BIT(13) -+#define DATAPATH_ENABLE BIT(12) -+#define PKTFIFO_ENABLE BIT(11) -+#define AVPUNIT_ENABLE BIT(8) -+#define MAIN_ENABLE BIT(0) -+#define GLOBAL_TIMER_REF_BASE 0x0028 -+#define CORE_CONFIG 0x0050 -+#define CMU_CONFIG0 0x0060 -+#define TMDSQPCLK_STABLE_FREQ_MARGIN_MASK GENMASK(30, 16) -+#define TMDSQPCLK_STABLE_FREQ_MARGIN(x) UPDATE(x, 30, 16) -+#define AUDCLK_STABLE_FREQ_MARGIN_MASK GENMASK(11, 9) -+#define AUDCLK_STABLE_FREQ_MARGIN(x) UPDATE(x, 11, 9) -+#define CMU_STATUS 0x007c -+#define TMDSQPCLK_LOCKED_ST BIT(4) -+#define CMU_TMDSQPCLK_FREQ 0x0084 -+#define PHY_CONFIG 0x00c0 -+#define LDO_AFE_PROG_MASK GENMASK(24, 23) -+#define LDO_AFE_PROG(x) UPDATE(x, 24, 23) -+#define LDO_PWRDN BIT(21) -+#define TMDS_CLOCK_RATIO BIT(16) -+#define RXDATA_WIDTH BIT(15) -+#define REFFREQ_SEL_MASK GENMASK(11, 9) -+#define REFFREQ_SEL(x) UPDATE(x, 11, 9) -+#define HDMI_DISABLE BIT(8) -+#define PHY_PDDQ BIT(1) -+#define PHY_RESET BIT(0) -+#define PHY_STATUS 0x00c8 -+#define HDMI_DISABLE_ACK BIT(1) -+#define PDDQ_ACK BIT(0) -+#define PHYCREG_CONFIG0 0x00e0 -+#define PHYCREG_CR_PARA_SELECTION_MODE_MASK GENMASK(1, 0) -+#define PHYCREG_CR_PARA_SELECTION_MODE(x) UPDATE(x, 1, 0) -+#define PHYCREG_CONFIG1 0x00e4 -+#define PHYCREG_CONFIG2 0x00e8 -+#define PHYCREG_CONFIG3 0x00ec -+#define PHYCREG_CONTROL 0x00f0 -+#define PHYCREG_CR_PARA_WRITE_P BIT(1) -+#define PHYCREG_CR_PARA_READ_P BIT(0) -+#define PHYCREG_STATUS 0x00f4 -+ -+#define MAINUNIT_STATUS 0x0150 -+#define TMDSVALID_STABLE_ST BIT(1) -+#define DESCRAND_EN_CONTROL 0x0210 -+#define SCRAMB_EN_SEL_QST_MASK GENMASK(1, 0) -+#define SCRAMB_EN_SEL_QST(x) UPDATE(x, 1, 0) -+#define DESCRAND_SYNC_CONTROL 0x0214 -+#define RECOVER_UNSYNC_STREAM_QST BIT(0) -+#define DESCRAND_SYNC_SEQ_CONFIG 0x022c -+#define DESCRAND_SYNC_SEQ_ERR_CNT_EN BIT(0) -+#define DESCRAND_SYNC_SEQ_STATUS 0x0234 -+#define DEFRAMER_CONFIG0 0x0270 -+#define VS_CNT_THR_QST_MASK GENMASK(27, 20) -+#define VS_CNT_THR_QST(x) UPDATE(x, 27, 20) -+#define HS_POL_QST_MASK GENMASK(19, 18) -+#define HS_POL_QST(x) UPDATE(x, 19, 18) -+#define VS_POL_QST_MASK GENMASK(17, 16) -+#define VS_POL_QST(x) UPDATE(x, 17, 16) -+#define VS_REMAPFILTER_EN_QST BIT(8) -+#define VS_FILTER_ORDER_QST_MASK GENMASK(1, 0) -+#define VS_FILTER_ORDER_QST(x) UPDATE(x, 1, 0) -+#define DEFRAMER_VSYNC_CNT_CLEAR 0x0278 -+#define VSYNC_CNT_CLR_P BIT(0) -+#define DEFRAMER_STATUS 0x027c -+#define OPMODE_STS_MASK GENMASK(6, 4) -+#define I2C_SLAVE_CONFIG1 0x0164 -+#define I2C_SDA_OUT_HOLD_VALUE_QST_MASK GENMASK(15, 8) -+#define I2C_SDA_OUT_HOLD_VALUE_QST(x) UPDATE(x, 15, 8) -+#define I2C_SDA_IN_HOLD_VALUE_QST_MASK GENMASK(7, 0) -+#define I2C_SDA_IN_HOLD_VALUE_QST(x) UPDATE(x, 7, 0) -+#define OPMODE_STS_MASK GENMASK(6, 4) -+#define REPEATER_QST BIT(28) -+#define FASTREAUTH_QST BIT(27) -+#define FEATURES_1DOT1_QST BIT(26) -+#define FASTI2C_QST BIT(25) -+#define EESS_CTL_THR_QST_MASK GENMASK(19, 16) -+#define EESS_CTL_THR_QST(x) UPDATE(x, 19, 16) -+#define OESS_CTL3_THR_QST_MASK GENMASK(11, 8) -+#define OESS_CTL3_THR_QST(x) UPDATE(x, 11, 8) -+#define EESS_OESS_SEL_QST_MASK GENMASK(5, 4) -+#define EESS_OESS_SEL_QST(x) UPDATE(x, 5, 4) -+#define KEY_DECRYPT_EN_QST BIT(0) -+#define KEY_DECRYPT_SEED_QST_MASK GENMASK(15, 0) -+#define KEY_DECRYPT_SEED_QST(x) UPDATE(x, 15, 0) -+#define HDCP_INT_CLEAR 0x50d8 -+#define HDCP_1_INT_CLEAR 0x50e8 -+#define HDCP2_CONFIG 0x02f0 -+#define HDCP2_SWITCH_OVR_VALUE BIT(2) -+#define HDCP2_SWITCH_OVR_EN BIT(1) -+ -+#define VIDEO_CONFIG2 0x042c -+#define VPROC_VSYNC_POL_OVR_VALUE BIT(19) -+#define VPROC_VSYNC_POL_OVR_EN BIT(18) -+#define VPROC_HSYNC_POL_OVR_VALUE BIT(17) -+#define VPROC_HSYNC_POL_OVR_EN BIT(16) -+#define VPROC_FMT_OVR_VALUE_MASK GENMASK(6, 4) -+#define VPROC_FMT_OVR_VALUE(x) UPDATE(x, 6, 4) -+#define VPROC_FMT_OVR_EN BIT(0) -+ -+#define AFIFO_FILL_RESTART BIT(0) -+#define AFIFO_INIT_P BIT(0) -+#define AFIFO_THR_LOW_QST_MASK GENMASK(25, 16) -+#define AFIFO_THR_LOW_QST(x) UPDATE(x, 25, 16) -+#define AFIFO_THR_HIGH_QST_MASK GENMASK(9, 0) -+#define AFIFO_THR_HIGH_QST(x) UPDATE(x, 9, 0) -+#define AFIFO_THR_MUTE_LOW_QST_MASK GENMASK(25, 16) -+#define AFIFO_THR_MUTE_LOW_QST(x) UPDATE(x, 25, 16) -+#define AFIFO_THR_MUTE_HIGH_QST_MASK GENMASK(9, 0) -+#define AFIFO_THR_MUTE_HIGH_QST(x) UPDATE(x, 9, 0) -+ -+#define AFIFO_UNDERFLOW_ST BIT(25) -+#define AFIFO_OVERFLOW_ST BIT(24) -+ -+#define SPEAKER_ALLOC_OVR_EN BIT(16) -+#define I2S_BPCUV_EN BIT(4) -+#define SPDIF_EN BIT(2) -+#define I2S_EN BIT(1) -+#define AFIFO_THR_PASS_DEMUTEMASK_N BIT(24) -+#define AVMUTE_DEMUTEMASK_N BIT(16) -+#define AFIFO_THR_MUTE_LOW_MUTEMASK_N BIT(9) -+#define AFIFO_THR_MUTE_HIGH_MUTEMASK_N BIT(8) -+#define AVMUTE_MUTEMASK_N BIT(0) -+#define SCDC_CONFIG 0x0580 -+#define HPDLOW BIT(1) -+#define POWERPROVIDED BIT(0) -+#define SCDC_REGBANK_STATUS1 0x058c -+#define SCDC_TMDSBITCLKRATIO BIT(1) -+#define SCDC_REGBANK_STATUS3 0x0594 -+#define SCDC_REGBANK_CONFIG0 0x05c0 -+#define SCDC_SINKVERSION_QST_MASK GENMASK(7, 0) -+#define SCDC_SINKVERSION_QST(x) UPDATE(x, 7, 0) -+#define AGEN_LAYOUT BIT(4) -+#define AGEN_SPEAKER_ALLOC GENMASK(15, 8) -+ -+#define CED_CONFIG 0x0760 -+#define CED_VIDDATACHECKEN_QST BIT(27) -+#define CED_DATAISCHECKEN_QST BIT(26) -+#define CED_GBCHECKEN_QST BIT(25) -+#define CED_CTRLCHECKEN_QST BIT(24) -+#define CED_CHLOCKMAXER_QST_MASK GENMASK(14, 0) -+#define CED_CHLOCKMAXER_QST(x) UPDATE(x, 14, 0) -+#define CED_DYN_CONFIG 0x0768 -+#define CED_DYN_CONTROL 0x076c -+#define PKTEX_BCH_ERRFILT_CONFIG 0x07c4 -+#define PKTEX_CHKSUM_ERRFILT_CONFIG 0x07c8 -+ -+#define PKTDEC_ACR_PH2_1 0x1100 -+#define PKTDEC_ACR_PB3_0 0x1104 -+#define PKTDEC_ACR_PB7_4 0x1108 -+#define PKTDEC_AVIIF_PH2_1 0x1200 -+#define PKTDEC_AVIIF_PB3_0 0x1204 -+#define PKTDEC_AVIIF_PB7_4 0x1208 -+#define VIC_VAL_MASK GENMASK(6, 0) -+#define PKTDEC_AVIIF_PB11_8 0x120c -+#define PKTDEC_AVIIF_PB15_12 0x1210 -+#define PKTDEC_AVIIF_PB19_16 0x1214 -+#define PKTDEC_AVIIF_PB23_20 0x1218 -+#define PKTDEC_AVIIF_PB27_24 0x121c -+ -+#define PKTFIFO_CONFIG 0x1500 -+#define PKTFIFO_STORE_FILT_CONFIG 0x1504 -+#define PKTFIFO_THR_CONFIG0 0x1508 -+#define PKTFIFO_THR_CONFIG1 0x150c -+#define PKTFIFO_CONTROL 0x1510 -+ -+#define VMON_STATUS1 0x1580 -+#define VMON_STATUS2 0x1584 -+#define VMON_STATUS3 0x1588 -+#define VMON_STATUS4 0x158c -+#define VMON_STATUS5 0x1590 -+#define VMON_STATUS6 0x1594 -+#define VMON_STATUS7 0x1598 -+#define VMON_ILACE_DETECT BIT(4) -+ -+#define CEC_TX_CONTROL 0x2000 -+#define CEC_STATUS 0x2004 -+#define CEC_CONFIG 0x2008 -+#define RX_AUTO_DRIVE_ACKNOWLEDGE BIT(9) -+#define CEC_ADDR 0x200c -+#define CEC_TX_COUNT 0x2020 -+#define CEC_TX_DATA3_0 0x2024 -+#define CEC_RX_COUNT_STATUS 0x2040 -+#define CEC_RX_DATA3_0 0x2044 -+#define CEC_LOCK_CONTROL 0x2054 -+#define CEC_RXQUAL_BITTIME_CONFIG 0x2060 -+#define CEC_RX_BITTIME_CONFIG 0x2064 -+#define CEC_TX_BITTIME_CONFIG 0x2068 -+ -+#define DMA_CONFIG1 0x4400 -+#define UV_WID_MASK GENMASK(31, 28) -+#define UV_WID(x) UPDATE(x, 31, 28) -+#define Y_WID_MASK GENMASK(27, 24) -+#define Y_WID(x) UPDATE(x, 27, 24) -+#define DDR_STORE_FORMAT_MASK GENMASK(15, 12) -+#define DDR_STORE_FORMAT(x) UPDATE(x, 15, 12) -+#define ABANDON_EN BIT(0) -+#define DMA_CONFIG2 0x4404 -+#define DMA_CONFIG3 0x4408 -+#define DMA_CONFIG4 0x440c // dma irq en -+#define DMA_CONFIG5 0x4410 // dma irq clear status -+#define LINE_FLAG_INT_EN BIT(8) -+#define HDMIRX_DMA_IDLE_INT BIT(7) -+#define HDMIRX_LOCK_DISABLE_INT BIT(6) -+#define LAST_FRAME_AXI_UNFINISH_INT_EN BIT(5) -+#define FIFO_OVERFLOW_INT_EN BIT(2) -+#define FIFO_UNDERFLOW_INT_EN BIT(1) -+#define HDMIRX_AXI_ERROR_INT_EN BIT(0) -+#define DMA_CONFIG6 0x4414 -+#define RB_SWAP_EN BIT(9) -+#define HSYNC_TOGGLE_EN BIT(5) -+#define VSYNC_TOGGLE_EN BIT(4) -+#define HDMIRX_DMA_EN BIT(1) -+#define DMA_CONFIG7 0x4418 -+#define LINE_FLAG_NUM_MASK GENMASK(31, 16) -+#define LINE_FLAG_NUM(x) UPDATE(x, 31, 16) -+#define LOCK_FRAME_NUM_MASK GENMASK(11, 0) -+#define LOCK_FRAME_NUM(x) UPDATE(x, 11, 0) -+#define DMA_CONFIG8 0x441c -+#define REG_MIRROR_EN BIT(0) -+#define DMA_CONFIG9 0x4420 -+#define DMA_CONFIG10 0x4424 -+#define DMA_CONFIG11 0x4428 -+#define EDID_READ_EN_MASK BIT(8) -+#define EDID_READ_EN(x) UPDATE(x, 8, 8) -+#define EDID_WRITE_EN_MASK BIT(7) -+#define EDID_WRITE_EN(x) UPDATE(x, 7, 7) -+#define EDID_SLAVE_ADDR_MASK GENMASK(6, 0) -+#define EDID_SLAVE_ADDR(x) UPDATE(x, 6, 0) -+#define DMA_STATUS1 0x4430 // dma irq status -+#define DMA_STATUS2 0x4434 -+#define DMA_STATUS3 0x4438 -+#define DMA_STATUS4 0x443c -+#define DMA_STATUS5 0x4440 -+#define DMA_STATUS6 0x4444 -+#define DMA_STATUS7 0x4448 -+#define DMA_STATUS8 0x444c -+#define DMA_STATUS9 0x4450 -+#define DMA_STATUS10 0x4454 -+#define HDMIRX_LOCK BIT(3) -+#define DMA_STATUS11 0x4458 -+#define HDMIRX_TYPE_MASK GENMASK(8, 7) -+#define HDMIRX_COLOR_DEPTH_MASK GENMASK(6, 3) -+#define HDMIRX_FORMAT_MASK GENMASK(2, 0) -+#define DMA_STATUS12 0x445c -+#define DMA_STATUS13 0x4460 -+#define DMA_STATUS14 0x4464 -+ -+#define MAINUNIT_INTVEC_INDEX 0x5000 -+#define MAINUNIT_0_INT_STATUS 0x5010 -+#define CECRX_NOTIFY_ERR BIT(12) -+#define CECRX_EOM BIT(11) -+#define CECTX_DRIVE_ERR BIT(10) -+#define CECRX_BUSY BIT(9) -+#define CECTX_BUSY BIT(8) -+#define CECTX_FRAME_DISCARDED BIT(5) -+#define CECTX_NRETRANSMIT_FAIL BIT(4) -+#define CECTX_LINE_ERR BIT(3) -+#define CECTX_ARBLOST BIT(2) -+#define CECTX_NACK BIT(1) -+#define CECTX_DONE BIT(0) -+#define MAINUNIT_0_INT_MASK_N 0x5014 -+#define MAINUNIT_0_INT_CLEAR 0x5018 -+#define MAINUNIT_0_INT_FORCE 0x501c -+#define TIMER_BASE_LOCKED_IRQ BIT(26) -+#define TMDSQPCLK_OFF_CHG BIT(5) -+#define TMDSQPCLK_LOCKED_CHG BIT(4) -+#define MAINUNIT_1_INT_STATUS 0x5020 -+#define MAINUNIT_1_INT_MASK_N 0x5024 -+#define MAINUNIT_1_INT_CLEAR 0x5028 -+#define MAINUNIT_1_INT_FORCE 0x502c -+#define MAINUNIT_2_INT_STATUS 0x5030 -+#define MAINUNIT_2_INT_MASK_N 0x5034 -+#define MAINUNIT_2_INT_CLEAR 0x5038 -+#define MAINUNIT_2_INT_FORCE 0x503c -+#define PHYCREG_CR_READ_DONE BIT(11) -+#define PHYCREG_CR_WRITE_DONE BIT(10) -+#define TMDSVALID_STABLE_CHG BIT(1) -+ -+#define AVPUNIT_0_INT_STATUS 0x5040 -+#define AVPUNIT_0_INT_MASK_N 0x5044 -+#define AVPUNIT_0_INT_CLEAR 0x5048 -+#define AVPUNIT_0_INT_FORCE 0x504c -+#define CED_DYN_CNT_CH2_IRQ BIT(22) -+#define CED_DYN_CNT_CH1_IRQ BIT(21) -+#define CED_DYN_CNT_CH0_IRQ BIT(20) -+#define AVPUNIT_1_INT_STATUS 0x5050 -+#define DEFRAMER_VSYNC_THR_REACHED_IRQ BIT(1) -+#define AVPUNIT_1_INT_MASK_N 0x5054 -+#define DEFRAMER_VSYNC_THR_REACHED_MASK_N BIT(1) -+#define DEFRAMER_VSYNC_MASK_N BIT(0) -+#define AVPUNIT_1_INT_CLEAR 0x5058 -+#define DEFRAMER_VSYNC_THR_REACHED_CLEAR BIT(1) -+#define PKT_0_INT_STATUS 0x5080 -+#define PKTDEC_ACR_CHG_IRQ BIT(3) -+#define PKT_0_INT_MASK_N 0x5084 -+#define PKTDEC_ACR_CHG_MASK_N BIT(3) -+#define PKT_0_INT_CLEAR 0x5088 -+#define PKT_1_INT_STATUS 0x5090 -+#define PKT_1_INT_MASK_N 0x5094 -+#define PKT_1_INT_CLEAR 0x5098 -+#define PKT_2_INT_STATUS 0x50a0 -+#define PKTDEC_ACR_RCV_IRQ BIT(3) -+#define PKT_2_INT_MASK_N 0x50a4 -+#define PKTDEC_AVIIF_RCV_IRQ BIT(11) -+#define PKTDEC_ACR_RCV_MASK_N BIT(3) -+#define PKT_2_INT_CLEAR 0x50a8 -+#define PKTDEC_AVIIF_RCV_CLEAR BIT(11) -+#define PKTDEC_ACR_RCV_CLEAR BIT(3) -+#define SCDC_INT_STATUS 0x50c0 -+#define SCDC_INT_MASK_N 0x50c4 -+#define SCDC_INT_CLEAR 0x50c8 -+#define SCDCTMDSCCFG_CHG BIT(2) -+ -+#define CEC_INT_STATUS 0x5100 -+#define CEC_INT_MASK_N 0x5104 -+#define CEC_INT_CLEAR 0x5108 -+ -+#endif -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c -@@ -0,0 +1,285 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * -+ * Author: Shunqing Chen -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "snps_hdmirx.h" -+#include "snps_hdmirx_cec.h" -+ -+static void hdmirx_cec_write(struct hdmirx_cec *cec, int reg, u32 val) -+{ -+ cec->ops->write(cec->hdmirx, reg, val); -+} -+ -+static u32 hdmirx_cec_read(struct hdmirx_cec *cec, int reg) -+{ -+ return cec->ops->read(cec->hdmirx, reg); -+} -+ -+static void hdmirx_cec_update_bits(struct hdmirx_cec *cec, int reg, u32 mask, -+ u32 data) -+{ -+ u32 val = hdmirx_cec_read(cec, reg) & ~mask; -+ -+ val |= (data & mask); -+ hdmirx_cec_write(cec, reg, val); -+} -+ -+static int hdmirx_cec_log_addr(struct cec_adapter *adap, u8 logical_addr) -+{ -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ -+ if (logical_addr == CEC_LOG_ADDR_INVALID) -+ cec->addresses = 0; -+ else -+ cec->addresses |= BIT(logical_addr) | BIT(15); -+ -+ hdmirx_cec_write(cec, CEC_ADDR, cec->addresses); -+ -+ return 0; -+} -+ -+/* signal_free_time is handled by the Synopsys Designware -+ * HDMIRX Controller hardware. -+ */ -+static int hdmirx_cec_transmit(struct cec_adapter *adap, u8 attempts, -+ u32 signal_free_time, struct cec_msg *msg) -+{ -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ u32 data[4] = {0}; -+ int i, data_len, msg_len; -+ -+ msg_len = msg->len; -+ -+ hdmirx_cec_write(cec, CEC_TX_COUNT, msg_len - 1); -+ for (i = 0; i < msg_len; i++) -+ data[i / 4] |= msg->msg[i] << (i % 4) * 8; -+ -+ data_len = DIV_ROUND_UP(msg_len, 4); -+ -+ for (i = 0; i < data_len; i++) -+ hdmirx_cec_write(cec, CEC_TX_DATA3_0 + i * 4, data[i]); -+ -+ hdmirx_cec_write(cec, CEC_TX_CONTROL, 0x1); -+ -+ return 0; -+} -+ -+static irqreturn_t hdmirx_cec_hardirq(int irq, void *data) -+{ -+ struct cec_adapter *adap = data; -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ u32 stat = hdmirx_cec_read(cec, CEC_INT_STATUS); -+ irqreturn_t ret = IRQ_HANDLED; -+ u32 val; -+ -+ if (!stat) -+ return IRQ_NONE; -+ -+ hdmirx_cec_write(cec, CEC_INT_CLEAR, stat); -+ -+ if (stat & CECTX_LINE_ERR) { -+ cec->tx_status = CEC_TX_STATUS_ERROR; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } else if (stat & CECTX_DONE) { -+ cec->tx_status = CEC_TX_STATUS_OK; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } else if (stat & CECTX_NACK) { -+ cec->tx_status = CEC_TX_STATUS_NACK; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } else if (stat & CECTX_ARBLOST) { -+ cec->tx_status = CEC_TX_STATUS_ARB_LOST; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; -+ } -+ -+ if (stat & CECRX_EOM) { -+ unsigned int len, i; -+ -+ val = hdmirx_cec_read(cec, CEC_RX_COUNT_STATUS); -+ /* rxbuffer locked status */ -+ if ((val & 0x80)) -+ return ret; -+ -+ len = (val & 0xf) + 1; -+ if (len > sizeof(cec->rx_msg.msg)) -+ len = sizeof(cec->rx_msg.msg); -+ -+ for (i = 0; i < len; i++) { -+ if (!(i % 4)) -+ val = hdmirx_cec_read(cec, CEC_RX_DATA3_0 + i / 4 * 4); -+ cec->rx_msg.msg[i] = (val >> ((i % 4) * 8)) & 0xff; -+ } -+ -+ cec->rx_msg.len = len; -+ smp_wmb(); /* receive RX msg */ -+ cec->rx_done = true; -+ hdmirx_cec_write(cec, CEC_LOCK_CONTROL, 0x1); -+ -+ ret = IRQ_WAKE_THREAD; -+ } -+ -+ return ret; -+} -+ -+static irqreturn_t hdmirx_cec_thread(int irq, void *data) -+{ -+ struct cec_adapter *adap = data; -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ -+ if (cec->tx_done) { -+ cec->tx_done = false; -+ cec_transmit_attempt_done(adap, cec->tx_status); -+ } -+ if (cec->rx_done) { -+ cec->rx_done = false; -+ smp_rmb(); /* RX msg has been received */ -+ cec_received_msg(adap, &cec->rx_msg); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int hdmirx_cec_enable(struct cec_adapter *adap, bool enable) -+{ -+ struct hdmirx_cec *cec = cec_get_drvdata(adap); -+ -+ if (!enable) { -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, 0); -+ hdmirx_cec_write(cec, CEC_INT_CLEAR, 0); -+ if (cec->ops->disable) -+ cec->ops->disable(cec->hdmirx); -+ } else { -+ unsigned int irqs; -+ -+ hdmirx_cec_log_addr(cec->adap, CEC_LOG_ADDR_INVALID); -+ if (cec->ops->enable) -+ cec->ops->enable(cec->hdmirx); -+ hdmirx_cec_update_bits(cec, GLOBAL_SWENABLE, CEC_ENABLE, CEC_ENABLE); -+ -+ irqs = CECTX_LINE_ERR | CECTX_NACK | CECRX_EOM | CECTX_DONE; -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, irqs); -+ } -+ -+ return 0; -+} -+ -+static const struct cec_adap_ops hdmirx_cec_ops = { -+ .adap_enable = hdmirx_cec_enable, -+ .adap_log_addr = hdmirx_cec_log_addr, -+ .adap_transmit = hdmirx_cec_transmit, -+}; -+ -+static void hdmirx_cec_del(void *data) -+{ -+ struct hdmirx_cec *cec = data; -+ -+ cec_delete_adapter(cec->adap); -+} -+ -+struct hdmirx_cec *snps_hdmirx_cec_register(struct hdmirx_cec_data *data) -+{ -+ struct hdmirx_cec *cec; -+ unsigned int irqs; -+ int ret; -+ -+ /* -+ * Our device is just a convenience - we want to link to the real -+ * hardware device here, so that userspace can see the association -+ * between the HDMI hardware and its associated CEC chardev. -+ */ -+ cec = devm_kzalloc(data->dev, sizeof(*cec), GFP_KERNEL); -+ if (!cec) -+ return NULL; -+ -+ cec->dev = data->dev; -+ cec->irq = data->irq; -+ cec->ops = data->ops; -+ cec->hdmirx = data->hdmirx; -+ -+ hdmirx_cec_update_bits(cec, GLOBAL_SWENABLE, CEC_ENABLE, CEC_ENABLE); -+ hdmirx_cec_update_bits(cec, CEC_CONFIG, RX_AUTO_DRIVE_ACKNOWLEDGE, -+ RX_AUTO_DRIVE_ACKNOWLEDGE); -+ -+ hdmirx_cec_write(cec, CEC_TX_COUNT, 0); -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, 0); -+ hdmirx_cec_write(cec, CEC_INT_CLEAR, ~0); -+ -+ cec->adap = cec_allocate_adapter(&hdmirx_cec_ops, cec, "snps-hdmirx", -+ CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | -+ CEC_CAP_RC | CEC_CAP_PASSTHROUGH | -+ CEC_CAP_MONITOR_ALL, -+ CEC_MAX_LOG_ADDRS); -+ if (IS_ERR(cec->adap)) { -+ dev_err(cec->dev, "cec adap allocate failed\n"); -+ return NULL; -+ } -+ -+ /* override the module pointer */ -+ cec->adap->owner = THIS_MODULE; -+ -+ ret = devm_add_action(cec->dev, hdmirx_cec_del, cec); -+ if (ret) { -+ cec_delete_adapter(cec->adap); -+ return NULL; -+ } -+ -+ irq_set_status_flags(cec->irq, IRQ_NOAUTOEN); -+ -+ ret = devm_request_threaded_irq(cec->dev, cec->irq, -+ hdmirx_cec_hardirq, -+ hdmirx_cec_thread, IRQF_ONESHOT, -+ "rk_hdmirx_cec", cec->adap); -+ if (ret) { -+ dev_err(cec->dev, "cec irq request failed\n"); -+ return NULL; -+ } -+ -+ cec->notify = cec_notifier_cec_adap_register(cec->dev, -+ NULL, cec->adap); -+ if (!cec->notify) { -+ dev_err(cec->dev, "cec notify register failed\n"); -+ return NULL; -+ } -+ -+ ret = cec_register_adapter(cec->adap, cec->dev); -+ if (ret < 0) { -+ dev_err(cec->dev, "cec register adapter failed\n"); -+ cec_unregister_adapter(cec->adap); -+ return NULL; -+ } -+ -+ irqs = CECTX_LINE_ERR | CECTX_NACK | CECRX_EOM | CECTX_DONE; -+ hdmirx_cec_write(cec, CEC_INT_MASK_N, irqs); -+ -+ /* -+ * CEC documentation says we must not call cec_delete_adapter -+ * after a successful call to cec_register_adapter(). -+ */ -+ devm_remove_action(cec->dev, hdmirx_cec_del, cec); -+ -+ enable_irq(cec->irq); -+ -+ return cec; -+} -+ -+void snps_hdmirx_cec_unregister(struct hdmirx_cec *cec) -+{ -+ disable_irq(cec->irq); -+ -+ cec_unregister_adapter(cec->adap); -+} -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h -new file mode 100644 -index 000000000000..111111111111 ---- /dev/null -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h -@@ -0,0 +1,44 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021 Rockchip Electronics Co. Ltd. -+ * -+ * Author: Shunqing Chen -+ */ -+ -+#ifndef DW_HDMI_RX_CEC_H -+#define DW_HDMI_RX_CEC_H -+ -+struct snps_hdmirx_dev; -+ -+struct hdmirx_cec_ops { -+ void (*write)(struct snps_hdmirx_dev *hdmirx_dev, int reg, u32 val); -+ u32 (*read)(struct snps_hdmirx_dev *hdmirx_dev, int reg); -+ void (*enable)(struct snps_hdmirx_dev *hdmirx); -+ void (*disable)(struct snps_hdmirx_dev *hdmirx); -+}; -+ -+struct hdmirx_cec_data { -+ struct snps_hdmirx_dev *hdmirx; -+ const struct hdmirx_cec_ops *ops; -+ struct device *dev; -+ int irq; -+}; -+ -+struct hdmirx_cec { -+ struct snps_hdmirx_dev *hdmirx; -+ struct device *dev; -+ const struct hdmirx_cec_ops *ops; -+ u32 addresses; -+ struct cec_adapter *adap; -+ struct cec_msg rx_msg; -+ unsigned int tx_status; -+ bool tx_done; -+ bool rx_done; -+ struct cec_notifier *notify; -+ int irq; -+}; -+ -+struct hdmirx_cec *snps_hdmirx_cec_register(struct hdmirx_cec_data *data); -+void snps_hdmirx_cec_unregister(struct hdmirx_cec *cec); -+ -+#endif /* DW_HDMI_RX_CEC_H */ --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Mon, 29 Jul 2024 17:29:46 +0200 -Subject: arm64: defconfig: Enable Synopsys HDMI receiver - -The Rockchip RK3588 has a built-in HDMI receiver block from -Synopsys. Let's enable the driver for it. - -Signed-off-by: Sebastian Reichel ---- - arch/arm64/configs/defconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 111111111111..222222222222 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -860,6 +860,7 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m - CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m - CONFIG_VIDEO_SAMSUNG_S5P_MFC=m - CONFIG_VIDEO_SUN6I_CSI=m -+CONFIG_VIDEO_SYNOPSYS_HDMIRX=m - CONFIG_VIDEO_TI_J721E_CSI2RX=m - CONFIG_VIDEO_HANTRO=m - CONFIG_VIDEO_IMX219=m --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Muhammed Efe Cetin -Date: Thu, 1 Aug 2024 16:47:35 +0300 -Subject: comment v4l2 error on hdmirx - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -1180,7 +1180,7 @@ static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) - break; - - if (!tx_5v_power_present(hdmirx_dev)) { -- v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); -+ //v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); - return -1; - } - --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Hoff -Date: Sun, 15 Sep 2024 14:52:17 -0400 -Subject: fix spurious triggering of irq 5v while plugout code is running - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 12 ++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -745,10 +745,17 @@ static void hdmirx_interrupts_setup(struct snps_hdmirx_dev *hdmirx_dev, bool en) - static void hdmirx_plugout(struct snps_hdmirx_dev *hdmirx_dev) - { - struct arm_smccc_res res; -+ int irq; - - hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 0); - hdmirx_interrupts_setup(hdmirx_dev, false); - hdmirx_hpd_ctrl(hdmirx_dev, false); -+ irq = gpiod_to_irq(hdmirx_dev->detect_5v_gpio); -+ -+ if (irq >= 0) { -+ disable_irq(irq); -+ } -+ - hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); - hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, - LINE_FLAG_INT_EN | -@@ -766,6 +773,11 @@ static void hdmirx_plugout(struct snps_hdmirx_dev *hdmirx_dev) - cancel_delayed_work_sync(&hdmirx_dev->delayed_work_heartbeat); - flush_work(&hdmirx_dev->work_wdt_config); - arm_smccc_smc(SIP_WDT_CFG, WDT_STOP, 0, 0, 0, 0, 0, 0, &res); -+ -+ hdmirx_hpd_ctrl(hdmirx_dev, true); -+ if (irq >= 0) { -+ enable_irq(irq); -+ } - } - - static int hdmirx_set_edid(struct file *file, void *fh, struct v4l2_edid *edid) --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Hoff -Date: Sun, 15 Sep 2024 14:53:25 -0400 -Subject: remove timing handling from plug in function - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -2202,13 +2202,6 @@ static void hdmirx_plugin(struct snps_hdmirx_dev *hdmirx_dev) - hdmirx_hpd_ctrl(hdmirx_dev, true); - hdmirx_phy_config(hdmirx_dev); - ret = hdmirx_wait_lock_and_get_timing(hdmirx_dev); -- if (ret) { -- hdmirx_plugout(hdmirx_dev); -- queue_delayed_work(system_unbound_wq, -- &hdmirx_dev->delayed_work_hotplug, -- msecs_to_jiffies(200)); -- return; -- } - hdmirx_dma_config(hdmirx_dev); - hdmirx_interrupts_setup(hdmirx_dev, true); - } --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Hoff -Date: Mon, 23 Sep 2024 09:43:38 -0400 -Subject: expose itc type to v4l2 in synopsys hdmir rx - ---- - drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 16 +++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -index 111111111111..222222222222 100644 ---- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c -@@ -151,6 +151,7 @@ struct snps_hdmirx_dev { - struct v4l2_ctrl_handler hdl; - struct v4l2_ctrl *detect_tx_5v_ctrl; - struct v4l2_ctrl *rgb_range; -+ struct v4l2_ctrl *content_type; - struct v4l2_dv_timings timings; - struct gpio_desc *detect_5v_gpio; - struct work_struct work_wdt_config; -@@ -512,6 +513,11 @@ static void hdmirx_get_avi_infoframe(struct snps_hdmirx_dev *hdmirx_dev) - } - - v4l2_ctrl_s_ctrl(hdmirx_dev->rgb_range, frame.avi.quantization_range); -+ if (frame.avi.itc) { -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, frame.avi.content_type); -+ } else { -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); -+ } - } - - /* -@@ -1192,6 +1198,7 @@ static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) - break; - - if (!tx_5v_power_present(hdmirx_dev)) { -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); - //v4l2_err(v4l2_dev, "%s: HDMI pull out, return\n", __func__); - return -1; - } -@@ -1204,6 +1211,7 @@ static int hdmirx_wait_lock_and_get_timing(struct snps_hdmirx_dev *hdmirx_dev) - __func__, hdmirx_dev->tmds_clk_ratio); - v4l2_err(v4l2_dev, "%s: mu_st:%#x, scdc_st:%#x, dma_st10:%#x\n", - __func__, mu_status, scdc_status, dma_st10); -+ v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); - return -1; - } - -@@ -2668,7 +2676,7 @@ static int hdmirx_probe(struct platform_device *pdev) - strscpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name)); - - hdl = &hdmirx_dev->hdl; -- v4l2_ctrl_handler_init(hdl, 1); -+ v4l2_ctrl_handler_init(hdl, 3); - - hdmirx_dev->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, - V4L2_CID_DV_RX_POWER_PRESENT, -@@ -2681,6 +2689,12 @@ static int hdmirx_probe(struct platform_device *pdev) - - hdmirx_dev->rgb_range->flags |= V4L2_CTRL_FLAG_READ_ONLY; - -+ hdmirx_dev->content_type = v4l2_ctrl_new_std_menu(hdl, NULL, -+ V4L2_CID_DV_RX_IT_CONTENT_TYPE, -+ V4L2_DV_IT_CONTENT_TYPE_NO_ITC, -+ 0, -+ V4L2_DV_IT_CONTENT_TYPE_NO_ITC); -+ - if (hdl->error) { - dev_err(dev, "v4l2 ctrl handler init failed\n"); - ret = hdl->error; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0130-add-hdmi1-support.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0130-add-hdmi1-support.patch deleted file mode 100644 index e137612d6c63..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0130-add-hdmi1-support.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 7 Dec 2024 21:45:12 +0200 -Subject: arm64: dts: rockchip: Add PHY node for HDMI1 TX port on RK3588 - -In preparation to enable the second HDMI output port found on RK3588 -SoC, add the related PHY node. This requires a GRF, hence add the -dependent node as well. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 21 ++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -90,6 +90,11 @@ u2phy1_otg: otg-port { - }; - }; - -+ hdptxphy1_grf: syscon@fd5e4000 { -+ compatible = "rockchip,rk3588-hdptxphy-grf", "syscon"; -+ reg = <0x0 0xfd5e4000 0x0 0x100>; -+ }; -+ - i2s8_8ch: i2s@fddc8000 { - compatible = "rockchip,rk3588-i2s-tdm"; - reg = <0x0 0xfddc8000 0x0 0x1000>; -@@ -454,6 +459,22 @@ sata-port@0 { - }; - }; - -+ hdptxphy1: phy@fed70000 { -+ compatible = "rockchip,rk3588-hdptx-phy"; -+ reg = <0x0 0xfed70000 0x0 0x2000>; -+ clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX1>; -+ clock-names = "ref", "apb"; -+ #phy-cells = <0>; -+ resets = <&cru SRST_HDPTX1>, <&cru SRST_P_HDPTX1>, -+ <&cru SRST_HDPTX1_INIT>, <&cru SRST_HDPTX1_CMN>, -+ <&cru SRST_HDPTX1_LANE>, <&cru SRST_HDPTX1_ROPLL>, -+ <&cru SRST_HDPTX1_LCPLL>; -+ reset-names = "phy", "apb", "init", "cmn", "lane", "ropll", -+ "lcpll"; -+ rockchip,grf = <&hdptxphy1_grf>; -+ status = "disabled"; -+ }; -+ - usbdp_phy1: phy@fed90000 { - compatible = "rockchip,rk3588-usbdp-phy"; - reg = <0x0 0xfed90000 0x0 0x10000>; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 7 Dec 2024 21:53:07 +0200 -Subject: arm64: dts: rockchip: Add HDMI1 node on RK3588 - -Add support for the second HDMI TX port found on RK3588 SoC. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 41 ++++++++++ - 1 file changed, 41 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -196,6 +196,47 @@ hdmi_receiver: hdmi_receiver@fdee0000 { - status = "disabled"; - }; - -+ hdmi1: hdmi@fdea0000 { -+ compatible = "rockchip,rk3588-dw-hdmi-qp"; -+ reg = <0x0 0xfdea0000 0x0 0x20000>; -+ clocks = <&cru PCLK_HDMITX1>, -+ <&cru CLK_HDMITX1_EARC>, -+ <&cru CLK_HDMITX1_REF>, -+ <&cru MCLK_I2S6_8CH_TX>, -+ <&cru CLK_HDMIHDP1>, -+ <&cru HCLK_VO1>; -+ clock-names = "pclk", "earc", "ref", "aud", "hdp", "hclk_vo1"; -+ interrupts = , -+ , -+ , -+ , -+ ; -+ interrupt-names = "avp", "cec", "earc", "main", "hpd"; -+ phys = <&hdptxphy1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&hdmim2_tx1_cec &hdmim0_tx1_hpd -+ &hdmim1_tx1_scl &hdmim1_tx1_sda>; -+ power-domains = <&power RK3588_PD_VO1>; -+ resets = <&cru SRST_HDMITX1_REF>, <&cru SRST_HDMIHDP1>; -+ reset-names = "ref", "hdp"; -+ rockchip,grf = <&sys_grf>; -+ rockchip,vo-grf = <&vo1_grf>; -+ status = "disabled"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ hdmi1_in: port@0 { -+ reg = <0>; -+ }; -+ -+ hdmi1_out: port@1 { -+ reg = <1>; -+ }; -+ }; -+ }; -+ - pcie3x4: pcie@fe150000 { - compatible = "rockchip,rk3588-pcie", "rockchip,rk3568-pcie"; - #address-cells = <3>; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0131-vop2-hdmi0-disp-modes-support.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0131-vop2-hdmi0-disp-modes-support.patch deleted file mode 100644 index c5f0cac41079..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0131-vop2-hdmi0-disp-modes-support.patch +++ /dev/null @@ -1,252 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 16 Nov 2024 03:19:43 +0200 -Subject: dt-bindings: display: vop2: Add optional PLL clock properties - -On RK3588, HDMI PHY PLL can be used as an alternative and more accurate -pixel clock source for VOP2 video ports 0, 1 and 2. - -Document the optional PLL clock properties corresponding to the two HDMI -PHYs available on the SoC. - -Signed-off-by: Cristian Ciocaltea ---- - Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -index 111111111111..222222222222 100644 ---- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -@@ -53,6 +53,8 @@ properties: - - description: Pixel clock for video port 2. - - description: Pixel clock for video port 3. - - description: Peripheral(vop grf/dsi) clock. -+ - description: Alternative pixel clock provided by HDMI0 PHY PLL. -+ - description: Alternative pixel clock provided by HDMI1 PHY PLL. - - clock-names: - minItems: 5 -@@ -64,6 +66,8 @@ properties: - - const: dclk_vp2 - - const: dclk_vp3 - - const: pclk_vop -+ - const: pll_hdmiphy0 -+ - const: pll_hdmiphy1 - - rockchip,grf: - $ref: /schemas/types.yaml#/definitions/phandle --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 12 Nov 2024 02:27:35 +0200 -Subject: drm/rockchip: vop2: Drop unnecessary if_pixclk_rate computation - -The if_pixclk_rate variable is not being used outside of the if-block in -rk3588_calc_cru_cfg(), hence move the superfluous assignment from the -first branch to the inner comment-block. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -1905,8 +1905,8 @@ static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id, - K = 2; - } - -- if_pixclk_rate = (dclk_core_rate << 1) / K; - /* -+ * if_pixclk_rate = (dclk_core_rate << 1) / K; - * if_dclk_rate = dclk_core_rate / K; - * *if_pixclk_div = dclk_rate / if_pixclk_rate; - * *if_dclk_div = dclk_rate / if_dclk_rate; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Fri, 3 Nov 2023 19:58:02 +0200 -Subject: drm/rockchip: vop2: Improve display modes handling on RK3588 HDMI0 - -The RK3588 specific implementation is currently quite limited in terms -of handling the full range of display modes supported by the connected -screens, e.g. 2560x1440@75Hz, 2048x1152@60Hz, 1024x768@60Hz are just a -few of them. - -Additionally, it doesn't cope well with non-integer refresh rates like -59.94, 29.97, 23.98, etc. - -Make use of HDMI0 PHY PLL as a more accurate DCLK source to handle -all display modes up to 4K@60Hz. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 34 ++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -159,6 +159,7 @@ struct vop2_video_port { - struct drm_crtc crtc; - struct vop2 *vop2; - struct clk *dclk; -+ struct clk *dclk_src; - unsigned int id; - const struct vop2_video_port_data *data; - -@@ -214,6 +215,7 @@ struct vop2 { - struct clk *hclk; - struct clk *aclk; - struct clk *pclk; -+ struct clk *pll_hdmiphy0; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; -@@ -222,6 +224,8 @@ struct vop2 { - struct vop2_win win[]; - }; - -+#define VOP2_MAX_DCLK_RATE 600000000 -+ - #define vop2_output_if_is_hdmi(x) ((x) == ROCKCHIP_VOP2_EP_HDMI0 || \ - (x) == ROCKCHIP_VOP2_EP_HDMI1) - -@@ -1155,6 +1159,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, - - vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID); - -+ if (vp->dclk_src) -+ clk_set_parent(vp->dclk, vp->dclk_src); -+ - clk_disable_unprepare(vp->dclk); - - vop2->enable_count--; -@@ -2259,6 +2266,27 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0); - -+ /* -+ * Switch to HDMI PHY PLL as DCLK source for display modes up -+ * to 4K@60Hz, if available, otherwise keep using the system CRU. -+ */ -+ if (vop2->pll_hdmiphy0 && clock <= VOP2_MAX_DCLK_RATE) { -+ drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { -+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); -+ -+ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { -+ if (!vp->dclk_src) -+ vp->dclk_src = clk_get_parent(vp->dclk); -+ -+ ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0); -+ if (ret < 0) -+ drm_warn(vop2->drm, -+ "Could not switch to HDMI0 PHY PLL: %d\n", ret); -+ break; -+ } -+ } -+ } -+ - clk_set_rate(vp->dclk, clock); - - vop2_post_config(crtc); -@@ -3699,6 +3727,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->pclk); - } - -+ vop2->pll_hdmiphy0 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy0"); -+ if (IS_ERR(vop2->pll_hdmiphy0)) { -+ drm_err(vop2->drm, "failed to get pll_hdmiphy0\n"); -+ return PTR_ERR(vop2->pll_hdmiphy0); -+ } -+ - vop2->irq = platform_get_irq(pdev, 0); - if (vop2->irq < 0) { - drm_err(vop2->drm, "cannot find irq for vop2\n"); --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Tue, 16 Jan 2024 03:13:38 +0200 -Subject: arm64: dts: rockchip: Enable HDMI0 PHY clk provider on RK3588 - -Since commit c4b09c562086 ("phy: phy-rockchip-samsung-hdptx: Add clock -provider support"), the HDMI PHY PLL can be used as an alternative and -more accurate pixel clock source for VOP2 to improve display modes -handling on RK3588 SoC. - -Add the missing #clock-cells property to allow using the clock provider -functionality of HDMI0 PHY. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -2812,6 +2812,7 @@ hdptxphy_hdmi0: phy@fed60000 { - reg = <0x0 0xfed60000 0x0 0x2000>; - clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>; - clock-names = "ref", "apb"; -+ #clock-cells = <0>; - #phy-cells = <0>; - resets = <&cru SRST_HDPTX0>, <&cru SRST_P_HDPTX0>, - <&cru SRST_HDPTX0_INIT>, <&cru SRST_HDPTX0_CMN>, --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 16 Nov 2024 04:33:46 +0200 -Subject: arm64: dts: rockchip: Add HDMI0 PHY PLL clock source to VOP2 on - RK3588 - -VOP2 on RK3588 is able to use the HDMI PHY PLL as an alternative and -more accurate pixel clock source to improve handling of display modes up -to 4K@60Hz on video ports 0, 1 and 2. - -For now only HDMI0 output is supported, hence add the related PLL clock. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -1261,14 +1261,16 @@ vop: vop@fdd90000 { - <&cru DCLK_VOP1>, - <&cru DCLK_VOP2>, - <&cru DCLK_VOP3>, -- <&cru PCLK_VOP_ROOT>; -+ <&cru PCLK_VOP_ROOT>, -+ <&hdptxphy_hdmi0>; - clock-names = "aclk", - "hclk", - "dclk_vp0", - "dclk_vp1", - "dclk_vp2", - "dclk_vp3", -- "pclk_vop"; -+ "pclk_vop", -+ "pll_hdmiphy0"; - iommus = <&vop_mmu>; - power-domains = <&power RK3588_PD_VOP>; - rockchip,grf = <&sys_grf>; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0132-Fix-label-name-of-hdptxphy-for-RK3588.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0132-Fix-label-name-of-hdptxphy-for-RK3588.patch deleted file mode 100644 index d0be50947848..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0132-Fix-label-name-of-hdptxphy-for-RK3588.patch +++ /dev/null @@ -1,318 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Damon Ding -Date: Thu, 6 Feb 2025 11:03:30 +0800 -Subject: arm64: dts: rockchip: Fix label name of hdptxphy for RK3588 - -The hdptxphy is a combo transmit-PHY for HDMI2.1 TMDS Link, FRL Link, DP -and eDP Link. Therefore, it is better to name it hdptxphy0 other than -hdptxphy_hdmi0, which will be referenced by both hdmi0 and edp0 nodes. - -Signed-off-by: Damon Ding -Link: https://lore.kernel.org/r/20250206030330.680424-3-damon.ding@rock-chips.com -[added armsom-sige7, where hdmi-support was added recently and also - the hdptxphy0-as-dclk source I just added] -Signed-off-by: Heiko Stuebner ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 6 +++--- - arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts | 2 +- - 20 files changed, 22 insertions(+), 22 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -1262,7 +1262,7 @@ vop: vop@fdd90000 { - <&cru DCLK_VOP2>, - <&cru DCLK_VOP3>, - <&cru PCLK_VOP_ROOT>, -- <&hdptxphy_hdmi0>; -+ <&hdptxphy0>; - clock-names = "aclk", - "hclk", - "dclk_vp0", -@@ -1387,7 +1387,7 @@ hdmi0: hdmi@fde80000 { - , - ; - interrupt-names = "avp", "cec", "earc", "main", "hpd"; -- phys = <&hdptxphy_hdmi0>; -+ phys = <&hdptxphy0>; - pinctrl-names = "default"; - pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd - &hdmim0_tx0_scl &hdmim0_tx0_sda>; -@@ -2809,7 +2809,7 @@ dmac2: dma-controller@fed10000 { - #dma-cells = <1>; - }; - -- hdptxphy_hdmi0: phy@fed60000 { -+ hdptxphy0: phy@fed60000 { - compatible = "rockchip,rk3588-hdptx-phy"; - reg = <0x0 0xfed60000 0x0 0x2000>; - clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>; -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts -@@ -129,7 +129,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts -@@ -166,7 +166,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts -@@ -364,7 +364,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts b/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dts -@@ -337,7 +337,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -@@ -335,7 +335,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts b/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dts -@@ -207,7 +207,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts -@@ -303,7 +303,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi -@@ -360,7 +360,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -@@ -39,7 +39,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -@@ -125,7 +125,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -220,7 +220,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts -@@ -189,7 +189,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts -@@ -236,7 +236,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts -@@ -278,7 +278,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi -@@ -251,7 +251,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts -@@ -266,7 +266,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi -@@ -197,7 +197,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts -@@ -334,7 +334,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts -@@ -278,7 +278,7 @@ hdmi0_out_con: endpoint { - }; - }; - --&hdptxphy_hdmi0 { -+&hdptxphy0 { - status = "okay"; - }; - --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0133-vop2-hdmi1-disp-modes-support.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0133-vop2-hdmi1-disp-modes-support.patch deleted file mode 100644 index 5e87f2459da3..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0133-vop2-hdmi1-disp-modes-support.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 15 Feb 2025 02:55:37 +0200 -Subject: drm/rockchip: vop2: Improve display modes handling on RK3588 HDMI1 - -The RK3588 specific implementation is currently quite limited in terms -of handling the full range of display modes supported by the connected -screens, e.g. 2560x1440@75Hz, 2048x1152@60Hz, 1024x768@60Hz are just a -few of them. - -Additionally, it doesn't cope well with non-integer refresh rates like -59.94, 29.97, 23.98, etc. - -Make use of HDMI1 PHY PLL as a more accurate DCLK source to handle -all display modes up to 4K@60Hz. - -Signed-off-by: Cristian Ciocaltea ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 26 +++++++++- - 1 file changed, 25 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -216,6 +216,7 @@ struct vop2 { - struct clk *aclk; - struct clk *pclk; - struct clk *pll_hdmiphy0; -+ struct clk *pll_hdmiphy1; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; -@@ -2270,11 +2271,14 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - * Switch to HDMI PHY PLL as DCLK source for display modes up - * to 4K@60Hz, if available, otherwise keep using the system CRU. - */ -- if (vop2->pll_hdmiphy0 && clock <= VOP2_MAX_DCLK_RATE) { -+ if ((vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) && clock <= VOP2_MAX_DCLK_RATE) { - drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { - struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); - - if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { -+ if (!vop2->pll_hdmiphy0) -+ break; -+ - if (!vp->dclk_src) - vp->dclk_src = clk_get_parent(vp->dclk); - -@@ -2284,6 +2288,20 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - "Could not switch to HDMI0 PHY PLL: %d\n", ret); - break; - } -+ -+ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) { -+ if (!vop2->pll_hdmiphy1) -+ break; -+ -+ if (!vp->dclk_src) -+ vp->dclk_src = clk_get_parent(vp->dclk); -+ -+ ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1); -+ if (ret < 0) -+ drm_warn(vop2->drm, -+ "Could not switch to HDMI1 PHY PLL: %d\n", ret); -+ break; -+ } - } - } - -@@ -3733,6 +3751,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) - return PTR_ERR(vop2->pll_hdmiphy0); - } - -+ vop2->pll_hdmiphy1 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy1"); -+ if (IS_ERR(vop2->pll_hdmiphy1)) { -+ drm_err(vop2->drm, "failed to get pll_hdmiphy1\n"); -+ return PTR_ERR(vop2->pll_hdmiphy1); -+ } -+ - vop2->irq = platform_get_irq(pdev, 0); - if (vop2->irq < 0) { - drm_err(vop2->drm, "cannot find irq for vop2\n"); --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 15 Feb 2025 02:55:38 +0200 -Subject: arm64: dts: rockchip: Enable HDMI1 PHY clk provider on RK3588 - -Since commit c4b09c562086 ("phy: phy-rockchip-samsung-hdptx: Add clock -provider support"), the HDMI PHY PLL can be used as an alternative and -more accurate pixel clock source for VOP2 to improve display modes -handling on RK3588 SoC. - -Add the missing #clock-cells property to allow using the clock provider -functionality of HDMI1 PHY. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -505,6 +505,7 @@ hdptxphy1: phy@fed70000 { - reg = <0x0 0xfed70000 0x0 0x2000>; - clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX1>; - clock-names = "ref", "apb"; -+ #clock-cells = <0>; - #phy-cells = <0>; - resets = <&cru SRST_HDPTX1>, <&cru SRST_P_HDPTX1>, - <&cru SRST_HDPTX1_INIT>, <&cru SRST_HDPTX1_CMN>, --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cristian Ciocaltea -Date: Sat, 15 Feb 2025 02:55:39 +0200 -Subject: arm64: dts: rockchip: Add HDMI1 PHY PLL clock source to VOP2 on - RK3588 - -VOP2 on RK3588 is able to use the HDMI PHY PLL as an alternative and -more accurate pixel clock source to improve handling of display modes up -to 4K@60Hz on video ports 0, 1 and 2. - -The HDMI1 PHY PLL clock source cannot be added directly to vop node in -rk3588-base.dtsi, along with the HDMI0 related one, because HDMI1 is an -optional feature and its PHY node belongs to a separate (extra) DT file. - -Therefore, add the HDMI1 PHY PLL clock source to VOP2 by overwriting its -clocks & clock-names properties in the extra DT file. - -Signed-off-by: Cristian Ciocaltea ---- - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 21 ++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -568,3 +568,24 @@ pcie30phy: phy@fee80000 { - status = "disabled"; - }; - }; -+ -+&vop { -+ clocks = <&cru ACLK_VOP>, -+ <&cru HCLK_VOP>, -+ <&cru DCLK_VOP0>, -+ <&cru DCLK_VOP1>, -+ <&cru DCLK_VOP2>, -+ <&cru DCLK_VOP3>, -+ <&cru PCLK_VOP_ROOT>, -+ <&hdptxphy0>, -+ <&hdptxphy1>; -+ clock-names = "aclk", -+ "hclk", -+ "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2", -+ "dclk_vp3", -+ "pclk_vop", -+ "pll_hdmiphy0", -+ "pll_hdmiphy1"; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0170-drm-rockchip-vop2-add-clocks-reset-support.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0170-drm-rockchip-vop2-add-clocks-reset-support.patch deleted file mode 100644 index f551867cd61e..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0170-drm-rockchip-vop2-add-clocks-reset-support.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Detlev Casanova -Date: Fri, 3 May 2024 14:27:39 -0400 -Subject: vop2: Add clock resets support - -At the end of initialization, each VP clock needs to be reset before -they can be used. - -Failing to do so can put the VOP in an undefined state where the -generated HDMI signal is either lost or not matching the selected mode. - -Signed-off-by: Detlev Casanova ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 30 ++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -158,6 +159,7 @@ struct vop2_win { - struct vop2_video_port { - struct drm_crtc crtc; - struct vop2 *vop2; -+ struct reset_control *dclk_rst; - struct clk *dclk; - struct clk *dclk_src; - unsigned int id; -@@ -2135,6 +2137,26 @@ static int us_to_vertical_line(struct drm_display_mode *mode, int us) - return us * mode->clock / mode->htotal / 1000; - } - -+static int vop2_clk_reset(struct vop2_video_port *vp) -+{ -+ struct reset_control *rstc = vp->dclk_rst; -+ struct vop2 *vop2 = vp->vop2; -+ int ret; -+ -+ if (!rstc) -+ return 0; -+ -+ ret = reset_control_assert(rstc); -+ if (ret < 0) -+ drm_warn(vop2->drm, "failed to assert reset\n"); -+ udelay(10); -+ ret = reset_control_deassert(rstc); -+ if (ret < 0) -+ drm_warn(vop2->drm, "failed to deassert reset\n"); -+ -+ return ret; -+} -+ - static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) - { -@@ -2315,6 +2337,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, - - vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state); - -+ vop2_clk_reset(vp); -+ - drm_crtc_vblank_on(crtc); - - vop2_unlock(vop2); -@@ -3272,6 +3296,12 @@ static int vop2_create_crtcs(struct vop2 *vop2) - vp->data = vp_data; - - snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id); -+ vp->dclk_rst = devm_reset_control_get_optional(vop2->dev, dclk_name); -+ if (IS_ERR(vp->dclk_rst)) { -+ drm_err(vop2->drm, "failed to get %s reset\n", dclk_name); -+ return PTR_ERR(vp->dclk_rst); -+ } -+ - vp->dclk = devm_clk_get(vop2->dev, dclk_name); - if (IS_ERR(vp->dclk)) { - drm_err(vop2->drm, "failed to get %s\n", dclk_name); --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Detlev Casanova -Date: Mon, 6 May 2024 13:54:01 -0400 -Subject: dt-bindings: display: vop2: Add VP clock resets - -Add the documentation for VOP2 video ports reset clocks. -One reset can be set per video port. - -Signed-off-by: Detlev Casanova ---- - Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml | 27 ++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -index 111111111111..222222222222 100644 ---- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml -@@ -69,6 +69,22 @@ properties: - - const: pll_hdmiphy0 - - const: pll_hdmiphy1 - -+ resets: -+ minItems: 3 -+ items: -+ - description: Pixel clock reset for video port 0. -+ - description: Pixel clock reset for video port 1. -+ - description: Pixel clock reset for video port 2. -+ - description: Pixel clock reset for video port 3. -+ -+ reset-names: -+ minItems: 3 -+ items: -+ - const: dclk_vp0 -+ - const: dclk_vp1 -+ - const: dclk_vp2 -+ - const: dclk_vp3 -+ - rockchip,grf: - $ref: /schemas/types.yaml#/definitions/phandle - description: -@@ -132,6 +148,11 @@ allOf: - clock-names: - minItems: 7 - -+ resets: -+ minItems: 4 -+ reset-names: -+ minItems: 4 -+ - ports: - required: - - port@0 -@@ -187,6 +208,12 @@ examples: - "dclk_vp0", - "dclk_vp1", - "dclk_vp2"; -+ resets = <&cru SRST_VOP0>, -+ <&cru SRST_VOP1>, -+ <&cru SRST_VOP2>; -+ reset-names = "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2"; - power-domains = <&power RK3568_PD_VO>; - iommus = <&vop_mmu>; - vop_out: ports { --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Muhammed Efe Cetin -Date: Fri, 2 Aug 2024 00:13:32 +0300 -Subject: arm64: dts: rockchip: rk3588: add VOP2 clock resets - ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -1273,6 +1273,14 @@ vop: vop@fdd90000 { - "pll_hdmiphy0"; - iommus = <&vop_mmu>; - power-domains = <&power RK3588_PD_VOP>; -+ resets = <&cru SRST_D_VOP0>, -+ <&cru SRST_D_VOP1>, -+ <&cru SRST_D_VOP2>, -+ <&cru SRST_D_VOP3>; -+ reset-names = "dclk_vp0", -+ "dclk_vp1", -+ "dclk_vp2", -+ "dclk_vp3"; - rockchip,grf = <&sys_grf>; - rockchip,vop-grf = <&vop_grf>; - rockchip,vo1-grf = <&vo1_grf>; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0180-drm-bridge-dw-hdmi-qp.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0180-drm-bridge-dw-hdmi-qp.patch deleted file mode 100644 index bce285c85fc9..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0180-drm-bridge-dw-hdmi-qp.patch +++ /dev/null @@ -1,580 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: palachzzz <7zzzzzzz@mail.ru> -Date: Thu, 27 Feb 2025 23:06:51 +0800 -Subject: [ARCHEOLOGY] RK3588 add HDMI sound, add support for OPi5 Max #7884 - -> X-Git-Archeology: - Revision 0b88561ec332114404ff8075ab6bc2419ca66a47: https://github.com/armbian/build/commit/0b88561ec332114404ff8075ab6bc2419ca66a47 -> X-Git-Archeology: Date: Thu, 27 Feb 2025 23:06:51 +0800 -> X-Git-Archeology: From: palachzzz <7zzzzzzz@mail.ru> -> X-Git-Archeology: Subject: RK3588 add HDMI sound, add support for OPi5 Max #7884 -> X-Git-Archeology: ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 489 ++++++++++ - 1 file changed, 489 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c -@@ -36,6 +36,88 @@ - - #define SCRAMB_POLL_DELAY_MS 3000 - -+/* -+ * Unless otherwise noted, entries in this table are 100% optimization. -+ * Values can be obtained from dw_hdmi_qp_compute_n() but that function is -+ * slow so we pre-compute values we expect to see. -+ * -+ * The values for TMDS 25175, 25200, 27000, 54000, 74250 and 148500 kHz are -+ * the recommended N values specified in the Audio chapter of the HDMI -+ * specification. -+ */ -+static const struct dw_hdmi_audio_tmds_n { -+ unsigned long tmds; -+ unsigned int n_32k; -+ unsigned int n_44k1; -+ unsigned int n_48k; -+} common_tmds_n_table[] = { -+ { .tmds = 25175000, .n_32k = 4576, .n_44k1 = 7007, .n_48k = 6864, }, -+ { .tmds = 25200000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 27000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 28320000, .n_32k = 4096, .n_44k1 = 5586, .n_48k = 6144, }, -+ { .tmds = 30240000, .n_32k = 4096, .n_44k1 = 5642, .n_48k = 6144, }, -+ { .tmds = 31500000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, }, -+ { .tmds = 32000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, }, -+ { .tmds = 33750000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 36000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, }, -+ { .tmds = 40000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, }, -+ { .tmds = 49500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, -+ { .tmds = 50000000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, }, -+ { .tmds = 54000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 65000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 68250000, .n_32k = 4096, .n_44k1 = 5376, .n_48k = 6144, }, -+ { .tmds = 71000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 72000000, .n_32k = 4096, .n_44k1 = 5635, .n_48k = 6144, }, -+ { .tmds = 73250000, .n_32k = 11648, .n_44k1 = 14112, .n_48k = 6144, }, -+ { .tmds = 74250000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 75000000, .n_32k = 4096, .n_44k1 = 5880, .n_48k = 6144, }, -+ { .tmds = 78750000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, }, -+ { .tmds = 78800000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, }, -+ { .tmds = 79500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, }, -+ { .tmds = 83500000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 85500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, -+ { .tmds = 88750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, }, -+ { .tmds = 97750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, }, -+ { .tmds = 101000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, }, -+ { .tmds = 106500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, }, -+ { .tmds = 108000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, }, -+ { .tmds = 115500000, .n_32k = 4096, .n_44k1 = 5712, .n_48k = 6144, }, -+ { .tmds = 119000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, }, -+ { .tmds = 135000000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, }, -+ { .tmds = 146250000, .n_32k = 11648, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 148500000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, }, -+ { .tmds = 154000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, }, -+ { .tmds = 162000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, }, -+ -+ /* For 297 MHz+ HDMI spec have some other rule for setting N */ -+ { .tmds = 297000000, .n_32k = 3073, .n_44k1 = 4704, .n_48k = 5120, }, -+ { .tmds = 594000000, .n_32k = 3073, .n_44k1 = 9408, .n_48k = 10240,}, -+ -+ /* End of table */ -+ { .tmds = 0, .n_32k = 0, .n_44k1 = 0, .n_48k = 0, }, -+}; -+ -+/* -+ * These are the CTS values as recommended in the Audio chapter of the HDMI -+ * specification. -+ */ -+static const struct dw_hdmi_audio_tmds_cts { -+ unsigned long tmds; -+ unsigned int cts_32k; -+ unsigned int cts_44k1; -+ unsigned int cts_48k; -+} common_tmds_cts_table[] = { -+ { .tmds = 25175000, .cts_32k = 28125, .cts_44k1 = 31250, .cts_48k = 28125, }, -+ { .tmds = 25200000, .cts_32k = 25200, .cts_44k1 = 28000, .cts_48k = 25200, }, -+ { .tmds = 27000000, .cts_32k = 27000, .cts_44k1 = 30000, .cts_48k = 27000, }, -+ { .tmds = 54000000, .cts_32k = 54000, .cts_44k1 = 60000, .cts_48k = 54000, }, -+ { .tmds = 74250000, .cts_32k = 74250, .cts_44k1 = 82500, .cts_48k = 74250, }, -+ { .tmds = 148500000, .cts_32k = 148500, .cts_44k1 = 165000, .cts_48k = 148500, }, -+ -+ /* End of table */ -+ { .tmds = 0, .cts_32k = 0, .cts_44k1 = 0, .cts_48k = 0, }, -+}; -+ - struct dw_hdmi_qp_i2c { - struct i2c_adapter adap; - -@@ -60,6 +142,8 @@ struct dw_hdmi_qp { - } phy; - - struct regmap *regm; -+ -+ unsigned long tmds_char_rate; - }; - - static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val, -@@ -83,6 +167,346 @@ static void dw_hdmi_qp_mod(struct dw_hdmi_qp *hdmi, unsigned int data, - regmap_update_bits(hdmi->regm, reg, mask, data); - } - -+static struct dw_hdmi_qp *dw_hdmi_qp_from_bridge(struct drm_bridge *bridge) -+{ -+ return container_of(bridge, struct dw_hdmi_qp, bridge); -+} -+ -+static void dw_hdmi_qp_set_cts_n(struct dw_hdmi_qp *hdmi, unsigned int cts, -+ unsigned int n) -+{ -+ /* Set N */ -+ dw_hdmi_qp_mod(hdmi, n, AUDPKT_ACR_N_VALUE, AUDPKT_ACR_CONTROL0); -+ -+ /* Set CTS */ -+ if (cts) -+ dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_EN, AUDPKT_ACR_CTS_OVR_EN_MSK, -+ AUDPKT_ACR_CONTROL1); -+ else -+ dw_hdmi_qp_mod(hdmi, 0, AUDPKT_ACR_CTS_OVR_EN_MSK, -+ AUDPKT_ACR_CONTROL1); -+ -+ dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_VAL(cts), AUDPKT_ACR_CTS_OVR_VAL_MSK, -+ AUDPKT_ACR_CONTROL1); -+} -+ -+static int dw_hdmi_qp_match_tmds_n_table(struct dw_hdmi_qp *hdmi, -+ unsigned long pixel_clk, -+ unsigned long freq) -+{ -+ const struct dw_hdmi_audio_tmds_n *tmds_n = NULL; -+ int i; -+ -+ for (i = 0; common_tmds_n_table[i].tmds != 0; i++) { -+ if (pixel_clk == common_tmds_n_table[i].tmds) { -+ tmds_n = &common_tmds_n_table[i]; -+ break; -+ } -+ } -+ -+ if (!tmds_n) -+ return -ENOENT; -+ -+ switch (freq) { -+ case 32000: -+ return tmds_n->n_32k; -+ case 44100: -+ case 88200: -+ case 176400: -+ return (freq / 44100) * tmds_n->n_44k1; -+ case 48000: -+ case 96000: -+ case 192000: -+ return (freq / 48000) * tmds_n->n_48k; -+ default: -+ return -ENOENT; -+ } -+} -+ -+static u32 dw_hdmi_qp_audio_math_diff(unsigned int freq, unsigned int n, -+ unsigned int pixel_clk) -+{ -+ u64 cts = mul_u32_u32(pixel_clk, n); -+ -+ return do_div(cts, 128 * freq); -+} -+ -+static unsigned int dw_hdmi_qp_compute_n(struct dw_hdmi_qp *hdmi, -+ unsigned long pixel_clk, -+ unsigned long freq) -+{ -+ unsigned int min_n = DIV_ROUND_UP((128 * freq), 1500); -+ unsigned int max_n = (128 * freq) / 300; -+ unsigned int ideal_n = (128 * freq) / 1000; -+ unsigned int best_n_distance = ideal_n; -+ unsigned int best_n = 0; -+ u64 best_diff = U64_MAX; -+ int n; -+ -+ /* If the ideal N could satisfy the audio math, then just take it */ -+ if (dw_hdmi_qp_audio_math_diff(freq, ideal_n, pixel_clk) == 0) -+ return ideal_n; -+ -+ for (n = min_n; n <= max_n; n++) { -+ u64 diff = dw_hdmi_qp_audio_math_diff(freq, n, pixel_clk); -+ -+ if (diff < best_diff || -+ (diff == best_diff && abs(n - ideal_n) < best_n_distance)) { -+ best_n = n; -+ best_diff = diff; -+ best_n_distance = abs(best_n - ideal_n); -+ } -+ -+ /* -+ * The best N already satisfy the audio math, and also be -+ * the closest value to ideal N, so just cut the loop. -+ */ -+ if (best_diff == 0 && (abs(n - ideal_n) > best_n_distance)) -+ break; -+ } -+ -+ return best_n; -+} -+ -+static unsigned int dw_hdmi_qp_find_n(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk, -+ unsigned long sample_rate) -+{ -+ int n = dw_hdmi_qp_match_tmds_n_table(hdmi, pixel_clk, sample_rate); -+ -+ if (n > 0) -+ return n; -+ -+ dev_warn(hdmi->dev, "Rate %lu missing; compute N dynamically\n", -+ pixel_clk); -+ -+ return dw_hdmi_qp_compute_n(hdmi, pixel_clk, sample_rate); -+} -+ -+static unsigned int dw_hdmi_qp_find_cts(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk, -+ unsigned long sample_rate) -+{ -+ const struct dw_hdmi_audio_tmds_cts *tmds_cts = NULL; -+ int i; -+ -+ for (i = 0; common_tmds_cts_table[i].tmds != 0; i++) { -+ if (pixel_clk == common_tmds_cts_table[i].tmds) { -+ tmds_cts = &common_tmds_cts_table[i]; -+ break; -+ } -+ } -+ -+ if (!tmds_cts) -+ return 0; -+ -+ switch (sample_rate) { -+ case 32000: -+ return tmds_cts->cts_32k; -+ case 44100: -+ case 88200: -+ case 176400: -+ return tmds_cts->cts_44k1; -+ case 48000: -+ case 96000: -+ case 192000: -+ return tmds_cts->cts_48k; -+ default: -+ return -ENOENT; -+ } -+} -+ -+static void dw_hdmi_qp_set_audio_interface(struct dw_hdmi_qp *hdmi, -+ struct hdmi_codec_daifmt *fmt, -+ struct hdmi_codec_params *hparms) -+{ -+ u32 conf0 = 0; -+ -+ /* Reset the audio data path of the AVP */ -+ dw_hdmi_qp_write(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWINIT_P, GLOBAL_SWRESET_REQUEST); -+ -+ /* Disable AUDS, ACR, AUDI */ -+ dw_hdmi_qp_mod(hdmi, 0, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDS_TX_EN | PKTSCHED_AUDI_TX_EN, -+ PKTSCHED_PKT_EN); -+ -+ /* Clear the audio FIFO */ -+ dw_hdmi_qp_write(hdmi, AUDIO_FIFO_CLR_P, AUDIO_INTERFACE_CONTROL0); -+ -+ /* Select I2S interface as the audio source */ -+ dw_hdmi_qp_mod(hdmi, AUD_IF_I2S, AUD_IF_SEL_MSK, AUDIO_INTERFACE_CONFIG0); -+ -+ /* Enable the active i2s lanes */ -+ switch (hparms->channels) { -+ case 7 ... 8: -+ conf0 |= I2S_LINES_EN(3); -+ fallthrough; -+ case 5 ... 6: -+ conf0 |= I2S_LINES_EN(2); -+ fallthrough; -+ case 3 ... 4: -+ conf0 |= I2S_LINES_EN(1); -+ fallthrough; -+ default: -+ conf0 |= I2S_LINES_EN(0); -+ break; -+ } -+ -+ dw_hdmi_qp_mod(hdmi, conf0, I2S_LINES_EN_MSK, AUDIO_INTERFACE_CONFIG0); -+ -+ /* -+ * Enable bpcuv generated internally for L-PCM, or received -+ * from stream for NLPCM/HBR. -+ */ -+ switch (fmt->bit_fmt) { -+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: -+ conf0 = (hparms->channels == 8) ? AUD_HBR : AUD_ASP; -+ conf0 |= I2S_BPCUV_RCV_EN; -+ break; -+ default: -+ conf0 = AUD_ASP | I2S_BPCUV_RCV_DIS; -+ break; -+ } -+ -+ dw_hdmi_qp_mod(hdmi, conf0, I2S_BPCUV_RCV_MSK | AUD_FORMAT_MSK, -+ AUDIO_INTERFACE_CONFIG0); -+ -+ /* Enable audio FIFO auto clear when overflow */ -+ dw_hdmi_qp_mod(hdmi, AUD_FIFO_INIT_ON_OVF_EN, AUD_FIFO_INIT_ON_OVF_MSK, -+ AUDIO_INTERFACE_CONFIG0); -+} -+ -+/* -+ * When transmitting IEC60958 linear PCM audio, these registers allow to -+ * configure the channel status information of all the channel status -+ * bits in the IEC60958 frame. For the moment this configuration is only -+ * used when the I2S audio interface, General Purpose Audio (GPA), -+ * or AHB audio DMA (AHBAUDDMA) interface is active -+ * (for S/PDIF interface this information comes from the stream). -+ */ -+static void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi, -+ u8 *channel_status, bool ref2stream) -+{ -+ /* -+ * AUDPKT_CHSTATUS_OVR0: { RSV, RSV, CS1, CS0 } -+ * AUDPKT_CHSTATUS_OVR1: { CS6, CS5, CS4, CS3 } -+ * -+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | -+ * CS0: | Mode | d | c | b | a | -+ * CS1: | Category Code | -+ * CS2: | Channel Number | Source Number | -+ * CS3: | Clock Accuracy | Sample Freq | -+ * CS4: | Ori Sample Freq | Word Length | -+ * CS5: | | CGMS-A | -+ * CS6~CS23: Reserved -+ * -+ * a: use of channel status block -+ * b: linear PCM identification: 0 for lpcm, 1 for nlpcm -+ * c: copyright information -+ * d: additional format information -+ */ -+ -+ if (ref2stream) -+ channel_status[0] |= IEC958_AES0_NONAUDIO; -+ -+ if ((dw_hdmi_qp_read(hdmi, AUDIO_INTERFACE_CONFIG0) & GENMASK(25, 24)) == AUD_HBR) { -+ /* fixup cs for HBR */ -+ channel_status[3] = (channel_status[3] & 0xf0) | IEC958_AES3_CON_FS_768000; -+ channel_status[4] = (channel_status[4] & 0x0f) | IEC958_AES4_CON_ORIGFS_NOTID; -+ } -+ -+ dw_hdmi_qp_write(hdmi, channel_status[0] | (channel_status[1] << 8), -+ AUDPKT_CHSTATUS_OVR0); -+ -+ regmap_bulk_write(hdmi->regm, AUDPKT_CHSTATUS_OVR1, &channel_status[3], 1); -+ -+ if (ref2stream) -+ dw_hdmi_qp_mod(hdmi, 0, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+ else -+ dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+} -+ -+static void dw_hdmi_qp_set_sample_rate(struct dw_hdmi_qp *hdmi, unsigned long long tmds_char_rate, -+ unsigned int sample_rate) -+{ -+ unsigned int n, cts; -+ -+ n = dw_hdmi_qp_find_n(hdmi, tmds_char_rate, sample_rate); -+ cts = dw_hdmi_qp_find_cts(hdmi, tmds_char_rate, sample_rate); -+ -+ dw_hdmi_qp_set_cts_n(hdmi, cts, n); -+} -+ -+static int dw_hdmi_qp_audio_enable(struct drm_connector *connector, -+ struct drm_bridge *bridge) -+{ -+ struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); -+ -+ if (hdmi->tmds_char_rate) -+ dw_hdmi_qp_mod(hdmi, 0, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE); -+ -+ return 0; -+} -+ -+static int dw_hdmi_qp_audio_prepare(struct drm_connector *connector, -+ struct drm_bridge *bridge, -+ struct hdmi_codec_daifmt *fmt, -+ struct hdmi_codec_params *hparms) -+{ -+ struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); -+ bool ref2stream = false; -+ -+ if (!hdmi->tmds_char_rate) -+ return -ENODEV; -+ -+ if (fmt->bit_clk_provider | fmt->frame_clk_provider) { -+ dev_err(hdmi->dev, "unsupported clock settings\n"); -+ return -EINVAL; -+ } -+ -+ if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) -+ ref2stream = true; -+ -+ dw_hdmi_qp_set_audio_interface(hdmi, fmt, hparms); -+ dw_hdmi_qp_set_sample_rate(hdmi, hdmi->tmds_char_rate, hparms->sample_rate); -+ dw_hdmi_qp_set_channel_status(hdmi, hparms->iec.status, ref2stream); -+ drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, &hparms->cea); -+ -+ return 0; -+} -+ -+static void dw_hdmi_qp_audio_disable_regs(struct dw_hdmi_qp *hdmi) -+{ -+ /* -+ * Keep ACR, AUDI, AUDS packet always on to make SINK device -+ * active for better compatibility and user experience. -+ * -+ * This also fix POP sound on some SINK devices which wakeup -+ * from suspend to active. -+ */ -+ dw_hdmi_qp_mod(hdmi, I2S_BPCUV_RCV_DIS, I2S_BPCUV_RCV_MSK, -+ AUDIO_INTERFACE_CONFIG0); -+ dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, -+ AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, -+ AUDPKT_CONTROL0); -+ -+ dw_hdmi_qp_mod(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, -+ AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE); -+} -+ -+static void dw_hdmi_qp_audio_disable(struct drm_connector *connector, -+ struct drm_bridge *bridge) -+{ -+ struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); -+ -+ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector); -+ -+ if (hdmi->tmds_char_rate) -+ dw_hdmi_qp_audio_disable_regs(hdmi); -+} -+ - static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi, - unsigned char *buf, unsigned int length) - { -@@ -361,6 +785,51 @@ static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi, - return 0; - } - -+/* -+ * Static values documented in the TRM -+ * Different values are only used for debug purposes -+ */ -+#define DW_HDMI_QP_AUDIO_INFOFRAME_HB1 0x1 -+#define DW_HDMI_QP_AUDIO_INFOFRAME_HB2 0xa -+ -+static int dw_hdmi_qp_config_audio_infoframe(struct dw_hdmi_qp *hdmi, -+ const u8 *buffer, size_t len) -+{ -+ /* -+ * AUDI_CONTENTS0: { RSV, HB2, HB1, RSV } -+ * AUDI_CONTENTS1: { PB3, PB2, PB1, PB0 } -+ * AUDI_CONTENTS2: { PB7, PB6, PB5, PB4 } -+ * -+ * PB0: CheckSum -+ * PB1: | CT3 | CT2 | CT1 | CT0 | F13 | CC2 | CC1 | CC0 | -+ * PB2: | F27 | F26 | F25 | SF2 | SF1 | SF0 | SS1 | SS0 | -+ * PB3: | F37 | F36 | F35 | F34 | F33 | F32 | F31 | F30 | -+ * PB4: | CA7 | CA6 | CA5 | CA4 | CA3 | CA2 | CA1 | CA0 | -+ * PB5: | DM_INH | LSV3 | LSV2 | LSV1 | LSV0 | F52 | F51 | F50 | -+ * PB6~PB10: Reserved -+ * -+ * AUDI_CONTENTS0 default value defined by HDMI specification, -+ * and shall only be changed for debug purposes. -+ */ -+ u32 header_bytes = (DW_HDMI_QP_AUDIO_INFOFRAME_HB1 << 8) | -+ (DW_HDMI_QP_AUDIO_INFOFRAME_HB2 << 16); -+ -+ regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS0, &header_bytes, 1); -+ regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS1, &buffer[3], 1); -+ regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS2, &buffer[4], 1); -+ -+ /* Enable ACR, AUDI, AMD */ -+ dw_hdmi_qp_mod(hdmi, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN, -+ PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN, -+ PKTSCHED_PKT_EN); -+ -+ /* Enable AUDS */ -+ dw_hdmi_qp_mod(hdmi, PKTSCHED_AUDS_TX_EN, PKTSCHED_AUDS_TX_EN, PKTSCHED_PKT_EN); -+ -+ return 0; -+} -+ - static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_state) - { -@@ -382,6 +851,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, - dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n", - __func__, conn_state->hdmi.tmds_char_rate); - op_mode = 0; -+ hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate; - } else { - dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__); - op_mode = OPMODE_DVI; -@@ -400,6 +870,8 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, - { - struct dw_hdmi_qp *hdmi = bridge->driver_private; - -+ hdmi->tmds_char_rate = 0; -+ - hdmi->phy.ops->disable(hdmi, hdmi->phy.data); - } - -@@ -455,6 +927,13 @@ static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge, - dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); - break; - -+ case HDMI_INFOFRAME_TYPE_AUDIO: -+ dw_hdmi_qp_mod(hdmi, 0, -+ PKTSCHED_ACR_TX_EN | -+ PKTSCHED_AUDS_TX_EN | -+ PKTSCHED_AUDI_TX_EN, -+ PKTSCHED_PKT_EN); -+ break; - default: - dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); - } -@@ -477,6 +956,9 @@ static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge, - case HDMI_INFOFRAME_TYPE_DRM: - return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len); - -+ case HDMI_INFOFRAME_TYPE_AUDIO: -+ return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len); -+ - default: - dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); - return 0; -@@ -494,6 +976,9 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = { - .hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid, - .hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe, - .hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe, -+ .hdmi_audio_startup = dw_hdmi_qp_audio_enable, -+ .hdmi_audio_shutdown = dw_hdmi_qp_audio_disable, -+ .hdmi_audio_prepare = dw_hdmi_qp_audio_prepare, - }; - - static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id) -@@ -603,6 +1088,10 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, - if (IS_ERR(hdmi->bridge.ddc)) - return ERR_CAST(hdmi->bridge.ddc); - -+ hdmi->bridge.hdmi_audio_max_i2s_playback_channels = 8; -+ hdmi->bridge.hdmi_audio_dev = dev; -+ hdmi->bridge.hdmi_audio_dai_port = 1; -+ - ret = devm_drm_bridge_add(dev, &hdmi->bridge); - if (ret) - return ERR_PTR(ret); --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0181-arm64-dts-rockchip-extra-sound.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-0181-arm64-dts-rockchip-extra-sound.patch deleted file mode 100644 index 8643f1dad2d6..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0181-arm64-dts-rockchip-extra-sound.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: palachzzz <7zzzzzzz@mail.ru> -Date: Thu, 27 Feb 2025 23:06:51 +0800 -Subject: [ARCHEOLOGY] RK3588 add HDMI sound, add support for OPi5 Max #7884 - -> X-Git-Archeology: - Revision 0b88561ec332114404ff8075ab6bc2419ca66a47: https://github.com/armbian/build/commit/0b88561ec332114404ff8075ab6bc2419ca66a47 -> X-Git-Archeology: Date: Thu, 27 Feb 2025 23:06:51 +0800 -> X-Git-Archeology: From: palachzzz <7zzzzzzz@mail.ru> -> X-Git-Archeology: Subject: RK3588 add HDMI sound, add support for OPi5 Max #7884 -> X-Git-Archeology: ---- - arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 17 ++++++++++ - arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 17 ++++++++++ - 2 files changed, 34 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -382,6 +382,22 @@ scmi_reset: protocol@16 { - }; - }; - -+ hdmi0_sound: hdmi0-sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,format = "i2s"; -+ simple-audio-card,mclk-fs = <128>; -+ simple-audio-card,name = "hdmi0"; -+ status = "disabled"; -+ -+ simple-audio-card,codec { -+ sound-dai = <&hdmi0>; -+ }; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&i2s5_8ch>; -+ }; -+ }; -+ - pmu-a55 { - compatible = "arm,cortex-a55-pmu"; - interrupts = ; -@@ -1404,6 +1420,7 @@ hdmi0: hdmi@fde80000 { - reset-names = "ref", "hdp"; - rockchip,grf = <&sys_grf>; - rockchip,vo-grf = <&vo1_grf>; -+ #sound-dai-cells = <0>; - status = "disabled"; - - ports { -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi -@@ -30,6 +30,22 @@ hdmi_receiver_cma: hdmi-receiver-cma { - }; - }; - -+ hdmi1_sound: hdmi1-sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,format = "i2s"; -+ simple-audio-card,mclk-fs = <128>; -+ simple-audio-card,name = "hdmi1"; -+ status = "disabled"; -+ -+ simple-audio-card,codec { -+ sound-dai = <&hdmi1>; -+ }; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&i2s6_8ch>; -+ }; -+ }; -+ - usb_host1_xhci: usb@fc400000 { - compatible = "rockchip,rk3588-dwc3", "snps,dwc3"; - reg = <0x0 0xfc400000 0x0 0x400000>; -@@ -221,6 +237,7 @@ hdmi1: hdmi@fdea0000 { - reset-names = "ref", "hdp"; - rockchip,grf = <&sys_grf>; - rockchip,vo-grf = <&vo1_grf>; -+ #sound-dai-cells = <0>; - status = "disabled"; - - ports { --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1011-rock5b-hdmi1.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-1011-rock5b-hdmi1.patch deleted file mode 100644 index 14177292401f..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1011-rock5b-hdmi1.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: amazingfate -Date: Thu, 26 Dec 2024 21:47:15 +0100 -Subject: [ARCHEOLOGY] rockchip64-6.13: add hdmi1 support to rock5b - -> X-Git-Archeology: - Revision 12bb4ea7dfd695901aba31ae4b5260398c932a17: https://github.com/armbian/build/commit/12bb4ea7dfd695901aba31ae4b5260398c932a17 -> X-Git-Archeology: Date: Thu, 26 Dec 2024 21:47:15 +0100 -> X-Git-Archeology: From: amazingfate -> X-Git-Archeology: Subject: rockchip64-6.13: add hdmi1 support to rock5b -> X-Git-Archeology: ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 44 +++++++++- - 1 file changed, 42 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -49,6 +49,17 @@ hdmi0_con_in: endpoint { - }; - }; - -+ hdmi1-con { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi1_con_in: endpoint { -+ remote-endpoint = <&hdmi1_out_con>; -+ }; -+ }; -+ }; -+ - leds { - compatible = "gpio-leds"; - pinctrl-names = "default"; -@@ -220,10 +231,32 @@ hdmi0_out_con: endpoint { - }; - }; - -+&hdmi1 { -+ pinctrl-0 = <&hdmim0_tx1_cec &hdmim0_tx1_hpd -+ &hdmim1_tx1_scl &hdmim1_tx1_sda>; -+ status = "okay"; -+}; -+ -+&hdmi1_in { -+ hdmi1_in_vp1: endpoint { -+ remote-endpoint = <&vp1_out_hdmi1>; -+ }; -+}; -+ -+&hdmi1_out { -+ hdmi1_out_con: endpoint { -+ remote-endpoint = <&hdmi1_con_in>; -+ }; -+}; -+ - &hdptxphy0 { - status = "okay"; - }; - -+&hdptxphy1 { -+ status = "okay"; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -896,11 +929,11 @@ &usb_host2_xhci { - status = "okay"; - }; - --&vop_mmu { -+&vop { - status = "okay"; - }; - --&vop { -+&vop_mmu { - status = "okay"; - }; - -@@ -910,3 +943,10 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { - remote-endpoint = <&hdmi0_in_vp0>; - }; - }; -+ -+&vp1 { -+ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { -+ reg = ; -+ remote-endpoint = <&hdmi1_in_vp1>; -+ }; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1012-arm64-dts-rockchip-add-hdmi1-support-to-ROCK-5-ITX.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-1012-arm64-dts-rockchip-add-hdmi1-support-to-ROCK-5-ITX.patch deleted file mode 100644 index 4abccfdae932..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1012-arm64-dts-rockchip-add-hdmi1-support-to-ROCK-5-ITX.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jianfeng Liu -Date: Sat, 15 Feb 2025 23:10:42 +0800 -Subject: arm64: dts: rockchip: add hdmi1 support to ROCK 5 ITX - -Enable the HDMI port next to ethernet port. - -Signed-off-by: Jianfeng Liu ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts | 49 ++++++++++ - 1 file changed, 49 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include "dt-bindings/usb/pd.h" - #include "rk3588.dtsi" - -@@ -89,6 +90,17 @@ fan0: pwm-fan { - pwms = <&pwm14 0 10000 0>; - }; - -+ hdmi1-con { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi1_con_in: endpoint { -+ remote-endpoint = <&hdmi1_out_con>; -+ }; -+ }; -+ }; -+ - /* M.2 E-KEY */ - sdio_pwrseq: sdio-pwrseq { - compatible = "mmc-pwrseq-simple"; -@@ -261,6 +273,28 @@ &gpu { - status = "okay"; - }; - -+&hdmi1 { -+ pinctrl-0 = <&hdmim0_tx1_cec &hdmim0_tx1_hpd -+ &hdmim1_tx1_scl &hdmim1_tx1_sda>; -+ status = "okay"; -+}; -+ -+&hdmi1_in { -+ hdmi1_in_vp1: endpoint { -+ remote-endpoint = <&vp1_out_hdmi1>; -+ }; -+}; -+ -+&hdmi1_out { -+ hdmi1_out_con: endpoint { -+ remote-endpoint = <&hdmi1_con_in>; -+ }; -+}; -+ -+&hdptxphy1 { -+ status = "okay"; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -1208,3 +1242,18 @@ &usbdp_phy1 { - rockchip,dp-lane-mux = <2 3>; - status = "okay"; - }; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vp1 { -+ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { -+ reg = ; -+ remote-endpoint = <&hdmi1_in_vp1>; -+ }; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1031-arm64-dts-rockchip-Add-HDMI-support-to-ArmSoM-Sige7.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-1031-arm64-dts-rockchip-Add-HDMI-support-to-ArmSoM-Sige7.patch deleted file mode 100644 index 2906ea40c554..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1031-arm64-dts-rockchip-Add-HDMI-support-to-ArmSoM-Sige7.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jianfeng Liu -Date: Thu, 6 Jun 2024 23:28:01 +0800 -Subject: arm64: dts: rockchip: Add HDMI support to ArmSoM Sige7 - ---- - arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts | 30 ++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -@@ -4,6 +4,7 @@ - - #include - #include -+#include - #include "rk3588.dtsi" - - / { -@@ -164,6 +165,20 @@ &gpu { - status = "okay"; - }; - -+&hdmi0 { -+ status = "okay"; -+}; -+ -+&hdmi0_in { -+ hdmi0_in_vp0: endpoint { -+ remote-endpoint = <&vp0_out_hdmi0>; -+ }; -+}; -+ -+&hdptxphy0 { -+ status = "okay"; -+}; -+ - &i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; -@@ -723,3 +738,18 @@ &usb_host1_xhci { - dr_mode = "host"; - status = "okay"; - }; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&vp0 { -+ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { -+ reg = ; -+ remote-endpoint = <&hdmi0_in_vp0>; -+ }; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1032-arm64-dts-rockchip-Add-ap6275p-wireless-support-to-A.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-1032-arm64-dts-rockchip-Add-ap6275p-wireless-support-to-A.patch deleted file mode 100644 index 3cfaee0136b2..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1032-arm64-dts-rockchip-Add-ap6275p-wireless-support-to-A.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jianfeng Liu -Date: Thu, 6 Jun 2024 23:29:39 +0800 -Subject: arm64: dts: rockchip: Add ap6275p wireless support to ArmSoM Sige7 - ---- - arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts | 16 ++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts -@@ -283,6 +283,22 @@ &pcie2x1l0 { - &pcie2x1l1 { - reset-gpios = <&gpio3 RK_PD4 GPIO_ACTIVE_HIGH>; - status = "okay"; -+ -+ pcie@0,0 { -+ reg = <0x300000 0 0 0 0>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges; -+ device_type = "pci"; -+ bus-range = <0x30 0x3f>; -+ -+ wifi: wifi@0,0 { -+ compatible = "pci14e4,449d"; -+ reg = <0x310000 0 0 0 0>; -+ clocks = <&hym8563>; -+ clock-names = "lpo"; -+ }; -+ }; - }; - - /* phy0 - left ethernet port */ --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1071-arm64-dts-Add-missing-nodes-to-Orange-Pi-5-Plus.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-1071-arm64-dts-Add-missing-nodes-to-Orange-Pi-5-Plus.patch deleted file mode 100644 index e813522347bb..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1071-arm64-dts-Add-missing-nodes-to-Orange-Pi-5-Plus.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Muhammed Efe Cetin -Date: Tue, 10 Dec 2024 21:10:02 +0300 -Subject: arm64: dts: rockchip: mark led as heartbeat indicator for Orange Pi - 5+ - ---- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi -@@ -93,7 +93,7 @@ led_blue_pwm: led-1 { - - led_green_pwm: led-2 { - color = ; -- function = LED_FUNCTION_INDICATOR; -+ function = LED_FUNCTION_HEARTBEAT; - function-enumerator = <2>; - max-brightness = <255>; - }; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Muhammed Efe Cetin -Date: Tue, 10 Dec 2024 21:11:02 +0300 -Subject: arm64: dts: rockchip: add bluetooth rfkill node for Orange Pi 5+ - ---- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -@@ -238,6 +238,13 @@ ir_receiver_pin: ir-receiver-pin { - }; - }; - -+ rfkill-bt { -+ compatible = "rfkill-gpio"; -+ label = "rfkill-m2-bt"; -+ radio-type = "bluetooth"; -+ shutdown-gpios = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; -+ }; -+ - sound { - hp_detect: hp-detect { - rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Muhammed Efe Cetin -Date: Tue, 10 Dec 2024 21:11:43 +0300 -Subject: arm64: dts: rockchip: fix hym8563 pinctrl for Orange Pi 5+ - ---- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -@@ -222,7 +222,7 @@ &pcie2x1l2 { - &pinctrl { - hym8563 { - hym8563_int: hym8563-int { -- rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; -+ rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - --- -Armbian - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Muhammed Efe Cetin -Date: Thu, 26 Dec 2024 23:45:39 +0300 -Subject: arm64: dts: rockchip: add support for HDMI1 port to OPi5+ - ---- - arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts | 38 ++++++++++ - 1 file changed, 38 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts -@@ -26,6 +26,17 @@ hdmi0_con_in: endpoint { - }; - }; - -+ hdmi1-con { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi1_con_in: endpoint { -+ remote-endpoint = <&hdmi1_out_con>; -+ }; -+ }; -+ }; -+ - ir-receiver { - compatible = "gpio-ir-receiver"; - gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>; -@@ -125,10 +136,30 @@ hdmi0_out_con: endpoint { - }; - }; - -+&hdmi1 { -+ status = "okay"; -+}; -+ -+&hdmi1_in { -+ hdmi1_in_vp1: endpoint { -+ remote-endpoint = <&vp1_out_hdmi1>; -+ }; -+}; -+ -+&hdmi1_out { -+ hdmi1_out_con: endpoint { -+ remote-endpoint = <&hdmi1_con_in>; -+ }; -+}; -+ - &hdptxphy0 { - status = "okay"; - }; - -+&hdptxphy1 { -+ status = "okay"; -+}; -+ - &hym8563 { - interrupt-parent = <&gpio0>; - interrupts = ; -@@ -349,3 +380,10 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { - remote-endpoint = <&hdmi0_in_vp0>; - }; - }; -+ -+&vp1 { -+ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { -+ reg = ; -+ remote-endpoint = <&hdmi1_in_vp1>; -+ }; -+}; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1090-arm64-dts-rockchip-Add-HDMI-RX-config-to-FriendlyElec-CM3588.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-1090-arm64-dts-rockchip-Add-HDMI-RX-config-to-FriendlyElec-CM3588.patch deleted file mode 100644 index 33dd1daa9474..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1090-arm64-dts-rockchip-Add-HDMI-RX-config-to-FriendlyElec-CM3588.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tim Surber -Date: Fri, 3 Jan 2025 23:12:26 +0100 -Subject: Add HDMI-RX configuration for friendlyelec-cm3588 - -Signed-off-by: Tim Surber ---- - arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts | 14 ++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts -@@ -101,6 +101,13 @@ hdmi0_con_in: endpoint { - }; - }; - -+ hdmi_receiver@fdee0000 { -+ compatible = "rockchip,rk3588-hdmirx-ctrler", "snps,dw-hdmi-rx"; -+ power-domains = <&power RK3588_PD_VO1>; -+ pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>; -+ hpd-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>; -+ }; -+ - ir-receiver { - compatible = "gpio-ir-receiver"; - gpios = <&gpio0 RK_PD4 GPIO_ACTIVE_LOW>; -@@ -478,6 +485,13 @@ key1_pin: key1-pin { - }; - }; - -+ -+ hdmirx { -+ hdmirx_hpd: hdmirx-5v-detection { -+ rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - pcie { - pcie2_0_rst: pcie2-0-rst { - rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1102-arm64-dts-rockchip-Rock-5B-add-hdmi-sound.patch b/patch/kernel/archive/rockchip64-6.14/rk3588-1102-arm64-dts-rockchip-Rock-5B-add-hdmi-sound.patch deleted file mode 100644 index fc3c04f36b5d..000000000000 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1102-arm64-dts-rockchip-Rock-5B-add-hdmi-sound.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aleksey Komarov -Date: Sat, 8 Mar 2025 19:43:05 +0100 -Subject: [ARCHEOLOGY] Enable HDMI audio outputs for Rock 5B by - detlev.casanova@collabora.com - -> X-Git-Archeology: > recovered message: > https://lore.kernel.org/all/20250217215641.372723-4-detlev.casanova@collabora.com/ -> X-Git-Archeology: - Revision bf9ffa6eedd5df804e3f9a86c84e00607289cd59: https://github.com/armbian/build/commit/bf9ffa6eedd5df804e3f9a86c84e00607289cd59 -> X-Git-Archeology: Date: Sat, 08 Mar 2025 19:43:05 +0100 -> X-Git-Archeology: From: Aleksey Komarov -> X-Git-Archeology: Subject: Enable HDMI audio outputs for Rock 5B by detlev.casanova@collabora.com -> X-Git-Archeology: ---- - arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts | 16 ++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -index 111111111111..222222222222 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -231,6 +231,10 @@ hdmi0_out_con: endpoint { - }; - }; - -+&hdmi0_sound { -+ status = "okay"; -+}; -+ - &hdmi1 { - pinctrl-0 = <&hdmim0_tx1_cec &hdmim0_tx1_hpd - &hdmim1_tx1_scl &hdmim1_tx1_sda>; -@@ -249,6 +253,10 @@ hdmi1_out_con: endpoint { - }; - }; - -+&hdmi1_sound { -+ status = "okay"; -+}; -+ - &hdptxphy0 { - status = "okay"; - }; -@@ -351,6 +359,14 @@ i2s0_8ch_p0_0: endpoint { - }; - }; - -+&i2s5_8ch { -+ status = "okay"; -+}; -+ -+&i2s6_8ch { -+ status = "okay"; -+}; -+ - &package_thermal { - polling-delay = <1000>; - --- -Armbian - diff --git a/patch/kernel/archive/rockchip64-6.14/0000.patching_config.yaml b/patch/kernel/archive/rockchip64-6.15/0000.patching_config.yaml similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/0000.patching_config.yaml rename to patch/kernel/archive/rockchip64-6.15/0000.patching_config.yaml diff --git a/patch/kernel/archive/rockchip64-6.14/add-board-fine3399-dts.patch b/patch/kernel/archive/rockchip64-6.15/add-board-fine3399-dts.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/add-board-fine3399-dts.patch rename to patch/kernel/archive/rockchip64-6.15/add-board-fine3399-dts.patch diff --git a/patch/kernel/archive/rockchip64-6.14/add-board-helios64.patch b/patch/kernel/archive/rockchip64-6.15/add-board-helios64.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/add-board-helios64.patch rename to patch/kernel/archive/rockchip64-6.15/add-board-helios64.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-firefly-rk3399-dts.patch b/patch/kernel/archive/rockchip64-6.15/board-firefly-rk3399-dts.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-firefly-rk3399-dts.patch rename to patch/kernel/archive/rockchip64-6.15/board-firefly-rk3399-dts.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-helios64-dts-fix-stability-issues.patch b/patch/kernel/archive/rockchip64-6.15/board-helios64-dts-fix-stability-issues.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-helios64-dts-fix-stability-issues.patch rename to patch/kernel/archive/rockchip64-6.15/board-helios64-dts-fix-stability-issues.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-helios64-remove-pcie-ep-gpios.patch b/patch/kernel/archive/rockchip64-6.15/board-helios64-remove-pcie-ep-gpios.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-helios64-remove-pcie-ep-gpios.patch rename to patch/kernel/archive/rockchip64-6.15/board-helios64-remove-pcie-ep-gpios.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-nanopc-t4-add-typec-dp.patch b/patch/kernel/archive/rockchip64-6.15/board-nanopc-t4-add-typec-dp.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-nanopc-t4-add-typec-dp.patch rename to patch/kernel/archive/rockchip64-6.15/board-nanopc-t4-add-typec-dp.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-nanopi-m4v2-dts-add-sound-card.patch b/patch/kernel/archive/rockchip64-6.15/board-nanopi-m4v2-dts-add-sound-card.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-nanopi-m4v2-dts-add-sound-card.patch rename to patch/kernel/archive/rockchip64-6.15/board-nanopi-m4v2-dts-add-sound-card.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-nanopi-r2c-plus.patch b/patch/kernel/archive/rockchip64-6.15/board-nanopi-r2c-plus.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-nanopi-r2c-plus.patch rename to patch/kernel/archive/rockchip64-6.15/board-nanopi-r2c-plus.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-nanopi-r2s.patch b/patch/kernel/archive/rockchip64-6.15/board-nanopi-r2s.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-nanopi-r2s.patch rename to patch/kernel/archive/rockchip64-6.15/board-nanopi-r2s.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-nanopi-r3s-fix-leds.patch b/patch/kernel/archive/rockchip64-6.15/board-nanopi-r3s-fix-leds.patch similarity index 94% rename from patch/kernel/archive/rockchip64-6.14/board-nanopi-r3s-fix-leds.patch rename to patch/kernel/archive/rockchip64-6.15/board-nanopi-r3s-fix-leds.patch index f7639fe2de9a..281c2735d20a 100644 --- a/patch/kernel/archive/rockchip64-6.14/board-nanopi-r3s-fix-leds.patch +++ b/patch/kernel/archive/rockchip64-6.15/board-nanopi-r3s-fix-leds.patch @@ -123,7 +123,7 @@ index 111111111111..222222222222 100644 #include #include #include -@@ -2436,6 +2437,15 @@ void r8169_apply_firmware(struct rtl8169_private *tp) +@@ -2438,6 +2439,15 @@ void r8169_apply_firmware(struct rtl8169_private *tp) } } @@ -139,7 +139,7 @@ index 111111111111..222222222222 100644 static void rtl8168_config_eee_mac(struct rtl8169_private *tp) { /* Adjust EEE LED frequency */ -@@ -3421,6 +3431,7 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp) +@@ -3449,6 +3459,7 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp) rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); rtl8168_config_eee_mac(tp); @@ -151,7 +151,7 @@ diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/re index 111111111111..222222222222 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -125,6 +125,15 @@ static int rtl821x_write_page(struct phy_device *phydev, int page) +@@ -135,6 +135,15 @@ static int rtl821x_write_page(struct phy_device *phydev, int page) return __phy_write(phydev, RTL821x_PAGE_SELECT, page); } @@ -167,9 +167,9 @@ index 111111111111..222222222222 100644 static int rtl821x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; -@@ -444,6 +453,8 @@ static int rtl8211f_config_init(struct phy_device *phydev) - val_rxdly ? "enabled" : "disabled"); - } +@@ -460,6 +469,8 @@ static int rtl8211f_config_init(struct phy_device *phydev) + if (ret) + return ret; + rtl821x_led_of_init(phydev); + diff --git a/patch/kernel/archive/rockchip64-6.14/board-nanopi-r4s-pwmfan.patch b/patch/kernel/archive/rockchip64-6.15/board-nanopi-r4s-pwmfan.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-nanopi-r4s-pwmfan.patch rename to patch/kernel/archive/rockchip64-6.15/board-nanopi-r4s-pwmfan.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-odroidm1-add-nodes-for-i2c-pwm-uart-spi.patch b/patch/kernel/archive/rockchip64-6.15/board-odroidm1-add-nodes-for-i2c-pwm-uart-spi.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-odroidm1-add-nodes-for-i2c-pwm-uart-spi.patch rename to patch/kernel/archive/rockchip64-6.15/board-odroidm1-add-nodes-for-i2c-pwm-uart-spi.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-odroidm2-fix-for-ethernet.patch b/patch/kernel/archive/rockchip64-6.15/board-odroidm2-fix-for-ethernet.patch similarity index 97% rename from patch/kernel/archive/rockchip64-6.14/board-odroidm2-fix-for-ethernet.patch rename to patch/kernel/archive/rockchip64-6.15/board-odroidm2-fix-for-ethernet.patch index eab9a256d7b3..92f694552e6d 100644 --- a/patch/kernel/archive/rockchip64-6.14/board-odroidm2-fix-for-ethernet.patch +++ b/patch/kernel/archive/rockchip64-6.15/board-odroidm2-fix-for-ethernet.patch @@ -46,7 +46,7 @@ index 111111111111..222222222222 100644 reset-assert-us = <20000>; reset-deassert-us = <100000>; reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; -@@ -475,6 +479,12 @@ pcf8563_int: pcf8563-int { +@@ -479,6 +483,12 @@ pcf8563_int: pcf8563-int { }; }; diff --git a/patch/kernel/archive/rockchip64-6.14/board-orangepi-r1-plus.patch b/patch/kernel/archive/rockchip64-6.15/board-orangepi-r1-plus.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-orangepi-r1-plus.patch rename to patch/kernel/archive/rockchip64-6.15/board-orangepi-r1-plus.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-orangepi-rk3399-pcie.patch b/patch/kernel/archive/rockchip64-6.15/board-orangepi-rk3399-pcie.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-orangepi-rk3399-pcie.patch rename to patch/kernel/archive/rockchip64-6.15/board-orangepi-rk3399-pcie.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-orangepi3b-add-uwe5622-wifi-bt-nodes.patch b/patch/kernel/archive/rockchip64-6.15/board-orangepi3b-add-uwe5622-wifi-bt-nodes.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-orangepi3b-add-uwe5622-wifi-bt-nodes.patch rename to patch/kernel/archive/rockchip64-6.15/board-orangepi3b-add-uwe5622-wifi-bt-nodes.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-pbp-add-dp-alt-mode.patch b/patch/kernel/archive/rockchip64-6.15/board-pbp-add-dp-alt-mode.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-pbp-add-dp-alt-mode.patch rename to patch/kernel/archive/rockchip64-6.15/board-pbp-add-dp-alt-mode.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-radxa-e25-sdmmc0-fix.patch b/patch/kernel/archive/rockchip64-6.15/board-radxa-e25-sdmmc0-fix.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-radxa-e25-sdmmc0-fix.patch rename to patch/kernel/archive/rockchip64-6.15/board-radxa-e25-sdmmc0-fix.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-radxa-e25-usb3-and-emmc-fix.patch b/patch/kernel/archive/rockchip64-6.15/board-radxa-e25-usb3-and-emmc-fix.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-radxa-e25-usb3-and-emmc-fix.patch rename to patch/kernel/archive/rockchip64-6.15/board-radxa-e25-usb3-and-emmc-fix.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-cc-dts-enable-dmc.patch b/patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-cc-dts-enable-dmc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-cc-dts-enable-dmc.patch rename to patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-cc-dts-enable-dmc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-cc-dts-ram-profile.patch b/patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-cc-dts-ram-profile.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-cc-dts-ram-profile.patch rename to patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-cc-dts-ram-profile.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-pc-dts-ram-profile.patch b/patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-pc-dts-ram-profile.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-pc-dts-ram-profile.patch rename to patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-pc-dts-ram-profile.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-pc.patch b/patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-pc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rk3328-roc-pc.patch rename to patch/kernel/archive/rockchip64-6.15/board-rk3328-roc-pc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rock3a-0001-emmc-sfc.patch b/patch/kernel/archive/rockchip64-6.15/board-rock3a-0001-emmc-sfc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rock3a-0001-emmc-sfc.patch rename to patch/kernel/archive/rockchip64-6.15/board-rock3a-0001-emmc-sfc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rock3a-0002-usb3.patch b/patch/kernel/archive/rockchip64-6.15/board-rock3a-0002-usb3.patch similarity index 98% rename from patch/kernel/archive/rockchip64-6.14/board-rock3a-0002-usb3.patch rename to patch/kernel/archive/rockchip64-6.15/board-rock3a-0002-usb3.patch index a49f809ba96e..25b42996fea1 100644 --- a/patch/kernel/archive/rockchip64-6.14/board-rock3a-0002-usb3.patch +++ b/patch/kernel/archive/rockchip64-6.15/board-rock3a-0002-usb3.patch @@ -31,7 +31,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts b/arch/arm64/boot/d index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts -@@ -819,6 +819,7 @@ &usb_host0_ohci { +@@ -805,6 +805,7 @@ &usb_host0_ohci { &usb_host0_xhci { extcon = <&usb2phy0>; diff --git a/patch/kernel/archive/rockchip64-6.14/board-rock3a-0003-add-gpio-names.patch b/patch/kernel/archive/rockchip64-6.15/board-rock3a-0003-add-gpio-names.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rock3a-0003-add-gpio-names.patch rename to patch/kernel/archive/rockchip64-6.15/board-rock3a-0003-add-gpio-names.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rock64-mail-supply.patch b/patch/kernel/archive/rockchip64-6.15/board-rock64-mail-supply.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rock64-mail-supply.patch rename to patch/kernel/archive/rockchip64-6.15/board-rock64-mail-supply.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpi3-enable-dmc.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpi3-enable-dmc.patch similarity index 98% rename from patch/kernel/archive/rockchip64-6.14/board-rockpi3-enable-dmc.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpi3-enable-dmc.patch index 1b1b0a0b12ff..45978089d1f1 100644 --- a/patch/kernel/archive/rockchip64-6.14/board-rockpi3-enable-dmc.patch +++ b/patch/kernel/archive/rockchip64-6.15/board-rockpi3-enable-dmc.patch @@ -29,7 +29,7 @@ index 111111111111..222222222222 100644 / { model = "Radxa ROCK Pi E"; -@@ -440,3 +441,9 @@ &usbdrd3 { +@@ -448,3 +449,9 @@ &usbdrd3 { &usb_host0_ehci { status = "okay"; }; diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpi4-0003-arm64-dts-pcie.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpi4-0003-arm64-dts-pcie.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpi4-0003-arm64-dts-pcie.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpi4-0003-arm64-dts-pcie.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpie-0001-arm64-dts-rockchip-fix-gmac-PHY-attach-error.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpie-0001-arm64-dts-rockchip-fix-gmac-PHY-attach-error.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpie-0001-arm64-dts-rockchip-fix-gmac-PHY-attach-error.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpie-0001-arm64-dts-rockchip-fix-gmac-PHY-attach-error.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpis-dts-fixes.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpis-dts-fixes.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpis-dts-fixes.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpis-dts-fixes.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpro64-0001-Add-pcie-bus-scan-delay.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpro64-0001-Add-pcie-bus-scan-delay.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpro64-0001-Add-pcie-bus-scan-delay.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpro64-0001-Add-pcie-bus-scan-delay.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpro64-change-rx_delay-for-gmac.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpro64-change-rx_delay-for-gmac.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpro64-change-rx_delay-for-gmac.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpro64-change-rx_delay-for-gmac.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpro64-fix-emmc.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpro64-fix-emmc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpro64-fix-emmc.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpro64-fix-emmc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpro64-fix-spi1-flash-speed.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpro64-fix-spi1-flash-speed.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpro64-fix-spi1-flash-speed.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpro64-fix-spi1-flash-speed.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rockpro64-work-led-heartbeat.patch b/patch/kernel/archive/rockchip64-6.15/board-rockpro64-work-led-heartbeat.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rockpro64-work-led-heartbeat.patch rename to patch/kernel/archive/rockchip64-6.15/board-rockpro64-work-led-heartbeat.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rocks0-0001-Revert-arm64-dts-rockchip-Fix-sdmmc-access-on-rk3308.patch b/patch/kernel/archive/rockchip64-6.15/board-rocks0-0001-Revert-arm64-dts-rockchip-Fix-sdmmc-access-on-rk3308.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rocks0-0001-Revert-arm64-dts-rockchip-Fix-sdmmc-access-on-rk3308.patch rename to patch/kernel/archive/rockchip64-6.15/board-rocks0-0001-Revert-arm64-dts-rockchip-Fix-sdmmc-access-on-rk3308.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-rocks0-0001-deviceTree.patch b/patch/kernel/archive/rockchip64-6.15/board-rocks0-0001-deviceTree.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-rocks0-0001-deviceTree.patch rename to patch/kernel/archive/rockchip64-6.15/board-rocks0-0001-deviceTree.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-station-m2.patch b/patch/kernel/archive/rockchip64-6.15/board-station-m2.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-station-m2.patch rename to patch/kernel/archive/rockchip64-6.15/board-station-m2.patch diff --git a/patch/kernel/archive/rockchip64-6.14/board-station-p2.patch b/patch/kernel/archive/rockchip64-6.15/board-station-p2.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/board-station-p2.patch rename to patch/kernel/archive/rockchip64-6.15/board-station-p2.patch diff --git a/patch/kernel/archive/rockchip64-6.14/drv-spi-spidev-remove-warnings.patch b/patch/kernel/archive/rockchip64-6.15/drv-spi-spidev-remove-warnings.patch similarity index 94% rename from patch/kernel/archive/rockchip64-6.14/drv-spi-spidev-remove-warnings.patch rename to patch/kernel/archive/rockchip64-6.15/drv-spi-spidev-remove-warnings.patch index 8df49aaee344..d17cdadc1dd3 100644 --- a/patch/kernel/archive/rockchip64-6.14/drv-spi-spidev-remove-warnings.patch +++ b/patch/kernel/archive/rockchip64-6.15/drv-spi-spidev-remove-warnings.patch @@ -20,7 +20,7 @@ index 111111111111..222222222222 100644 { .name = /* cisco */ "spi-petra" }, { .name = /* dh */ "dhcom-board" }, { .name = /* elgin */ "jg10309-01" }, -@@ -734,6 +735,7 @@ static int spidev_of_check(struct device *dev) +@@ -735,6 +736,7 @@ static int spidev_of_check(struct device *dev) } static const struct of_device_id spidev_dt_ids[] = { diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3308-sakurapi-rk3308b.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3308-sakurapi-rk3308b.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3308-sakurapi-rk3308b.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3308-sakurapi-rk3308b.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3318-box.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3318-box.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3318-box.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3318-box.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-heltec.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-heltec.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-heltec.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-heltec.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-mksklipad50.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-mksklipad50.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-mksklipad50.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-mksklipad50.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-mkspi.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-mkspi.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-mkspi.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-mkspi.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-neo3-rev02.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-neo3-rev02.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-neo3-rev02.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-neo3-rev02.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2-rev00.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2-rev00.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2-rev00.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2-rev00.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2-rev06.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2-rev06.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2-rev06.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2-rev06.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2-rev20.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2-rev20.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2-rev20.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2-rev20.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2s-plus-rev00.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2s-plus-rev00.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-nanopi-r2s-plus-rev00.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-nanopi-r2s-plus-rev00.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3328-z28pro.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3328-z28pro.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3328-z28pro.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3328-z28pro.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-am40.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-am40.dts similarity index 97% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-am40.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-am40.dts index 9c402bc137e1..a9f293851c35 100644 --- a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-am40.dts +++ b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-am40.dts @@ -18,6 +18,7 @@ ethernet0 = &gmac; mmc0 = &sdhci; mmc1 = &sdmmc; + rtc0 = &pt7c4563; /* * The rk808 circuit design on this board does not have the ability to maintain real-time time after a power outage. * Registering rk808 as rtc99 (most kernel configurations read time from rtc0) can prevent the kernel from reading the time (2013) from rk808 during startup. @@ -499,6 +500,20 @@ &i2c4 { status = "okay"; + i2c-scl-rising-time-ns = <300>; + i2c-scl-falling-time-ns = <300>; + + pt7c4563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "rtc_xin32k"; + wakeup-source; + interrupt-parent = <&gpio0>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&rtc_int>; + pinctrl-names = "default"; + }; }; &i2s2 { @@ -583,6 +598,12 @@ }; }; + rtc { + rtc_int: rtc-int { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + usb2 { vcc5v0_host_en: vcc5v0-hots-en { rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-nanopi-m4v2.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-nanopi-m4v2.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-nanopi-m4v2.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-nanopi-m4v2.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-nanopi-r4se.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-nanopi-r4se.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-nanopi-r4se.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-nanopi-r4se.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4-lts.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-orangepi-4-lts.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4-lts.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-orangepi-4-lts.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-orangepi-4.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-orangepi-4.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-rock-pi-4.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-rock-pi-4.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-rock-pi-4.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-rock-pi-4.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-tinker-2.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-tinker-2.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-tinker-2.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-tinker-2.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-xiaobao-nas.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3399-xiaobao-nas.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3399-xiaobao-nas.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3399-xiaobao-nas.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3566-h96-tvbox.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3566-h96-tvbox.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3566-h96-tvbox.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3566-h96-tvbox.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3566-jp-tvbox.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3566-jp-tvbox.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3566-jp-tvbox.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3566-jp-tvbox.dts diff --git a/patch/kernel/archive/rockchip64-6.15/dt/rk3566-nanopi-r3s-lts.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3566-nanopi-r3s-lts.dts new file mode 100644 index 000000000000..e3305f4044db --- /dev/null +++ b/patch/kernel/archive/rockchip64-6.15/dt/rk3566-nanopi-r3s-lts.dts @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * Copyright (c) 2024 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyelec.com) + */ + +/dts-v1/; + +#include "rk3566-nanopi-r3s.dts" + +/ { + compatible = "friendlyarm,nanopi-r3s-lts", "rockchip,rk3566"; + model = "FriendlyElec NanoPi R3S LTS"; + + hdmi-con { + compatible = "hdmi-connector"; + type = "d"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; +}; + +&hdmi { + avdd-0v9-supply = <&vdda_0v9>; + avdd-1v8-supply = <&vcca1v8_image>; + status = "okay"; +}; + +&hdmi_in { + hdmi_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi>; + }; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdmi_sound { + status = "okay"; +}; + +&i2s0_8ch { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi_in_vp0>; + }; +}; diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3566-panther-x2.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3566-panther-x2.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3566-panther-x2.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3566-panther-x2.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3568-hinlink-h66k.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3568-hinlink-h66k.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3568-hinlink-h66k.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3568-hinlink-h66k.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3568-hinlink-h68k.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3568-hinlink-h68k.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3568-hinlink-h68k.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3568-hinlink-h68k.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3568-hinlink-hnas.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3568-hinlink-hnas.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3568-hinlink-hnas.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3568-hinlink-hnas.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3568-mixtile-edge2.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3568-mixtile-edge2.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3568-mixtile-edge2.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3568-mixtile-edge2.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3568-yy3568.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3568-yy3568.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3568-yy3568.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3568-yy3568.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3588-bananapi-m7.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3588-bananapi-m7.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3588-bananapi-m7.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3588-bananapi-m7.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3588-cyber-aib.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3588-cyber-aib.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3588-cyber-aib.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3588-cyber-aib.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3588-hinlink-h88k.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3588-hinlink-h88k.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3588-hinlink-h88k.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3588-hinlink-h88k.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3588-mixtile-blade3.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3588-mixtile-blade3.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3588-mixtile-blade3.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3588-mixtile-blade3.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3588-rock-5b-plus.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3588-rock-5b-plus.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3588-rock-5b-plus.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3588-rock-5b-plus.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3588s-nanopi-m6.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3588s-nanopi-m6.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3588s-nanopi-m6.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3588s-nanopi-m6.dts diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3588s-youyeetoo-r1.dts b/patch/kernel/archive/rockchip64-6.15/dt/rk3588s-youyeetoo-r1.dts similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/dt/rk3588s-youyeetoo-r1.dts rename to patch/kernel/archive/rockchip64-6.15/dt/rk3588s-youyeetoo-r1.dts diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-hdmi-mks-ips50-resolutions.patch b/patch/kernel/archive/rockchip64-6.15/general-add-hdmi-mks-ips50-resolutions.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-add-hdmi-mks-ips50-resolutions.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-hdmi-mks-ips50-resolutions.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-miniDP-dt-doc.patch b/patch/kernel/archive/rockchip64-6.15/general-add-miniDP-dt-doc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-add-miniDP-dt-doc.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-miniDP-dt-doc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-miniDP-virtual-extcon.patch b/patch/kernel/archive/rockchip64-6.15/general-add-miniDP-virtual-extcon.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-add-miniDP-virtual-extcon.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-miniDP-virtual-extcon.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-overlay-compilation-support.patch b/patch/kernel/archive/rockchip64-6.15/general-add-overlay-compilation-support.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-add-overlay-compilation-support.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-overlay-compilation-support.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-overlay-configfs.patch b/patch/kernel/archive/rockchip64-6.15/general-add-overlay-configfs.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-add-overlay-configfs.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-overlay-configfs.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-panel-simple-dsi.patch b/patch/kernel/archive/rockchip64-6.15/general-add-panel-simple-dsi.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-add-panel-simple-dsi.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-panel-simple-dsi.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-pll-hdmi-timings.patch b/patch/kernel/archive/rockchip64-6.15/general-add-pll-hdmi-timings.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-add-pll-hdmi-timings.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-pll-hdmi-timings.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-add-xtx-spi-nor-chips.patch b/patch/kernel/archive/rockchip64-6.15/general-add-xtx-spi-nor-chips.patch similarity index 97% rename from patch/kernel/archive/rockchip64-6.14/general-add-xtx-spi-nor-chips.patch rename to patch/kernel/archive/rockchip64-6.15/general-add-xtx-spi-nor-chips.patch index 4513e8ce4f03..4a0b9251b235 100644 --- a/patch/kernel/archive/rockchip64-6.14/general-add-xtx-spi-nor-chips.patch +++ b/patch/kernel/archive/rockchip64-6.15/general-add-xtx-spi-nor-chips.patch @@ -30,7 +30,7 @@ diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 111111111111..222222222222 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c -@@ -1981,6 +1981,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = { +@@ -1954,6 +1954,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_sst, &spi_nor_winbond, &spi_nor_xmc, diff --git a/patch/kernel/archive/rockchip64-6.14/general-clk-rockchip-rk3568-Add-PLL-rate-for-33.3MHz.patch b/patch/kernel/archive/rockchip64-6.15/general-clk-rockchip-rk3568-Add-PLL-rate-for-33.3MHz.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-clk-rockchip-rk3568-Add-PLL-rate-for-33.3MHz.patch rename to patch/kernel/archive/rockchip64-6.15/general-clk-rockchip-rk3568-Add-PLL-rate-for-33.3MHz.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-cryptov1-trng.patch b/patch/kernel/archive/rockchip64-6.15/general-cryptov1-trng.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-cryptov1-trng.patch rename to patch/kernel/archive/rockchip64-6.15/general-cryptov1-trng.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-disable-mtu-validation.patch b/patch/kernel/archive/rockchip64-6.15/general-disable-mtu-validation.patch similarity index 96% rename from patch/kernel/archive/rockchip64-6.14/general-disable-mtu-validation.patch rename to patch/kernel/archive/rockchip64-6.15/general-disable-mtu-validation.patch index a350a44e6aa4..20a154c9d163 100644 --- a/patch/kernel/archive/rockchip64-6.14/general-disable-mtu-validation.patch +++ b/patch/kernel/archive/rockchip64-6.15/general-disable-mtu-validation.patch @@ -18,7 +18,7 @@ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/eth index 111111111111..222222222222 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -5878,27 +5878,15 @@ static void stmmac_set_rx_mode(struct net_device *dev) +@@ -5921,27 +5921,15 @@ static void stmmac_set_rx_mode(struct net_device *dev) static int stmmac_change_mtu(struct net_device *dev, int new_mtu) { struct stmmac_priv *priv = netdev_priv(dev); diff --git a/patch/kernel/archive/rockchip64-6.14/general-driver-tm16xx-led-driver.patch b/patch/kernel/archive/rockchip64-6.15/general-driver-tm16xx-led-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-driver-tm16xx-led-driver.patch rename to patch/kernel/archive/rockchip64-6.15/general-driver-tm16xx-led-driver.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-drm-rockchip-Set-dma-mask-to-64-bit.patch b/patch/kernel/archive/rockchip64-6.15/general-drm-rockchip-Set-dma-mask-to-64-bit.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-drm-rockchip-Set-dma-mask-to-64-bit.patch rename to patch/kernel/archive/rockchip64-6.15/general-drm-rockchip-Set-dma-mask-to-64-bit.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-fix-es8316-kernel-panic.patch b/patch/kernel/archive/rockchip64-6.15/general-fix-es8316-kernel-panic.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-fix-es8316-kernel-panic.patch rename to patch/kernel/archive/rockchip64-6.15/general-fix-es8316-kernel-panic.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-fix-mmc-signal-voltage-before-reboot.patch b/patch/kernel/archive/rockchip64-6.15/general-fix-mmc-signal-voltage-before-reboot.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-fix-mmc-signal-voltage-before-reboot.patch rename to patch/kernel/archive/rockchip64-6.15/general-fix-mmc-signal-voltage-before-reboot.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-hdmi-clock-fixes.patch b/patch/kernel/archive/rockchip64-6.15/general-hdmi-clock-fixes.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-hdmi-clock-fixes.patch rename to patch/kernel/archive/rockchip64-6.15/general-hdmi-clock-fixes.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-increase-spdif-dma-burst.patch b/patch/kernel/archive/rockchip64-6.15/general-increase-spdif-dma-burst.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-increase-spdif-dma-burst.patch rename to patch/kernel/archive/rockchip64-6.15/general-increase-spdif-dma-burst.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-increasing_DMA_block_memory_allocation_to_2048.patch b/patch/kernel/archive/rockchip64-6.15/general-increasing_DMA_block_memory_allocation_to_2048.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-increasing_DMA_block_memory_allocation_to_2048.patch rename to patch/kernel/archive/rockchip64-6.15/general-increasing_DMA_block_memory_allocation_to_2048.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-pl330-01-fix-periodic-transfers.patch b/patch/kernel/archive/rockchip64-6.15/general-pl330-01-fix-periodic-transfers.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-pl330-01-fix-periodic-transfers.patch rename to patch/kernel/archive/rockchip64-6.15/general-pl330-01-fix-periodic-transfers.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-pl330-02-add-support-for-interleaved-transfers.patch b/patch/kernel/archive/rockchip64-6.15/general-pl330-02-add-support-for-interleaved-transfers.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-pl330-02-add-support-for-interleaved-transfers.patch rename to patch/kernel/archive/rockchip64-6.15/general-pl330-02-add-support-for-interleaved-transfers.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-pl330-04-bigger-mcode-buffer.patch b/patch/kernel/archive/rockchip64-6.15/general-pl330-04-bigger-mcode-buffer.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-pl330-04-bigger-mcode-buffer.patch rename to patch/kernel/archive/rockchip64-6.15/general-pl330-04-bigger-mcode-buffer.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-pl330-05-fix-unbalanced-power-down.patch b/patch/kernel/archive/rockchip64-6.15/general-pl330-05-fix-unbalanced-power-down.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-pl330-05-fix-unbalanced-power-down.patch rename to patch/kernel/archive/rockchip64-6.15/general-pl330-05-fix-unbalanced-power-down.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-pl330-06-fix-buffer-underruns.patch b/patch/kernel/archive/rockchip64-6.15/general-pl330-06-fix-buffer-underruns.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-pl330-06-fix-buffer-underruns.patch rename to patch/kernel/archive/rockchip64-6.15/general-pl330-06-fix-buffer-underruns.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-possibility-of-disabling-rk808-rtc.patch b/patch/kernel/archive/rockchip64-6.15/general-possibility-of-disabling-rk808-rtc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-possibility-of-disabling-rk808-rtc.patch rename to patch/kernel/archive/rockchip64-6.15/general-possibility-of-disabling-rk808-rtc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-rk3328-dtsi-trb-ent-quirk.patch b/patch/kernel/archive/rockchip64-6.15/general-rk3328-dtsi-trb-ent-quirk.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-rk3328-dtsi-trb-ent-quirk.patch rename to patch/kernel/archive/rockchip64-6.15/general-rk3328-dtsi-trb-ent-quirk.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-rk808-configurable-switch-voltage-steps.patch b/patch/kernel/archive/rockchip64-6.15/general-rk808-configurable-switch-voltage-steps.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-rk808-configurable-switch-voltage-steps.patch rename to patch/kernel/archive/rockchip64-6.15/general-rk808-configurable-switch-voltage-steps.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-rockchip-overlays.patch b/patch/kernel/archive/rockchip64-6.15/general-rockchip-overlays.patch similarity index 92% rename from patch/kernel/archive/rockchip64-6.14/general-rockchip-overlays.patch rename to patch/kernel/archive/rockchip64-6.15/general-rockchip-overlays.patch index a7fdef6a25fc..21ee72530c4a 100644 --- a/patch/kernel/archive/rockchip64-6.14/general-rockchip-overlays.patch +++ b/patch/kernel/archive/rockchip64-6.15/general-rockchip-overlays.patch @@ -13,7 +13,7 @@ diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 111111111111..222222222222 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib -@@ -75,6 +75,9 @@ always-y += $(hostprogs-always-y) $(hostprogs-always-m) +@@ -70,6 +70,9 @@ always-y += $(hostprogs-always-y) $(hostprogs-always-m) userprogs += $(userprogs-always-y) $(userprogs-always-m) always-y += $(userprogs-always-y) $(userprogs-always-m) diff --git a/patch/kernel/archive/rockchip64-6.14/general-rt5651-add-mclk.patch b/patch/kernel/archive/rockchip64-6.15/general-rt5651-add-mclk.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-rt5651-add-mclk.patch rename to patch/kernel/archive/rockchip64-6.15/general-rt5651-add-mclk.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-st7796-driver.patch b/patch/kernel/archive/rockchip64-6.15/general-st7796-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-st7796-driver.patch rename to patch/kernel/archive/rockchip64-6.15/general-st7796-driver.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-v4l2-iep-driver.patch b/patch/kernel/archive/rockchip64-6.15/general-v4l2-iep-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-v4l2-iep-driver.patch rename to patch/kernel/archive/rockchip64-6.15/general-v4l2-iep-driver.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-00-fixes.patch b/patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-00-fixes.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-00-fixes.patch rename to patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-00-fixes.patch index 5f9769809439..d2800a31422e 100644 --- a/patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-00-fixes.patch +++ b/patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-00-fixes.patch @@ -173,7 +173,7 @@ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2 index 111111111111..222222222222 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c -@@ -1367,6 +1367,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) +@@ -1369,6 +1369,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV42: descr = "Y/VU 4:4:4"; break; case V4L2_PIX_FMT_P010: descr = "10-bit Y/UV 4:2:0"; break; case V4L2_PIX_FMT_P012: descr = "12-bit Y/UV 4:2:0"; break; diff --git a/patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-01-vp9.patch b/patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-01-vp9.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-01-vp9.patch rename to patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-01-vp9.patch index ef16e26ff7a7..8847b2bcabdb 100644 --- a/patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-01-vp9.patch +++ b/patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-01-vp9.patch @@ -51,7 +51,7 @@ diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/ index 111111111111..222222222222 100644 --- a/drivers/pmdomain/rockchip/pm-domains.c +++ b/drivers/pmdomain/rockchip/pm-domains.c -@@ -392,6 +392,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, +@@ -399,6 +399,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, return 0; } diff --git a/patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-02-hevc.patch b/patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-02-hevc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-v4l2-rkvdec-02-hevc.patch rename to patch/kernel/archive/rockchip64-6.15/general-v4l2-rkvdec-02-hevc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/general-workaround-broadcom-bt-serdev.patch b/patch/kernel/archive/rockchip64-6.15/general-workaround-broadcom-bt-serdev.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/general-workaround-broadcom-bt-serdev.patch rename to patch/kernel/archive/rockchip64-6.15/general-workaround-broadcom-bt-serdev.patch diff --git a/patch/kernel/archive/rockchip64-6.14/kernel-6.8-tools-cgroup-makefile.patch b/patch/kernel/archive/rockchip64-6.15/kernel-6.8-tools-cgroup-makefile.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/kernel-6.8-tools-cgroup-makefile.patch rename to patch/kernel/archive/rockchip64-6.15/kernel-6.8-tools-cgroup-makefile.patch diff --git a/patch/kernel/archive/rockchip64-6.14/media-0001-Add-rkvdec2-Support-v3.patch b/patch/kernel/archive/rockchip64-6.15/media-0001-Add-rkvdec2-Support-v3.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/media-0001-Add-rkvdec2-Support-v3.patch rename to patch/kernel/archive/rockchip64-6.15/media-0001-Add-rkvdec2-Support-v3.patch index 0f0a2d7adb7a..7e0417a533f7 100644 --- a/patch/kernel/archive/rockchip64-6.14/media-0001-Add-rkvdec2-Support-v3.patch +++ b/patch/kernel/archive/rockchip64-6.15/media-0001-Add-rkvdec2-Support-v3.patch @@ -3679,7 +3679,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -2883,6 +2883,16 @@ system_sram2: sram@ff001000 { +@@ -2973,6 +2973,16 @@ system_sram2: sram@ff001000 { ranges = <0x0 0x0 0xff001000 0xef000>; #address-cells = <1>; #size-cells = <1>; @@ -3696,7 +3696,7 @@ index 111111111111..222222222222 100644 }; pinctrl: pinctrl { -@@ -2952,6 +2962,46 @@ gpio4: gpio@fec50000 { +@@ -3042,6 +3052,46 @@ gpio4: gpio@fec50000 { #interrupt-cells = <2>; }; }; diff --git a/patch/kernel/archive/rockchip64-6.14/media-0002-v4l2-core-Initialize-h264-frame_mbs_only_flag-.patch b/patch/kernel/archive/rockchip64-6.15/media-0002-v4l2-core-Initialize-h264-frame_mbs_only_flag-.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/media-0002-v4l2-core-Initialize-h264-frame_mbs_only_flag-.patch rename to patch/kernel/archive/rockchip64-6.15/media-0002-v4l2-core-Initialize-h264-frame_mbs_only_flag-.patch diff --git a/patch/kernel/archive/rockchip64-6.14/media-0003-rk3568-disable-hantro-h264.patch b/patch/kernel/archive/rockchip64-6.15/media-0003-rk3568-disable-hantro-h264.patch similarity index 98% rename from patch/kernel/archive/rockchip64-6.14/media-0003-rk3568-disable-hantro-h264.patch rename to patch/kernel/archive/rockchip64-6.15/media-0003-rk3568-disable-hantro-h264.patch index ca2a6c85545f..4c8bd8109865 100644 --- a/patch/kernel/archive/rockchip64-6.14/media-0003-rk3568-disable-hantro-h264.patch +++ b/patch/kernel/archive/rockchip64-6.15/media-0003-rk3568-disable-hantro-h264.patch @@ -20,7 +20,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -1126,7 +1126,7 @@ power-domain@RK3588_PD_SDMMC { +@@ -1137,7 +1137,7 @@ power-domain@RK3588_PD_SDMMC { }; vpu121: video-codec@fdb50000 { diff --git a/patch/kernel/archive/rockchip64-6.14/net-usb-r8152-add-LED-configuration-from-OF.patch b/patch/kernel/archive/rockchip64-6.15/net-usb-r8152-add-LED-configuration-from-OF.patch similarity index 87% rename from patch/kernel/archive/rockchip64-6.14/net-usb-r8152-add-LED-configuration-from-OF.patch rename to patch/kernel/archive/rockchip64-6.15/net-usb-r8152-add-LED-configuration-from-OF.patch index f98bff28d0ac..2ec83048df1b 100644 --- a/patch/kernel/archive/rockchip64-6.14/net-usb-r8152-add-LED-configuration-from-OF.patch +++ b/patch/kernel/archive/rockchip64-6.15/net-usb-r8152-add-LED-configuration-from-OF.patch @@ -24,7 +24,7 @@ index 111111111111..222222222222 100644 #include #include #include -@@ -7046,6 +7047,22 @@ static void rtl_tally_reset(struct r8152 *tp) +@@ -7047,6 +7048,22 @@ static void rtl_tally_reset(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); } @@ -47,7 +47,7 @@ index 111111111111..222222222222 100644 static void r8152b_init(struct r8152 *tp) { u32 ocp_data; -@@ -7087,6 +7104,8 @@ static void r8152b_init(struct r8152 *tp) +@@ -7088,6 +7105,8 @@ static void r8152b_init(struct r8152 *tp) ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); @@ -56,7 +56,7 @@ index 111111111111..222222222222 100644 } static void r8153_init(struct r8152 *tp) -@@ -7227,6 +7246,8 @@ static void r8153_init(struct r8152 *tp) +@@ -7228,6 +7247,8 @@ static void r8153_init(struct r8152 *tp) tp->coalesce = COALESCE_SLOW; break; } @@ -65,7 +65,7 @@ index 111111111111..222222222222 100644 } static void r8153b_init(struct r8152 *tp) -@@ -7309,6 +7330,8 @@ static void r8153b_init(struct r8152 *tp) +@@ -7310,6 +7331,8 @@ static void r8153b_init(struct r8152 *tp) rtl_tally_reset(tp); tp->coalesce = 15000; /* 15 us */ diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/Makefile b/patch/kernel/archive/rockchip64-6.15/overlay/Makefile similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/Makefile rename to patch/kernel/archive/rockchip64-6.15/overlay/Makefile diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/README.rockchip-overlays b/patch/kernel/archive/rockchip64-6.15/overlay/README.rockchip-overlays similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/README.rockchip-overlays rename to patch/kernel/archive/rockchip64-6.15/overlay/README.rockchip-overlays diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/hinlink-h88k-240x135-lcd.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/hinlink-h88k-240x135-lcd.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/hinlink-h88k-240x135-lcd.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/hinlink-h88k-240x135-lcd.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rk3308-b@1.3ghz.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rk3308-b@1.3ghz.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rk3308-b@1.3ghz.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rk3308-b@1.3ghz.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rk3308-bs.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rk3308-bs.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rk3308-bs.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rk3308-bs.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rk3308-bs@1.3ghz.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rk3308-bs@1.3ghz.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rk3308-bs@1.3ghz.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rk3308-bs@1.3ghz.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rk3308-emmc.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rk3308-emmc.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rk3308-emmc.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rk3308-emmc.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rk3308-s0-ext-antenna.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rk3308-s0-ext-antenna.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rk3308-s0-ext-antenna.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rk3308-s0-ext-antenna.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rk3308-sdio@10mhz.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rk3308-sdio@10mhz.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rk3308-sdio@10mhz.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rk3308-sdio@10mhz.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rk3308-sdio@4mhz.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rk3308-sdio@4mhz.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rk3308-sdio@4mhz.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rk3308-sdio@4mhz.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-fixup.scr-cmd b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-fixup.scr-cmd similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-fixup.scr-cmd rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-fixup.scr-cmd diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-cpu-hs.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-cpu-hs.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-cpu-hs.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-cpu-hs.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-emmc-ddr.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-emmc-ddr.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-emmc-ddr.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-emmc-ddr.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-emmc-hs200.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-emmc-hs200.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-emmc-hs200.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-emmc-hs200.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf3.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf3.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf3.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf3.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf4.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf4.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf4.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf4.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf5.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf5.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-led-conf5.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-led-conf5.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-wlan-ap6330.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-wlan-ap6330.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-wlan-ap6330.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-wlan-ap6330.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-wlan-ap6334.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-wlan-ap6334.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-wlan-ap6334.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-wlan-ap6334.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-wlan-ext.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-wlan-ext.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3318-box-wlan-ext.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3318-box-wlan-ext.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-i2c0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-i2c0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-i2c0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-i2c0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-i2s1-pcm5102.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-i2s1-pcm5102.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-i2s1-pcm5102.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-i2s1-pcm5102.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-mksklipad50-enable-rtc-end1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-mksklipad50-enable-rtc-end1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-mksklipad50-enable-rtc-end1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-mksklipad50-enable-rtc-end1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-mksklipad50-enable-v4l2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-mksklipad50-enable-v4l2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-mksklipad50-enable-v4l2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-mksklipad50-enable-v4l2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-mkspi-disable-lcd-spi.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-mkspi-disable-lcd-spi.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-mkspi-disable-lcd-spi.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-mkspi-disable-lcd-spi.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-opp-1.4ghz.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-opp-1.4ghz.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-opp-1.4ghz.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-opp-1.4ghz.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-opp-1.5ghz.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-opp-1.5ghz.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-opp-1.5ghz.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-opp-1.5ghz.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-spi-spidev.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-spi-spidev.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-spi-spidev.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-spi-spidev.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-uart1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-uart1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3328-uart1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3328-uart1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-dwc3-0-host.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-dwc3-0-host.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-dwc3-0-host.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-dwc3-0-host.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-i2c7.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-i2c7.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-i2c7.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-i2c7.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-i2c8.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-i2c8.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-i2c8.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-i2c8.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-opp-2ghz.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-opp-2ghz.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-opp-2ghz.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-opp-2ghz.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-pcie-gen2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-pcie-gen2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-pcie-gen2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-pcie-gen2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-spi-jedec-nor.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-spi-jedec-nor.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-spi-jedec-nor.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-spi-jedec-nor.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-spi-spidev.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-spi-spidev.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-spi-spidev.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-spi-spidev.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-uart4.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-uart4.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-uart4.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-uart4.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-w1-gpio.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-w1-gpio.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3399-w1-gpio.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3399-w1-gpio.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3566-sata2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3566-sata2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3566-sata2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3566-sata2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-i2c0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-i2c0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-i2c0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-i2c0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-i2c1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-i2c1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-i2c1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-i2c1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-pwm1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-pwm1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-pwm1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-pwm1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-pwm2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-pwm2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-pwm2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-pwm2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-pwm9.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-pwm9.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-pwm9.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-pwm9.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-spi-spidev.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-spi-spidev.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-spi-spidev.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-spi-spidev.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-uart0-rts_cts.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-uart0-rts_cts.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-uart0-rts_cts.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-uart0-rts_cts.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-uart0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-uart0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-uart0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-uart0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-uart1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-uart1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-hk-uart1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-hk-uart1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-nanopi-r5c-leds.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-nanopi-r5c-leds.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-nanopi-r5c-leds.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-nanopi-r5c-leds.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-nanopi-r5s-leds.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-nanopi-r5s-leds.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-nanopi-r5s-leds.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-nanopi-r5s-leds.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-rock-3a-disable-uart2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-rock-3a-disable-uart2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3568-rock-3a-disable-uart2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3568-rock-3a-disable-uart2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-fanctrl.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-fanctrl.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-fanctrl.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-fanctrl.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-hdmirx.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-hdmirx.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-hdmirx.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-hdmirx.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-i2c8-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-i2c8-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-i2c8-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-i2c8-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-nanopi-m6-spi-nor-flash.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-nanopi-m6-spi-nor-flash.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-nanopi-m6-spi-nor-flash.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-nanopi-m6-spi-nor-flash.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm0-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm0-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm0-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm0-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm0-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm0-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm0-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm0-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm0-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm0-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm0-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm0-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm1-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm1-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm1-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm1-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm1-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm1-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm1-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm1-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm1-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm1-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm1-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm1-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm10-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm10-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm10-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm10-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm11-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm11-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm11-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm11-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm11-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm11-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm11-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm11-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm12-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm12-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm12-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm12-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm13-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm13-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm13-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm13-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm13-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm13-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm13-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm13-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm14-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm14-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm14-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm14-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm14-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm14-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm14-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm14-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm14-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm14-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm14-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm14-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m3.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m3.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm15-m3.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm15-m3.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm2-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm2-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm2-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm2-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m3.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m3.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm3-m3.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm3-m3.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm5-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm5-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm5-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm5-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm6-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm6-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm6-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm6-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm6-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm6-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm6-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm6-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm7-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm7-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm7-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm7-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm7-m3.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm7-m3.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm7-m3.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm7-m3.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm8-m0.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm8-m0.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-pwm8-m0.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-pwm8-m0.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-rkvenc-overlay.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-rkvenc-overlay.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-rkvenc-overlay.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-rkvenc-overlay.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-sata1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-sata1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-sata1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-sata1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-sata2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-sata2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-sata2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-sata2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart1-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart1-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart1-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart1-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart3-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart3-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart3-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart3-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart4-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart4-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart4-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart4-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart6-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart6-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart6-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart6-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart7-m2.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart7-m2.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart7-m2.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart7-m2.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart8-m1.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart8-m1.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rk3588-uart8-m1.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rk3588-uart8-m1.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rockpi4cplus-usb-host.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rockpi4cplus-usb-host.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rockpi4cplus-usb-host.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rockpi4cplus-usb-host.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rockpro64-lcd.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rockpro64-lcd.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-rockpro64-lcd.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-rockpro64-lcd.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/overlay/rockchip-sakurapi-rk3308b-ws2812.dtso b/patch/kernel/archive/rockchip64-6.15/overlay/rockchip-sakurapi-rk3308b-ws2812.dtso similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/overlay/rockchip-sakurapi-rk3308b-ws2812.dtso rename to patch/kernel/archive/rockchip64-6.15/overlay/rockchip-sakurapi-rk3308b-ws2812.dtso diff --git a/patch/kernel/archive/rockchip64-6.14/regulator-add-fan53200-driver.patch b/patch/kernel/archive/rockchip64-6.15/regulator-add-fan53200-driver.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/regulator-add-fan53200-driver.patch rename to patch/kernel/archive/rockchip64-6.15/regulator-add-fan53200-driver.patch index d9aad0cdfc2b..35df44e00802 100644 --- a/patch/kernel/archive/rockchip64-6.14/regulator-add-fan53200-driver.patch +++ b/patch/kernel/archive/rockchip64-6.15/regulator-add-fan53200-driver.patch @@ -24,7 +24,7 @@ diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 111111111111..222222222222 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig -@@ -784,6 +784,7 @@ CONFIG_REGULATOR_BD9571MWV=y +@@ -786,6 +786,7 @@ CONFIG_REGULATOR_BD9571MWV=y CONFIG_REGULATOR_CROS_EC=y CONFIG_REGULATOR_DA9211=m CONFIG_REGULATOR_FAN53555=y diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-0001-pinctrl-slew-mux.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-0001-pinctrl-slew-mux.patch similarity index 96% rename from patch/kernel/archive/rockchip64-6.14/rk3308-0001-pinctrl-slew-mux.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-0001-pinctrl-slew-mux.patch index 0e530b893b22..2605c1e605bc 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3308-0001-pinctrl-slew-mux.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3308-0001-pinctrl-slew-mux.patch @@ -96,7 +96,7 @@ diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockch index 111111111111..222222222222 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c -@@ -2888,6 +2888,26 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, +@@ -3000,6 +3000,26 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, return ret; } @@ -123,7 +123,7 @@ index 111111111111..222222222222 100644 #define RK3328_SCHMITT_BITS_PER_PIN 1 #define RK3328_SCHMITT_PINS_PER_REG 16 #define RK3328_SCHMITT_BANK_STRIDE 8 -@@ -3003,6 +3023,51 @@ static int rockchip_set_schmitt(struct rockchip_pin_bank *bank, +@@ -3115,6 +3135,51 @@ static int rockchip_set_schmitt(struct rockchip_pin_bank *bank, return regmap_update_bits(regmap, reg, rmask, data); } @@ -175,7 +175,7 @@ index 111111111111..222222222222 100644 /* * Pinmux_ops handling */ -@@ -3240,6 +3305,15 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, +@@ -3353,6 +3418,15 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, if (rc < 0) return rc; break; @@ -191,7 +191,7 @@ index 111111111111..222222222222 100644 default: return -ENOTSUPP; break; -@@ -3314,6 +3388,26 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, +@@ -3427,6 +3501,26 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, if (rc < 0) return rc; @@ -218,7 +218,7 @@ index 111111111111..222222222222 100644 arg = rc; break; default: -@@ -4116,6 +4210,7 @@ static struct rockchip_pin_ctrl rk3308_pin_ctrl = { +@@ -4229,6 +4323,7 @@ static struct rockchip_pin_ctrl rk3308_pin_ctrl = { .pull_calc_reg = rk3308_calc_pull_reg_and_bit, .drv_calc_reg = rk3308_calc_drv_reg_and_bit, .schmitt_calc_reg = rk3308_calc_schmitt_reg_and_bit, @@ -230,7 +230,7 @@ diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockch index 111111111111..222222222222 100644 --- a/drivers/pinctrl/pinctrl-rockchip.h +++ b/drivers/pinctrl/pinctrl-rockchip.h -@@ -409,6 +409,9 @@ struct rockchip_pin_ctrl { +@@ -410,6 +410,9 @@ struct rockchip_pin_ctrl { int (*schmitt_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, struct regmap **regmap, int *reg, u8 *bit); diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-0003-pinctrl-io-voltage-domains.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-0003-pinctrl-io-voltage-domains.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/rk3308-0003-pinctrl-io-voltage-domains.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-0003-pinctrl-io-voltage-domains.patch index 463c92769125..467d2784245c 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3308-0003-pinctrl-io-voltage-domains.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3308-0003-pinctrl-io-voltage-domains.patch @@ -95,7 +95,7 @@ index 111111111111..222222222222 100644 /* * Generate a bitmask for setting a value (v) with a write mask bit in hiword * register 31:16 area. -@@ -3873,6 +3879,24 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) +@@ -3986,6 +3992,24 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) if (ret) return ret; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-add-gmac-alias.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-add-gmac-alias.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3308-add-gmac-alias.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-add-gmac-alias.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-add-missing-i2s-controllers.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-add-missing-i2s-controllers.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3308-add-missing-i2s-controllers.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-add-missing-i2s-controllers.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-add-tsadc-driver.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-add-tsadc-driver.patch similarity index 94% rename from patch/kernel/archive/rockchip64-6.14/rk3308-add-tsadc-driver.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-add-tsadc-driver.patch index 7ad4c277f6f1..ed8f6d73d17a 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3308-add-tsadc-driver.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3308-add-tsadc-driver.patch @@ -26,7 +26,7 @@ diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_therm index 111111111111..222222222222 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c -@@ -1060,6 +1060,28 @@ static void rk_tsadcv3_tshut_mode(int chn, void __iomem *regs, +@@ -1061,6 +1061,28 @@ static void rk_tsadcv3_tshut_mode(int chn, void __iomem *regs, writel_relaxed(val_cru, regs + TSADCV3_HSHUT_CRU_INT_EN); } @@ -55,7 +55,7 @@ index 111111111111..222222222222 100644 static const struct rockchip_tsadc_chip px30_tsadc_data = { /* cpu, gpu */ .chn_offset = 0, -@@ -1321,6 +1343,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { +@@ -1322,6 +1344,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { .compatible = "rockchip,rk3288-tsadc", .data = (void *)&rk3288_tsadc_data, }, diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-dts-legacy-cryptov2.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-dts-legacy-cryptov2.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3308-dts-legacy-cryptov2.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-dts-legacy-cryptov2.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-dts-thermal-zones.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-dts-thermal-zones.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3308-dts-thermal-zones.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-dts-thermal-zones.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-fix-uart-dma.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-fix-uart-dma.patch similarity index 62% rename from patch/kernel/archive/rockchip64-6.14/rk3308-fix-uart-dma.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-fix-uart-dma.patch index 0185dc02099c..a6b17d1b7408 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3308-fix-uart-dma.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3308-fix-uart-dma.patch @@ -5,57 +5,15 @@ Subject: rk3308: fix uart dma. Signed-off-by: ssp97 --- - arch/arm64/boot/dts/rockchip/rk3308.dtsi | 10 ++++++++++ - drivers/soc/rockchip/grf.c | 14 ++++++++++ - 2 file changed, 24 insertions(+) + arch/arm64/boot/dts/rockchip/rk3308.dtsi | 10 +++++++ + drivers/soc/rockchip/grf.c | 14 ++++++++++ + 2 files changed, 24 insertions(+) -diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c -index 5fd62046b..78138cee6 100644 ---- a/drivers/soc/rockchip/grf.c -+++ b/drivers/soc/rockchip/grf.c -@@ -84,10 +84,21 @@ static const struct rockchip_grf_value rk3328_defaults[] __initconst = { - static const struct rockchip_grf_info rk3328_grf __initconst = { - .values = rk3328_defaults, - .num_values = ARRAY_SIZE(rk3328_defaults), - }; - -+#define RK3308_GRF_SOC_CON3 0x30c -+ -+static const struct rockchip_grf_value rk3308_defaults[] __initconst = { -+ { "uart dma mask", RK3308_GRF_SOC_CON3, HIWORD_UPDATE(0, 0x1f, 10) }, -+}; -+ -+static const struct rockchip_grf_info rk3308_grf __initconst = { -+ .values = rk3308_defaults, -+ .num_values = ARRAY_SIZE(rk3308_defaults), -+}; -+ - #define RK3368_GRF_SOC_CON15 0x43c - - static const struct rockchip_grf_value rk3368_defaults[] __initconst = { - { "jtag switching", RK3368_GRF_SOC_CON15, HIWORD_UPDATE(0, 1, 13) }, - }; -@@ -147,10 +158,13 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = { - .compatible = "rockchip,rk3288-grf", - .data = (void *)&rk3288_grf, - }, { - .compatible = "rockchip,rk3328-grf", - .data = (void *)&rk3328_grf, -+ }, { -+ .compatible = "rockchip,rk3308-grf", -+ .data = (void *)&rk3308_grf, - }, { - .compatible = "rockchip,rk3368-grf", - .data = (void *)&rk3368_grf, - }, { - .compatible = "rockchip,rk3399-grf", diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi -index 7d1571e4f..a6b8dc8df 100644 +index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi -@@ -351,10 +351,12 @@ uart0: serial@ff0a0000 { - interrupts = ; - clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; +@@ -323,6 +323,8 @@ uart0: serial@ff0a0000 { clock-names = "baudclk", "apb_pclk"; reg-shift = <2>; reg-io-width = <4>; @@ -64,11 +22,7 @@ index 7d1571e4f..a6b8dc8df 100644 pinctrl-names = "default"; pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; status = "disabled"; - }; - -@@ -364,10 +366,12 @@ uart1: serial@ff0b0000 { - interrupts = ; - clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; +@@ -336,6 +338,8 @@ uart1: serial@ff0b0000 { clock-names = "baudclk", "apb_pclk"; reg-shift = <2>; reg-io-width = <4>; @@ -77,11 +31,7 @@ index 7d1571e4f..a6b8dc8df 100644 pinctrl-names = "default"; pinctrl-0 = <&uart1_xfer &uart1_cts &uart1_rts>; status = "disabled"; - }; - -@@ -377,10 +381,12 @@ uart2: serial@ff0c0000 { - interrupts = ; - clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; +@@ -349,6 +353,8 @@ uart2: serial@ff0c0000 { clock-names = "baudclk", "apb_pclk"; reg-shift = <2>; reg-io-width = <4>; @@ -90,11 +40,7 @@ index 7d1571e4f..a6b8dc8df 100644 pinctrl-names = "default"; pinctrl-0 = <&uart2m0_xfer>; status = "disabled"; - }; - -@@ -390,10 +396,12 @@ uart3: serial@ff0d0000 { - interrupts = ; - clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>; +@@ -362,6 +368,8 @@ uart3: serial@ff0d0000 { clock-names = "baudclk", "apb_pclk"; reg-shift = <2>; reg-io-width = <4>; @@ -103,11 +49,7 @@ index 7d1571e4f..a6b8dc8df 100644 pinctrl-names = "default"; pinctrl-0 = <&uart3_xfer>; status = "disabled"; - }; - -@@ -403,10 +411,12 @@ uart4: serial@ff0e0000 { - interrupts = ; - clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>; +@@ -375,6 +383,8 @@ uart4: serial@ff0e0000 { clock-names = "baudclk", "apb_pclk"; reg-shift = <2>; reg-io-width = <4>; @@ -116,8 +58,38 @@ index 7d1571e4f..a6b8dc8df 100644 pinctrl-names = "default"; pinctrl-0 = <&uart4_xfer &uart4_cts &uart4_rts>; status = "disabled"; - }; - +diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c +index 111111111111..222222222222 100644 +--- a/drivers/soc/rockchip/grf.c ++++ b/drivers/soc/rockchip/grf.c +@@ -88,6 +88,17 @@ static const struct rockchip_grf_info rk3328_grf __initconst = { + .num_values = ARRAY_SIZE(rk3328_defaults), + }; + ++#define RK3308_GRF_SOC_CON3 0x30c ++ ++static const struct rockchip_grf_value rk3308_defaults[] __initconst = { ++ { "uart dma mask", RK3308_GRF_SOC_CON3, HIWORD_UPDATE(0, 0x1f, 10) }, ++}; ++ ++static const struct rockchip_grf_info rk3308_grf __initconst = { ++ .values = rk3308_defaults, ++ .num_values = ARRAY_SIZE(rk3308_defaults), ++}; ++ + #define RK3368_GRF_SOC_CON15 0x43c + + static const struct rockchip_grf_value rk3368_defaults[] __initconst = { +@@ -173,6 +184,9 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = { + }, { + .compatible = "rockchip,rk3328-grf", + .data = (void *)&rk3328_grf, ++ }, { ++ .compatible = "rockchip,rk3308-grf", ++ .data = (void *)&rk3308_grf, + }, { + .compatible = "rockchip,rk3368-grf", + .data = (void *)&rk3368_grf, -- -Created with Armbian build tools https://github.com/armbian/build +Armbian diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-internal-rgb-lcdc.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-internal-rgb-lcdc.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3308-internal-rgb-lcdc.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-internal-rgb-lcdc.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3308-vop-output.patch b/patch/kernel/archive/rockchip64-6.15/rk3308-vop-output.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/rk3308-vop-output.patch rename to patch/kernel/archive/rockchip64-6.15/rk3308-vop-output.patch index ba95ba317ac7..1b56ab0b463b 100755 --- a/patch/kernel/archive/rockchip64-6.14/rk3308-vop-output.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3308-vop-output.patch @@ -27,7 +27,7 @@ index 111111111111..222222222222 100644 mac_clkin: external-mac-clock { compatible = "fixed-clock"; clock-frequency = <50000000>; -@@ -687,6 +693,26 @@ dmac1: dma-controller@ff2d0000 { +@@ -697,6 +703,26 @@ dmac1: dma-controller@ff2d0000 { #dma-cells = <1>; }; @@ -54,7 +54,7 @@ index 111111111111..222222222222 100644 i2s_8ch_0: i2s@ff300000 { compatible = "rockchip,rk3308-i2s-tdm"; reg = <0x0 0xff300000 0x0 0x1000>; -@@ -2111,5 +2137,89 @@ uart4_rts_pin: uart4-rts-pin { +@@ -2118,5 +2144,89 @@ uart4_rts_pin: uart4-rts-pin { <4 RK_PA7 0 &pcfg_pull_none>; }; }; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3328-add-dmc-driver.patch b/patch/kernel/archive/rockchip64-6.15/rk3328-add-dmc-driver.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/rk3328-add-dmc-driver.patch rename to patch/kernel/archive/rockchip64-6.15/rk3328-add-dmc-driver.patch index 92debe4194c1..c4b1f26b56d4 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3328-add-dmc-driver.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3328-add-dmc-driver.patch @@ -588,7 +588,7 @@ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 111111111111..222222222222 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h -@@ -539,7 +539,8 @@ struct clk *rockchip_clk_register_mmc(const char *name, +@@ -600,7 +600,8 @@ struct clk *rockchip_clk_register_mmc(const char *name, * DDRCLK flags, including method of setting the rate * ROCKCHIP_DDRCLK_SIP: use SIP call to bl31 to change ddrclk rate. */ @@ -654,7 +654,7 @@ index 111111111111..222222222222 100644 struct regmap *regmap_pmu; struct clk *clk; int usecount; -@@ -669,6 +672,46 @@ static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi) +@@ -668,6 +671,46 @@ static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi) } #endif @@ -701,7 +701,7 @@ index 111111111111..222222222222 100644 static int rk3399_dfi_init(struct rockchip_dfi *dfi) { struct regmap *regmap_pmu = dfi->regmap_pmu; -@@ -757,6 +800,8 @@ static int rk3588_dfi_init(struct rockchip_dfi *dfi) +@@ -756,6 +799,8 @@ static int rk3588_dfi_init(struct rockchip_dfi *dfi) }; static const struct of_device_id rockchip_dfi_id_match[] = { @@ -710,7 +710,7 @@ index 111111111111..222222222222 100644 { .compatible = "rockchip,rk3399-dfi", .data = rk3399_dfi_init }, { .compatible = "rockchip,rk3568-dfi", .data = rk3568_dfi_init }, { .compatible = "rockchip,rk3588-dfi", .data = rk3588_dfi_init }, -@@ -786,14 +831,30 @@ static int rockchip_dfi_probe(struct platform_device *pdev) +@@ -785,14 +830,30 @@ static int rockchip_dfi_probe(struct platform_device *pdev) if (IS_ERR(dfi->regs)) return PTR_ERR(dfi->regs); @@ -748,7 +748,7 @@ index 111111111111..222222222222 100644 dfi->dev = dev; mutex_init(&dfi->mutex); -@@ -818,6 +879,8 @@ static int rockchip_dfi_probe(struct platform_device *pdev) +@@ -817,6 +878,8 @@ static int rockchip_dfi_probe(struct platform_device *pdev) if (ret) return ret; @@ -1877,7 +1877,7 @@ diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip index 111111111111..222222222222 100644 --- a/include/soc/rockchip/rockchip_sip.h +++ b/include/soc/rockchip/rockchip_sip.h -@@ -16,5 +16,16 @@ +@@ -19,5 +19,16 @@ #define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ 0x06 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM 0x07 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD 0x08 diff --git a/patch/kernel/archive/rockchip64-6.14/rk3328-add-rga-node.patch b/patch/kernel/archive/rockchip64-6.15/rk3328-add-rga-node.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3328-add-rga-node.patch rename to patch/kernel/archive/rockchip64-6.15/rk3328-add-rga-node.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3328-dtsi-mali-opp-table.patch b/patch/kernel/archive/rockchip64-6.15/rk3328-dtsi-mali-opp-table.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3328-dtsi-mali-opp-table.patch rename to patch/kernel/archive/rockchip64-6.15/rk3328-dtsi-mali-opp-table.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3328-dtsi-spdif.patch b/patch/kernel/archive/rockchip64-6.15/rk3328-dtsi-spdif.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3328-dtsi-spdif.patch rename to patch/kernel/archive/rockchip64-6.15/rk3328-dtsi-spdif.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3328-dtsi-usb3-reset-properties.patch b/patch/kernel/archive/rockchip64-6.15/rk3328-dtsi-usb3-reset-properties.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3328-dtsi-usb3-reset-properties.patch rename to patch/kernel/archive/rockchip64-6.15/rk3328-dtsi-usb3-reset-properties.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3328-gpu-cooling-target.patch b/patch/kernel/archive/rockchip64-6.15/rk3328-gpu-cooling-target.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3328-gpu-cooling-target.patch rename to patch/kernel/archive/rockchip64-6.15/rk3328-gpu-cooling-target.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3328-roc-cc-add-missing-nodes.patch b/patch/kernel/archive/rockchip64-6.15/rk3328-roc-cc-add-missing-nodes.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3328-roc-cc-add-missing-nodes.patch rename to patch/kernel/archive/rockchip64-6.15/rk3328-roc-cc-add-missing-nodes.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-add-sclk-i2sout-src-clock.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-add-sclk-i2sout-src-clock.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-add-sclk-i2sout-src-clock.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-add-sclk-i2sout-src-clock.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-dmc-polling-rate.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-dmc-polling-rate.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-dmc-polling-rate.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-dmc-polling-rate.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-enable-dwc3-xhci-usb-trb-quirk.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-enable-dwc3-xhci-usb-trb-quirk.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-enable-dwc3-xhci-usb-trb-quirk.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-enable-dwc3-xhci-usb-trb-quirk.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-fix-pci-lanes.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-fix-pci-lanes.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-fix-pci-lanes.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-fix-pci-lanes.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-fix-pci-phy.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-fix-pci-phy.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-fix-pci-phy.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-fix-pci-phy.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-fix-usb-phy.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-fix-usb-phy.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-fix-usb-phy.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-fix-usb-phy.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-rp64-pcie-Reimplement-rockchip-PCIe-bus-scan-delay.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-rp64-pcie-Reimplement-rockchip-PCIe-bus-scan-delay.patch similarity index 98% rename from patch/kernel/archive/rockchip64-6.14/rk3399-rp64-pcie-Reimplement-rockchip-PCIe-bus-scan-delay.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-rp64-pcie-Reimplement-rockchip-PCIe-bus-scan-delay.patch index 92aed7af0186..a9ccbd66c4f9 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3399-rp64-pcie-Reimplement-rockchip-PCIe-bus-scan-delay.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3399-rp64-pcie-Reimplement-rockchip-PCIe-bus-scan-delay.patch @@ -20,7 +20,7 @@ diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/adm index 111111111111..222222222222 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -4877,6 +4877,14 @@ +@@ -4924,6 +4924,14 @@ nomsi Do not use MSI for native PCIe PME signaling (this makes all PCIe root ports use INTx for all services). @@ -110,7 +110,7 @@ diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pci index 111111111111..222222222222 100644 --- a/drivers/pci/controller/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h -@@ -351,6 +351,8 @@ struct rockchip_pcie { +@@ -350,6 +350,8 @@ struct rockchip_pcie { phys_addr_t msg_bus_addr; bool is_rc; struct resource *mem_res; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-sd-drive-level-8ma.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-sd-drive-level-8ma.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-sd-drive-level-8ma.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-sd-drive-level-8ma.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-sd-pwr-pinctrl.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-sd-pwr-pinctrl.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-sd-pwr-pinctrl.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-sd-pwr-pinctrl.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3399-unlock-temperature.patch b/patch/kernel/archive/rockchip64-6.15/rk3399-unlock-temperature.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3399-unlock-temperature.patch rename to patch/kernel/archive/rockchip64-6.15/rk3399-unlock-temperature.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk356x-add-rkvdec2-support.patch b/patch/kernel/archive/rockchip64-6.15/rk356x-add-rkvdec2-support.patch similarity index 95% rename from patch/kernel/archive/rockchip64-6.14/rk356x-add-rkvdec2-support.patch rename to patch/kernel/archive/rockchip64-6.15/rk356x-add-rkvdec2-support.patch index b615aa9ac2b0..d32a62fe85eb 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk356x-add-rkvdec2-support.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk356x-add-rkvdec2-support.patch @@ -16,7 +16,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi -@@ -369,6 +369,19 @@ usb2phy1_grf: syscon@fdca8000 { +@@ -380,6 +380,19 @@ usb2phy1_grf: syscon@fdca8000 { reg = <0x0 0xfdca8000 0x0 0x8000>; }; @@ -36,7 +36,7 @@ index 111111111111..222222222222 100644 pmucru: clock-controller@fdd00000 { compatible = "rockchip,rk3568-pmucru"; reg = <0x0 0xfdd00000 0x0 0x1000>; -@@ -554,7 +567,7 @@ gpu: gpu@fde60000 { +@@ -565,7 +578,7 @@ gpu: gpu@fde60000 { }; vpu: video-codec@fdea0400 { @@ -45,7 +45,7 @@ index 111111111111..222222222222 100644 reg = <0x0 0xfdea0000 0x0 0x800>; interrupts = ; interrupt-names = "vdpu"; -@@ -605,6 +618,26 @@ vepu_mmu: iommu@fdee0800 { +@@ -616,6 +629,26 @@ vepu_mmu: iommu@fdee0800 { #iommu-cells = <0>; }; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0010-fix-clk-divisions.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0010-fix-clk-divisions.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/rk3588-0010-fix-clk-divisions.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-0010-fix-clk-divisions.patch index 4a38b653891d..21d5f10f0910 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-0010-fix-clk-divisions.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-0010-fix-clk-divisions.patch @@ -15,7 +15,7 @@ diff --git a/include/linux/math.h b/include/linux/math.h index 111111111111..222222222222 100644 --- a/include/linux/math.h +++ b/include/linux/math.h -@@ -36,6 +36,17 @@ +@@ -48,6 +48,17 @@ #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0011-irqchip-fix-its-timeout-issue.patch.bak b/patch/kernel/archive/rockchip64-6.15/rk3588-0011-irqchip-fix-its-timeout-issue.patch.bak similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3588-0011-irqchip-fix-its-timeout-issue.patch.bak rename to patch/kernel/archive/rockchip64-6.15/rk3588-0011-irqchip-fix-its-timeout-issue.patch.bak diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-0025-add-missing-op-nodes.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-0025-add-missing-op-nodes.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3588-0025-add-missing-op-nodes.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-0025-add-missing-op-nodes.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1010-arm64-dts-rock-5b-Slow-down-emmc-to-hs200-and-add-ts.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1010-arm64-dts-rock-5b-Slow-down-emmc-to-hs200-and-add-ts.patch similarity index 93% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1010-arm64-dts-rock-5b-Slow-down-emmc-to-hs200-and-add-ts.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1010-arm64-dts-rock-5b-Slow-down-emmc-to-hs200-and-add-ts.patch index da673926a175..cc6bc768383c 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1010-arm64-dts-rock-5b-Slow-down-emmc-to-hs200-and-add-ts.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1010-arm64-dts-rock-5b-Slow-down-emmc-to-hs200-and-add-ts.patch @@ -11,7 +11,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/d index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts -@@ -440,6 +440,7 @@ &sdhci { +@@ -510,6 +510,7 @@ &sdhci { no-sdio; no-sd; non-removable; @@ -19,7 +19,7 @@ index 111111111111..222222222222 100644 mmc-hs400-1_8v; mmc-hs400-enhanced-strobe; status = "okay"; -@@ -495,6 +496,10 @@ flash@0 { +@@ -565,6 +566,10 @@ flash@0 { }; }; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1040-board-khadas-edge2-add-nodes.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1040-board-khadas-edge2-add-nodes.patch similarity index 97% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1040-board-khadas-edge2-add-nodes.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1040-board-khadas-edge2-add-nodes.patch index be3c89e264a4..890b7bfae0df 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1040-board-khadas-edge2-add-nodes.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1040-board-khadas-edge2-add-nodes.patch @@ -98,7 +98,7 @@ index 111111111111..222222222222 100644 hym8563: rtc@51 { compatible = "haoyu,hym8563"; reg = <0x51>; -@@ -256,6 +319,16 @@ vcc5v0_host_en: vcc5v0-host-en { +@@ -260,6 +323,16 @@ vcc5v0_host_en: vcc5v0-host-en { }; }; @@ -115,7 +115,7 @@ index 111111111111..222222222222 100644 ir-receiver { ir_receiver_pin: ir-receiver-pin { rockchip,pins = <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; -@@ -697,6 +770,14 @@ &uart9 { +@@ -701,6 +774,14 @@ &uart9 { status = "okay"; }; @@ -130,7 +130,7 @@ index 111111111111..222222222222 100644 &u2phy2 { status = "okay"; }; -@@ -723,6 +804,44 @@ &usb_host0_ohci { +@@ -727,6 +808,44 @@ &usb_host0_ohci { status = "okay"; }; @@ -191,7 +191,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts b/arch/arm64/ index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts -@@ -766,8 +766,24 @@ &uart2 { +@@ -770,8 +770,24 @@ &uart2 { &uart9 { pinctrl-names = "default"; @@ -286,7 +286,7 @@ index 111111111111..222222222222 100644 &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0m2_xfer>; -@@ -869,3 +901,18 @@ &usb_host1_ohci { +@@ -873,3 +905,18 @@ &usb_host1_ohci { &usb_host2_xhci { status = "okay"; }; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1041-board-khadas-edge2-mcu.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1041-board-khadas-edge2-mcu.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1041-board-khadas-edge2-mcu.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1041-board-khadas-edge2-mcu.patch index 73dc9c550899..02efe8426d96 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1041-board-khadas-edge2-mcu.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1041-board-khadas-edge2-mcu.patch @@ -356,7 +356,7 @@ index 111111111111..222222222222 100644 + }; }; - &pinctrl { + &pd_gpu { -- Armbian @@ -373,8 +373,8 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts b/arch/arm64/ index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts -@@ -335,6 +335,62 @@ khadas_mcu: system-controller@18 { - }; +@@ -339,6 +339,62 @@ &pd_gpu { + domain-supply = <&vdd_gpu_s0>; }; +&package_thermal { diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1051-board-nanopc-t6-fan-support.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1051-board-nanopc-t6-fan-support.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1051-board-nanopc-t6-fan-support.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1051-board-nanopc-t6-fan-support.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1052-board-nanopc-t6-fix-usb3-a.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1052-board-nanopc-t6-fix-usb3-a.patch similarity index 91% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1052-board-nanopc-t6-fix-usb3-a.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1052-board-nanopc-t6-fix-usb3-a.patch index 2b7268ba22a9..1f4d7039547a 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1052-board-nanopc-t6-fix-usb3-a.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1052-board-nanopc-t6-fix-usb3-a.patch @@ -12,7 +12,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boo index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi -@@ -1056,6 +1056,7 @@ &u2phy0 { +@@ -1060,6 +1060,7 @@ &u2phy0 { }; &u2phy0_otg { @@ -20,7 +20,7 @@ index 111111111111..222222222222 100644 status = "okay"; }; -@@ -1121,6 +1122,7 @@ &usb_host0_ohci { +@@ -1125,6 +1126,7 @@ &usb_host0_ohci { &usb_host0_xhci { dr_mode = "host"; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1053-board-nanopc-t6-hdmi1-and-audio-support.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1053-board-nanopc-t6-hdmi1-and-audio-support.patch similarity index 96% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1053-board-nanopc-t6-hdmi1-and-audio-support.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1053-board-nanopc-t6-hdmi1-and-audio-support.patch index e690e5772f35..c3bec3588920 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1053-board-nanopc-t6-hdmi1-and-audio-support.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1053-board-nanopc-t6-hdmi1-and-audio-support.patch @@ -93,7 +93,7 @@ index 111111111111..222222222222 100644 &package_thermal { polling-delay = <1000>; -@@ -1160,3 +1209,10 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { +@@ -1164,3 +1213,10 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { remote-endpoint = <&hdmi0_in_vp0>; }; }; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1063-arm64-dts-rockchip-Enable-automatic-fan-control-on-t.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1063-arm64-dts-rockchip-Enable-automatic-fan-control-on-t.patch similarity index 98% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1063-arm64-dts-rockchip-Enable-automatic-fan-control-on-t.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1063-arm64-dts-rockchip-Enable-automatic-fan-control-on-t.patch index 83a88e0dea39..c3d19ae22a20 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1063-arm64-dts-rockchip-Enable-automatic-fan-control-on-t.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1063-arm64-dts-rockchip-Enable-automatic-fan-control-on-t.patch @@ -20,7 +20,7 @@ index 111111111111..222222222222 100644 fan-supply = <&vcc5v0_sys>; pinctrl-names = "default"; pinctrl-0 = <&pwm0m2_pins &fan_int>; -@@ -266,6 +266,36 @@ map5 { +@@ -268,6 +268,36 @@ map5 { }; }; diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1064-arm64-dts-rockchip-Add-missing-hym8563-clock-frequen.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1064-arm64-dts-rockchip-Add-missing-hym8563-clock-frequen.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1064-arm64-dts-rockchip-Add-missing-hym8563-clock-frequen.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1064-arm64-dts-rockchip-Add-missing-hym8563-clock-frequen.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1072-arm64-dts-rockchip-add-AP6275P-wifi-to-Orange-Pi-5B.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1072-arm64-dts-rockchip-add-AP6275P-wifi-to-Orange-Pi-5B.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1072-arm64-dts-rockchip-add-AP6275P-wifi-to-Orange-Pi-5B.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1072-arm64-dts-rockchip-add-AP6275P-wifi-to-Orange-Pi-5B.patch diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1080-arm64-dts-rockchip-add-USB3-support-to-NanoPi-R6-ser.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1080-arm64-dts-rockchip-add-USB3-support-to-NanoPi-R6-ser.patch similarity index 93% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1080-arm64-dts-rockchip-add-USB3-support-to-NanoPi-R6-ser.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1080-arm64-dts-rockchip-add-USB3-support-to-NanoPi-R6-ser.patch index 5364c0605b6c..cec8709ad7eb 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1080-arm64-dts-rockchip-add-USB3-support-to-NanoPi-R6-ser.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1080-arm64-dts-rockchip-add-USB3-support-to-NanoPi-R6-ser.patch @@ -11,7 +11,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi b/arch/arm64/bo index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi -@@ -784,6 +784,15 @@ &u2phy0_otg { +@@ -788,6 +788,15 @@ &u2phy0_otg { status = "okay"; }; @@ -27,7 +27,7 @@ index 111111111111..222222222222 100644 &u2phy2 { status = "okay"; }; -@@ -815,6 +824,16 @@ &usbdp_phy0 { +@@ -819,6 +828,16 @@ &usbdp_phy0 { status = "okay"; }; diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-1090-arm64-dts-rockchip-Enable-HDMI-receiver-on-CM3588-NAS.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1090-arm64-dts-rockchip-Enable-HDMI-receiver-on-CM3588-NAS.patch new file mode 100644 index 000000000000..17131481a4a9 --- /dev/null +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1090-arm64-dts-rockchip-Enable-HDMI-receiver-on-CM3588-NAS.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ricardo Pardini +Date: Fri, 23 May 2025 15:33:24 +0200 +Subject: arm64: dts: rockchip: Enable HDMI receiver on CM3588-NAS + +The CM3588-NAS has a full-size HDMI port, which can be used for receiving +HDMI data. This enables support for it. + +Signed-off-by: Ricardo Pardini +--- + arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts | 17 ++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts +index 111111111111..222222222222 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts +@@ -335,6 +335,17 @@ hdmi0_out_con: endpoint { + }; + }; + ++&hdmi_receiver_cma { ++ status = "okay"; ++}; ++ ++&hdmi_receiver { ++ hpd-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; ++ pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &hdptxphy0 { + status = "okay"; + }; +@@ -478,6 +489,12 @@ key1_pin: key1-pin { + }; + }; + ++ hdmirx { ++ hdmirx_hpd: hdmirx-5v-detection { ++ rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + pcie { + pcie2_0_rst: pcie2-0-rst { + rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; +-- +Armbian + diff --git a/patch/kernel/archive/rockchip64-6.15/rk3588-1091-arm64-dts-rockchip-Enable-HDMI-receiver-on-NanoPC-T6.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1091-arm64-dts-rockchip-Enable-HDMI-receiver-on-NanoPC-T6.patch new file mode 100644 index 000000000000..ffa60b67f5a8 --- /dev/null +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1091-arm64-dts-rockchip-Enable-HDMI-receiver-on-NanoPC-T6.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ricardo Pardini +Date: Fri, 23 May 2025 18:00:28 +0200 +Subject: arm64: dts: rockchip: Enable HDMI receiver on NanoPC-T6 + +The NanoPC-T6 (and its LTS variant) has a full-size HDMI port, which can be used +for receiving HDMI data. This enables support for it. + +Signed-off-by: Ricardo Pardini +--- + arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 17 ++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi +index 111111111111..222222222222 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi +@@ -404,6 +404,17 @@ &hdmi1_sound { + status = "okay"; + }; + ++&hdmi_receiver_cma { ++ status = "okay"; ++}; ++ ++&hdmi_receiver { ++ hpd-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; ++ pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &hdptxphy0 { + status = "okay"; + }; +@@ -665,6 +676,12 @@ usr_led_pin: usr-led-pin { + }; + }; + ++ hdmirx { ++ hdmirx_hpd: hdmirx-5v-detection { ++ rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + headphone { + hp_det: hp-det { + rockchip,pins = <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; +-- +Armbian + diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1100-arm64-dts-rockchip-opi5-max-add-2nd-hdmi.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1100-arm64-dts-rockchip-opi5-max-add-2nd-hdmi.patch similarity index 89% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1100-arm64-dts-rockchip-opi5-max-add-2nd-hdmi.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1100-arm64-dts-rockchip-opi5-max-add-2nd-hdmi.patch index d0451f1e260a..e0fcf97b300b 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1100-arm64-dts-rockchip-opi5-max-add-2nd-hdmi.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1100-arm64-dts-rockchip-opi5-max-add-2nd-hdmi.patch @@ -16,7 +16,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts b/arch/arm64 index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -@@ -21,6 +21,17 @@ hdmi0_con_in: endpoint { +@@ -32,6 +32,17 @@ hdmi1_con_in: endpoint { }; }; }; @@ -34,10 +34,16 @@ index 111111111111..222222222222 100644 }; &hdmi0 { -@@ -58,3 +69,34 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { - remote-endpoint = <&hdmi0_in_vp0>; +@@ -117,6 +128,37 @@ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { }; }; + ++&vp1 { ++ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { ++ reg = ; ++ remote-endpoint = <&hdmi1_in_vp1>; ++ }; ++}; + +&hdmi1 { + pinctrl-names = "default"; @@ -63,12 +69,9 @@ index 111111111111..222222222222 100644 +}; + + -+&vp1 { -+ vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { -+ reg = ; -+ remote-endpoint = <&hdmi1_in_vp1>; -+ }; -+}; + &vp1 { + vp1_out_hdmi1: endpoint@ROCKCHIP_VOP2_EP_HDMI1 { + reg = ; -- Armbian diff --git a/patch/kernel/archive/rockchip64-6.14/rk3588-1101-arm64-dts-rockchip-opi5-max-add-hdmi-sound.patch b/patch/kernel/archive/rockchip64-6.15/rk3588-1101-arm64-dts-rockchip-opi5-max-add-hdmi-sound.patch similarity index 97% rename from patch/kernel/archive/rockchip64-6.14/rk3588-1101-arm64-dts-rockchip-opi5-max-add-hdmi-sound.patch rename to patch/kernel/archive/rockchip64-6.15/rk3588-1101-arm64-dts-rockchip-opi5-max-add-hdmi-sound.patch index e37e5f1452d1..91d3b363a79b 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk3588-1101-arm64-dts-rockchip-opi5-max-add-hdmi-sound.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk3588-1101-arm64-dts-rockchip-opi5-max-add-hdmi-sound.patch @@ -16,7 +16,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts b/arch/arm64 index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dts -@@ -38,6 +38,22 @@ &hdmi0 { +@@ -49,6 +49,22 @@ &hdmi0 { status = "okay"; }; diff --git a/patch/kernel/archive/rockchip64-6.14/rk35xx-montjoie-crypto-v2-rk35xx.patch b/patch/kernel/archive/rockchip64-6.15/rk35xx-montjoie-crypto-v2-rk35xx.patch similarity index 99% rename from patch/kernel/archive/rockchip64-6.14/rk35xx-montjoie-crypto-v2-rk35xx.patch rename to patch/kernel/archive/rockchip64-6.15/rk35xx-montjoie-crypto-v2-rk35xx.patch index 6843ddfba6c0..c24f957309d3 100644 --- a/patch/kernel/archive/rockchip64-6.14/rk35xx-montjoie-crypto-v2-rk35xx.patch +++ b/patch/kernel/archive/rockchip64-6.15/rk35xx-montjoie-crypto-v2-rk35xx.patch @@ -102,8 +102,8 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi -@@ -1948,6 +1948,18 @@ sdhci: mmc@fe2e0000 { - status = "disabled"; +@@ -1973,6 +1973,18 @@ rng@fe378000 { + resets = <&scmi_reset 48>; }; + crypto: crypto@fe370000 { @@ -142,7 +142,7 @@ diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts index 111111111111..222222222222 100644 --- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi -@@ -1074,6 +1074,18 @@ rng: rng@fe388000 { +@@ -1090,6 +1090,18 @@ rng: rng@fe388000 { status = "disabled"; }; diff --git a/patch/kernel/archive/rockchip64-6.14/wifi-4003-add-bcm43342-chip.patch b/patch/kernel/archive/rockchip64-6.15/wifi-4003-add-bcm43342-chip.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/wifi-4003-add-bcm43342-chip.patch rename to patch/kernel/archive/rockchip64-6.15/wifi-4003-add-bcm43342-chip.patch diff --git a/patch/kernel/archive/rockchip64-6.14/wifi-4003-ssv-6051-driver.patch b/patch/kernel/archive/rockchip64-6.15/wifi-4003-ssv-6051-driver.patch similarity index 100% rename from patch/kernel/archive/rockchip64-6.14/wifi-4003-ssv-6051-driver.patch rename to patch/kernel/archive/rockchip64-6.15/wifi-4003-ssv-6051-driver.patch diff --git a/patch/kernel/archive/rockchip64-6.15/wifi-4004-ssv6051-fix-build-for-6.15-del_timer_sync-timer_dele.patch b/patch/kernel/archive/rockchip64-6.15/wifi-4004-ssv6051-fix-build-for-6.15-del_timer_sync-timer_dele.patch new file mode 100644 index 000000000000..e86c0f587655 --- /dev/null +++ b/patch/kernel/archive/rockchip64-6.15/wifi-4004-ssv6051-fix-build-for-6.15-del_timer_sync-timer_dele.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ricardo Pardini +Date: Fri, 23 May 2025 09:30:52 +0200 +Subject: ssv6051: fix build for 6.15 (2x del_timer_sync->timer_delete_sync) + +--- + drivers/net/wireless/ssv6051/smac/dev.c | 4 ++++ + drivers/net/wireless/ssv6051/smac/init.c | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/ssv6051/smac/dev.c b/drivers/net/wireless/ssv6051/smac/dev.c +index 111111111111..222222222222 100644 +--- a/drivers/net/wireless/ssv6051/smac/dev.c ++++ b/drivers/net/wireless/ssv6051/smac/dev.c +@@ -2190,7 +2190,11 @@ static void ssv6200_stop(struct ieee80211_hw *hw, bool flag) + } + sc->watchdog_flag = WD_SLEEP; + mutex_unlock(&sc->mutex); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0) ++ timer_delete_sync(&sc->watchdog_timeout); ++ #else + del_timer_sync(&sc->watchdog_timeout); ++ #endif + #ifdef CONFIG_SSV_SMARTLINK + { + extern void ksmartlink_exit(void); +diff --git a/drivers/net/wireless/ssv6051/smac/init.c b/drivers/net/wireless/ssv6051/smac/init.c +index 111111111111..222222222222 100644 +--- a/drivers/net/wireless/ssv6051/smac/init.c ++++ b/drivers/net/wireless/ssv6051/smac/init.c +@@ -461,7 +461,11 @@ static int ssv6xxx_deinit_softc(struct ssv_softc *sc) + ssv6xxx_rate_control_unregister(); + cancel_delayed_work_sync(&sc->bcast_tx_work); + //ssv6xxx_watchdog_controller(sc->sh ,(u8)SSV6XXX_HOST_CMD_WATCHDOG_STOP); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0) ++ timer_delete_sync(&sc->watchdog_timeout); ++ #else + del_timer_sync(&sc->watchdog_timeout); ++ #endif + cancel_delayed_work(&sc->thermal_monitor_work); + sc->ps_status = PWRSV_PREPARE; + flush_workqueue(sc->thermal_wq); +-- +Armbian + diff --git a/patch/kernel/archive/spacemit-6.6/patch-6.6.87-88.patch b/patch/kernel/archive/spacemit-6.6/patch-6.6.87-88.patch new file mode 100644 index 000000000000..f8333c4b5123 --- /dev/null +++ b/patch/kernel/archive/spacemit-6.6/patch-6.6.87-88.patch @@ -0,0 +1,13715 @@ +diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml +index ea3c5db6b52d2d..0f7e1b6ea81e9a 100644 +--- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml ++++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml +@@ -55,8 +55,7 @@ properties: + - const: arm,primecell + + reg: +- minItems: 1 +- maxItems: 2 ++ maxItems: 1 + + clocks: + maxItems: 1 +diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +index 3bad47b7b02bb9..0b4afb4078ef81 100644 +--- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml ++++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +@@ -41,8 +41,7 @@ properties: + - const: arm,primecell + + reg: +- minItems: 1 +- maxItems: 2 ++ maxItems: 1 + + clocks: + maxItems: 1 +diff --git a/Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml b/Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml +index b68141264c0e9f..4d40e75b4e1eff 100644 +--- a/Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml +@@ -71,7 +71,7 @@ properties: + description: + Any lane can be inverted or not. + minItems: 1 +- maxItems: 2 ++ maxItems: 3 + + required: + - data-lanes +diff --git a/Documentation/netlink/specs/rt_link.yaml b/Documentation/netlink/specs/rt_link.yaml +index d86a68f8475ca8..a8a1466adf1796 100644 +--- a/Documentation/netlink/specs/rt_link.yaml ++++ b/Documentation/netlink/specs/rt_link.yaml +@@ -892,11 +892,10 @@ attribute-sets: + - + name: prop-list + type: nest +- nested-attributes: link-attrs ++ nested-attributes: prop-list-link-attrs + - + name: alt-ifname + type: string +- multi-attr: true + - + name: perm-address + type: binary +@@ -931,6 +930,13 @@ attribute-sets: + - + name: gro-ipv4-max-size + type: u32 ++ - ++ name: prop-list-link-attrs ++ subset-of: link-attrs ++ attributes: ++ - ++ name: alt-ifname ++ multi-attr: true + - + name: af-spec-attrs + attributes: +@@ -1193,9 +1199,10 @@ attribute-sets: + type: u32 + - + name: mctp-attrs ++ name-prefix: ifla-mctp- + attributes: + - +- name: mctp-net ++ name: net + type: u32 + - + name: stats-attrs +@@ -1362,7 +1369,6 @@ operations: + - min-mtu + - max-mtu + - prop-list +- - alt-ifname + - perm-address + - proto-down-reason + - parent-dev-name +diff --git a/MAINTAINERS b/MAINTAINERS +index ae4c0cec507360..294d2ce29b7356 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4784,6 +4784,7 @@ S: Maintained + F: Documentation/admin-guide/module-signing.rst + F: certs/ + F: scripts/sign-file.c ++F: scripts/ssl-common.h + F: tools/certs/ + + CFAG12864B LCD DRIVER +diff --git a/Makefile b/Makefile +index 45f6b7d3d51e26..b1dfe3df7dfc9d 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 87 ++SUBLEVEL = 88 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +@@ -1004,6 +1004,9 @@ ifdef CONFIG_CC_IS_GCC + KBUILD_CFLAGS += -fconserve-stack + endif + ++# Ensure compilers do not transform certain loops into calls to wcslen() ++KBUILD_CFLAGS += -fno-builtin-wcslen ++ + # change __FILE__ to the relative path from the srctree + KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi +index c47d7d900f2836..0582d75349ba77 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi +@@ -1246,8 +1246,7 @@ dpi0_out: endpoint { + }; + + pwm0: pwm@1401e000 { +- compatible = "mediatek,mt8173-disp-pwm", +- "mediatek,mt6595-disp-pwm"; ++ compatible = "mediatek,mt8173-disp-pwm"; + reg = <0 0x1401e000 0 0x1000>; + #pwm-cells = <2>; + clocks = <&mmsys CLK_MM_DISP_PWM026M>, +@@ -1257,8 +1256,7 @@ pwm0: pwm@1401e000 { + }; + + pwm1: pwm@1401f000 { +- compatible = "mediatek,mt8173-disp-pwm", +- "mediatek,mt6595-disp-pwm"; ++ compatible = "mediatek,mt8173-disp-pwm"; + reg = <0 0x1401f000 0 0x1000>; + #pwm-cells = <2>; + clocks = <&mmsys CLK_MM_DISP_PWM126M>, +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index 488f8e75134959..2a4e686e633c62 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -75,6 +75,7 @@ + #define ARM_CPU_PART_CORTEX_A76 0xD0B + #define ARM_CPU_PART_NEOVERSE_N1 0xD0C + #define ARM_CPU_PART_CORTEX_A77 0xD0D ++#define ARM_CPU_PART_CORTEX_A76AE 0xD0E + #define ARM_CPU_PART_NEOVERSE_V1 0xD40 + #define ARM_CPU_PART_CORTEX_A78 0xD41 + #define ARM_CPU_PART_CORTEX_A78AE 0xD42 +@@ -119,6 +120,7 @@ + #define QCOM_CPU_PART_KRYO 0x200 + #define QCOM_CPU_PART_KRYO_2XX_GOLD 0x800 + #define QCOM_CPU_PART_KRYO_2XX_SILVER 0x801 ++#define QCOM_CPU_PART_KRYO_3XX_GOLD 0x802 + #define QCOM_CPU_PART_KRYO_3XX_SILVER 0x803 + #define QCOM_CPU_PART_KRYO_4XX_GOLD 0x804 + #define QCOM_CPU_PART_KRYO_4XX_SILVER 0x805 +@@ -158,6 +160,7 @@ + #define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76) + #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1) + #define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77) ++#define MIDR_CORTEX_A76AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76AE) + #define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1) + #define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78) + #define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE) +@@ -195,6 +198,7 @@ + #define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) + #define MIDR_QCOM_KRYO_2XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_GOLD) + #define MIDR_QCOM_KRYO_2XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_SILVER) ++#define MIDR_QCOM_KRYO_3XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_GOLD) + #define MIDR_QCOM_KRYO_3XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_SILVER) + #define MIDR_QCOM_KRYO_4XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_GOLD) + #define MIDR_QCOM_KRYO_4XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_SILVER) +diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spectre.h +index 9cc501450486d8..0c2b47673922e3 100644 +--- a/arch/arm64/include/asm/spectre.h ++++ b/arch/arm64/include/asm/spectre.h +@@ -97,7 +97,6 @@ enum mitigation_state arm64_get_meltdown_state(void); + + enum mitigation_state arm64_get_spectre_bhb_state(void); + bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope); +-u8 spectre_bhb_loop_affected(int scope); + void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused); + bool try_emulate_el1_ssbs(struct pt_regs *regs, u32 instr); + +diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h +index b73baaf8ae47be..d37db2f7a54cf0 100644 +--- a/arch/arm64/include/asm/tlbflush.h ++++ b/arch/arm64/include/asm/tlbflush.h +@@ -369,31 +369,33 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch) + #define __flush_tlb_range_op(op, start, pages, stride, \ + asid, tlb_level, tlbi_user) \ + do { \ ++ typeof(start) __flush_start = start; \ ++ typeof(pages) __flush_pages = pages; \ + int num = 0; \ + int scale = 3; \ + unsigned long addr; \ + \ +- while (pages > 0) { \ ++ while (__flush_pages > 0) { \ + if (!system_supports_tlb_range() || \ +- pages == 1) { \ +- addr = __TLBI_VADDR(start, asid); \ ++ __flush_pages == 1) { \ ++ addr = __TLBI_VADDR(__flush_start, asid); \ + __tlbi_level(op, addr, tlb_level); \ + if (tlbi_user) \ + __tlbi_user_level(op, addr, tlb_level); \ +- start += stride; \ +- pages -= stride >> PAGE_SHIFT; \ ++ __flush_start += stride; \ ++ __flush_pages -= stride >> PAGE_SHIFT; \ + continue; \ + } \ + \ +- num = __TLBI_RANGE_NUM(pages, scale); \ ++ num = __TLBI_RANGE_NUM(__flush_pages, scale); \ + if (num >= 0) { \ +- addr = __TLBI_VADDR_RANGE(start, asid, scale, \ +- num, tlb_level); \ ++ addr = __TLBI_VADDR_RANGE(__flush_start, asid, \ ++ scale, num, tlb_level); \ + __tlbi(r##op, addr); \ + if (tlbi_user) \ + __tlbi_user(r##op, addr); \ +- start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \ +- pages -= __TLBI_RANGE_PAGES(num, scale); \ ++ __flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \ ++ __flush_pages -= __TLBI_RANGE_PAGES(num, scale);\ + } \ + scale--; \ + } \ +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index 57503dc4b22faf..ecfbff6991bb5d 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -845,52 +845,86 @@ static unsigned long system_bhb_mitigations; + * This must be called with SCOPE_LOCAL_CPU for each type of CPU, before any + * SCOPE_SYSTEM call will give the right answer. + */ +-u8 spectre_bhb_loop_affected(int scope) ++static bool is_spectre_bhb_safe(int scope) ++{ ++ static const struct midr_range spectre_bhb_safe_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A35), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A510), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A520), ++ MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53), ++ MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_2XX_SILVER), ++ MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER), ++ MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER), ++ {}, ++ }; ++ static bool all_safe = true; ++ ++ if (scope != SCOPE_LOCAL_CPU) ++ return all_safe; ++ ++ if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_safe_list)) ++ return true; ++ ++ all_safe = false; ++ ++ return false; ++} ++ ++static u8 spectre_bhb_loop_affected(void) + { + u8 k = 0; +- static u8 max_bhb_k; +- +- if (scope == SCOPE_LOCAL_CPU) { +- static const struct midr_range spectre_bhb_k32_list[] = { +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A78), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A78AE), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_X1), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_X2), +- MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), +- MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1), +- {}, +- }; +- static const struct midr_range spectre_bhb_k24_list[] = { +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A76), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A77), +- MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), +- {}, +- }; +- static const struct midr_range spectre_bhb_k11_list[] = { +- MIDR_ALL_VERSIONS(MIDR_AMPERE1), +- {}, +- }; +- static const struct midr_range spectre_bhb_k8_list[] = { +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), +- {}, +- }; +- +- if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k32_list)) +- k = 32; +- else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k24_list)) +- k = 24; +- else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k11_list)) +- k = 11; +- else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k8_list)) +- k = 8; +- +- max_bhb_k = max(max_bhb_k, k); +- } else { +- k = max_bhb_k; +- } ++ ++ static const struct midr_range spectre_bhb_k132_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X3), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2), ++ }; ++ static const struct midr_range spectre_bhb_k38_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A715), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A720), ++ }; ++ static const struct midr_range spectre_bhb_k32_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A78), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A78AE), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X1), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X2), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1), ++ {}, ++ }; ++ static const struct midr_range spectre_bhb_k24_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A76), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A76AE), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A77), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), ++ MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_GOLD), ++ {}, ++ }; ++ static const struct midr_range spectre_bhb_k11_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_AMPERE1), ++ {}, ++ }; ++ static const struct midr_range spectre_bhb_k8_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), ++ {}, ++ }; ++ ++ if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k132_list)) ++ k = 132; ++ else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k38_list)) ++ k = 38; ++ else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k32_list)) ++ k = 32; ++ else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k24_list)) ++ k = 24; ++ else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k11_list)) ++ k = 11; ++ else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k8_list)) ++ k = 8; + + return k; + } +@@ -916,29 +950,13 @@ static enum mitigation_state spectre_bhb_get_cpu_fw_mitigation_state(void) + } + } + +-static bool is_spectre_bhb_fw_affected(int scope) ++static bool has_spectre_bhb_fw_mitigation(void) + { +- static bool system_affected; + enum mitigation_state fw_state; + bool has_smccc = arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_NONE; +- static const struct midr_range spectre_bhb_firmware_mitigated_list[] = { +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), +- MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), +- {}, +- }; +- bool cpu_in_list = is_midr_in_range_list(read_cpuid_id(), +- spectre_bhb_firmware_mitigated_list); +- +- if (scope != SCOPE_LOCAL_CPU) +- return system_affected; + + fw_state = spectre_bhb_get_cpu_fw_mitigation_state(); +- if (cpu_in_list || (has_smccc && fw_state == SPECTRE_MITIGATED)) { +- system_affected = true; +- return true; +- } +- +- return false; ++ return has_smccc && fw_state == SPECTRE_MITIGATED; + } + + static bool supports_ecbhb(int scope) +@@ -954,6 +972,8 @@ static bool supports_ecbhb(int scope) + ID_AA64MMFR1_EL1_ECBHB_SHIFT); + } + ++static u8 max_bhb_k; ++ + bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, + int scope) + { +@@ -962,16 +982,18 @@ bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, + if (supports_csv2p3(scope)) + return false; + +- if (supports_clearbhb(scope)) +- return true; +- +- if (spectre_bhb_loop_affected(scope)) +- return true; ++ if (is_spectre_bhb_safe(scope)) ++ return false; + +- if (is_spectre_bhb_fw_affected(scope)) +- return true; ++ /* ++ * At this point the core isn't known to be "safe" so we're going to ++ * assume it's vulnerable. We still need to update `max_bhb_k` though, ++ * but only if we aren't mitigating with clearbhb though. ++ */ ++ if (scope == SCOPE_LOCAL_CPU && !supports_clearbhb(SCOPE_LOCAL_CPU)) ++ max_bhb_k = max(max_bhb_k, spectre_bhb_loop_affected()); + +- return false; ++ return true; + } + + static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot) +@@ -1002,7 +1024,7 @@ early_param("nospectre_bhb", parse_spectre_bhb_param); + void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry) + { + bp_hardening_cb_t cpu_cb; +- enum mitigation_state fw_state, state = SPECTRE_VULNERABLE; ++ enum mitigation_state state = SPECTRE_VULNERABLE; + struct bp_hardening_data *data = this_cpu_ptr(&bp_hardening_data); + + if (!is_spectre_bhb_affected(entry, SCOPE_LOCAL_CPU)) +@@ -1028,7 +1050,7 @@ void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry) + this_cpu_set_vectors(EL1_VECTOR_BHB_CLEAR_INSN); + state = SPECTRE_MITIGATED; + set_bit(BHB_INSN, &system_bhb_mitigations); +- } else if (spectre_bhb_loop_affected(SCOPE_LOCAL_CPU)) { ++ } else if (spectre_bhb_loop_affected()) { + /* + * Ensure KVM uses the indirect vector which will have the + * branchy-loop added. A57/A72-r0 will already have selected +@@ -1041,32 +1063,29 @@ void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry) + this_cpu_set_vectors(EL1_VECTOR_BHB_LOOP); + state = SPECTRE_MITIGATED; + set_bit(BHB_LOOP, &system_bhb_mitigations); +- } else if (is_spectre_bhb_fw_affected(SCOPE_LOCAL_CPU)) { +- fw_state = spectre_bhb_get_cpu_fw_mitigation_state(); +- if (fw_state == SPECTRE_MITIGATED) { +- /* +- * Ensure KVM uses one of the spectre bp_hardening +- * vectors. The indirect vector doesn't include the EL3 +- * call, so needs upgrading to +- * HYP_VECTOR_SPECTRE_INDIRECT. +- */ +- if (!data->slot || data->slot == HYP_VECTOR_INDIRECT) +- data->slot += 1; +- +- this_cpu_set_vectors(EL1_VECTOR_BHB_FW); +- +- /* +- * The WA3 call in the vectors supersedes the WA1 call +- * made during context-switch. Uninstall any firmware +- * bp_hardening callback. +- */ +- cpu_cb = spectre_v2_get_sw_mitigation_cb(); +- if (__this_cpu_read(bp_hardening_data.fn) != cpu_cb) +- __this_cpu_write(bp_hardening_data.fn, NULL); +- +- state = SPECTRE_MITIGATED; +- set_bit(BHB_FW, &system_bhb_mitigations); +- } ++ } else if (has_spectre_bhb_fw_mitigation()) { ++ /* ++ * Ensure KVM uses one of the spectre bp_hardening ++ * vectors. The indirect vector doesn't include the EL3 ++ * call, so needs upgrading to ++ * HYP_VECTOR_SPECTRE_INDIRECT. ++ */ ++ if (!data->slot || data->slot == HYP_VECTOR_INDIRECT) ++ data->slot += 1; ++ ++ this_cpu_set_vectors(EL1_VECTOR_BHB_FW); ++ ++ /* ++ * The WA3 call in the vectors supersedes the WA1 call ++ * made during context-switch. Uninstall any firmware ++ * bp_hardening callback. ++ */ ++ cpu_cb = spectre_v2_get_sw_mitigation_cb(); ++ if (__this_cpu_read(bp_hardening_data.fn) != cpu_cb) ++ __this_cpu_write(bp_hardening_data.fn, NULL); ++ ++ state = SPECTRE_MITIGATED; ++ set_bit(BHB_FW, &system_bhb_mitigations); + } + + update_mitigation_state(&spectre_bhb_state, state); +@@ -1100,7 +1119,6 @@ void noinstr spectre_bhb_patch_loop_iter(struct alt_instr *alt, + { + u8 rd; + u32 insn; +- u16 loop_count = spectre_bhb_loop_affected(SCOPE_SYSTEM); + + BUG_ON(nr_inst != 1); /* MOV -> MOV */ + +@@ -1109,7 +1127,7 @@ void noinstr spectre_bhb_patch_loop_iter(struct alt_instr *alt, + + insn = le32_to_cpu(*origptr); + rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn); +- insn = aarch64_insn_gen_movewide(rd, loop_count, 0, ++ insn = aarch64_insn_gen_movewide(rd, max_bhb_k, 0, + AARCH64_INSN_VARIANT_64BIT, + AARCH64_INSN_MOVEWIDE_ZERO); + *updptr++ = cpu_to_le32(insn); +diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c +index 9818cde948ca9c..fe4314af8eeccc 100644 +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -391,7 +391,11 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) + if (err) + return err; + +- return kvm_share_hyp(vcpu, vcpu + 1); ++ err = kvm_share_hyp(vcpu, vcpu + 1); ++ if (err) ++ kvm_vgic_vcpu_destroy(vcpu); ++ ++ return err; + } + + void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) +diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c +index 38f3fe2e6bf6b0..bc97916a035a64 100644 +--- a/arch/arm64/mm/mmu.c ++++ b/arch/arm64/mm/mmu.c +@@ -1328,7 +1328,8 @@ int arch_add_memory(int nid, u64 start, u64 size, + __remove_pgd_mapping(swapper_pg_dir, + __phys_to_virt(start), size); + else { +- max_pfn = PFN_UP(start + size); ++ /* Address of hotplugged memory can be smaller */ ++ max_pfn = max(max_pfn, PFN_UP(start + size)); + max_low_pfn = max_pfn; + } + +diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c +index 55d6a48c76a821..1f529b13490b3b 100644 +--- a/arch/loongarch/kernel/acpi.c ++++ b/arch/loongarch/kernel/acpi.c +@@ -216,18 +216,6 @@ static __init int setup_node(int pxm) + return acpi_map_pxm_to_node(pxm); + } + +-/* +- * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for +- * I/O localities since SRAT does not list them. I/O localities are +- * not supported at this point. +- */ +-unsigned int numa_distance_cnt; +- +-static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit) +-{ +- return slit->locality_count; +-} +- + void __init numa_set_distance(int from, int to, int distance) + { + if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) { +diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c +index cb12eb211a49e0..8d74d7d6c05b47 100644 +--- a/arch/mips/dec/prom/init.c ++++ b/arch/mips/dec/prom/init.c +@@ -42,7 +42,7 @@ int (*__pmax_close)(int); + * Detect which PROM the DECSTATION has, and set the callback vectors + * appropriately. + */ +-void __init which_prom(s32 magic, s32 *prom_vec) ++static void __init which_prom(s32 magic, s32 *prom_vec) + { + /* + * No sign of the REX PROM's magic number means we assume a non-REX +diff --git a/arch/mips/include/asm/ds1287.h b/arch/mips/include/asm/ds1287.h +index 46cfb01f9a14e7..51cb61fd4c0330 100644 +--- a/arch/mips/include/asm/ds1287.h ++++ b/arch/mips/include/asm/ds1287.h +@@ -8,7 +8,7 @@ + #define __ASM_DS1287_H + + extern int ds1287_timer_state(void); +-extern void ds1287_set_base_clock(unsigned int clock); ++extern int ds1287_set_base_clock(unsigned int hz); + extern int ds1287_clockevent_init(int irq); + + #endif +diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c +index 9a47fbcd4638a6..de64d6bb7ba36c 100644 +--- a/arch/mips/kernel/cevt-ds1287.c ++++ b/arch/mips/kernel/cevt-ds1287.c +@@ -10,6 +10,7 @@ + #include + #include + ++#include + #include + + int ds1287_timer_state(void) +diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c +index 46b9476d758249..dc294c95da21cb 100644 +--- a/arch/powerpc/kernel/rtas.c ++++ b/arch/powerpc/kernel/rtas.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1839,6 +1840,9 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) + || nargs + nret > ARRAY_SIZE(args.args)) + return -EINVAL; + ++ nargs = array_index_nospec(nargs, ARRAY_SIZE(args.args)); ++ nret = array_index_nospec(nret, ARRAY_SIZE(args.args) - nargs); ++ + /* Copy in args. */ + if (copy_from_user(args.args, uargs->args, + nargs * sizeof(rtas_arg_t)) != 0) +diff --git a/arch/riscv/include/asm/kgdb.h b/arch/riscv/include/asm/kgdb.h +index 46677daf708bd0..cc11c4544cffd1 100644 +--- a/arch/riscv/include/asm/kgdb.h ++++ b/arch/riscv/include/asm/kgdb.h +@@ -19,16 +19,9 @@ + + #ifndef __ASSEMBLY__ + ++void arch_kgdb_breakpoint(void); + extern unsigned long kgdb_compiled_break; + +-static inline void arch_kgdb_breakpoint(void) +-{ +- asm(".global kgdb_compiled_break\n" +- ".option norvc\n" +- "kgdb_compiled_break: ebreak\n" +- ".option rvc\n"); +-} +- + #endif /* !__ASSEMBLY__ */ + + #define DBG_REG_ZERO "zero" +diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h +index 121fff429dce66..eceabf59ae482a 100644 +--- a/arch/riscv/include/asm/syscall.h ++++ b/arch/riscv/include/asm/syscall.h +@@ -62,8 +62,11 @@ static inline void syscall_get_arguments(struct task_struct *task, + unsigned long *args) + { + args[0] = regs->orig_a0; +- args++; +- memcpy(args, ®s->a1, 5 * sizeof(args[0])); ++ args[1] = regs->a1; ++ args[2] = regs->a2; ++ args[3] = regs->a3; ++ args[4] = regs->a4; ++ args[5] = regs->a5; + } + + static inline int syscall_get_arch(struct task_struct *task) +diff --git a/arch/riscv/kernel/kgdb.c b/arch/riscv/kernel/kgdb.c +index 2e0266ae6bd728..9f3db3503dabd6 100644 +--- a/arch/riscv/kernel/kgdb.c ++++ b/arch/riscv/kernel/kgdb.c +@@ -254,6 +254,12 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) + regs->epc = pc; + } + ++noinline void arch_kgdb_breakpoint(void) ++{ ++ asm(".global kgdb_compiled_break\n" ++ "kgdb_compiled_break: ebreak\n"); ++} ++ + void kgdb_arch_handle_qxfer_pkt(char *remcom_in_buffer, + char *remcom_out_buffer) + { +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index 175184b0592649..f598e0eb3b0a04 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -73,6 +73,9 @@ static struct resource bss_res = { .name = "Kernel bss", }; + static struct resource elfcorehdr_res = { .name = "ELF Core hdr", }; + #endif + ++static int num_standard_resources; ++static struct resource *standard_resources; ++ + static int __init add_resource(struct resource *parent, + struct resource *res) + { +@@ -146,7 +149,7 @@ static void __init init_resources(void) + struct resource *res = NULL; + struct resource *mem_res = NULL; + size_t mem_res_sz = 0; +- int num_resources = 0, res_idx = 0; ++ int num_resources = 0, res_idx = 0, non_resv_res = 0; + int ret = 0; + + /* + 1 as memblock_alloc() might increase memblock.reserved.cnt */ +@@ -215,6 +218,7 @@ static void __init init_resources(void) + /* Add /memory regions to the resource tree */ + for_each_mem_region(region) { + res = &mem_res[res_idx--]; ++ non_resv_res++; + + if (unlikely(memblock_is_nomap(region))) { + res->name = "Reserved"; +@@ -232,6 +236,9 @@ static void __init init_resources(void) + goto error; + } + ++ num_standard_resources = non_resv_res; ++ standard_resources = &mem_res[res_idx + 1]; ++ + /* Clean-up any unused pre-allocated resources */ + if (res_idx >= 0) + memblock_free(mem_res, (res_idx + 1) * sizeof(*mem_res)); +@@ -243,6 +250,33 @@ static void __init init_resources(void) + memblock_free(mem_res, mem_res_sz); + } + ++static int __init reserve_memblock_reserved_regions(void) ++{ ++ u64 i, j; ++ ++ for (i = 0; i < num_standard_resources; i++) { ++ struct resource *mem = &standard_resources[i]; ++ phys_addr_t r_start, r_end, mem_size = resource_size(mem); ++ ++ if (!memblock_is_region_reserved(mem->start, mem_size)) ++ continue; ++ ++ for_each_reserved_mem_range(j, &r_start, &r_end) { ++ resource_size_t start, end; ++ ++ start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); ++ end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); ++ ++ if (start > mem->end || end < mem->start) ++ continue; ++ ++ reserve_region_with_split(mem, start, end, "Reserved"); ++ } ++ } ++ ++ return 0; ++} ++arch_initcall(reserve_memblock_reserved_regions); + + static void __init parse_dtb(void) + { +diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h +index 5e41033bf4ca4b..01aaee703c6c57 100644 +--- a/arch/sparc/include/asm/pgtable_64.h ++++ b/arch/sparc/include/asm/pgtable_64.h +@@ -931,7 +931,6 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, + static inline void set_ptes(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte, unsigned int nr) + { +- arch_enter_lazy_mmu_mode(); + for (;;) { + __set_pte_at(mm, addr, ptep, pte, 0); + if (--nr == 0) +@@ -940,7 +939,6 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, + pte_val(pte) += PAGE_SIZE; + addr += PAGE_SIZE; + } +- arch_leave_lazy_mmu_mode(); + } + #define set_ptes set_ptes + +diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c +index ef69127d7e5e8b..148e1c85abb259 100644 +--- a/arch/sparc/mm/tlb.c ++++ b/arch/sparc/mm/tlb.c +@@ -52,8 +52,10 @@ void flush_tlb_pending(void) + + void arch_enter_lazy_mmu_mode(void) + { +- struct tlb_batch *tb = this_cpu_ptr(&tlb_batch); ++ struct tlb_batch *tb; + ++ preempt_disable(); ++ tb = this_cpu_ptr(&tlb_batch); + tb->active = 1; + } + +@@ -64,6 +66,7 @@ void arch_leave_lazy_mmu_mode(void) + if (tb->tlb_nr) + flush_tlb_pending(); + tb->active = 0; ++ preempt_enable(); + } + + static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index a0af6e8d584b02..d874ea22512b5c 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -881,6 +881,7 @@ config INTEL_TDX_GUEST + depends on X86_64 && CPU_SUP_INTEL + depends on X86_X2APIC + depends on EFI_STUB ++ depends on PARAVIRT + select ARCH_HAS_CC_PLATFORM + select X86_MEM_ENCRYPT + select X86_MCE +diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c +index b3c3a4be7471f1..18bb201e4354db 100644 +--- a/arch/x86/boot/compressed/mem.c ++++ b/arch/x86/boot/compressed/mem.c +@@ -34,11 +34,14 @@ static bool early_is_tdx_guest(void) + + void arch_accept_memory(phys_addr_t start, phys_addr_t end) + { ++ static bool sevsnp; ++ + /* Platform-specific memory-acceptance call goes here */ + if (early_is_tdx_guest()) { + if (!tdx_accept_memory(start, end)) + panic("TDX: Failed to accept memory\n"); +- } else if (sev_snp_enabled()) { ++ } else if (sevsnp || (sev_get_status() & MSR_AMD64_SEV_SNP_ENABLED)) { ++ sevsnp = true; + snp_accept_memory(start, end); + } else { + error("Cannot accept memory: unknown platform\n"); +diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c +index 01d61f0609ab4d..5616c3b258060e 100644 +--- a/arch/x86/boot/compressed/sev.c ++++ b/arch/x86/boot/compressed/sev.c +@@ -135,10 +135,7 @@ bool sev_snp_enabled(void) + + static void __page_state_change(unsigned long paddr, enum psc_op op) + { +- u64 val; +- +- if (!sev_snp_enabled()) +- return; ++ u64 val, msr; + + /* + * If private -> shared then invalidate the page before requesting the +@@ -147,6 +144,9 @@ static void __page_state_change(unsigned long paddr, enum psc_op op) + if (op == SNP_PAGE_STATE_SHARED && pvalidate(paddr, RMP_PG_SIZE_4K, 0)) + sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE); + ++ /* Save the current GHCB MSR value */ ++ msr = sev_es_rd_ghcb_msr(); ++ + /* Issue VMGEXIT to change the page state in RMP table. */ + sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op)); + VMGEXIT(); +@@ -156,6 +156,9 @@ static void __page_state_change(unsigned long paddr, enum psc_op op) + if ((GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) || GHCB_MSR_PSC_RESP_VAL(val)) + sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); + ++ /* Restore the GHCB MSR value */ ++ sev_es_wr_ghcb_msr(msr); ++ + /* + * Now that page state is changed in the RMP table, validate it so that it is + * consistent with the RMP entry. +@@ -166,11 +169,17 @@ static void __page_state_change(unsigned long paddr, enum psc_op op) + + void snp_set_page_private(unsigned long paddr) + { ++ if (!sev_snp_enabled()) ++ return; ++ + __page_state_change(paddr, SNP_PAGE_STATE_PRIVATE); + } + + void snp_set_page_shared(unsigned long paddr) + { ++ if (!sev_snp_enabled()) ++ return; ++ + __page_state_change(paddr, SNP_PAGE_STATE_SHARED); + } + +@@ -194,56 +203,10 @@ static bool early_setup_ghcb(void) + return true; + } + +-static phys_addr_t __snp_accept_memory(struct snp_psc_desc *desc, +- phys_addr_t pa, phys_addr_t pa_end) +-{ +- struct psc_hdr *hdr; +- struct psc_entry *e; +- unsigned int i; +- +- hdr = &desc->hdr; +- memset(hdr, 0, sizeof(*hdr)); +- +- e = desc->entries; +- +- i = 0; +- while (pa < pa_end && i < VMGEXIT_PSC_MAX_ENTRY) { +- hdr->end_entry = i; +- +- e->gfn = pa >> PAGE_SHIFT; +- e->operation = SNP_PAGE_STATE_PRIVATE; +- if (IS_ALIGNED(pa, PMD_SIZE) && (pa_end - pa) >= PMD_SIZE) { +- e->pagesize = RMP_PG_SIZE_2M; +- pa += PMD_SIZE; +- } else { +- e->pagesize = RMP_PG_SIZE_4K; +- pa += PAGE_SIZE; +- } +- +- e++; +- i++; +- } +- +- if (vmgexit_psc(boot_ghcb, desc)) +- sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); +- +- pvalidate_pages(desc); +- +- return pa; +-} +- + void snp_accept_memory(phys_addr_t start, phys_addr_t end) + { +- struct snp_psc_desc desc = {}; +- unsigned int i; +- phys_addr_t pa; +- +- if (!boot_ghcb && !early_setup_ghcb()) +- sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); +- +- pa = start; +- while (pa < end) +- pa = __snp_accept_memory(&desc, pa, end); ++ for (phys_addr_t pa = start; pa < end; pa += PAGE_SIZE) ++ __page_state_change(pa, SNP_PAGE_STATE_PRIVATE); + } + + void sev_es_shutdown_ghcb(void) +diff --git a/arch/x86/boot/compressed/sev.h b/arch/x86/boot/compressed/sev.h +index fc725a981b093b..4e463f33186df4 100644 +--- a/arch/x86/boot/compressed/sev.h ++++ b/arch/x86/boot/compressed/sev.h +@@ -12,11 +12,13 @@ + + bool sev_snp_enabled(void); + void snp_accept_memory(phys_addr_t start, phys_addr_t end); ++u64 sev_get_status(void); + + #else + + static inline bool sev_snp_enabled(void) { return false; } + static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { } ++static inline u64 sev_get_status(void) { return 0; } + + #endif + +diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c +index 2f67e196a2ead2..98d0ee9600eb54 100644 +--- a/arch/x86/coco/tdx/tdx.c ++++ b/arch/x86/coco/tdx/tdx.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -334,7 +335,7 @@ static int handle_halt(struct ve_info *ve) + return ve_instr_len(ve); + } + +-void __cpuidle tdx_safe_halt(void) ++void __cpuidle tdx_halt(void) + { + const bool irq_disabled = false; + +@@ -345,6 +346,16 @@ void __cpuidle tdx_safe_halt(void) + WARN_ONCE(1, "HLT instruction emulation failed\n"); + } + ++static void __cpuidle tdx_safe_halt(void) ++{ ++ tdx_halt(); ++ /* ++ * "__cpuidle" section doesn't support instrumentation, so stick ++ * with raw_* variant that avoids tracing hooks. ++ */ ++ raw_local_irq_enable(); ++} ++ + static int read_msr(struct pt_regs *regs, struct ve_info *ve) + { + struct tdx_hypercall_args args = { +@@ -888,6 +899,19 @@ void __init tdx_early_init(void) + x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; + x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; + ++ /* ++ * Avoid "sti;hlt" execution in TDX guests as HLT induces a #VE that ++ * will enable interrupts before HLT TDCALL invocation if executed ++ * in STI-shadow, possibly resulting in missed wakeup events. ++ * ++ * Modify all possible HLT execution paths to use TDX specific routines ++ * that directly execute TDCALL and toggle the interrupt state as ++ * needed after TDCALL completion. This also reduces HLT related #VEs ++ * in addition to having a reliable halt logic execution. ++ */ ++ pv_ops.irq.safe_halt = tdx_safe_halt; ++ pv_ops.irq.halt = tdx_halt; ++ + /* + * TDX intercepts the RDMSR to read the X2APIC ID in the parallel + * bringup low level code. That raises #VE which cannot be handled +diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c +index dcb1e9b8d86629..7dcf5305d695dc 100644 +--- a/arch/x86/events/intel/ds.c ++++ b/arch/x86/events/intel/ds.c +@@ -1203,8 +1203,10 @@ static u64 pebs_update_adaptive_cfg(struct perf_event *event) + * + precise_ip < 2 for the non event IP + * + For RTM TSX weight we need GPRs for the abort code. + */ +- gprs = (sample_type & PERF_SAMPLE_REGS_INTR) && +- (attr->sample_regs_intr & PEBS_GP_REGS); ++ gprs = ((sample_type & PERF_SAMPLE_REGS_INTR) && ++ (attr->sample_regs_intr & PEBS_GP_REGS)) || ++ ((sample_type & PERF_SAMPLE_REGS_USER) && ++ (attr->sample_regs_user & PEBS_GP_REGS)); + + tsx_weight = (sample_type & PERF_SAMPLE_WEIGHT_TYPE) && + ((attr->config & INTEL_ARCH_EVENT_MASK) == +@@ -1856,7 +1858,7 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event, + regs->flags &= ~PERF_EFLAGS_EXACT; + } + +- if (sample_type & PERF_SAMPLE_REGS_INTR) ++ if (sample_type & (PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER)) + adaptive_pebs_save_regs(regs, gprs); + } + +diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c +index a8f11e60b98794..091ed4651471ee 100644 +--- a/arch/x86/events/intel/uncore_snbep.c ++++ b/arch/x86/events/intel/uncore_snbep.c +@@ -4882,28 +4882,28 @@ static struct uncore_event_desc snr_uncore_iio_freerunning_events[] = { + INTEL_UNCORE_EVENT_DESC(ioclk, "event=0xff,umask=0x10"), + /* Free-Running IIO BANDWIDTH IN Counters */ + INTEL_UNCORE_EVENT_DESC(bw_in_port0, "event=0xff,umask=0x20"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port0.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port0.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port0.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(bw_in_port1, "event=0xff,umask=0x21"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port1.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port1.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port1.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(bw_in_port2, "event=0xff,umask=0x22"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port2.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port2.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port2.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(bw_in_port3, "event=0xff,umask=0x23"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port3.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port3.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port3.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(bw_in_port4, "event=0xff,umask=0x24"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port4.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port4.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port4.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(bw_in_port5, "event=0xff,umask=0x25"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port5.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port5.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port5.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(bw_in_port6, "event=0xff,umask=0x26"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port6.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port6.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port6.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(bw_in_port7, "event=0xff,umask=0x27"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port7.scale, "3.814697266e-6"), ++ INTEL_UNCORE_EVENT_DESC(bw_in_port7.scale, "3.0517578125e-5"), + INTEL_UNCORE_EVENT_DESC(bw_in_port7.unit, "MiB"), + { /* end: all zeroes */ }, + }; +@@ -5476,37 +5476,6 @@ static struct freerunning_counters icx_iio_freerunning[] = { + [ICX_IIO_MSR_BW_IN] = { 0xaa0, 0x1, 0x10, 8, 48, icx_iio_bw_freerunning_box_offsets }, + }; + +-static struct uncore_event_desc icx_uncore_iio_freerunning_events[] = { +- /* Free-Running IIO CLOCKS Counter */ +- INTEL_UNCORE_EVENT_DESC(ioclk, "event=0xff,umask=0x10"), +- /* Free-Running IIO BANDWIDTH IN Counters */ +- INTEL_UNCORE_EVENT_DESC(bw_in_port0, "event=0xff,umask=0x20"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port0.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port0.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port1, "event=0xff,umask=0x21"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port1.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port1.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port2, "event=0xff,umask=0x22"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port2.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port2.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port3, "event=0xff,umask=0x23"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port3.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port3.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port4, "event=0xff,umask=0x24"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port4.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port4.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port5, "event=0xff,umask=0x25"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port5.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port5.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port6, "event=0xff,umask=0x26"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port6.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port6.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port7, "event=0xff,umask=0x27"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port7.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port7.unit, "MiB"), +- { /* end: all zeroes */ }, +-}; +- + static struct intel_uncore_type icx_uncore_iio_free_running = { + .name = "iio_free_running", + .num_counters = 9, +@@ -5514,7 +5483,7 @@ static struct intel_uncore_type icx_uncore_iio_free_running = { + .num_freerunning_types = ICX_IIO_FREERUNNING_TYPE_MAX, + .freerunning = icx_iio_freerunning, + .ops = &skx_uncore_iio_freerunning_ops, +- .event_descs = icx_uncore_iio_freerunning_events, ++ .event_descs = snr_uncore_iio_freerunning_events, + .format_group = &skx_uncore_iio_freerunning_format_group, + }; + +@@ -6241,69 +6210,13 @@ static struct freerunning_counters spr_iio_freerunning[] = { + [SPR_IIO_MSR_BW_OUT] = { 0x3808, 0x1, 0x10, 8, 48 }, + }; + +-static struct uncore_event_desc spr_uncore_iio_freerunning_events[] = { +- /* Free-Running IIO CLOCKS Counter */ +- INTEL_UNCORE_EVENT_DESC(ioclk, "event=0xff,umask=0x10"), +- /* Free-Running IIO BANDWIDTH IN Counters */ +- INTEL_UNCORE_EVENT_DESC(bw_in_port0, "event=0xff,umask=0x20"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port0.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port0.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port1, "event=0xff,umask=0x21"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port1.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port1.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port2, "event=0xff,umask=0x22"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port2.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port2.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port3, "event=0xff,umask=0x23"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port3.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port3.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port4, "event=0xff,umask=0x24"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port4.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port4.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port5, "event=0xff,umask=0x25"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port5.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port5.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port6, "event=0xff,umask=0x26"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port6.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port6.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port7, "event=0xff,umask=0x27"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port7.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_in_port7.unit, "MiB"), +- /* Free-Running IIO BANDWIDTH OUT Counters */ +- INTEL_UNCORE_EVENT_DESC(bw_out_port0, "event=0xff,umask=0x30"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port0.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port0.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port1, "event=0xff,umask=0x31"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port1.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port1.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port2, "event=0xff,umask=0x32"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port2.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port2.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port3, "event=0xff,umask=0x33"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port3.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port3.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port4, "event=0xff,umask=0x34"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port4.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port4.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port5, "event=0xff,umask=0x35"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port5.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port5.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port6, "event=0xff,umask=0x36"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port6.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port6.unit, "MiB"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port7, "event=0xff,umask=0x37"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port7.scale, "3.814697266e-6"), +- INTEL_UNCORE_EVENT_DESC(bw_out_port7.unit, "MiB"), +- { /* end: all zeroes */ }, +-}; +- + static struct intel_uncore_type spr_uncore_iio_free_running = { + .name = "iio_free_running", + .num_counters = 17, + .num_freerunning_types = SPR_IIO_FREERUNNING_TYPE_MAX, + .freerunning = spr_iio_freerunning, + .ops = &skx_uncore_iio_freerunning_ops, +- .event_descs = spr_uncore_iio_freerunning_events, ++ .event_descs = snr_uncore_iio_freerunning_events, + .format_group = &skx_uncore_iio_freerunning_format_group, + }; + +diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h +index 8c5ae649d2df82..9acfe2bcf1fd5b 100644 +--- a/arch/x86/include/asm/irqflags.h ++++ b/arch/x86/include/asm/irqflags.h +@@ -56,6 +56,28 @@ static __always_inline void native_halt(void) + + #endif + ++#ifndef CONFIG_PARAVIRT ++#ifndef __ASSEMBLY__ ++/* ++ * Used in the idle loop; sti takes one instruction cycle ++ * to complete: ++ */ ++static __always_inline void arch_safe_halt(void) ++{ ++ native_safe_halt(); ++} ++ ++/* ++ * Used when interrupts are already enabled or to ++ * shutdown the processor: ++ */ ++static __always_inline void halt(void) ++{ ++ native_halt(); ++} ++#endif /* __ASSEMBLY__ */ ++#endif /* CONFIG_PARAVIRT */ ++ + #ifdef CONFIG_PARAVIRT_XXL + #include + #else +@@ -77,24 +99,6 @@ static __always_inline void arch_local_irq_enable(void) + native_irq_enable(); + } + +-/* +- * Used in the idle loop; sti takes one instruction cycle +- * to complete: +- */ +-static __always_inline void arch_safe_halt(void) +-{ +- native_safe_halt(); +-} +- +-/* +- * Used when interrupts are already enabled or to +- * shutdown the processor: +- */ +-static __always_inline void halt(void) +-{ +- native_halt(); +-} +- + /* + * For spinlocks, etc: + */ +diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h +index 6c8ff12140aea9..d8537e30cee192 100644 +--- a/arch/x86/include/asm/paravirt.h ++++ b/arch/x86/include/asm/paravirt.h +@@ -103,6 +103,16 @@ static inline void notify_page_enc_status_changed(unsigned long pfn, + PVOP_VCALL3(mmu.notify_page_enc_status_changed, pfn, npages, enc); + } + ++static __always_inline void arch_safe_halt(void) ++{ ++ PVOP_VCALL0(irq.safe_halt); ++} ++ ++static inline void halt(void) ++{ ++ PVOP_VCALL0(irq.halt); ++} ++ + #ifdef CONFIG_PARAVIRT_XXL + static inline void load_sp0(unsigned long sp0) + { +@@ -168,16 +178,6 @@ static inline void __write_cr4(unsigned long x) + PVOP_VCALL1(cpu.write_cr4, x); + } + +-static __always_inline void arch_safe_halt(void) +-{ +- PVOP_VCALL0(irq.safe_halt); +-} +- +-static inline void halt(void) +-{ +- PVOP_VCALL0(irq.halt); +-} +- + extern noinstr void pv_native_wbinvd(void); + + static __always_inline void wbinvd(void) +diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h +index 772d03487520e5..4149df559aaeac 100644 +--- a/arch/x86/include/asm/paravirt_types.h ++++ b/arch/x86/include/asm/paravirt_types.h +@@ -130,10 +130,9 @@ struct pv_irq_ops { + struct paravirt_callee_save save_fl; + struct paravirt_callee_save irq_disable; + struct paravirt_callee_save irq_enable; +- ++#endif + void (*safe_halt)(void); + void (*halt)(void); +-#endif + } __no_randomize_layout; + + struct pv_mmu_ops { +diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h +index 603e6d1e9d4aac..c632f09f0c9721 100644 +--- a/arch/x86/include/asm/tdx.h ++++ b/arch/x86/include/asm/tdx.h +@@ -46,7 +46,7 @@ void tdx_get_ve_info(struct ve_info *ve); + + bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve); + +-void tdx_safe_halt(void); ++void tdx_halt(void); + + bool tdx_early_handle_ve(struct pt_regs *regs); + +@@ -55,7 +55,7 @@ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport); + #else + + static inline void tdx_early_init(void) { }; +-static inline void tdx_safe_halt(void) { }; ++static inline void tdx_halt(void) { }; + + static inline bool tdx_early_handle_ve(struct pt_regs *regs) { return false; } + +diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h +index 64fbd2dbc5b761..a9088250770f2a 100644 +--- a/arch/x86/include/asm/xen/hypervisor.h ++++ b/arch/x86/include/asm/xen/hypervisor.h +@@ -62,11 +62,6 @@ void xen_arch_unregister_cpu(int num); + #ifdef CONFIG_PVH + void __init xen_pvh_init(struct boot_params *boot_params); + void __init mem_map_via_hcall(struct boot_params *boot_params_p); +-#ifdef CONFIG_XEN_PVH +-void __init xen_reserve_extra_memory(struct boot_params *bootp); +-#else +-static inline void xen_reserve_extra_memory(struct boot_params *bootp) { } +-#endif + #endif + + /* Lazy mode for batching updates / context switch */ +diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c +index 9413fb767c6a71..498f2753777292 100644 +--- a/arch/x86/kernel/cpu/amd.c ++++ b/arch/x86/kernel/cpu/amd.c +@@ -825,7 +825,7 @@ static void init_amd_k8(struct cpuinfo_x86 *c) + * (model = 0x14) and later actually support it. + * (AMD Erratum #110, docId: 25759). + */ +- if (c->x86_model < 0x14 && cpu_has(c, X86_FEATURE_LAHF_LM)) { ++ if (c->x86_model < 0x14 && cpu_has(c, X86_FEATURE_LAHF_LM) && !cpu_has(c, X86_FEATURE_HYPERVISOR)) { + clear_cpu_cap(c, X86_FEATURE_LAHF_LM); + if (!rdmsrl_amd_safe(0xc001100d, &value)) { + value &= ~BIT_64(32); +@@ -1039,6 +1039,16 @@ static void init_amd_zen1(struct cpuinfo_x86 *c) + + pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n"); + setup_force_cpu_bug(X86_BUG_DIV0); ++ ++ /* ++ * Turn off the Instructions Retired free counter on machines that are ++ * susceptible to erratum #1054 "Instructions Retired Performance ++ * Counter May Be Inaccurate". ++ */ ++ if (c->x86_model < 0x30) { ++ msr_clear_bit(MSR_K7_HWCR, MSR_K7_HWCR_IRPERF_EN_BIT); ++ clear_cpu_cap(c, X86_FEATURE_IRPERF); ++ } + } + + static bool cpu_has_zenbleed_microcode(void) +@@ -1185,13 +1195,8 @@ static void init_amd(struct cpuinfo_x86 *c) + if (!cpu_feature_enabled(X86_FEATURE_XENPV)) + set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + +- /* +- * Turn on the Instructions Retired free counter on machines not +- * susceptible to erratum #1054 "Instructions Retired Performance +- * Counter May Be Inaccurate". +- */ +- if (cpu_has(c, X86_FEATURE_IRPERF) && +- (boot_cpu_has(X86_FEATURE_ZEN1) && c->x86_model > 0x2f)) ++ /* Enable the Instructions Retired free counter */ ++ if (cpu_has(c, X86_FEATURE_IRPERF)) + msr_set_bit(MSR_K7_HWCR, MSR_K7_HWCR_IRPERF_EN_BIT); + + check_null_seg_clears_base(c); +diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c +index 38eeff91109f9b..6c0e0619e6d325 100644 +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -1168,7 +1168,13 @@ static void __split_lock_reenable(struct work_struct *work) + { + sld_update_msr(true); + } +-static DECLARE_DELAYED_WORK(sl_reenable, __split_lock_reenable); ++/* ++ * In order for each CPU to schedule its delayed work independently of the ++ * others, delayed work struct must be per-CPU. This is not required when ++ * sysctl_sld_mitigate is enabled because of the semaphore that limits ++ * the number of simultaneously scheduled delayed works to 1. ++ */ ++static DEFINE_PER_CPU(struct delayed_work, sl_reenable); + + /* + * If a CPU goes offline with pending delayed work to re-enable split lock +@@ -1189,7 +1195,7 @@ static int splitlock_cpu_offline(unsigned int cpu) + + static void split_lock_warn(unsigned long ip) + { +- struct delayed_work *work; ++ struct delayed_work *work = NULL; + int cpu; + + if (!current->reported_split_lock) +@@ -1211,11 +1217,17 @@ static void split_lock_warn(unsigned long ip) + if (down_interruptible(&buslock_sem) == -EINTR) + return; + work = &sl_reenable_unlock; +- } else { +- work = &sl_reenable; + } + + cpu = get_cpu(); ++ ++ if (!work) { ++ work = this_cpu_ptr(&sl_reenable); ++ /* Deferred initialization of per-CPU struct */ ++ if (!work->work.func) ++ INIT_DELAYED_WORK(work, __split_lock_reenable); ++ } ++ + schedule_delayed_work_on(cpu, work, 2); + + /* Disable split lock detection on this CPU to make progress */ +diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c +index 0ee172ce2d2124..ce78e39004e0ea 100644 +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -201,6 +201,12 @@ static bool need_sha_check(u32 cur_rev) + case 0xa70c0: return cur_rev <= 0xa70C009; break; + case 0xaa001: return cur_rev <= 0xaa00116; break; + case 0xaa002: return cur_rev <= 0xaa00218; break; ++ case 0xb0021: return cur_rev <= 0xb002146; break; ++ case 0xb1010: return cur_rev <= 0xb101046; break; ++ case 0xb2040: return cur_rev <= 0xb204031; break; ++ case 0xb4040: return cur_rev <= 0xb404031; break; ++ case 0xb6000: return cur_rev <= 0xb600031; break; ++ case 0xb7000: return cur_rev <= 0xb700031; break; + default: break; + } + +@@ -216,8 +222,7 @@ static bool verify_sha256_digest(u32 patch_id, u32 cur_rev, const u8 *data, unsi + struct sha256_state s; + int i; + +- if (x86_family(bsp_cpuid_1_eax) < 0x17 || +- x86_family(bsp_cpuid_1_eax) > 0x19) ++ if (x86_family(bsp_cpuid_1_eax) < 0x17) + return true; + + if (!need_sha_check(cur_rev)) +diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c +index b66f540de054a7..1f6fb8e85e0f60 100644 +--- a/arch/x86/kernel/e820.c ++++ b/arch/x86/kernel/e820.c +@@ -753,22 +753,21 @@ void __init e820__memory_setup_extended(u64 phys_addr, u32 data_len) + void __init e820__register_nosave_regions(unsigned long limit_pfn) + { + int i; +- unsigned long pfn = 0; ++ u64 last_addr = 0; + + for (i = 0; i < e820_table->nr_entries; i++) { + struct e820_entry *entry = &e820_table->entries[i]; + +- if (pfn < PFN_UP(entry->addr)) +- register_nosave_region(pfn, PFN_UP(entry->addr)); +- +- pfn = PFN_DOWN(entry->addr + entry->size); +- + if (entry->type != E820_TYPE_RAM && entry->type != E820_TYPE_RESERVED_KERN) +- register_nosave_region(PFN_UP(entry->addr), pfn); ++ continue; + +- if (pfn >= limit_pfn) +- break; ++ if (last_addr < entry->addr) ++ register_nosave_region(PFN_DOWN(last_addr), PFN_UP(entry->addr)); ++ ++ last_addr = entry->addr + entry->size; + } ++ ++ register_nosave_region(PFN_DOWN(last_addr), limit_pfn); + } + + #ifdef CONFIG_ACPI +diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c +index 8d51c86caa415f..234851fe0ef8e7 100644 +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -142,6 +142,11 @@ int paravirt_disable_iospace(void) + return request_resource(&ioport_resource, &reserve_ioports); + } + ++static noinstr void pv_native_safe_halt(void) ++{ ++ native_safe_halt(); ++} ++ + #ifdef CONFIG_PARAVIRT_XXL + static noinstr void pv_native_write_cr2(unsigned long val) + { +@@ -162,11 +167,6 @@ noinstr void pv_native_wbinvd(void) + { + native_wbinvd(); + } +- +-static noinstr void pv_native_safe_halt(void) +-{ +- native_safe_halt(); +-} + #endif + + struct pv_info pv_info = { +@@ -224,9 +224,11 @@ struct paravirt_patch_template pv_ops = { + .irq.save_fl = __PV_IS_CALLEE_SAVE(pv_native_save_fl), + .irq.irq_disable = __PV_IS_CALLEE_SAVE(pv_native_irq_disable), + .irq.irq_enable = __PV_IS_CALLEE_SAVE(pv_native_irq_enable), ++#endif /* CONFIG_PARAVIRT_XXL */ ++ ++ /* Irq HLT ops. */ + .irq.safe_halt = pv_native_safe_halt, + .irq.halt = native_halt, +-#endif /* CONFIG_PARAVIRT_XXL */ + + /* Mmu ops. */ + .mmu.flush_tlb_user = native_flush_tlb_local, +diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c +index bbe11363550bea..419353904173ff 100644 +--- a/arch/x86/kernel/process.c ++++ b/arch/x86/kernel/process.c +@@ -955,7 +955,7 @@ void select_idle_routine(const struct cpuinfo_x86 *c) + static_call_update(x86_idle, mwait_idle); + } else if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) { + pr_info("using TDX aware idle routine\n"); +- static_call_update(x86_idle, tdx_safe_halt); ++ static_call_update(x86_idle, tdx_halt); + } else + static_call_update(x86_idle, default_idle); + } +diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c +index c12624bc82a31b..983f8f5893a48c 100644 +--- a/arch/x86/kernel/signal_32.c ++++ b/arch/x86/kernel/signal_32.c +@@ -33,25 +33,55 @@ + #include + #include + ++/* ++ * The first GDT descriptor is reserved as 'NULL descriptor'. As bits 0 ++ * and 1 of a segment selector, i.e., the RPL bits, are NOT used to index ++ * GDT, selector values 0~3 all point to the NULL descriptor, thus values ++ * 0, 1, 2 and 3 are all valid NULL selector values. ++ * ++ * However IRET zeros ES, FS, GS, and DS segment registers if any of them ++ * is found to have any nonzero NULL selector value, which can be used by ++ * userspace in pre-FRED systems to spot any interrupt/exception by loading ++ * a nonzero NULL selector and waiting for it to become zero. Before FRED ++ * there was nothing software could do to prevent such an information leak. ++ * ++ * ERETU, the only legit instruction to return to userspace from kernel ++ * under FRED, by design does NOT zero any segment register to avoid this ++ * problem behavior. ++ * ++ * As such, leave NULL selector values 0~3 unchanged. ++ */ ++static inline u16 fixup_rpl(u16 sel) ++{ ++ return sel <= 3 ? sel : sel | 3; ++} ++ + #ifdef CONFIG_IA32_EMULATION + #include + + static inline void reload_segments(struct sigcontext_32 *sc) + { +- unsigned int cur; ++ u16 cur; + ++ /* ++ * Reload fs and gs if they have changed in the signal ++ * handler. This does not handle long fs/gs base changes in ++ * the handler, but does not clobber them at least in the ++ * normal case. ++ */ + savesegment(gs, cur); +- if ((sc->gs | 0x03) != cur) +- load_gs_index(sc->gs | 0x03); ++ if (fixup_rpl(sc->gs) != cur) ++ load_gs_index(fixup_rpl(sc->gs)); + savesegment(fs, cur); +- if ((sc->fs | 0x03) != cur) +- loadsegment(fs, sc->fs | 0x03); ++ if (fixup_rpl(sc->fs) != cur) ++ loadsegment(fs, fixup_rpl(sc->fs)); ++ + savesegment(ds, cur); +- if ((sc->ds | 0x03) != cur) +- loadsegment(ds, sc->ds | 0x03); ++ if (fixup_rpl(sc->ds) != cur) ++ loadsegment(ds, fixup_rpl(sc->ds)); + savesegment(es, cur); +- if ((sc->es | 0x03) != cur) +- loadsegment(es, sc->es | 0x03); ++ if (fixup_rpl(sc->es) != cur) ++ loadsegment(es, fixup_rpl(sc->es)); + } + + #define sigset32_t compat_sigset_t +@@ -105,18 +135,12 @@ static bool ia32_restore_sigcontext(struct pt_regs *regs, + regs->orig_ax = -1; + + #ifdef CONFIG_IA32_EMULATION +- /* +- * Reload fs and gs if they have changed in the signal +- * handler. This does not handle long fs/gs base changes in +- * the handler, but does not clobber them at least in the +- * normal case. +- */ + reload_segments(&sc); + #else +- loadsegment(gs, sc.gs); +- regs->fs = sc.fs; +- regs->es = sc.es; +- regs->ds = sc.ds; ++ loadsegment(gs, fixup_rpl(sc.gs)); ++ regs->fs = fixup_rpl(sc.fs); ++ regs->es = fixup_rpl(sc.es); ++ regs->ds = fixup_rpl(sc.ds); + #endif + + return fpu__restore_sig(compat_ptr(sc.fpstate), 1); +diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c +index 5fb12d9c71befa..a6cffeff75d40b 100644 +--- a/arch/x86/kvm/cpuid.c ++++ b/arch/x86/kvm/cpuid.c +@@ -1011,8 +1011,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + } + break; + case 0xa: { /* Architectural Performance Monitoring */ +- union cpuid10_eax eax; +- union cpuid10_edx edx; ++ union cpuid10_eax eax = { }; ++ union cpuid10_edx edx = { }; + + if (!enable_pmu || !static_cpu_has(X86_FEATURE_ARCH_PERFMON)) { + entry->eax = entry->ebx = entry->ecx = entry->edx = 0; +@@ -1028,8 +1028,6 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + + if (kvm_pmu_cap.version) + edx.split.anythread_deprecated = 1; +- edx.split.reserved1 = 0; +- edx.split.reserved2 = 0; + + entry->eax = eax.full; + entry->ebx = kvm_pmu_cap.events_mask; +@@ -1303,7 +1301,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + break; + /* AMD Extended Performance Monitoring and Debug */ + case 0x80000022: { +- union cpuid_0x80000022_ebx ebx; ++ union cpuid_0x80000022_ebx ebx = { }; + + entry->ecx = entry->edx = 0; + if (!enable_pmu || !kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2)) { +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index dcd0c12c308e59..2a2dbeb56897d8 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -11396,6 +11396,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, + if (kvm_mpx_supported()) + kvm_load_guest_fpu(vcpu); + ++ kvm_vcpu_srcu_read_lock(vcpu); ++ + r = kvm_apic_accept_events(vcpu); + if (r < 0) + goto out; +@@ -11409,6 +11411,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, + mp_state->mp_state = vcpu->arch.mp_state; + + out: ++ kvm_vcpu_srcu_read_unlock(vcpu); ++ + if (kvm_mpx_supported()) + kvm_put_guest_fpu(vcpu); + vcpu_put(vcpu); +diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c +index 2d850f6bae701c..525794f1eefb3f 100644 +--- a/arch/x86/mm/pat/set_memory.c ++++ b/arch/x86/mm/pat/set_memory.c +@@ -2374,7 +2374,7 @@ static int __set_pages_np(struct page *page, int numpages) + .pgd = NULL, + .numpages = numpages, + .mask_set = __pgprot(0), +- .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW), ++ .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY), + .flags = CPA_NO_CHECK_ALIAS }; + + /* +@@ -2453,7 +2453,7 @@ int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, + .pgd = pgd, + .numpages = numpages, + .mask_set = __pgprot(0), +- .mask_clr = __pgprot(~page_flags & (_PAGE_NX|_PAGE_RW)), ++ .mask_clr = __pgprot(~page_flags & (_PAGE_NX|_PAGE_RW|_PAGE_DIRTY)), + .flags = CPA_NO_CHECK_ALIAS, + }; + +@@ -2496,7 +2496,7 @@ int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address, + .pgd = pgd, + .numpages = numpages, + .mask_set = __pgprot(0), +- .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW), ++ .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY), + .flags = CPA_NO_CHECK_ALIAS, + }; + +diff --git a/arch/x86/platform/pvh/enlighten.c b/arch/x86/platform/pvh/enlighten.c +index a12117f3d4de72..00a92cb2c81474 100644 +--- a/arch/x86/platform/pvh/enlighten.c ++++ b/arch/x86/platform/pvh/enlighten.c +@@ -74,9 +74,6 @@ static void __init init_pvh_bootparams(bool xen_guest) + } else + xen_raw_printk("Warning: Can fit ISA range into e820\n"); + +- if (xen_guest) +- xen_reserve_extra_memory(&pvh_bootparams); +- + pvh_bootparams.hdr.cmd_line_ptr = + pvh_start_info.cmdline_paddr; + +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 0219f1c90202df..638de313fc4ed5 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -75,6 +75,9 @@ EXPORT_SYMBOL(xen_start_flags); + */ + struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info; + ++/* Number of pages released from the initial allocation. */ ++unsigned long xen_released_pages; ++ + static __ref void xen_get_vendor(void) + { + init_cpu_devs(); +@@ -471,6 +474,13 @@ int __init arch_xen_unpopulated_init(struct resource **res) + xen_free_unpopulated_pages(1, &pg); + } + ++ /* ++ * Account for the region being in the physmap but unpopulated. ++ * The value in xen_released_pages is used by the balloon ++ * driver to know how much of the physmap is unpopulated and ++ * set an accurate initial memory target. ++ */ ++ xen_released_pages += xen_extra_mem[i].n_pfns; + /* Zero so region is not also added to the balloon driver. */ + xen_extra_mem[i].n_pfns = 0; + } +diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c +index 60b358c2f43484..ac0a8adb2c50b1 100644 +--- a/arch/x86/xen/enlighten_pvh.c ++++ b/arch/x86/xen/enlighten_pvh.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -26,47 +27,6 @@ + bool __ro_after_init xen_pvh; + EXPORT_SYMBOL_GPL(xen_pvh); + +-void __init xen_pvh_init(struct boot_params *boot_params) +-{ +- xen_pvh = 1; +- xen_domain_type = XEN_HVM_DOMAIN; +- xen_start_flags = pvh_start_info.flags; +- +- if (xen_initial_domain()) +- x86_init.oem.arch_setup = xen_add_preferred_consoles; +- x86_init.oem.banner = xen_banner; +- +- xen_efi_init(boot_params); +- +- if (xen_initial_domain()) { +- struct xen_platform_op op = { +- .cmd = XENPF_get_dom0_console, +- }; +- int ret = HYPERVISOR_platform_op(&op); +- +- if (ret > 0) +- xen_init_vga(&op.u.dom0_console, +- min(ret * sizeof(char), +- sizeof(op.u.dom0_console)), +- &boot_params->screen_info); +- } +-} +- +-void __init mem_map_via_hcall(struct boot_params *boot_params_p) +-{ +- struct xen_memory_map memmap; +- int rc; +- +- memmap.nr_entries = ARRAY_SIZE(boot_params_p->e820_table); +- set_xen_guest_handle(memmap.buffer, boot_params_p->e820_table); +- rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); +- if (rc) { +- xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc); +- BUG(); +- } +- boot_params_p->e820_entries = memmap.nr_entries; +-} +- + /* + * Reserve e820 UNUSABLE regions to inflate the memory balloon. + * +@@ -81,8 +41,9 @@ void __init mem_map_via_hcall(struct boot_params *boot_params_p) + * hypervisor should notify us which memory ranges are suitable for creating + * foreign mappings, but that's not yet implemented. + */ +-void __init xen_reserve_extra_memory(struct boot_params *bootp) ++static void __init pvh_reserve_extra_memory(void) + { ++ struct boot_params *bootp = &boot_params; + unsigned int i, ram_pages = 0, extra_pages; + + for (i = 0; i < bootp->e820_entries; i++) { +@@ -133,3 +94,51 @@ void __init xen_reserve_extra_memory(struct boot_params *bootp) + xen_add_extra_mem(PFN_UP(e->addr), pages); + } + } ++ ++static void __init pvh_arch_setup(void) ++{ ++ pvh_reserve_extra_memory(); ++ ++ if (xen_initial_domain()) ++ xen_add_preferred_consoles(); ++} ++ ++void __init xen_pvh_init(struct boot_params *boot_params) ++{ ++ xen_pvh = 1; ++ xen_domain_type = XEN_HVM_DOMAIN; ++ xen_start_flags = pvh_start_info.flags; ++ ++ x86_init.oem.arch_setup = pvh_arch_setup; ++ x86_init.oem.banner = xen_banner; ++ ++ xen_efi_init(boot_params); ++ ++ if (xen_initial_domain()) { ++ struct xen_platform_op op = { ++ .cmd = XENPF_get_dom0_console, ++ }; ++ int ret = HYPERVISOR_platform_op(&op); ++ ++ if (ret > 0) ++ xen_init_vga(&op.u.dom0_console, ++ min(ret * sizeof(char), ++ sizeof(op.u.dom0_console)), ++ &boot_params->screen_info); ++ } ++} ++ ++void __init mem_map_via_hcall(struct boot_params *boot_params_p) ++{ ++ struct xen_memory_map memmap; ++ int rc; ++ ++ memmap.nr_entries = ARRAY_SIZE(boot_params_p->e820_table); ++ set_xen_guest_handle(memmap.buffer, boot_params_p->e820_table); ++ rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); ++ if (rc) { ++ xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc); ++ BUG(); ++ } ++ boot_params_p->e820_entries = memmap.nr_entries; ++} +diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c +index dc822124cacb9c..ec3ffb94807d3a 100644 +--- a/arch/x86/xen/setup.c ++++ b/arch/x86/xen/setup.c +@@ -38,9 +38,6 @@ + + #define GB(x) ((uint64_t)(x) * 1024 * 1024 * 1024) + +-/* Number of pages released from the initial allocation. */ +-unsigned long xen_released_pages; +- + /* Memory map would allow PCI passthrough. */ + bool xen_pv_pci_possible; + +diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c +index 4990a19e601334..74839f6f2e0cb3 100644 +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -854,6 +854,8 @@ int blk_register_queue(struct gendisk *disk) + out_debugfs_remove: + blk_debugfs_remove(disk); + mutex_unlock(&q->sysfs_lock); ++ if (queue_is_mq(q)) ++ blk_mq_sysfs_unregister(disk); + out_put_queue_kobj: + kobject_put(&disk->queue_kobj); + mutex_unlock(&q->sysfs_dir_lock); +diff --git a/certs/Makefile b/certs/Makefile +index 799ad7b9e68a0f..67e1f2707c2fad 100644 +--- a/certs/Makefile ++++ b/certs/Makefile +@@ -84,5 +84,5 @@ targets += x509_revocation_list + + hostprogs := extract-cert + +-HOSTCFLAGS_extract-cert.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) ++HOSTCFLAGS_extract-cert.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) -I$(srctree)/scripts + HOSTLDLIBS_extract-cert = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) +diff --git a/certs/extract-cert.c b/certs/extract-cert.c +index 70e9ec89d87d36..7d6d468ed6129d 100644 +--- a/certs/extract-cert.c ++++ b/certs/extract-cert.c +@@ -21,14 +21,17 @@ + #include + #include + #include +-#include +- +-/* +- * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API. +- * +- * Remove this if/when that API is no longer used +- */ +-#pragma GCC diagnostic ignored "-Wdeprecated-declarations" ++#if OPENSSL_VERSION_MAJOR >= 3 ++# define USE_PKCS11_PROVIDER ++# include ++# include ++#else ++# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0) ++# define USE_PKCS11_ENGINE ++# include ++# endif ++#endif ++#include "ssl-common.h" + + #define PKEY_ID_PKCS7 2 + +@@ -40,41 +43,6 @@ void format(void) + exit(2); + } + +-static void display_openssl_errors(int l) +-{ +- const char *file; +- char buf[120]; +- int e, line; +- +- if (ERR_peek_error() == 0) +- return; +- fprintf(stderr, "At main.c:%d:\n", l); +- +- while ((e = ERR_get_error_line(&file, &line))) { +- ERR_error_string(e, buf); +- fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); +- } +-} +- +-static void drain_openssl_errors(void) +-{ +- const char *file; +- int line; +- +- if (ERR_peek_error() == 0) +- return; +- while (ERR_get_error_line(&file, &line)) {} +-} +- +-#define ERR(cond, fmt, ...) \ +- do { \ +- bool __cond = (cond); \ +- display_openssl_errors(__LINE__); \ +- if (__cond) { \ +- err(1, fmt, ## __VA_ARGS__); \ +- } \ +- } while(0) +- + static const char *key_pass; + static BIO *wb; + static char *cert_dst; +@@ -94,6 +62,66 @@ static void write_cert(X509 *x509) + fprintf(stderr, "Extracted cert: %s\n", buf); + } + ++static X509 *load_cert_pkcs11(const char *cert_src) ++{ ++ X509 *cert = NULL; ++#ifdef USE_PKCS11_PROVIDER ++ OSSL_STORE_CTX *store; ++ ++ if (!OSSL_PROVIDER_try_load(NULL, "pkcs11", true)) ++ ERR(1, "OSSL_PROVIDER_try_load(pkcs11)"); ++ if (!OSSL_PROVIDER_try_load(NULL, "default", true)) ++ ERR(1, "OSSL_PROVIDER_try_load(default)"); ++ ++ store = OSSL_STORE_open(cert_src, NULL, NULL, NULL, NULL); ++ ERR(!store, "OSSL_STORE_open"); ++ ++ while (!OSSL_STORE_eof(store)) { ++ OSSL_STORE_INFO *info = OSSL_STORE_load(store); ++ ++ if (!info) { ++ drain_openssl_errors(__LINE__, 0); ++ continue; ++ } ++ if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_CERT) { ++ cert = OSSL_STORE_INFO_get1_CERT(info); ++ ERR(!cert, "OSSL_STORE_INFO_get1_CERT"); ++ } ++ OSSL_STORE_INFO_free(info); ++ if (cert) ++ break; ++ } ++ OSSL_STORE_close(store); ++#elif defined(USE_PKCS11_ENGINE) ++ ENGINE *e; ++ struct { ++ const char *cert_id; ++ X509 *cert; ++ } parms; ++ ++ parms.cert_id = cert_src; ++ parms.cert = NULL; ++ ++ ENGINE_load_builtin_engines(); ++ drain_openssl_errors(__LINE__, 1); ++ e = ENGINE_by_id("pkcs11"); ++ ERR(!e, "Load PKCS#11 ENGINE"); ++ if (ENGINE_init(e)) ++ drain_openssl_errors(__LINE__, 1); ++ else ++ ERR(1, "ENGINE_init"); ++ if (key_pass) ++ ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); ++ ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); ++ ERR(!parms.cert, "Get X.509 from PKCS#11"); ++ cert = parms.cert; ++#else ++ fprintf(stderr, "no pkcs11 engine/provider available\n"); ++ exit(1); ++#endif ++ return cert; ++} ++ + int main(int argc, char **argv) + { + char *cert_src; +@@ -122,28 +150,10 @@ int main(int argc, char **argv) + fclose(f); + exit(0); + } else if (!strncmp(cert_src, "pkcs11:", 7)) { +- ENGINE *e; +- struct { +- const char *cert_id; +- X509 *cert; +- } parms; +- +- parms.cert_id = cert_src; +- parms.cert = NULL; ++ X509 *cert = load_cert_pkcs11(cert_src); + +- ENGINE_load_builtin_engines(); +- drain_openssl_errors(); +- e = ENGINE_by_id("pkcs11"); +- ERR(!e, "Load PKCS#11 ENGINE"); +- if (ENGINE_init(e)) +- drain_openssl_errors(); +- else +- ERR(1, "ENGINE_init"); +- if (key_pass) +- ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); +- ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); +- ERR(!parms.cert, "Get X.509 from PKCS#11"); +- write_cert(parms.cert); ++ ERR(!cert, "load_cert_pkcs11 failed"); ++ write_cert(cert); + } else { + BIO *b; + X509 *x509; +diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c +index d418462ab79192..89f34310237c36 100644 +--- a/drivers/acpi/platform_profile.c ++++ b/drivers/acpi/platform_profile.c +@@ -22,8 +22,8 @@ static const char * const profile_names[] = { + }; + static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST); + +-static ssize_t platform_profile_choices_show(struct device *dev, +- struct device_attribute *attr, ++static ssize_t platform_profile_choices_show(struct kobject *kobj, ++ struct kobj_attribute *attr, + char *buf) + { + int len = 0; +@@ -49,8 +49,8 @@ static ssize_t platform_profile_choices_show(struct device *dev, + return len; + } + +-static ssize_t platform_profile_show(struct device *dev, +- struct device_attribute *attr, ++static ssize_t platform_profile_show(struct kobject *kobj, ++ struct kobj_attribute *attr, + char *buf) + { + enum platform_profile_option profile = PLATFORM_PROFILE_BALANCED; +@@ -77,8 +77,8 @@ static ssize_t platform_profile_show(struct device *dev, + return sysfs_emit(buf, "%s\n", profile_names[profile]); + } + +-static ssize_t platform_profile_store(struct device *dev, +- struct device_attribute *attr, ++static ssize_t platform_profile_store(struct kobject *kobj, ++ struct kobj_attribute *attr, + const char *buf, size_t count) + { + int err, i; +@@ -115,12 +115,12 @@ static ssize_t platform_profile_store(struct device *dev, + return count; + } + +-static DEVICE_ATTR_RO(platform_profile_choices); +-static DEVICE_ATTR_RW(platform_profile); ++static struct kobj_attribute attr_platform_profile_choices = __ATTR_RO(platform_profile_choices); ++static struct kobj_attribute attr_platform_profile = __ATTR_RW(platform_profile); + + static struct attribute *platform_profile_attrs[] = { +- &dev_attr_platform_profile_choices.attr, +- &dev_attr_platform_profile.attr, ++ &attr_platform_profile_choices.attr, ++ &attr_platform_profile.attr, + NULL + }; + +diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c +index 6e76780fb43083..98104d0b842bd7 100644 +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -591,6 +591,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { + .driver_data = board_ahci_yes_fbs }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3), + .driver_data = board_ahci_yes_fbs }, ++ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9215), ++ .driver_data = board_ahci_yes_fbs }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), + .driver_data = board_ahci_yes_fbs }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235), +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index 9cc02252218497..3263fc13491e1d 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -1496,8 +1496,15 @@ unsigned int atapi_eh_request_sense(struct ata_device *dev, + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.command = ATA_CMD_PACKET; + +- /* is it pointless to prefer PIO for "safety reasons"? */ +- if (ap->flags & ATA_FLAG_PIO_DMA) { ++ /* ++ * Do not use DMA if the connected device only supports PIO, even if the ++ * port prefers PIO commands via DMA. ++ * ++ * Ideally, we should call atapi_check_dma() to check if it is safe for ++ * the LLD to use DMA for REQUEST_SENSE, but we don't have a qc. ++ * Since we can't check the command, perhaps we should only use pio? ++ */ ++ if ((ap->flags & ATA_FLAG_PIO_DMA) && !(dev->flags & ATA_DFLAG_PIO)) { + tf.protocol = ATAPI_PROT_DMA; + tf.feature |= ATAPI_PKT_DMA; + } else { +diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c +index a701e1538482f0..be72030a500d44 100644 +--- a/drivers/ata/libata-sata.c ++++ b/drivers/ata/libata-sata.c +@@ -1365,6 +1365,8 @@ int ata_eh_read_sense_success_ncq_log(struct ata_link *link) + unsigned int err_mask, tag; + u8 *sense, sk = 0, asc = 0, ascq = 0; + u64 sense_valid, val; ++ u16 extended_sense; ++ bool aux_icc_valid; + int ret = 0; + + err_mask = ata_read_log_page(dev, ATA_LOG_SENSE_NCQ, 0, buf, 2); +@@ -1384,6 +1386,8 @@ int ata_eh_read_sense_success_ncq_log(struct ata_link *link) + + sense_valid = (u64)buf[8] | ((u64)buf[9] << 8) | + ((u64)buf[10] << 16) | ((u64)buf[11] << 24); ++ extended_sense = get_unaligned_le16(&buf[14]); ++ aux_icc_valid = extended_sense & BIT(15); + + ata_qc_for_each_raw(ap, qc, tag) { + if (!(qc->flags & ATA_QCFLAG_EH) || +@@ -1411,6 +1415,17 @@ int ata_eh_read_sense_success_ncq_log(struct ata_link *link) + continue; + } + ++ qc->result_tf.nsect = sense[6]; ++ qc->result_tf.hob_nsect = sense[7]; ++ qc->result_tf.lbal = sense[8]; ++ qc->result_tf.lbam = sense[9]; ++ qc->result_tf.lbah = sense[10]; ++ qc->result_tf.hob_lbal = sense[11]; ++ qc->result_tf.hob_lbam = sense[12]; ++ qc->result_tf.hob_lbah = sense[13]; ++ if (aux_icc_valid) ++ qc->result_tf.auxiliary = get_unaligned_le32(&sense[16]); ++ + /* Set sense without also setting scsicmd->result */ + scsi_build_sense_buffer(dev->flags & ATA_DFLAG_D_SENSE, + qc->scsicmd->sense_buffer, sk, +diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c +index 5275c6464f57fc..821bcf20741eae 100644 +--- a/drivers/ata/pata_pxa.c ++++ b/drivers/ata/pata_pxa.c +@@ -223,10 +223,16 @@ static int pxa_ata_probe(struct platform_device *pdev) + + ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, cmd_res->start, + resource_size(cmd_res)); ++ if (!ap->ioaddr.cmd_addr) ++ return -ENOMEM; + ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start, + resource_size(ctl_res)); ++ if (!ap->ioaddr.ctl_addr) ++ return -ENOMEM; + ap->ioaddr.bmdma_addr = devm_ioremap(&pdev->dev, dma_res->start, + resource_size(dma_res)); ++ if (!ap->ioaddr.bmdma_addr) ++ return -ENOMEM; + + /* + * Adjust register offsets +diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c +index a482741eb181ff..c3042eca6332df 100644 +--- a/drivers/ata/sata_sx4.c ++++ b/drivers/ata/sata_sx4.c +@@ -1117,9 +1117,14 @@ static int pdc20621_prog_dimm0(struct ata_host *host) + mmio += PDC_CHIP0_OFS; + + for (i = 0; i < ARRAY_SIZE(pdc_i2c_read_data); i++) +- pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, +- pdc_i2c_read_data[i].reg, +- &spd0[pdc_i2c_read_data[i].ofs]); ++ if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, ++ pdc_i2c_read_data[i].reg, ++ &spd0[pdc_i2c_read_data[i].ofs])) { ++ dev_err(host->dev, ++ "Failed in i2c read at index %d: device=%#x, reg=%#x\n", ++ i, PDC_DIMM0_SPD_DEV_ADDRESS, pdc_i2c_read_data[i].reg); ++ return -EIO; ++ } + + data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4); + data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | +@@ -1284,6 +1289,8 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) + + /* Programming DIMM0 Module Control Register (index_CID0:80h) */ + size = pdc20621_prog_dimm0(host); ++ if (size < 0) ++ return size; + dev_dbg(host->dev, "Local DIMM Size = %dMB\n", size); + + /* Programming DIMM Module Global Control Register (index_CID0:88h) */ +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index e9b0d94aeabd90..8a0f000221271f 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -687,6 +687,13 @@ int devres_release_group(struct device *dev, void *id) + spin_unlock_irqrestore(&dev->devres_lock, flags); + + release_nodes(dev, &todo); ++ } else if (list_empty(&dev->devres_head)) { ++ /* ++ * dev is probably dying via devres_release_all(): groups ++ * have already been removed and are on the process of ++ * being released - don't touch and don't warn. ++ */ ++ spin_unlock_irqrestore(&dev->devres_lock, flags); + } else { + WARN_ON(1); + spin_unlock_irqrestore(&dev->devres_lock, flags); +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 886c6359903779..8a6c1146df00fd 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -624,19 +624,20 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + * dependency. + */ + fput(old_file); ++ dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0); + if (partscan) + loop_reread_partitions(lo); + + error = 0; + done: +- /* enable and uncork uevent now that we are done */ +- dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0); ++ kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE); + return error; + + out_err: + loop_global_unlock(lo, is_loop); + out_putf: + fput(file); ++ dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0); + goto done; + } + +@@ -1104,8 +1105,8 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode, + if (partscan) + clear_bit(GD_SUPPRESS_PART_SCAN, &lo->lo_disk->state); + +- /* enable and uncork uevent now that we are done */ + dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0); ++ kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE); + + loop_global_unlock(lo, is_loop); + if (partscan) +diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c +index 892e2540f008ae..5651f40db1736e 100644 +--- a/drivers/bluetooth/btqca.c ++++ b/drivers/bluetooth/btqca.c +@@ -807,6 +807,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + const char *firmware_name) + { + struct qca_fw_config config = {}; ++ const char *variant = ""; + int err; + u8 rom_ver = 0; + u32 soc_ver; +@@ -901,13 +902,11 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: +- if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) { +- snprintf(config.fwname, sizeof(config.fwname), +- "qca/crnv%02xu.bin", rom_ver); +- } else { +- snprintf(config.fwname, sizeof(config.fwname), +- "qca/crnv%02x.bin", rom_ver); +- } ++ if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) ++ variant = "u"; ++ ++ snprintf(config.fwname, sizeof(config.fwname), ++ "qca/crnv%02x%s.bin", rom_ver, variant); + break; + case QCA_WCN3988: + snprintf(config.fwname, sizeof(config.fwname), +diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c +index 1e7c1f9db9e4b9..7f67e460f7f491 100644 +--- a/drivers/bluetooth/btrtl.c ++++ b/drivers/bluetooth/btrtl.c +@@ -1194,6 +1194,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, + rtl_dev_err(hdev, "mandatory config file %s not found", + btrtl_dev->ic_info->cfg_name); + ret = btrtl_dev->cfg_len; ++ if (!ret) ++ ret = -EINVAL; + goto err_free; + } + } +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index 17a2f158a0dfab..70320b8f1aa1c0 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -102,7 +102,8 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) + if (!skb) { + percpu_down_read(&hu->proto_lock); + +- if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) ++ if (test_bit(HCI_UART_PROTO_READY, &hu->flags) || ++ test_bit(HCI_UART_PROTO_INIT, &hu->flags)) + skb = hu->proto->dequeue(hu); + + percpu_up_read(&hu->proto_lock); +@@ -124,7 +125,8 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) + if (!percpu_down_read_trylock(&hu->proto_lock)) + return 0; + +- if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) ++ if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && ++ !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) + goto no_schedule; + + set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); +@@ -278,7 +280,8 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) + + percpu_down_read(&hu->proto_lock); + +- if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { ++ if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && ++ !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) { + percpu_up_read(&hu->proto_lock); + return -EUNATCH; + } +@@ -582,7 +585,8 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) + if (tty != hu->tty) + return; + +- if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) ++ if (test_bit(HCI_UART_PROTO_READY, &hu->flags) || ++ test_bit(HCI_UART_PROTO_INIT, &hu->flags)) + hci_uart_tx_wakeup(hu); + } + +@@ -608,7 +612,8 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, + + percpu_down_read(&hu->proto_lock); + +- if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { ++ if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && ++ !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) { + percpu_up_read(&hu->proto_lock); + return; + } +@@ -704,12 +709,16 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) + + hu->proto = p; + ++ set_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ + err = hci_uart_register_dev(hu); + if (err) { + return err; + } + + set_bit(HCI_UART_PROTO_READY, &hu->flags); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ + return 0; + } + +diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h +index 00bf7ae82c5b72..39f39704be41fd 100644 +--- a/drivers/bluetooth/hci_uart.h ++++ b/drivers/bluetooth/hci_uart.h +@@ -89,6 +89,7 @@ struct hci_uart { + #define HCI_UART_REGISTERED 1 + #define HCI_UART_PROTO_READY 2 + #define HCI_UART_NO_SUSPEND_NOTIFIER 3 ++#define HCI_UART_PROTO_INIT 4 + + /* TX states */ + #define HCI_UART_SENDING 1 +diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c +index 28750a40f0ed52..4bfc78f9781ede 100644 +--- a/drivers/bluetooth/hci_vhci.c ++++ b/drivers/bluetooth/hci_vhci.c +@@ -289,18 +289,18 @@ static void vhci_coredump(struct hci_dev *hdev) + + static void vhci_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb) + { +- char buf[80]; ++ const char *buf; + +- snprintf(buf, sizeof(buf), "Controller Name: vhci_ctrl\n"); ++ buf = "Controller Name: vhci_ctrl\n"; + skb_put_data(skb, buf, strlen(buf)); + +- snprintf(buf, sizeof(buf), "Firmware Version: vhci_fw\n"); ++ buf = "Firmware Version: vhci_fw\n"; + skb_put_data(skb, buf, strlen(buf)); + +- snprintf(buf, sizeof(buf), "Driver: vhci_drv\n"); ++ buf = "Driver: vhci_drv\n"; + skb_put_data(skb, buf, strlen(buf)); + +- snprintf(buf, sizeof(buf), "Vendor: vhci\n"); ++ buf = "Vendor: vhci\n"; + skb_put_data(skb, buf, strlen(buf)); + } + +diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c +index d6653cbcf94a2e..ad1e97222a0f49 100644 +--- a/drivers/bus/mhi/host/main.c ++++ b/drivers/bus/mhi/host/main.c +@@ -1204,11 +1204,16 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, + struct mhi_ring_element *mhi_tre; + struct mhi_buf_info *buf_info; + int eot, eob, chain, bei; +- int ret; ++ int ret = 0; + + /* Protect accesses for reading and incrementing WP */ + write_lock_bh(&mhi_chan->lock); + ++ if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED) { ++ ret = -ENODEV; ++ goto out; ++ } ++ + buf_ring = &mhi_chan->buf_ring; + tre_ring = &mhi_chan->tre_ring; + +@@ -1226,10 +1231,8 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, + + if (!info->pre_mapped) { + ret = mhi_cntrl->map_single(mhi_cntrl, buf_info); +- if (ret) { +- write_unlock_bh(&mhi_chan->lock); +- return ret; +- } ++ if (ret) ++ goto out; + } + + eob = !!(flags & MHI_EOB); +@@ -1246,9 +1249,10 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, + mhi_add_ring_element(mhi_cntrl, tre_ring); + mhi_add_ring_element(mhi_cntrl, buf_ring); + ++out: + write_unlock_bh(&mhi_chan->lock); + +- return 0; ++ return ret; + } + + int mhi_queue_buf(struct mhi_device *mhi_dev, enum dma_data_direction dir, +diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c +index 78999f7f248cb2..70e3fe20fdcf5e 100644 +--- a/drivers/char/tpm/tpm-chip.c ++++ b/drivers/char/tpm/tpm-chip.c +@@ -165,6 +165,11 @@ int tpm_try_get_ops(struct tpm_chip *chip) + goto out_ops; + + mutex_lock(&chip->tpm_mutex); ++ ++ /* tmp_chip_start may issue IO that is denied while suspended */ ++ if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) ++ goto out_lock; ++ + rc = tpm_chip_start(chip); + if (rc) + goto out_lock; +diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c +index c8ea52dfa55678..3a6223cafeb31a 100644 +--- a/drivers/char/tpm/tpm-interface.c ++++ b/drivers/char/tpm/tpm-interface.c +@@ -468,18 +468,11 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) + if (!chip) + return -ENODEV; + +- /* Give back zero bytes, as TPM chip has not yet fully resumed: */ +- if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) { +- rc = 0; +- goto out; +- } +- + if (chip->flags & TPM_CHIP_FLAG_TPM2) + rc = tpm2_get_random(chip, out, max); + else + rc = tpm1_get_random(chip, out, max); + +-out: + tpm_put_ops(chip); + return rc; + } +diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c +index f6aa0dfadb93ee..c71e61ccb95a2b 100644 +--- a/drivers/char/tpm/tpm_tis_core.c ++++ b/drivers/char/tpm/tpm_tis_core.c +@@ -114,11 +114,10 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, + return 0; + /* process status changes without irq support */ + do { ++ usleep_range(priv->timeout_min, priv->timeout_max); + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; +- usleep_range(priv->timeout_min, +- priv->timeout_max); + } while (time_before(jiffies, stop)); + return -ETIME; + } +@@ -464,7 +463,10 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) + + if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, + &priv->int_queue, false) < 0) { +- rc = -ETIME; ++ if (test_bit(TPM_TIS_STATUS_VALID_RETRY, &priv->flags)) ++ rc = -EAGAIN; ++ else ++ rc = -ETIME; + goto out_err; + } + status = tpm_tis_status(chip); +@@ -481,7 +483,10 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) + + if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, + &priv->int_queue, false) < 0) { +- rc = -ETIME; ++ if (test_bit(TPM_TIS_STATUS_VALID_RETRY, &priv->flags)) ++ rc = -EAGAIN; ++ else ++ rc = -ETIME; + goto out_err; + } + status = tpm_tis_status(chip); +@@ -546,9 +551,11 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len) + if (rc >= 0) + /* Data transfer done successfully */ + break; +- else if (rc != -EIO) ++ else if (rc != -EAGAIN && rc != -EIO) + /* Data transfer failed, not recoverable */ + return rc; ++ ++ usleep_range(priv->timeout_min, priv->timeout_max); + } + + /* go and do it */ +@@ -1147,6 +1154,9 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, + priv->timeout_max = TIS_TIMEOUT_MAX_ATML; + } + ++ if (priv->manufacturer_id == TPM_VID_IFX) ++ set_bit(TPM_TIS_STATUS_VALID_RETRY, &priv->flags); ++ + if (is_bsw()) { + priv->ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR, + ILB_REMAP_SIZE); +diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h +index 13e99cf65efe44..369496a6aebf13 100644 +--- a/drivers/char/tpm/tpm_tis_core.h ++++ b/drivers/char/tpm/tpm_tis_core.h +@@ -89,6 +89,7 @@ enum tpm_tis_flags { + TPM_TIS_INVALID_STATUS = 1, + TPM_TIS_DEFAULT_CANCELLATION = 2, + TPM_TIS_IRQ_TESTED = 3, ++ TPM_TIS_STATUS_VALID_RETRY = 4, + }; + + struct tpm_tis_data { +diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c +index fc4735f74f0f15..fefbfe7c42e7ea 100644 +--- a/drivers/clk/qcom/clk-branch.c ++++ b/drivers/clk/qcom/clk-branch.c +@@ -27,7 +27,7 @@ static bool clk_branch_in_hwcg_mode(const struct clk_branch *br) + + static bool clk_branch_check_halt(const struct clk_branch *br, bool enabling) + { +- bool invert = (br->halt_check == BRANCH_HALT_ENABLE); ++ bool invert = (br->halt_check & BRANCH_HALT_ENABLE); + u32 val; + + regmap_read(br->clkr.regmap, br->halt_reg, &val); +@@ -43,7 +43,7 @@ static bool clk_branch2_check_halt(const struct clk_branch *br, bool enabling) + { + u32 val; + u32 mask; +- bool invert = (br->halt_check == BRANCH_HALT_ENABLE); ++ bool invert = (br->halt_check & BRANCH_HALT_ENABLE); + + mask = CBCR_NOC_FSM_STATUS; + mask |= CBCR_CLK_OFF; +diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c +index 5358e28122abe4..5a8c93b12efa2b 100644 +--- a/drivers/clk/qcom/gdsc.c ++++ b/drivers/clk/qcom/gdsc.c +@@ -292,6 +292,9 @@ static int gdsc_enable(struct generic_pm_domain *domain) + */ + udelay(1); + ++ if (sc->flags & RETAIN_FF_ENABLE) ++ gdsc_retain_ff_on(sc); ++ + /* Turn on HW trigger mode if supported */ + if (sc->flags & HW_CTRL) { + ret = gdsc_hwctrl(sc, true); +@@ -308,9 +311,6 @@ static int gdsc_enable(struct generic_pm_domain *domain) + udelay(1); + } + +- if (sc->flags & RETAIN_FF_ENABLE) +- gdsc_retain_ff_on(sc); +- + return 0; + } + +@@ -420,13 +420,6 @@ static int gdsc_init(struct gdsc *sc) + goto err_disable_supply; + } + +- /* Turn on HW trigger mode if supported */ +- if (sc->flags & HW_CTRL) { +- ret = gdsc_hwctrl(sc, true); +- if (ret < 0) +- goto err_disable_supply; +- } +- + /* + * Make sure the retain bit is set if the GDSC is already on, + * otherwise we end up turning off the GDSC and destroying all +@@ -434,6 +427,14 @@ static int gdsc_init(struct gdsc *sc) + */ + if (sc->flags & RETAIN_FF_ENABLE) + gdsc_retain_ff_on(sc); ++ ++ /* Turn on HW trigger mode if supported */ ++ if (sc->flags & HW_CTRL) { ++ ret = gdsc_hwctrl(sc, true); ++ if (ret < 0) ++ goto err_disable_supply; ++ } ++ + } else if (sc->flags & ALWAYS_ON) { + /* If ALWAYS_ON GDSCs are not ON, turn them ON */ + gdsc_enable(&sc->pd); +@@ -465,6 +466,23 @@ static int gdsc_init(struct gdsc *sc) + return ret; + } + ++static void gdsc_pm_subdomain_remove(struct gdsc_desc *desc, size_t num) ++{ ++ struct device *dev = desc->dev; ++ struct gdsc **scs = desc->scs; ++ int i; ++ ++ /* Remove subdomains */ ++ for (i = num - 1; i >= 0; i--) { ++ if (!scs[i]) ++ continue; ++ if (scs[i]->parent) ++ pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd); ++ else if (!IS_ERR_OR_NULL(dev->pm_domain)) ++ pm_genpd_remove_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd); ++ } ++} ++ + int gdsc_register(struct gdsc_desc *desc, + struct reset_controller_dev *rcdev, struct regmap *regmap) + { +@@ -509,30 +527,27 @@ int gdsc_register(struct gdsc_desc *desc, + if (!scs[i]) + continue; + if (scs[i]->parent) +- pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd); ++ ret = pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd); + else if (!IS_ERR_OR_NULL(dev->pm_domain)) +- pm_genpd_add_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd); ++ ret = pm_genpd_add_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd); ++ if (ret) ++ goto err_pm_subdomain_remove; + } + + return of_genpd_add_provider_onecell(dev->of_node, data); ++ ++err_pm_subdomain_remove: ++ gdsc_pm_subdomain_remove(desc, i); ++ ++ return ret; + } + + void gdsc_unregister(struct gdsc_desc *desc) + { +- int i; + struct device *dev = desc->dev; +- struct gdsc **scs = desc->scs; + size_t num = desc->num; + +- /* Remove subdomains */ +- for (i = 0; i < num; i++) { +- if (!scs[i]) +- continue; +- if (scs[i]->parent) +- pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd); +- else if (!IS_ERR_OR_NULL(dev->pm_domain)) +- pm_genpd_remove_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd); +- } ++ gdsc_pm_subdomain_remove(desc, num); + of_genpd_del_provider(dev->of_node); + } + +diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c +index a4c95161cb22c4..193e4f643358bc 100644 +--- a/drivers/clocksource/timer-stm32-lp.c ++++ b/drivers/clocksource/timer-stm32-lp.c +@@ -168,9 +168,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) + } + + if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { +- ret = device_init_wakeup(&pdev->dev, true); +- if (ret) +- goto out_clk_disable; ++ device_set_wakeup_capable(&pdev->dev, true); + + ret = dev_pm_set_wake_irq(&pdev->dev, irq); + if (ret) +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index df445b44e9ec0b..0ac0998152ce81 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -2725,10 +2725,18 @@ EXPORT_SYMBOL(cpufreq_update_policy); + */ + void cpufreq_update_limits(unsigned int cpu) + { ++ struct cpufreq_policy *policy; ++ ++ policy = cpufreq_cpu_get(cpu); ++ if (!policy) ++ return; ++ + if (cpufreq_driver->update_limits) + cpufreq_driver->update_limits(cpu); + else + cpufreq_update_policy(cpu); ++ ++ cpufreq_cpu_put(policy); + } + EXPORT_SYMBOL_GPL(cpufreq_update_limits); + +diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c +index 7a3a104557f035..fa5bd64b7407d5 100644 +--- a/drivers/crypto/caam/qi.c ++++ b/drivers/crypto/caam/qi.c +@@ -122,12 +122,12 @@ int caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req) + qm_fd_addr_set64(&fd, addr); + + do { ++ refcount_inc(&req->drv_ctx->refcnt); + ret = qman_enqueue(req->drv_ctx->req_fq, &fd); +- if (likely(!ret)) { +- refcount_inc(&req->drv_ctx->refcnt); ++ if (likely(!ret)) + return 0; +- } + ++ refcount_dec(&req->drv_ctx->refcnt); + if (ret != -EBUSY) + break; + num_retries++; +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index b6ab56abeb682f..0caa57dafc525a 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -243,14 +243,17 @@ static bool sp_pci_is_master(struct sp_device *sp) + pdev_new = to_pci_dev(dev_new); + pdev_cur = to_pci_dev(dev_cur); + +- if (pdev_new->bus->number < pdev_cur->bus->number) +- return true; ++ if (pci_domain_nr(pdev_new->bus) != pci_domain_nr(pdev_cur->bus)) ++ return pci_domain_nr(pdev_new->bus) < pci_domain_nr(pdev_cur->bus); + +- if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn)) +- return true; ++ if (pdev_new->bus->number != pdev_cur->bus->number) ++ return pdev_new->bus->number < pdev_cur->bus->number; + +- if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn)) +- return true; ++ if (PCI_SLOT(pdev_new->devfn) != PCI_SLOT(pdev_cur->devfn)) ++ return PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn); ++ ++ if (PCI_FUNC(pdev_new->devfn) != PCI_FUNC(pdev_cur->devfn)) ++ return PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn); + + return false; + } +diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h +index fc18fd649ed771..5ecb9d3f3e9f94 100644 +--- a/drivers/firmware/efi/libstub/efistub.h ++++ b/drivers/firmware/efi/libstub/efistub.h +@@ -171,7 +171,7 @@ void efi_set_u64_split(u64 data, u32 *lo, u32 *hi) + * the EFI memory map. Other related structures, e.g. x86 e820ext, need + * to factor in this headroom requirement as well. + */ +-#define EFI_MMAP_NR_SLACK_SLOTS 8 ++#define EFI_MMAP_NR_SLACK_SLOTS 32 + + typedef struct efi_generic_dev_path efi_device_path_protocol_t; + +diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c +index 9130c691a2dd32..58648949f7bab2 100644 +--- a/drivers/gpio/gpio-tegra186.c ++++ b/drivers/gpio/gpio-tegra186.c +@@ -822,6 +822,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) + struct gpio_irq_chip *irq; + struct tegra_gpio *gpio; + struct device_node *np; ++ struct resource *res; + char **names; + int err; + +@@ -841,19 +842,19 @@ static int tegra186_gpio_probe(struct platform_device *pdev) + gpio->num_banks++; + + /* get register apertures */ +- gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security"); +- if (IS_ERR(gpio->secure)) { +- gpio->secure = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(gpio->secure)) +- return PTR_ERR(gpio->secure); +- } +- +- gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio"); +- if (IS_ERR(gpio->base)) { +- gpio->base = devm_platform_ioremap_resource(pdev, 1); +- if (IS_ERR(gpio->base)) +- return PTR_ERR(gpio->base); +- } ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "security"); ++ if (!res) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ gpio->secure = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(gpio->secure)) ++ return PTR_ERR(gpio->secure); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio"); ++ if (!res) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ gpio->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(gpio->base)) ++ return PTR_ERR(gpio->base); + + err = platform_irq_count(pdev); + if (err < 0) +diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c +index 324e942c0650bb..f70b72fe6edf59 100644 +--- a/drivers/gpio/gpio-zynq.c ++++ b/drivers/gpio/gpio-zynq.c +@@ -1018,6 +1018,7 @@ static int zynq_gpio_remove(struct platform_device *pdev) + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) + dev_warn(&pdev->dev, "pm_runtime_get_sync() Failed\n"); ++ device_init_wakeup(&pdev->dev, 0); + gpiochip_remove(&gpio->chip); + clk_disable_unprepare(gpio->clk); + device_set_wakeup_capable(&pdev->dev, 0); +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index ec4abf9ff47b5f..a2b4c97bcb319b 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -69,6 +69,7 @@ config DRM_USE_DYNAMIC_DEBUG + config DRM_KUNIT_TEST_HELPERS + tristate + depends on DRM && KUNIT ++ select DRM_KMS_HELPER + help + KUnit Helpers for KMS drivers. + +@@ -79,7 +80,6 @@ config DRM_KUNIT_TEST + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER + select DRM_LIB_RANDOM +- select DRM_KMS_HELPER + select DRM_BUDDY + select DRM_EXPORT_FOR_TESTS if m + select DRM_KUNIT_TEST_HELPERS +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 45dd6cbad81e79..10f5a3d0f59163 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -6015,6 +6015,7 @@ struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev, + { + struct dma_fence *old = NULL; + ++ dma_fence_get(gang); + do { + dma_fence_put(old); + rcu_read_lock(); +@@ -6024,12 +6025,19 @@ struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev, + if (old == gang) + break; + +- if (!dma_fence_is_signaled(old)) ++ if (!dma_fence_is_signaled(old)) { ++ dma_fence_put(gang); + return old; ++ } + + } while (cmpxchg((struct dma_fence __force **)&adev->gang_submit, + old, gang) != old); + ++ /* ++ * Drop it once for the exchanged reference in adev and once for the ++ * thread local reference acquired in amdgpu_device_get_gang(). ++ */ ++ dma_fence_put(old); + dma_fence_put(old); + return NULL; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +index ba3a87cb88ccc9..be4cc4868a748e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +@@ -211,7 +211,7 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach, + struct sg_table *sgt, + enum dma_data_direction dir) + { +- if (sgt->sgl->page_link) { ++ if (sg_page(sgt->sgl)) { + dma_unmap_sgtable(attach->dev, sgt, dir, 0); + sg_free_table(sgt); + kfree(sgt); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index a51ceebb80547e..bacf2e5de2abce 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -1651,7 +1651,6 @@ static const u16 amdgpu_unsupported_pciidlist[] = { + }; + + static const struct pci_device_id pciidlist[] = { +-#ifdef CONFIG_DRM_AMDGPU_SI + {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI}, + {0x1002, 0x6784, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI}, + {0x1002, 0x6788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI}, +@@ -1724,8 +1723,6 @@ static const struct pci_device_id pciidlist[] = { + {0x1002, 0x6665, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY}, + {0x1002, 0x6667, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY}, + {0x1002, 0x666F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|AMD_IS_MOBILITY}, +-#endif +-#ifdef CONFIG_DRM_AMDGPU_CIK + /* Kaveri */ + {0x1002, 0x1304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_MOBILITY|AMD_IS_APU}, + {0x1002, 0x1305, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMD_IS_APU}, +@@ -1808,7 +1805,6 @@ static const struct pci_device_id pciidlist[] = { + {0x1002, 0x985D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU}, + {0x1002, 0x985E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU}, + {0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU}, +-#endif + /* topaz */ + {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, + {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, +@@ -2090,14 +2086,14 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + return -ENOTSUPP; + } + ++ switch (flags & AMD_ASIC_MASK) { ++ case CHIP_TAHITI: ++ case CHIP_PITCAIRN: ++ case CHIP_VERDE: ++ case CHIP_OLAND: ++ case CHIP_HAINAN: + #ifdef CONFIG_DRM_AMDGPU_SI +- if (!amdgpu_si_support) { +- switch (flags & AMD_ASIC_MASK) { +- case CHIP_TAHITI: +- case CHIP_PITCAIRN: +- case CHIP_VERDE: +- case CHIP_OLAND: +- case CHIP_HAINAN: ++ if (!amdgpu_si_support) { + dev_info(&pdev->dev, + "SI support provided by radeon.\n"); + dev_info(&pdev->dev, +@@ -2105,16 +2101,18 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + ); + return -ENODEV; + } +- } ++ break; ++#else ++ dev_info(&pdev->dev, "amdgpu is built without SI support.\n"); ++ return -ENODEV; + #endif ++ case CHIP_KAVERI: ++ case CHIP_BONAIRE: ++ case CHIP_HAWAII: ++ case CHIP_KABINI: ++ case CHIP_MULLINS: + #ifdef CONFIG_DRM_AMDGPU_CIK +- if (!amdgpu_cik_support) { +- switch (flags & AMD_ASIC_MASK) { +- case CHIP_KAVERI: +- case CHIP_BONAIRE: +- case CHIP_HAWAII: +- case CHIP_KABINI: +- case CHIP_MULLINS: ++ if (!amdgpu_cik_support) { + dev_info(&pdev->dev, + "CIK support provided by radeon.\n"); + dev_info(&pdev->dev, +@@ -2122,8 +2120,14 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + ); + return -ENODEV; + } +- } ++ break; ++#else ++ dev_info(&pdev->dev, "amdgpu is built without CIK support.\n"); ++ return -ENODEV; + #endif ++ default: ++ break; ++ } + + adev = devm_drm_dev_alloc(&pdev->dev, &amdgpu_kms_driver, typeof(*adev), ddev); + if (IS_ERR(adev)) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +index 8669677662d0c0..35dc926f234e39 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +@@ -212,6 +212,11 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties, + return -EINVAL; + } + ++ if (args->ring_size < KFD_MIN_QUEUE_RING_SIZE) { ++ args->ring_size = KFD_MIN_QUEUE_RING_SIZE; ++ pr_debug("Size lower. clamped to KFD_MIN_QUEUE_RING_SIZE"); ++ } ++ + if (!access_ok((const void __user *) args->read_pointer_address, + sizeof(uint32_t))) { + pr_err("Can't access read pointer\n"); +@@ -477,6 +482,11 @@ static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p, + return -EINVAL; + } + ++ if (args->ring_size < KFD_MIN_QUEUE_RING_SIZE) { ++ args->ring_size = KFD_MIN_QUEUE_RING_SIZE; ++ pr_debug("Size lower. clamped to KFD_MIN_QUEUE_RING_SIZE"); ++ } ++ + properties.queue_address = args->ring_base_address; + properties.queue_size = args->ring_size; + properties.queue_percent = args->queue_percentage & 0xFF; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +index 9d0b0bf70ad1ea..2786d47961e075 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +@@ -1388,6 +1388,11 @@ int kfd_debugfs_hang_hws(struct kfd_node *dev) + return -EINVAL; + } + ++ if (dev->kfd->shared_resources.enable_mes) { ++ dev_err(dev->adev->dev, "Inducing MES hang is not supported\n"); ++ return -EINVAL; ++ } ++ + return dqm_debugfs_hang_hws(dev->dqm); + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index 64346c71c62a30..a6d08dee74f6ea 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -35,6 +35,7 @@ + #include + #include "amdgpu_amdkfd.h" + #include "amdgpu.h" ++#include "amdgpu_reset.h" + + struct mm_struct; + +@@ -1110,6 +1111,17 @@ static void kfd_process_remove_sysfs(struct kfd_process *p) + p->kobj = NULL; + } + ++/* ++ * If any GPU is ongoing reset, wait for reset complete. ++ */ ++static void kfd_process_wait_gpu_reset_complete(struct kfd_process *p) ++{ ++ int i; ++ ++ for (i = 0; i < p->n_pdds; i++) ++ flush_workqueue(p->pdds[i]->dev->adev->reset_domain->wq); ++} ++ + /* No process locking is needed in this function, because the process + * is not findable any more. We must assume that no other thread is + * using it any more, otherwise we couldn't safely free the process +@@ -1123,6 +1135,11 @@ static void kfd_process_wq_release(struct work_struct *work) + kfd_process_dequeue_from_all_devices(p); + pqm_uninit(&p->pqm); + ++ /* ++ * If GPU in reset, user queues may still running, wait for reset complete. ++ */ ++ kfd_process_wait_gpu_reset_complete(p); ++ + /* Signal the eviction fence after user mode queues are + * destroyed. This allows any BOs to be freed without + * triggering pointless evictions or waiting for fences. +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index e057c2bc7be424..d11a71e8aa1413 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -510,7 +510,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) + pr_err("Pasid 0x%x destroy queue %d failed, ret %d\n", + pqm->process->pasid, + pqn->q->properties.queue_id, retval); +- if (retval != -ETIME) ++ if (retval != -ETIME && retval != -EIO) + goto err_destroy_queue; + } + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 3696b9112c74e3..28f2b4022d34e3 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -4484,17 +4484,17 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + } + } + ++ if (link_cnt > (MAX_PIPES * 2)) { ++ DRM_ERROR( ++ "KMS: Cannot support more than %d display indexes\n", ++ MAX_PIPES * 2); ++ goto fail; ++ } ++ + /* loops over all connectors on the board */ + for (i = 0; i < link_cnt; i++) { + struct dc_link *link = NULL; + +- if (i > AMDGPU_DM_MAX_DISPLAY_INDEX) { +- DRM_ERROR( +- "KMS: Cannot support more than %d display indexes\n", +- AMDGPU_DM_MAX_DISPLAY_INDEX); +- continue; +- } +- + aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL); + if (!aconnector) + goto fail; +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index cc5e01df151356..88e64b280c90f5 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -1563,7 +1563,9 @@ struct dc_link { + bool dongle_mode_timing_override; + bool blank_stream_on_ocs_change; + bool read_dpcd204h_on_irq_hpd; ++ bool force_dp_ffe_preset; + } wa_flags; ++ union dc_dp_ffe_preset forced_dp_ffe_preset; + struct link_mst_stream_allocation_table mst_stream_alloc_table; + + struct dc_link_status link_status; +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +index ff38a85c4fa22d..e71b79f5a66cda 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +@@ -1930,20 +1930,11 @@ static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx) + dc->hwss.get_position(&pipe_ctx, 1, &position); + vpos = position.vertical_count; + +- /* Avoid wraparound calculation issues */ +- vupdate_start += stream->timing.v_total; +- vupdate_end += stream->timing.v_total; +- vpos += stream->timing.v_total; +- + if (vpos <= vupdate_start) { + /* VPOS is in VACTIVE or back porch. */ + lines_to_vupdate = vupdate_start - vpos; +- } else if (vpos > vupdate_end) { +- /* VPOS is in the front porch. */ +- return; + } else { +- /* VPOS is in VUPDATE. */ +- lines_to_vupdate = 0; ++ lines_to_vupdate = stream->timing.v_total - vpos + vupdate_start; + } + + /* Calculate time until VUPDATE in microseconds. */ +@@ -1951,13 +1942,18 @@ static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx) + stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; + us_to_vupdate = lines_to_vupdate * us_per_line; + ++ /* Stall out until the cursor update completes. */ ++ if (vupdate_end < vupdate_start) ++ vupdate_end += stream->timing.v_total; ++ ++ /* Position is in the range of vupdate start and end*/ ++ if (lines_to_vupdate > stream->timing.v_total - vupdate_end + vupdate_start) ++ us_to_vupdate = 0; ++ + /* 70 us is a conservative estimate of cursor update time*/ + if (us_to_vupdate > 70) + return; + +- /* Stall out until the cursor update completes. */ +- if (vupdate_end < vupdate_start) +- vupdate_end += stream->timing.v_total; + us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; + udelay(us_to_vupdate + us_vupdate); + } +diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c +index 39a57bcd78667a..576acf2ce10dd5 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c +@@ -44,7 +44,7 @@ void hubp31_set_unbounded_requesting(struct hubp *hubp, bool enable) + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_UNBOUNDED_REQ_MODE, enable); +- REG_UPDATE(CURSOR_CONTROL, CURSOR_REQ_MODE, enable); ++ REG_UPDATE(CURSOR_CONTROL, CURSOR_REQ_MODE, 1); + } + + void hubp31_soft_reset(struct hubp *hubp, bool reset) +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +index 9d1adfc09fb2aa..51e88efee11e4a 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +@@ -697,6 +697,8 @@ void override_training_settings( + lt_settings->pre_emphasis = overrides->pre_emphasis; + if (overrides->post_cursor2 != NULL) + lt_settings->post_cursor2 = overrides->post_cursor2; ++ if (link->wa_flags.force_dp_ffe_preset && !dp_is_lttpr_present(link)) ++ lt_settings->ffe_preset = &link->forced_dp_ffe_preset; + if (overrides->ffe_preset != NULL) + lt_settings->ffe_preset = overrides->ffe_preset; + /* Override HW lane settings with BIOS forced values if present */ +diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +index 86f95a291d65f6..bef6578ac4bfef 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +@@ -51,6 +51,11 @@ static int amd_powerplay_create(struct amdgpu_device *adev) + hwmgr->adev = adev; + hwmgr->not_vf = !amdgpu_sriov_vf(adev); + hwmgr->device = amdgpu_cgs_create_device(adev); ++ if (!hwmgr->device) { ++ kfree(hwmgr); ++ return -ENOMEM; ++ } ++ + mutex_init(&hwmgr->msg_lock); + hwmgr->chip_family = adev->family; + hwmgr->chip_id = adev->asic_type; +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c +index a6c3610db23ee6..7209e965dc5247 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c +@@ -267,10 +267,10 @@ int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) + if (hwmgr->thermal_controller.fanInfo.bNoFan || + (hwmgr->thermal_controller.fanInfo. + ucTachometerPulsesPerRevolution == 0) || +- speed == 0 || ++ (!speed || speed > UINT_MAX/8) || + (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || + (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) +- return 0; ++ return -EINVAL; + + if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) + smu7_fan_ctrl_stop_smc_fan_control(hwmgr); +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c +index 190af79f3236fd..e93b7c4aa8c941 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c +@@ -307,10 +307,10 @@ int vega10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) + int result = 0; + + if (hwmgr->thermal_controller.fanInfo.bNoFan || +- speed == 0 || ++ (!speed || speed > UINT_MAX/8) || + (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || + (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) +- return -1; ++ return -EINVAL; + + if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) + result = vega10_fan_ctrl_stop_smc_fan_control(hwmgr); +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c +index e9737ca8418a52..a1b1c985ca9ac1 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c +@@ -191,7 +191,7 @@ int vega20_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) + uint32_t tach_period, crystal_clock_freq; + int result = 0; + +- if (!speed) ++ if (!speed || speed > UINT_MAX/8) + return -EINVAL; + + if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) { +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +index 4c58c2cd26d886..0cdf3257b19b3b 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +@@ -1274,6 +1274,9 @@ static int arcturus_set_fan_speed_rpm(struct smu_context *smu, + uint32_t crystal_clock_freq = 2500; + uint32_t tach_period; + ++ if (!speed || speed > UINT_MAX/8) ++ return -EINVAL; ++ + tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); + WREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT, + REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT), +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +index 123c19bb622808..1b726489d86a0f 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +@@ -1202,7 +1202,7 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, + uint32_t crystal_clock_freq = 2500; + uint32_t tach_period; + +- if (speed == 0) ++ if (!speed || speed > UINT_MAX/8) + return -EINVAL; + /* + * To prevent from possible overheat, some ASICs may have requirement +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +index c0adfa46ac7896..8504692be47f17 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +@@ -1227,7 +1227,7 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu, + uint32_t tach_period; + int ret; + +- if (!speed) ++ if (!speed || speed > UINT_MAX/8) + return -EINVAL; + + ret = smu_v13_0_auto_fan_control(smu, 0); +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 554d4468aa7c08..f3681970887cc8 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -1373,7 +1373,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) + mode = &new_crtc_state->mode; + adjusted_mode = &new_crtc_state->adjusted_mode; + +- if (!new_crtc_state->mode_changed) ++ if (!new_crtc_state->mode_changed && !new_crtc_state->connectors_changed) + continue; + + drm_dbg_atomic(dev, "modeset on [ENCODER:%d:%s]\n", +diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c +index cfbe020de54e01..98df4788d096f0 100644 +--- a/drivers/gpu/drm/drm_panel.c ++++ b/drivers/gpu/drm/drm_panel.c +@@ -49,7 +49,7 @@ static LIST_HEAD(panel_list); + * @dev: parent device of the panel + * @funcs: panel operations + * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to +- * the panel interface ++ * the panel interface (must NOT be DRM_MODE_CONNECTOR_Unknown) + * + * Initialize the panel structure for subsequent registration with + * drm_panel_add(). +@@ -57,6 +57,9 @@ static LIST_HEAD(panel_list); + void drm_panel_init(struct drm_panel *panel, struct device *dev, + const struct drm_panel_funcs *funcs, int connector_type) + { ++ if (connector_type == DRM_MODE_CONNECTOR_Unknown) ++ DRM_WARN("%s: %s: a valid connector type is required!\n", __func__, dev_name(dev)); ++ + INIT_LIST_HEAD(&panel->list); + INIT_LIST_HEAD(&panel->followers); + mutex_init(&panel->follower_lock); +diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c +index c00f6f16244c0d..036b095c988828 100644 +--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c ++++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c +@@ -93,6 +93,12 @@ static const struct drm_dmi_panel_orientation_data onegx1_pro = { + .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, + }; + ++static const struct drm_dmi_panel_orientation_data lcd640x960_leftside_up = { ++ .width = 640, ++ .height = 960, ++ .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, ++}; ++ + static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = { + .width = 720, + .height = 1280, +@@ -123,6 +129,12 @@ static const struct drm_dmi_panel_orientation_data lcd1080x1920_rightside_up = { + .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, + }; + ++static const struct drm_dmi_panel_orientation_data lcd1200x1920_leftside_up = { ++ .width = 1200, ++ .height = 1920, ++ .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, ++}; ++ + static const struct drm_dmi_panel_orientation_data lcd1200x1920_rightside_up = { + .width = 1200, + .height = 1920, +@@ -184,10 +196,10 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T103HAF"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, +- }, { /* AYA NEO AYANEO 2 */ ++ }, { /* AYA NEO AYANEO 2/2S */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"), +- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "AYANEO 2"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "AYANEO 2"), + }, + .driver_data = (void *)&lcd1200x1920_rightside_up, + }, { /* AYA NEO 2021 */ +@@ -202,6 +214,18 @@ static const struct dmi_system_id orientation_data[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "AIR"), + }, + .driver_data = (void *)&lcd1080x1920_leftside_up, ++ }, { /* AYA NEO Flip DS Bottom Screen */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FLIP DS"), ++ }, ++ .driver_data = (void *)&lcd640x960_leftside_up, ++ }, { /* AYA NEO Flip KB/DS Top Screen */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "FLIP"), ++ }, ++ .driver_data = (void *)&lcd1080x1920_leftside_up, + }, { /* AYA NEO Founder */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYA NEO"), +@@ -226,6 +250,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_MATCH(DMI_BOARD_NAME, "KUN"), + }, + .driver_data = (void *)&lcd1600x2560_rightside_up, ++ }, { /* AYA NEO SLIDE */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "SLIDE"), ++ }, ++ .driver_data = (void *)&lcd1080x1920_leftside_up, + }, { /* AYN Loki Max */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ayn"), +@@ -315,6 +345,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"), + }, + .driver_data = (void *)&gpd_win2, ++ }, { /* GPD Win 2 (correct DMI strings) */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "WIN2") ++ }, ++ .driver_data = (void *)&lcd720x1280_rightside_up, + }, { /* GPD Win 3 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"), +@@ -443,6 +479,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"), + }, + .driver_data = (void *)&lcd1600x2560_leftside_up, ++ }, { /* OneXPlayer Mini (Intel) */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK TECHNOLOGY CO., LTD."), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"), ++ }, ++ .driver_data = (void *)&lcd1200x1920_leftside_up, + }, { /* OrangePi Neo */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "OrangePi"), +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +index d9bb352b8baab7..0729ab5955171e 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +@@ -1218,7 +1218,8 @@ static int intel_engine_init_tlb_invalidation(struct intel_engine_cs *engine) + num = ARRAY_SIZE(xelpmp_regs); + } + } else { +- if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 71) || ++ if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 74) || ++ GRAPHICS_VER_FULL(i915) == IP_VER(12, 71) || + GRAPHICS_VER_FULL(i915) == IP_VER(12, 70) || + GRAPHICS_VER_FULL(i915) == IP_VER(12, 50) || + GRAPHICS_VER_FULL(i915) == IP_VER(12, 55)) { +diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c +index 07269ff3be136d..25c1023eb5f9fa 100644 +--- a/drivers/gpu/drm/i915/gt/intel_mocs.c ++++ b/drivers/gpu/drm/i915/gt/intel_mocs.c +@@ -487,7 +487,7 @@ static bool has_mocs(const struct drm_i915_private *i915) + return !IS_DGFX(i915); + } + +-static unsigned int get_mocs_settings(const struct drm_i915_private *i915, ++static unsigned int get_mocs_settings(struct drm_i915_private *i915, + struct drm_i915_mocs_table *table) + { + unsigned int flags; +@@ -495,7 +495,7 @@ static unsigned int get_mocs_settings(const struct drm_i915_private *i915, + memset(table, 0, sizeof(struct drm_i915_mocs_table)); + + table->unused_entries_index = I915_MOCS_PTE; +- if (IS_GFX_GT_IP_RANGE(&i915->gt0, IP_VER(12, 70), IP_VER(12, 71))) { ++ if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 74))) { + table->size = ARRAY_SIZE(mtl_mocs_table); + table->table = mtl_mocs_table; + table->n_entries = MTL_NUM_MOCS_ENTRIES; +diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c +index 6e8c182b2559e7..3c7f4ed51bb05d 100644 +--- a/drivers/gpu/drm/i915/gt/intel_rc6.c ++++ b/drivers/gpu/drm/i915/gt/intel_rc6.c +@@ -117,21 +117,10 @@ static void gen11_rc6_enable(struct intel_rc6 *rc6) + GEN6_RC_CTL_RC6_ENABLE | + GEN6_RC_CTL_EI_MODE(1); + +- /* +- * BSpec 52698 - Render powergating must be off. +- * FIXME BSpec is outdated, disabling powergating for MTL is just +- * temporary wa and should be removed after fixing real cause +- * of forcewake timeouts. +- */ +- if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) +- pg_enable = +- GEN9_MEDIA_PG_ENABLE | +- GEN11_MEDIA_SAMPLER_PG_ENABLE; +- else +- pg_enable = +- GEN9_RENDER_PG_ENABLE | +- GEN9_MEDIA_PG_ENABLE | +- GEN11_MEDIA_SAMPLER_PG_ENABLE; ++ pg_enable = ++ GEN9_RENDER_PG_ENABLE | ++ GEN9_MEDIA_PG_ENABLE | ++ GEN11_MEDIA_SAMPLER_PG_ENABLE; + + if (GRAPHICS_VER(gt->i915) >= 12 && !IS_DG1(gt->i915)) { + for (i = 0; i < I915_MAX_VCS; i++) +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c +index ba9e07fc2b5770..552662953e7a44 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c ++++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c +@@ -316,6 +316,11 @@ void intel_huc_init_early(struct intel_huc *huc) + } + } + ++void intel_huc_fini_late(struct intel_huc *huc) ++{ ++ delayed_huc_load_fini(huc); ++} ++ + #define HUC_LOAD_MODE_STRING(x) (x ? "GSC" : "legacy") + static int check_huc_loading_mode(struct intel_huc *huc) + { +@@ -413,12 +418,6 @@ int intel_huc_init(struct intel_huc *huc) + + void intel_huc_fini(struct intel_huc *huc) + { +- /* +- * the fence is initialized in init_early, so we need to clean it up +- * even if HuC loading is off. +- */ +- delayed_huc_load_fini(huc); +- + if (huc->heci_pkt) + i915_vma_unpin_and_release(&huc->heci_pkt, 0); + +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h +index ba5cb08e9e7bf1..09aff3148f7ddb 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h ++++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h +@@ -55,6 +55,7 @@ struct intel_huc { + + int intel_huc_sanitize(struct intel_huc *huc); + void intel_huc_init_early(struct intel_huc *huc); ++void intel_huc_fini_late(struct intel_huc *huc); + int intel_huc_init(struct intel_huc *huc); + void intel_huc_fini(struct intel_huc *huc); + void intel_huc_suspend(struct intel_huc *huc); +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c +index 98b103375b7ab0..c29d187ddad1cd 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c ++++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c +@@ -145,6 +145,7 @@ void intel_uc_init_late(struct intel_uc *uc) + + void intel_uc_driver_late_release(struct intel_uc *uc) + { ++ intel_huc_fini_late(&uc->huc); + } + + /** +diff --git a/drivers/gpu/drm/i915/gvt/opregion.c b/drivers/gpu/drm/i915/gvt/opregion.c +index d2bed466540ab2..3da476dec1da26 100644 +--- a/drivers/gpu/drm/i915/gvt/opregion.c ++++ b/drivers/gpu/drm/i915/gvt/opregion.c +@@ -222,7 +222,6 @@ int intel_vgpu_init_opregion(struct intel_vgpu *vgpu) + u8 *buf; + struct opregion_header *header; + struct vbt v; +- const char opregion_signature[16] = OPREGION_SIGNATURE; + + gvt_dbg_core("init vgpu%d opregion\n", vgpu->id); + vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_KERNEL | +@@ -236,8 +235,10 @@ int intel_vgpu_init_opregion(struct intel_vgpu *vgpu) + /* emulated opregion with VBT mailbox only */ + buf = (u8 *)vgpu_opregion(vgpu)->va; + header = (struct opregion_header *)buf; +- memcpy(header->signature, opregion_signature, +- sizeof(opregion_signature)); ++ ++ static_assert(sizeof(header->signature) == sizeof(OPREGION_SIGNATURE) - 1); ++ memcpy(header->signature, OPREGION_SIGNATURE, sizeof(header->signature)); ++ + header->size = 0x8; + header->opregion_ver = 0x02000000; + header->mboxes = MBOX_VBT; +diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c +index 7a90a2e32c9f1b..1fde21d8bb59a9 100644 +--- a/drivers/gpu/drm/i915/i915_debugfs.c ++++ b/drivers/gpu/drm/i915/i915_debugfs.c +@@ -144,7 +144,7 @@ static const char *i915_cache_level_str(struct drm_i915_gem_object *obj) + { + struct drm_i915_private *i915 = obj_to_i915(obj); + +- if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) { ++ if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 74))) { + switch (obj->pat_index) { + case 0: return " WB"; + case 1: return " WT"; +diff --git a/drivers/gpu/drm/i915/selftests/i915_selftest.c b/drivers/gpu/drm/i915/selftests/i915_selftest.c +index ee79e0809a6ddf..889281819c5b13 100644 +--- a/drivers/gpu/drm/i915/selftests/i915_selftest.c ++++ b/drivers/gpu/drm/i915/selftests/i915_selftest.c +@@ -23,7 +23,9 @@ + + #include + ++#include "gt/intel_gt.h" + #include "gt/intel_gt_pm.h" ++#include "gt/intel_gt_regs.h" + #include "gt/uc/intel_gsc_fw.h" + + #include "i915_driver.h" +@@ -154,6 +156,30 @@ __wait_gsc_proxy_completed(struct drm_i915_private *i915) + pr_warn(DRIVER_NAME "Timed out waiting for gsc_proxy_completion!\n"); + } + ++static void ++__wait_gsc_huc_load_completed(struct drm_i915_private *i915) ++{ ++ /* this only applies to DG2, so we only care about GT0 */ ++ struct intel_huc *huc = &to_gt(i915)->uc.huc; ++ bool need_to_wait = (IS_ENABLED(CONFIG_INTEL_MEI_PXP) && ++ intel_huc_wait_required(huc)); ++ /* ++ * The GSC and PXP mei bringup depends on the kernel boot ordering, so ++ * to account for the worst case scenario the HuC code waits for up to ++ * 10s for the GSC driver to load and then another 5s for the PXP ++ * component to bind before giving up, even though those steps normally ++ * complete in less than a second from the i915 load. We match that ++ * timeout here, but we expect to bail early due to the fence being ++ * signalled even in a failure case, as it is extremely unlikely that ++ * both components will use their full timeout. ++ */ ++ unsigned long timeout_ms = 15000; ++ ++ if (need_to_wait && ++ wait_for(i915_sw_fence_done(&huc->delayed_load.fence), timeout_ms)) ++ pr_warn(DRIVER_NAME "Timed out waiting for huc load via GSC!\n"); ++} ++ + static int __run_selftests(const char *name, + struct selftest *st, + unsigned int count, +@@ -228,14 +254,32 @@ int i915_mock_selftests(void) + + int i915_live_selftests(struct pci_dev *pdev) + { ++ struct drm_i915_private *i915 = pdev_to_i915(pdev); ++ struct intel_uncore *uncore = &i915->uncore; + int err; ++ u32 pg_enable; ++ intel_wakeref_t wakeref; + + if (!i915_selftest.live) + return 0; + +- __wait_gsc_proxy_completed(pdev_to_i915(pdev)); ++ /* ++ * FIXME Disable render powergating, this is temporary wa and should be removed ++ * after fixing real cause of forcewake timeouts. ++ */ ++ with_intel_runtime_pm(uncore->rpm, wakeref) { ++ if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 00), IP_VER(12, 74))) { ++ pg_enable = intel_uncore_read(uncore, GEN9_PG_ENABLE); ++ if (pg_enable & GEN9_RENDER_PG_ENABLE) ++ intel_uncore_write_fw(uncore, GEN9_PG_ENABLE, ++ pg_enable & ~GEN9_RENDER_PG_ENABLE); ++ } ++ } ++ ++ __wait_gsc_proxy_completed(i915); ++ __wait_gsc_huc_load_completed(i915); + +- err = run_selftests(live, pdev_to_i915(pdev)); ++ err = run_selftests(live, i915); + if (err) { + i915_selftest.live = err; + return err; +@@ -251,14 +295,16 @@ int i915_live_selftests(struct pci_dev *pdev) + + int i915_perf_selftests(struct pci_dev *pdev) + { ++ struct drm_i915_private *i915 = pdev_to_i915(pdev); + int err; + + if (!i915_selftest.perf) + return 0; + +- __wait_gsc_proxy_completed(pdev_to_i915(pdev)); ++ __wait_gsc_proxy_completed(i915); ++ __wait_gsc_huc_load_completed(i915); + +- err = run_selftests(perf, pdev_to_i915(pdev)); ++ err = run_selftests(perf, i915); + if (err) { + i915_selftest.perf = err; + return err; +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index bc073a6b367e5b..54fc3f819577e3 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -127,14 +127,14 @@ struct mtk_dpi_yc_limit { + * @is_ck_de_pol: Support CK/DE polarity. + * @swap_input_support: Support input swap function. + * @support_direct_pin: IP supports direct connection to dpi panels. +- * @input_2pixel: Input pixel of dp_intf is 2 pixel per round, so enable this +- * config to enable this feature. + * @dimension_mask: Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH + * (no shift). + * @hvsize_mask: Mask of HSIZE and VSIZE mask (no shift). + * @channel_swap_shift: Shift value of channel swap. + * @yuv422_en_bit: Enable bit of yuv422. + * @csc_enable_bit: Enable bit of CSC. ++ * @input_2p_en_bit: Enable bit for input two pixel per round feature. ++ * If present, implies that the feature must be enabled. + * @pixels_per_iter: Quantity of transferred pixels per iteration. + * @edge_cfg_in_mmsys: If the edge configuration for DPI's output needs to be set in MMSYS. + */ +@@ -148,12 +148,12 @@ struct mtk_dpi_conf { + bool is_ck_de_pol; + bool swap_input_support; + bool support_direct_pin; +- bool input_2pixel; + u32 dimension_mask; + u32 hvsize_mask; + u32 channel_swap_shift; + u32 yuv422_en_bit; + u32 csc_enable_bit; ++ u32 input_2p_en_bit; + u32 pixels_per_iter; + bool edge_cfg_in_mmsys; + }; +@@ -471,6 +471,7 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi) + + mtk_dpi_disable(dpi); + clk_disable_unprepare(dpi->pixel_clk); ++ clk_disable_unprepare(dpi->tvd_clk); + clk_disable_unprepare(dpi->engine_clk); + } + +@@ -487,6 +488,12 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi) + goto err_refcount; + } + ++ ret = clk_prepare_enable(dpi->tvd_clk); ++ if (ret) { ++ dev_err(dpi->dev, "Failed to enable tvd pll: %d\n", ret); ++ goto err_engine; ++ } ++ + ret = clk_prepare_enable(dpi->pixel_clk); + if (ret) { + dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret); +@@ -496,6 +503,8 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi) + return 0; + + err_pixel: ++ clk_disable_unprepare(dpi->tvd_clk); ++err_engine: + clk_disable_unprepare(dpi->engine_clk); + err_refcount: + dpi->refcount--; +@@ -610,9 +619,9 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, + mtk_dpi_dual_edge(dpi); + mtk_dpi_config_disable_edge(dpi); + } +- if (dpi->conf->input_2pixel) { +- mtk_dpi_mask(dpi, DPI_CON, DPINTF_INPUT_2P_EN, +- DPINTF_INPUT_2P_EN); ++ if (dpi->conf->input_2p_en_bit) { ++ mtk_dpi_mask(dpi, DPI_CON, dpi->conf->input_2p_en_bit, ++ dpi->conf->input_2p_en_bit); + } + mtk_dpi_sw_reset(dpi, false); + +@@ -980,12 +989,12 @@ static const struct mtk_dpi_conf mt8195_dpintf_conf = { + .output_fmts = mt8195_output_fmts, + .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts), + .pixels_per_iter = 4, +- .input_2pixel = true, + .dimension_mask = DPINTF_HPW_MASK, + .hvsize_mask = DPINTF_HSIZE_MASK, + .channel_swap_shift = DPINTF_CH_SWAP, + .yuv422_en_bit = DPINTF_YUV422_EN, + .csc_enable_bit = DPINTF_CSC_ENABLE, ++ .input_2p_en_bit = DPINTF_INPUT_2P_EN, + }; + + static int mtk_dpi_probe(struct platform_device *pdev) +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +index 9009442b543dda..e7136b7759cb33 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +@@ -1042,49 +1042,50 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu) + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + u32 val; ++ int ret; + + /* +- * The GMU may still be in slumber unless the GPU started so check and +- * skip putting it back into slumber if so ++ * GMU firmware's internal power state gets messed up if we send "prepare_slumber" hfi when ++ * oob_gpu handshake wasn't done after the last wake up. So do a dummy handshake here when ++ * required + */ +- val = gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE); ++ if (adreno_gpu->base.needs_hw_init) { ++ if (a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET)) ++ goto force_off; + +- if (val != 0xf) { +- int ret = a6xx_gmu_wait_for_idle(gmu); ++ a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); ++ } + +- /* If the GMU isn't responding assume it is hung */ +- if (ret) { +- a6xx_gmu_force_off(gmu); +- return; +- } ++ ret = a6xx_gmu_wait_for_idle(gmu); + +- a6xx_bus_clear_pending_transactions(adreno_gpu, a6xx_gpu->hung); ++ /* If the GMU isn't responding assume it is hung */ ++ if (ret) ++ goto force_off; + +- /* tell the GMU we want to slumber */ +- ret = a6xx_gmu_notify_slumber(gmu); +- if (ret) { +- a6xx_gmu_force_off(gmu); +- return; +- } ++ a6xx_bus_clear_pending_transactions(adreno_gpu, a6xx_gpu->hung); + +- ret = gmu_poll_timeout(gmu, +- REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, val, +- !(val & A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS_GPUBUSYIGNAHB), +- 100, 10000); ++ /* tell the GMU we want to slumber */ ++ ret = a6xx_gmu_notify_slumber(gmu); ++ if (ret) ++ goto force_off; + +- /* +- * Let the user know we failed to slumber but don't worry too +- * much because we are powering down anyway +- */ ++ ret = gmu_poll_timeout(gmu, ++ REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, val, ++ !(val & A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS_GPUBUSYIGNAHB), ++ 100, 10000); + +- if (ret) +- DRM_DEV_ERROR(gmu->dev, +- "Unable to slumber GMU: status = 0%x/0%x\n", +- gmu_read(gmu, +- REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS), +- gmu_read(gmu, +- REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2)); +- } ++ /* ++ * Let the user know we failed to slumber but don't worry too ++ * much because we are powering down anyway ++ */ ++ ++ if (ret) ++ DRM_DEV_ERROR(gmu->dev, ++ "Unable to slumber GMU: status = 0%x/0%x\n", ++ gmu_read(gmu, ++ REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS), ++ gmu_read(gmu, ++ REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2)); + + /* Turn off HFI */ + a6xx_hfi_stop(gmu); +@@ -1094,6 +1095,11 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu) + + /* Tell RPMh to power off the GPU */ + a6xx_rpmh_stop(gmu); ++ ++ return; ++ ++force_off: ++ a6xx_gmu_force_off(gmu); + } + + +diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c +index 5d398a422459e1..036ee034397283 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bo.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c +@@ -144,6 +144,9 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) + nouveau_bo_del_io_reserve_lru(bo); + nv10_bo_put_tile_region(dev, nvbo->tile, NULL); + ++ if (bo->base.import_attach) ++ drm_prime_gem_destroy(&bo->base, bo->sg); ++ + /* + * If nouveau_bo_new() allocated this buffer, the GEM object was never + * initialized, so don't attempt to release it. +diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c +index 7b69e6df57486a..cd97df6903352c 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_gem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_gem.c +@@ -87,9 +87,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem) + return; + } + +- if (gem->import_attach) +- drm_prime_gem_destroy(gem, nvbo->bo.sg); +- + ttm_bo_put(&nvbo->bo); + + pm_runtime_mark_last_busy(dev); +diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile +index f203ac5514ae0b..f778a4eee7c9cf 100644 +--- a/drivers/gpu/drm/sti/Makefile ++++ b/drivers/gpu/drm/sti/Makefile +@@ -7,8 +7,6 @@ sti-drm-y := \ + sti_compositor.o \ + sti_crtc.o \ + sti_plane.o \ +- sti_crtc.o \ +- sti_plane.o \ + sti_hdmi.o \ + sti_hdmi_tx3g4c28phy.o \ + sti_dvo.o \ +diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c +index 7516f6cb36e4e3..3e9518d7b8b7eb 100644 +--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c ++++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c +@@ -95,6 +95,9 @@ static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test) + expected_mode = drm_mode_find_dmt(priv->drm, 1920, 1080, 60, false); + KUNIT_ASSERT_NOT_NULL(test, expected_mode); + ++ ret = drm_kunit_add_mode_destroy_action(test, expected_mode); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + KUNIT_ASSERT_TRUE(test, + drm_mode_parse_command_line_for_connector(cmdline, + connector, +diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +index 88f7f518ffb3bc..05dd5cc3b604b3 100644 +--- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c ++++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c +@@ -7,6 +7,7 @@ + #include + + #include ++#include + #include + + static const struct drm_connector no_connector = {}; +@@ -955,8 +956,15 @@ struct drm_cmdline_tv_option_test { + static void drm_test_cmdline_tv_options(struct kunit *test) + { + const struct drm_cmdline_tv_option_test *params = test->param_value; +- const struct drm_display_mode *expected_mode = params->mode_fn(NULL); ++ struct drm_display_mode *expected_mode; + struct drm_cmdline_mode mode = { }; ++ int ret; ++ ++ expected_mode = params->mode_fn(NULL); ++ KUNIT_ASSERT_NOT_NULL(test, expected_mode); ++ ++ ret = drm_kunit_add_mode_destroy_action(test, expected_mode); ++ KUNIT_ASSERT_EQ(test, ret, 0); + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline, + &no_connector, &mode)); +diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c +index bccb33b900f390..04d98f81c52277 100644 +--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c ++++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c +@@ -1,7 +1,10 @@ + // SPDX-License-Identifier: GPL-2.0 + + #include ++#include + #include ++#include ++#include + #include + #include + +@@ -13,6 +16,8 @@ + #define KUNIT_DEVICE_NAME "drm-kunit-mock-device" + + static const struct drm_mode_config_funcs drm_mode_config_funcs = { ++ .atomic_check = drm_atomic_helper_check, ++ .atomic_commit = drm_atomic_helper_commit, + }; + + static int fake_probe(struct platform_device *pdev) +@@ -233,5 +238,213 @@ drm_kunit_helper_atomic_state_alloc(struct kunit *test, + } + EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc); + ++static const uint32_t default_plane_formats[] = { ++ DRM_FORMAT_XRGB8888, ++}; ++ ++static const uint64_t default_plane_modifiers[] = { ++ DRM_FORMAT_MOD_LINEAR, ++ DRM_FORMAT_MOD_INVALID ++}; ++ ++static const struct drm_plane_helper_funcs default_plane_helper_funcs = { ++}; ++ ++static const struct drm_plane_funcs default_plane_funcs = { ++ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, ++ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, ++ .reset = drm_atomic_helper_plane_reset, ++}; ++ ++/** ++ * drm_kunit_helper_create_primary_plane - Creates a mock primary plane for a KUnit test ++ * @test: The test context object ++ * @drm: The device to alloc the plane for ++ * @funcs: Callbacks for the new plane. Optional. ++ * @helper_funcs: Helpers callbacks for the new plane. Optional. ++ * @formats: array of supported formats (DRM_FORMAT\_\*). Optional. ++ * @num_formats: number of elements in @formats ++ * @modifiers: array of struct drm_format modifiers terminated by ++ * DRM_FORMAT_MOD_INVALID. Optional. ++ * ++ * This allocates and initializes a mock struct &drm_plane meant to be ++ * part of a mock device for a KUnit test. ++ * ++ * Resources will be cleaned up automatically. ++ * ++ * @funcs will default to the default helpers implementations. ++ * @helper_funcs will default to an empty implementation. @formats will ++ * default to XRGB8888 only. @modifiers will default to a linear ++ * modifier only. ++ * ++ * Returns: ++ * A pointer to the new plane, or an ERR_PTR() otherwise. ++ */ ++struct drm_plane * ++drm_kunit_helper_create_primary_plane(struct kunit *test, ++ struct drm_device *drm, ++ const struct drm_plane_funcs *funcs, ++ const struct drm_plane_helper_funcs *helper_funcs, ++ const uint32_t *formats, ++ unsigned int num_formats, ++ const uint64_t *modifiers) ++{ ++ struct drm_plane *plane; ++ ++ if (!funcs) ++ funcs = &default_plane_funcs; ++ ++ if (!helper_funcs) ++ helper_funcs = &default_plane_helper_funcs; ++ ++ if (!formats || !num_formats) { ++ formats = default_plane_formats; ++ num_formats = ARRAY_SIZE(default_plane_formats); ++ } ++ ++ if (!modifiers) ++ modifiers = default_plane_modifiers; ++ ++ plane = __drmm_universal_plane_alloc(drm, ++ sizeof(struct drm_plane), 0, ++ 0, ++ funcs, ++ formats, ++ num_formats, ++ default_plane_modifiers, ++ DRM_PLANE_TYPE_PRIMARY, ++ NULL); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); ++ ++ drm_plane_helper_add(plane, helper_funcs); ++ ++ return plane; ++} ++EXPORT_SYMBOL_GPL(drm_kunit_helper_create_primary_plane); ++ ++static const struct drm_crtc_helper_funcs default_crtc_helper_funcs = { ++}; ++ ++static const struct drm_crtc_funcs default_crtc_funcs = { ++ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, ++ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, ++ .reset = drm_atomic_helper_crtc_reset, ++}; ++ ++/** ++ * drm_kunit_helper_create_crtc - Creates a mock CRTC for a KUnit test ++ * @test: The test context object ++ * @drm: The device to alloc the plane for ++ * @primary: Primary plane for CRTC ++ * @cursor: Cursor plane for CRTC. Optional. ++ * @funcs: Callbacks for the new plane. Optional. ++ * @helper_funcs: Helpers callbacks for the new plane. Optional. ++ * ++ * This allocates and initializes a mock struct &drm_crtc meant to be ++ * part of a mock device for a KUnit test. ++ * ++ * Resources will be cleaned up automatically. ++ * ++ * @funcs will default to the default helpers implementations. ++ * @helper_funcs will default to an empty implementation. ++ * ++ * Returns: ++ * A pointer to the new CRTC, or an ERR_PTR() otherwise. ++ */ ++struct drm_crtc * ++drm_kunit_helper_create_crtc(struct kunit *test, ++ struct drm_device *drm, ++ struct drm_plane *primary, ++ struct drm_plane *cursor, ++ const struct drm_crtc_funcs *funcs, ++ const struct drm_crtc_helper_funcs *helper_funcs) ++{ ++ struct drm_crtc *crtc; ++ int ret; ++ ++ if (!funcs) ++ funcs = &default_crtc_funcs; ++ ++ if (!helper_funcs) ++ helper_funcs = &default_crtc_helper_funcs; ++ ++ crtc = drmm_kzalloc(drm, sizeof(*crtc), GFP_KERNEL); ++ KUNIT_ASSERT_NOT_NULL(test, crtc); ++ ++ ret = drmm_crtc_init_with_planes(drm, crtc, ++ primary, ++ cursor, ++ funcs, ++ NULL); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ ++ drm_crtc_helper_add(crtc, helper_funcs); ++ ++ return crtc; ++} ++EXPORT_SYMBOL_GPL(drm_kunit_helper_create_crtc); ++ ++static void kunit_action_drm_mode_destroy(void *ptr) ++{ ++ struct drm_display_mode *mode = ptr; ++ ++ drm_mode_destroy(NULL, mode); ++} ++ ++/** ++ * drm_kunit_add_mode_destroy_action() - Add a drm_destroy_mode kunit action ++ * @test: The test context object ++ * @mode: The drm_display_mode to destroy eventually ++ * ++ * Registers a kunit action that will destroy the drm_display_mode at ++ * the end of the test. ++ * ++ * If an error occurs, the drm_display_mode will be destroyed. ++ * ++ * Returns: ++ * 0 on success, an error code otherwise. ++ */ ++int drm_kunit_add_mode_destroy_action(struct kunit *test, ++ struct drm_display_mode *mode) ++{ ++ return kunit_add_action_or_reset(test, ++ kunit_action_drm_mode_destroy, ++ mode); ++} ++EXPORT_SYMBOL_GPL(drm_kunit_add_mode_destroy_action); ++ ++/** ++ * drm_kunit_display_mode_from_cea_vic() - return a mode for CEA VIC for a KUnit test ++ * @test: The test context object ++ * @dev: DRM device ++ * @video_code: CEA VIC of the mode ++ * ++ * Creates a new mode matching the specified CEA VIC for a KUnit test. ++ * ++ * Resources will be cleaned up automatically. ++ * ++ * Returns: A new drm_display_mode on success or NULL on failure ++ */ ++struct drm_display_mode * ++drm_kunit_display_mode_from_cea_vic(struct kunit *test, struct drm_device *dev, ++ u8 video_code) ++{ ++ struct drm_display_mode *mode; ++ int ret; ++ ++ mode = drm_display_mode_from_cea_vic(dev, video_code); ++ if (!mode) ++ return NULL; ++ ++ ret = kunit_add_action_or_reset(test, ++ kunit_action_drm_mode_destroy, ++ mode); ++ if (ret) ++ return NULL; ++ ++ return mode; ++} ++EXPORT_SYMBOL_GPL(drm_kunit_display_mode_from_cea_vic); ++ + MODULE_AUTHOR("Maxime Ripard "); + MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c +index 1e9f63fbfead35..e23067252d18a7 100644 +--- a/drivers/gpu/drm/tests/drm_modes_test.c ++++ b/drivers/gpu/drm/tests/drm_modes_test.c +@@ -40,6 +40,7 @@ static void drm_test_modes_analog_tv_ntsc_480i(struct kunit *test) + { + struct drm_test_modes_priv *priv = test->priv; + struct drm_display_mode *mode; ++ int ret; + + mode = drm_analog_tv_mode(priv->drm, + DRM_MODE_TV_MODE_NTSC, +@@ -47,6 +48,9 @@ static void drm_test_modes_analog_tv_ntsc_480i(struct kunit *test) + true); + KUNIT_ASSERT_NOT_NULL(test, mode); + ++ ret = drm_kunit_add_mode_destroy_action(test, mode); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 60); + KUNIT_EXPECT_EQ(test, mode->hdisplay, 720); + +@@ -70,6 +74,7 @@ static void drm_test_modes_analog_tv_ntsc_480i_inlined(struct kunit *test) + { + struct drm_test_modes_priv *priv = test->priv; + struct drm_display_mode *expected, *mode; ++ int ret; + + expected = drm_analog_tv_mode(priv->drm, + DRM_MODE_TV_MODE_NTSC, +@@ -77,9 +82,15 @@ static void drm_test_modes_analog_tv_ntsc_480i_inlined(struct kunit *test) + true); + KUNIT_ASSERT_NOT_NULL(test, expected); + ++ ret = drm_kunit_add_mode_destroy_action(test, expected); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + mode = drm_mode_analog_ntsc_480i(priv->drm); + KUNIT_ASSERT_NOT_NULL(test, mode); + ++ ret = drm_kunit_add_mode_destroy_action(test, mode); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode)); + } + +@@ -87,6 +98,7 @@ static void drm_test_modes_analog_tv_pal_576i(struct kunit *test) + { + struct drm_test_modes_priv *priv = test->priv; + struct drm_display_mode *mode; ++ int ret; + + mode = drm_analog_tv_mode(priv->drm, + DRM_MODE_TV_MODE_PAL, +@@ -94,6 +106,9 @@ static void drm_test_modes_analog_tv_pal_576i(struct kunit *test) + true); + KUNIT_ASSERT_NOT_NULL(test, mode); + ++ ret = drm_kunit_add_mode_destroy_action(test, mode); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 50); + KUNIT_EXPECT_EQ(test, mode->hdisplay, 720); + +@@ -117,6 +132,7 @@ static void drm_test_modes_analog_tv_pal_576i_inlined(struct kunit *test) + { + struct drm_test_modes_priv *priv = test->priv; + struct drm_display_mode *expected, *mode; ++ int ret; + + expected = drm_analog_tv_mode(priv->drm, + DRM_MODE_TV_MODE_PAL, +@@ -124,9 +140,15 @@ static void drm_test_modes_analog_tv_pal_576i_inlined(struct kunit *test) + true); + KUNIT_ASSERT_NOT_NULL(test, expected); + ++ ret = drm_kunit_add_mode_destroy_action(test, expected); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + mode = drm_mode_analog_pal_576i(priv->drm); + KUNIT_ASSERT_NOT_NULL(test, mode); + ++ ret = drm_kunit_add_mode_destroy_action(test, mode); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode)); + } + +diff --git a/drivers/gpu/drm/tests/drm_probe_helper_test.c b/drivers/gpu/drm/tests/drm_probe_helper_test.c +index 1a2044070a6cb8..2a7984431d47b4 100644 +--- a/drivers/gpu/drm/tests/drm_probe_helper_test.c ++++ b/drivers/gpu/drm/tests/drm_probe_helper_test.c +@@ -98,7 +98,7 @@ drm_test_connector_helper_tv_get_modes_check(struct kunit *test) + struct drm_connector *connector = &priv->connector; + struct drm_cmdline_mode *cmdline = &connector->cmdline_mode; + struct drm_display_mode *mode; +- const struct drm_display_mode *expected; ++ struct drm_display_mode *expected; + size_t len; + int ret; + +@@ -134,6 +134,9 @@ drm_test_connector_helper_tv_get_modes_check(struct kunit *test) + + KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected)); + KUNIT_EXPECT_TRUE(test, mode->type & DRM_MODE_TYPE_PREFERRED); ++ ++ ret = drm_kunit_add_mode_destroy_action(test, expected); ++ KUNIT_ASSERT_EQ(test, ret, 0); + } + + if (params->num_expected_modes >= 2) { +@@ -145,6 +148,9 @@ drm_test_connector_helper_tv_get_modes_check(struct kunit *test) + + KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected)); + KUNIT_EXPECT_FALSE(test, mode->type & DRM_MODE_TYPE_PREFERRED); ++ ++ ret = drm_kunit_add_mode_destroy_action(test, expected); ++ KUNIT_ASSERT_EQ(test, ret, 0); + } + + mutex_unlock(&priv->drm->mode_config.mutex); +diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c +index 13ae148f59b9b5..7796ca579cbd99 100644 +--- a/drivers/gpu/drm/tiny/repaper.c ++++ b/drivers/gpu/drm/tiny/repaper.c +@@ -455,7 +455,7 @@ static void repaper_frame_fixed_repeat(struct repaper_epd *epd, u8 fixed_value, + enum repaper_stage stage) + { + u64 start = local_clock(); +- u64 end = start + (epd->factored_stage_time * 1000 * 1000); ++ u64 end = start + ((u64)epd->factored_stage_time * 1000 * 1000); + + do { + repaper_frame_fixed(epd, fixed_value, stage); +@@ -466,7 +466,7 @@ static void repaper_frame_data_repeat(struct repaper_epd *epd, const u8 *image, + const u8 *mask, enum repaper_stage stage) + { + u64 start = local_clock(); +- u64 end = start + (epd->factored_stage_time * 1000 * 1000); ++ u64 end = start + ((u64)epd->factored_stage_time * 1000 * 1000); + + do { + repaper_frame_data(epd, image, mask, stage); +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 979ebe69c8e303..ffbeb39341e1a4 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1202,6 +1202,20 @@ config HID_U2FZERO + allow setting the brightness to anything but 1, which will + trigger a single blink and immediately reset back to 0. + ++config HID_UNIVERSAL_PIDFF ++ tristate "universal-pidff: extended USB PID driver compatibility and usage" ++ depends on USB_HID ++ depends on HID_PID ++ help ++ Extended PID support for selected devices. ++ ++ Contains report fixups, extended usable button range and ++ pidff quirk management to extend compatibility with slightly ++ non-compliant USB PID devices and better fuzz/flat values for ++ high precision direct drive devices. ++ ++ Supports Moza Racing, Cammus, VRS, FFBeast and more. ++ + config HID_WACOM + tristate "Wacom Intuos/Graphire tablet support (USB)" + depends on USB_HID +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index f5a06b62b385db..dcb81891c725a9 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -138,6 +138,7 @@ hid-uclogic-objs := hid-uclogic-core.o \ + hid-uclogic-params.o + obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o + obj-$(CONFIG_HID_UDRAW_PS3) += hid-udraw-ps3.o ++obj-$(CONFIG_HID_UNIVERSAL_PIDFF) += hid-universal-pidff.o + obj-$(CONFIG_HID_LED) += hid-led.o + obj-$(CONFIG_HID_XIAOMI) += hid-xiaomi.o + obj-$(CONFIG_HID_XINMO) += hid-xinmo.o +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 09090803f1dd2a..8e721ec3faaff3 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -262,6 +262,10 @@ + #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 + #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 + ++#define USB_VENDOR_ID_CAMMUS 0x3416 ++#define USB_DEVICE_ID_CAMMUS_C5 0x0301 ++#define USB_DEVICE_ID_CAMMUS_C12 0x0302 ++ + #define USB_VENDOR_ID_CANDO 0x2087 + #define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703 + #define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 +@@ -453,6 +457,11 @@ + #define USB_VENDOR_ID_EVISION 0x320f + #define USB_DEVICE_ID_EVISION_ICL01 0x5041 + ++#define USB_VENDOR_ID_FFBEAST 0x045b ++#define USB_DEVICE_ID_FFBEAST_JOYSTICK 0x58f9 ++#define USB_DEVICE_ID_FFBEAST_RUDDER 0x5968 ++#define USB_DEVICE_ID_FFBEAST_WHEEL 0x59d7 ++ + #define USB_VENDOR_ID_FLATFROG 0x25b5 + #define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 + +@@ -812,6 +821,13 @@ + #define I2C_DEVICE_ID_LG_8001 0x8001 + #define I2C_DEVICE_ID_LG_7010 0x7010 + ++#define USB_VENDOR_ID_LITE_STAR 0x11ff ++#define USB_DEVICE_ID_PXN_V10 0x3245 ++#define USB_DEVICE_ID_PXN_V12 0x1212 ++#define USB_DEVICE_ID_PXN_V12_LITE 0x1112 ++#define USB_DEVICE_ID_PXN_V12_LITE_2 0x1211 ++#define USB_DEVICE_LITE_STAR_GT987_FF 0x2141 ++ + #define USB_VENDOR_ID_LOGITECH 0x046d + #define USB_DEVICE_ID_LOGITECH_Z_10_SPK 0x0a07 + #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e +@@ -959,6 +975,18 @@ + #define USB_VENDOR_ID_MONTEREY 0x0566 + #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 + ++#define USB_VENDOR_ID_MOZA 0x346e ++#define USB_DEVICE_ID_MOZA_R3 0x0005 ++#define USB_DEVICE_ID_MOZA_R3_2 0x0015 ++#define USB_DEVICE_ID_MOZA_R5 0x0004 ++#define USB_DEVICE_ID_MOZA_R5_2 0x0014 ++#define USB_DEVICE_ID_MOZA_R9 0x0002 ++#define USB_DEVICE_ID_MOZA_R9_2 0x0012 ++#define USB_DEVICE_ID_MOZA_R12 0x0006 ++#define USB_DEVICE_ID_MOZA_R12_2 0x0016 ++#define USB_DEVICE_ID_MOZA_R16_R21 0x0000 ++#define USB_DEVICE_ID_MOZA_R16_R21_2 0x0010 ++ + #define USB_VENDOR_ID_MSI 0x1770 + #define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 + +@@ -1360,6 +1388,9 @@ + #define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061 + #define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068 + ++#define USB_VENDOR_ID_VRS 0x0483 ++#define USB_DEVICE_ID_VRS_DFP 0xa355 ++ + #define USB_VENDOR_ID_VTL 0x0306 + #define USB_DEVICE_ID_VTL_MULTITOUCH_FF3F 0xff3f + +diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c +new file mode 100644 +index 00000000000000..7ef5ab9146b1cf +--- /dev/null ++++ b/drivers/hid/hid-universal-pidff.c +@@ -0,0 +1,197 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * HID UNIVERSAL PIDFF ++ * hid-pidff wrapper for PID-enabled devices ++ * Handles device reports, quirks and extends usable button range ++ * ++ * Copyright (c) 2024, 2025 Makarenko Oleg ++ * Copyright (c) 2024, 2025 Tomasz Pakuła ++ */ ++ ++#include ++#include ++#include ++#include ++#include "hid-ids.h" ++ ++#define JOY_RANGE (BTN_DEAD - BTN_JOYSTICK + 1) ++ ++/* ++ * Map buttons manually to extend the default joystick button limit ++ */ ++static int universal_pidff_input_mapping(struct hid_device *hdev, ++ struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON) ++ return 0; ++ ++ if (field->application != HID_GD_JOYSTICK) ++ return 0; ++ ++ int button = ((usage->hid - 1) & HID_USAGE); ++ int code = button + BTN_JOYSTICK; ++ ++ /* Detect the end of JOYSTICK buttons range */ ++ if (code > BTN_DEAD) ++ code = button + KEY_NEXT_FAVORITE - JOY_RANGE; ++ ++ /* ++ * Map overflowing buttons to KEY_RESERVED to not ignore ++ * them and let them still trigger MSC_SCAN ++ */ ++ if (code > KEY_MAX) ++ code = KEY_RESERVED; ++ ++ hid_map_usage(hi, usage, bit, max, EV_KEY, code); ++ hid_dbg(hdev, "Button %d: usage %d", button, code); ++ return 1; ++} ++ ++/* ++ * Check if the device is PID and initialize it ++ * Add quirks after initialisation ++ */ ++static int universal_pidff_probe(struct hid_device *hdev, ++ const struct hid_device_id *id) ++{ ++ int i, error; ++ error = hid_parse(hdev); ++ if (error) { ++ hid_err(hdev, "HID parse failed\n"); ++ goto err; ++ } ++ ++ error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); ++ if (error) { ++ hid_err(hdev, "HID hw start failed\n"); ++ goto err; ++ } ++ ++ /* Check if device contains PID usage page */ ++ error = 1; ++ for (i = 0; i < hdev->collection_size; i++) ++ if ((hdev->collection[i].usage & HID_USAGE_PAGE) == HID_UP_PID) { ++ error = 0; ++ hid_dbg(hdev, "PID usage page found\n"); ++ break; ++ } ++ ++ /* ++ * Do not fail as this might be the second "device" ++ * just for additional buttons/axes. Exit cleanly if force ++ * feedback usage page wasn't found (included devices were ++ * tested and confirmed to be USB PID after all). ++ */ ++ if (error) { ++ hid_dbg(hdev, "PID usage page not found in the descriptor\n"); ++ return 0; ++ } ++ ++ /* Check if HID_PID support is enabled */ ++ int (*init_function)(struct hid_device *, __u32); ++ init_function = hid_pidff_init_with_quirks; ++ ++ if (!init_function) { ++ hid_warn(hdev, "HID_PID support not enabled!\n"); ++ return 0; ++ } ++ ++ error = init_function(hdev, id->driver_data); ++ if (error) { ++ hid_warn(hdev, "Error initialising force feedback\n"); ++ goto err; ++ } ++ ++ hid_info(hdev, "Universal pidff driver loaded sucesfully!"); ++ ++ return 0; ++err: ++ return error; ++} ++ ++static int universal_pidff_input_configured(struct hid_device *hdev, ++ struct hid_input *hidinput) ++{ ++ int axis; ++ struct input_dev *input = hidinput->input; ++ ++ if (!input->absinfo) ++ return 0; ++ ++ /* Decrease fuzz and deadzone on available axes */ ++ for (axis = ABS_X; axis <= ABS_BRAKE; axis++) { ++ if (!test_bit(axis, input->absbit)) ++ continue; ++ ++ input_set_abs_params(input, axis, ++ input->absinfo[axis].minimum, ++ input->absinfo[axis].maximum, ++ axis == ABS_X ? 0 : 8, 0); ++ } ++ ++ /* Remove fuzz and deadzone from the second joystick axis */ ++ if (hdev->vendor == USB_VENDOR_ID_FFBEAST && ++ hdev->product == USB_DEVICE_ID_FFBEAST_JOYSTICK) ++ input_set_abs_params(input, ABS_Y, ++ input->absinfo[ABS_Y].minimum, ++ input->absinfo[ABS_Y].maximum, 0, 0); ++ ++ return 0; ++} ++ ++static const struct hid_device_id universal_pidff_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_2), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_2), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_2), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_2), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_2), ++ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP), ++ .driver_data = HID_PIDFF_QUIRK_PERMISSIVE_CONTROL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_JOYSTICK), }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_RUDDER), }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_WHEEL) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V10), ++ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12), ++ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE), ++ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2), ++ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_LITE_STAR_GT987_FF), ++ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, universal_pidff_devices); ++ ++static struct hid_driver universal_pidff = { ++ .name = "hid-universal-pidff", ++ .id_table = universal_pidff_devices, ++ .input_mapping = universal_pidff_input_mapping, ++ .probe = universal_pidff_probe, ++ .input_configured = universal_pidff_input_configured ++}; ++module_hid_driver(universal_pidff); ++ ++MODULE_DESCRIPTION("Universal driver for USB PID Force Feedback devices"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Makarenko Oleg "); ++MODULE_AUTHOR("Tomasz Pakuła "); +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 3b4ee21cd81119..25dbed076f5304 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -21,6 +21,7 @@ + #include "usbhid.h" + + #define PID_EFFECTS_MAX 64 ++#define PID_INFINITE 0xffff + + /* Report usage table used to put reports into an array */ + +@@ -136,6 +137,9 @@ static const u8 pidff_block_load_status[] = { 0x8c, 0x8d }; + #define PID_EFFECT_STOP 1 + static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; + ++/* Polar direction 90 degrees (North) */ ++#define PIDFF_FIXED_WHEEL_DIRECTION 0x4000 ++ + struct pidff_usage { + struct hid_field *field; + s32 *value; +@@ -184,6 +188,8 @@ struct pidff_device { + int operation_id[sizeof(pidff_effect_operation_status)]; + + int pid_id[PID_EFFECTS_MAX]; ++ ++ u32 quirks; + }; + + /* +@@ -261,10 +267,22 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, + static int pidff_needs_set_envelope(struct ff_envelope *envelope, + struct ff_envelope *old) + { +- return envelope->attack_level != old->attack_level || +- envelope->fade_level != old->fade_level || ++ bool needs_new_envelope; ++ needs_new_envelope = envelope->attack_level != 0 || ++ envelope->fade_level != 0 || ++ envelope->attack_length != 0 || ++ envelope->fade_length != 0; ++ ++ if (!needs_new_envelope) ++ return false; ++ ++ if (!old) ++ return needs_new_envelope; ++ ++ return envelope->attack_level != old->attack_level || ++ envelope->fade_level != old->fade_level || + envelope->attack_length != old->attack_length || +- envelope->fade_length != old->fade_length; ++ envelope->fade_length != old->fade_length; + } + + /* +@@ -301,17 +319,28 @@ static void pidff_set_effect_report(struct pidff_device *pidff, + pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; + pidff->set_effect_type->value[0] = + pidff->create_new_effect_type->value[0]; +- pidff->set_effect[PID_DURATION].value[0] = effect->replay.length; ++ ++ /* Convert infinite length from Linux API (0) ++ to PID standard (NULL) if needed */ ++ pidff->set_effect[PID_DURATION].value[0] = ++ effect->replay.length == 0 ? PID_INFINITE : effect->replay.length; ++ + pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; + pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = + effect->trigger.interval; + pidff->set_effect[PID_GAIN].value[0] = + pidff->set_effect[PID_GAIN].field->logical_maximum; + pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; +- pidff->effect_direction->value[0] = +- pidff_rescale(effect->direction, 0xffff, +- pidff->effect_direction); +- pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; ++ ++ /* Use fixed direction if needed */ ++ pidff->effect_direction->value[0] = pidff_rescale( ++ pidff->quirks & HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION ? ++ PIDFF_FIXED_WHEEL_DIRECTION : effect->direction, ++ 0xffff, pidff->effect_direction); ++ ++ /* Omit setting delay field if it's missing */ ++ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY)) ++ pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; + + hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], + HID_REQ_SET_REPORT); +@@ -368,13 +397,19 @@ static int pidff_needs_set_periodic(struct ff_effect *effect, + static void pidff_set_condition_report(struct pidff_device *pidff, + struct ff_effect *effect) + { +- int i; ++ int i, max_axis; ++ ++ /* Devices missing Parameter Block Offset can only have one axis */ ++ max_axis = pidff->quirks & HID_PIDFF_QUIRK_MISSING_PBO ? 1 : 2; + + pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] = + pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; + +- for (i = 0; i < 2; i++) { +- pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i; ++ for (i = 0; i < max_axis; i++) { ++ /* Omit Parameter Block Offset if missing */ ++ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_PBO)) ++ pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i; ++ + pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET], + effect->u.condition[i].center); + pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT], +@@ -574,11 +609,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, + pidff_set_effect_report(pidff, effect); + if (!old || pidff_needs_set_constant(effect, old)) + pidff_set_constant_force_report(pidff, effect); +- if (!old || +- pidff_needs_set_envelope(&effect->u.constant.envelope, +- &old->u.constant.envelope)) +- pidff_set_envelope_report(pidff, +- &effect->u.constant.envelope); ++ if (pidff_needs_set_envelope(&effect->u.constant.envelope, ++ old ? &old->u.constant.envelope : NULL)) ++ pidff_set_envelope_report(pidff, &effect->u.constant.envelope); + break; + + case FF_PERIODIC: +@@ -604,6 +637,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, + return -EINVAL; + } + ++ if (pidff->quirks & HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY) ++ type_id = PID_SINE; ++ + error = pidff_request_effect_upload(pidff, + pidff->type_id[type_id]); + if (error) +@@ -613,11 +649,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, + pidff_set_effect_report(pidff, effect); + if (!old || pidff_needs_set_periodic(effect, old)) + pidff_set_periodic_report(pidff, effect); +- if (!old || +- pidff_needs_set_envelope(&effect->u.periodic.envelope, +- &old->u.periodic.envelope)) +- pidff_set_envelope_report(pidff, +- &effect->u.periodic.envelope); ++ if (pidff_needs_set_envelope(&effect->u.periodic.envelope, ++ old ? &old->u.periodic.envelope : NULL)) ++ pidff_set_envelope_report(pidff, &effect->u.periodic.envelope); + break; + + case FF_RAMP: +@@ -631,11 +665,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, + pidff_set_effect_report(pidff, effect); + if (!old || pidff_needs_set_ramp(effect, old)) + pidff_set_ramp_force_report(pidff, effect); +- if (!old || +- pidff_needs_set_envelope(&effect->u.ramp.envelope, +- &old->u.ramp.envelope)) +- pidff_set_envelope_report(pidff, +- &effect->u.ramp.envelope); ++ if (pidff_needs_set_envelope(&effect->u.ramp.envelope, ++ old ? &old->u.ramp.envelope : NULL)) ++ pidff_set_envelope_report(pidff, &effect->u.ramp.envelope); + break; + + case FF_SPRING: +@@ -736,7 +768,10 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) + pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0; + pidff_set(&pidff->set_effect[PID_GAIN], magnitude); + pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; +- pidff->set_effect[PID_START_DELAY].value[0] = 0; ++ ++ /* Omit setting delay field if it's missing */ ++ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY)) ++ pidff->set_effect[PID_START_DELAY].value[0] = 0; + + hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], + HID_REQ_SET_REPORT); +@@ -758,7 +793,13 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude) + static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, + struct hid_report *report, int count, int strict) + { ++ if (!report) { ++ pr_debug("pidff_find_fields, null report\n"); ++ return -1; ++ } ++ + int i, j, k, found; ++ int return_value = 0; + + for (k = 0; k < count; k++) { + found = 0; +@@ -783,12 +824,22 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, + if (found) + break; + } +- if (!found && strict) { ++ if (!found && table[k] == pidff_set_effect[PID_START_DELAY]) { ++ pr_debug("Delay field not found, but that's OK\n"); ++ pr_debug("Setting MISSING_DELAY quirk\n"); ++ return_value |= HID_PIDFF_QUIRK_MISSING_DELAY; ++ } ++ else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) { ++ pr_debug("PBO field not found, but that's OK\n"); ++ pr_debug("Setting MISSING_PBO quirk\n"); ++ return_value |= HID_PIDFF_QUIRK_MISSING_PBO; ++ } ++ else if (!found && strict) { + pr_debug("failed to locate %d\n", k); + return -1; + } + } +- return 0; ++ return return_value; + } + + /* +@@ -871,6 +922,11 @@ static int pidff_reports_ok(struct pidff_device *pidff) + static struct hid_field *pidff_find_special_field(struct hid_report *report, + int usage, int enforce_min) + { ++ if (!report) { ++ pr_debug("pidff_find_special_field, null report\n"); ++ return NULL; ++ } ++ + int i; + + for (i = 0; i < report->maxfield; i++) { +@@ -932,7 +988,8 @@ static int pidff_find_special_fields(struct pidff_device *pidff) + 0x57, 0); + pidff->device_control = + pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL], +- 0x96, 1); ++ 0x96, !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL)); ++ + pidff->block_load_status = + pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD], + 0x8b, 1); +@@ -1062,12 +1119,19 @@ static int pidff_find_effects(struct pidff_device *pidff, + */ + static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) + { +- int envelope_ok = 0; ++ int status = 0; + +- if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) { ++ /* Save info about the device not having the DELAY ffb field. */ ++ status = PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1); ++ if (status == -1) { + hid_err(pidff->hid, "unknown set_effect report layout\n"); + return -ENODEV; + } ++ pidff->quirks |= status; ++ ++ if (status & HID_PIDFF_QUIRK_MISSING_DELAY) ++ hid_dbg(pidff->hid, "Adding MISSING_DELAY quirk\n"); ++ + + PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0); + if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) { +@@ -1085,13 +1149,10 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) + return -ENODEV; + } + +- if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1)) +- envelope_ok = 1; +- + if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev)) + return -ENODEV; + +- if (!envelope_ok) { ++ if (PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1)) { + if (test_and_clear_bit(FF_CONSTANT, dev->ffbit)) + hid_warn(pidff->hid, + "has constant effect but no envelope\n"); +@@ -1116,16 +1177,20 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) + clear_bit(FF_RAMP, dev->ffbit); + } + +- if ((test_bit(FF_SPRING, dev->ffbit) || +- test_bit(FF_DAMPER, dev->ffbit) || +- test_bit(FF_FRICTION, dev->ffbit) || +- test_bit(FF_INERTIA, dev->ffbit)) && +- PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) { +- hid_warn(pidff->hid, "unknown condition effect layout\n"); +- clear_bit(FF_SPRING, dev->ffbit); +- clear_bit(FF_DAMPER, dev->ffbit); +- clear_bit(FF_FRICTION, dev->ffbit); +- clear_bit(FF_INERTIA, dev->ffbit); ++ if (test_bit(FF_SPRING, dev->ffbit) || ++ test_bit(FF_DAMPER, dev->ffbit) || ++ test_bit(FF_FRICTION, dev->ffbit) || ++ test_bit(FF_INERTIA, dev->ffbit)) { ++ status = PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1); ++ ++ if (status < 0) { ++ hid_warn(pidff->hid, "unknown condition effect layout\n"); ++ clear_bit(FF_SPRING, dev->ffbit); ++ clear_bit(FF_DAMPER, dev->ffbit); ++ clear_bit(FF_FRICTION, dev->ffbit); ++ clear_bit(FF_INERTIA, dev->ffbit); ++ } ++ pidff->quirks |= status; + } + + if (test_bit(FF_PERIODIC, dev->ffbit) && +@@ -1222,8 +1287,9 @@ static int pidff_check_autocenter(struct pidff_device *pidff, + + /* + * Check if the device is PID and initialize it ++ * Set initial quirks + */ +-int hid_pidff_init(struct hid_device *hid) ++int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks) + { + struct pidff_device *pidff; + struct hid_input *hidinput = list_entry(hid->inputs.next, +@@ -1245,6 +1311,7 @@ int hid_pidff_init(struct hid_device *hid) + return -ENOMEM; + + pidff->hid = hid; ++ pidff->quirks = initial_quirks; + + hid_device_io_start(hid); + +@@ -1311,6 +1378,7 @@ int hid_pidff_init(struct hid_device *hid) + ff->playback = pidff_playback; + + hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula \n"); ++ hid_dbg(dev, "Active quirks mask: 0x%x\n", pidff->quirks); + + hid_device_io_stop(hid); + +@@ -1322,3 +1390,14 @@ int hid_pidff_init(struct hid_device *hid) + kfree(pidff); + return error; + } ++EXPORT_SYMBOL_GPL(hid_pidff_init_with_quirks); ++ ++/* ++ * Check if the device is PID and initialize it ++ * Wrapper made to keep the compatibility with old ++ * init function ++ */ ++int hid_pidff_init(struct hid_device *hid) ++{ ++ return hid_pidff_init_with_quirks(hid, 0); ++} +diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c +index da6a7abd584f7f..f8ccb29c63807e 100644 +--- a/drivers/hsi/clients/ssi_protocol.c ++++ b/drivers/hsi/clients/ssi_protocol.c +@@ -401,6 +401,7 @@ static void ssip_reset(struct hsi_client *cl) + del_timer(&ssi->rx_wd); + del_timer(&ssi->tx_wd); + del_timer(&ssi->keep_alive); ++ cancel_work_sync(&ssi->work); + ssi->main_state = 0; + ssi->send_state = 0; + ssi->recv_state = 0; +diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c +index 2737fd8abd3249..0cad18ae959eb9 100644 +--- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c ++++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c +@@ -247,6 +247,9 @@ static int ec_i2c_probe(struct platform_device *pdev) + u32 remote_bus; + int err; + ++ if (!ec) ++ return dev_err_probe(dev, -EPROBE_DEFER, "couldn't find parent EC device\n"); ++ + if (!ec->cmd_xfer) { + dev_err(dev, "Missing sendrecv\n"); + return -EINVAL; +diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c +index c03196da116351..03caa4ef012f14 100644 +--- a/drivers/i2c/i2c-atr.c ++++ b/drivers/i2c/i2c-atr.c +@@ -8,12 +8,12 @@ + * Originally based on i2c-mux.c + */ + +-#include + #include + #include + #include + #include + #include ++#include + #include + #include + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index c073ee74e3dabb..33254bc338b9c0 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2512,6 +2512,9 @@ static void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master) + */ + void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) + { ++ if (!dev->ibi || !slot) ++ return; ++ + atomic_inc(&dev->ibi->pending_ibis); + queue_work(dev->common.master->wq, &slot->work); + } +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index 652a666909a552..fa1f12a89158cf 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -376,7 +376,7 @@ static int svc_i3c_master_handle_ibi(struct svc_i3c_master *master, + slot->len < SVC_I3C_FIFO_SIZE) { + mdatactrl = readl(master->regs + SVC_I3C_MDATACTRL); + count = SVC_I3C_MDATACTRL_RXCOUNT(mdatactrl); +- readsl(master->regs + SVC_I3C_MRDATAB, buf, count); ++ readsb(master->regs + SVC_I3C_MRDATAB, buf, count); + slot->len += count; + buf += count; + } +diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c +index 64ace0b968f07f..348527cf1e7bfc 100644 +--- a/drivers/infiniband/core/cma.c ++++ b/drivers/infiniband/core/cma.c +@@ -72,6 +72,8 @@ static const char * const cma_events[] = { + static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid, + enum ib_gid_type gid_type); + ++static void cma_netevent_work_handler(struct work_struct *_work); ++ + const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event) + { + size_t index = event; +@@ -1017,6 +1019,7 @@ __rdma_create_id(struct net *net, rdma_cm_event_handler event_handler, + get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); + id_priv->id.route.addr.dev_addr.net = get_net(net); + id_priv->seq_num &= 0x00ffffff; ++ INIT_WORK(&id_priv->id.net_work, cma_netevent_work_handler); + + rdma_restrack_new(&id_priv->res, RDMA_RESTRACK_CM_ID); + if (parent) +@@ -5211,7 +5214,6 @@ static int cma_netevent_callback(struct notifier_block *self, + if (!memcmp(current_id->id.route.addr.dev_addr.dst_dev_addr, + neigh->ha, ETH_ALEN)) + continue; +- INIT_WORK(¤t_id->id.net_work, cma_netevent_work_handler); + cma_id_get(current_id); + queue_work(cma_wq, ¤t_id->id.net_work); + } +diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c +index e9fa22d31c2332..c48ef608302055 100644 +--- a/drivers/infiniband/core/umem_odp.c ++++ b/drivers/infiniband/core/umem_odp.c +@@ -76,12 +76,14 @@ static inline int ib_init_umem_odp(struct ib_umem_odp *umem_odp, + + npfns = (end - start) >> PAGE_SHIFT; + umem_odp->pfn_list = kvcalloc( +- npfns, sizeof(*umem_odp->pfn_list), GFP_KERNEL); ++ npfns, sizeof(*umem_odp->pfn_list), ++ GFP_KERNEL | __GFP_NOWARN); + if (!umem_odp->pfn_list) + return -ENOMEM; + + umem_odp->dma_list = kvcalloc( +- ndmas, sizeof(*umem_odp->dma_list), GFP_KERNEL); ++ ndmas, sizeof(*umem_odp->dma_list), ++ GFP_KERNEL | __GFP_NOWARN); + if (!umem_odp->dma_list) { + ret = -ENOMEM; + goto out_pfn_list; +diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c +index dcd763dbb636d9..a7e4c951f8fe40 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_main.c ++++ b/drivers/infiniband/hw/hns/hns_roce_main.c +@@ -731,7 +731,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) + if (ret) + return ret; + } +- dma_set_max_seg_size(dev, UINT_MAX); ++ dma_set_max_seg_size(dev, SZ_2G); + ret = ib_register_device(ib_dev, "hns_%d", dev); + if (ret) { + dev_err(dev, "ib_register_device failed!\n"); +diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c +index 13b654ddd3cc8d..bcf7d8607d56ef 100644 +--- a/drivers/infiniband/hw/usnic/usnic_ib_main.c ++++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c +@@ -380,7 +380,7 @@ static void *usnic_ib_device_add(struct pci_dev *dev) + if (!us_ibdev) { + usnic_err("Device %s context alloc failed\n", + netdev_name(pci_get_drvdata(dev))); +- return ERR_PTR(-EFAULT); ++ return NULL; + } + + us_ibdev->ufdev = usnic_fwd_dev_alloc(dev); +@@ -500,8 +500,8 @@ static struct usnic_ib_dev *usnic_ib_discover_pf(struct usnic_vnic *vnic) + } + + us_ibdev = usnic_ib_device_add(parent_pci); +- if (IS_ERR_OR_NULL(us_ibdev)) { +- us_ibdev = us_ibdev ? us_ibdev : ERR_PTR(-EFAULT); ++ if (!us_ibdev) { ++ us_ibdev = ERR_PTR(-EFAULT); + goto out; + } + +@@ -569,10 +569,10 @@ static int usnic_ib_pci_probe(struct pci_dev *pdev, + } + + pf = usnic_ib_discover_pf(vf->vnic); +- if (IS_ERR_OR_NULL(pf)) { +- usnic_err("Failed to discover pf of vnic %s with err%ld\n", +- pci_name(pdev), PTR_ERR(pf)); +- err = pf ? PTR_ERR(pf) : -EFAULT; ++ if (IS_ERR(pf)) { ++ err = PTR_ERR(pf); ++ usnic_err("Failed to discover pf of vnic %s with err%d\n", ++ pci_name(pdev), err); + goto out_clean_vnic; + } + +diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c +index ce78c3671539c7..ff6386fd1e8fec 100644 +--- a/drivers/iommu/iommufd/device.c ++++ b/drivers/iommu/iommufd/device.c +@@ -407,6 +407,17 @@ iommufd_device_do_attach(struct iommufd_device *idev, + return NULL; + } + ++/* Check if idev is attached to igroup->hwpt */ ++static bool iommufd_device_is_attached(struct iommufd_device *idev) ++{ ++ struct iommufd_device *cur; ++ ++ list_for_each_entry(cur, &idev->igroup->device_list, group_item) ++ if (cur == idev) ++ return true; ++ return false; ++} ++ + static struct iommufd_hw_pagetable * + iommufd_device_do_replace(struct iommufd_device *idev, + struct iommufd_hw_pagetable *hwpt) +@@ -424,6 +435,11 @@ iommufd_device_do_replace(struct iommufd_device *idev, + goto err_unlock; + } + ++ if (!iommufd_device_is_attached(idev)) { ++ rc = -EINVAL; ++ goto err_unlock; ++ } ++ + if (hwpt == igroup->hwpt) { + mutex_unlock(&idev->igroup->lock); + return NULL; +@@ -1076,7 +1092,7 @@ int iommufd_access_rw(struct iommufd_access *access, unsigned long iova, + struct io_pagetable *iopt; + struct iopt_area *area; + unsigned long last_iova; +- int rc; ++ int rc = -EINVAL; + + if (!length) + return -EINVAL; +diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c +index de698463e94ad9..06c0770ff894eb 100644 +--- a/drivers/iommu/mtk_iommu.c ++++ b/drivers/iommu/mtk_iommu.c +@@ -1354,15 +1354,6 @@ static int mtk_iommu_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, data); + mutex_init(&data->mutex); + +- ret = iommu_device_sysfs_add(&data->iommu, dev, NULL, +- "mtk-iommu.%pa", &ioaddr); +- if (ret) +- goto out_link_remove; +- +- ret = iommu_device_register(&data->iommu, &mtk_iommu_ops, dev); +- if (ret) +- goto out_sysfs_remove; +- + if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE)) { + list_add_tail(&data->list, data->plat_data->hw_list); + data->hw_list = data->plat_data->hw_list; +@@ -1372,19 +1363,28 @@ static int mtk_iommu_probe(struct platform_device *pdev) + data->hw_list = &data->hw_list_head; + } + ++ ret = iommu_device_sysfs_add(&data->iommu, dev, NULL, ++ "mtk-iommu.%pa", &ioaddr); ++ if (ret) ++ goto out_list_del; ++ ++ ret = iommu_device_register(&data->iommu, &mtk_iommu_ops, dev); ++ if (ret) ++ goto out_sysfs_remove; ++ + if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { + ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, match); + if (ret) +- goto out_list_del; ++ goto out_device_unregister; + } + return ret; + +-out_list_del: +- list_del(&data->list); ++out_device_unregister: + iommu_device_unregister(&data->iommu); + out_sysfs_remove: + iommu_device_sysfs_remove(&data->iommu); +-out_link_remove: ++out_list_del: ++ list_del(&data->list); + if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) + device_link_remove(data->smicomm_dev, dev); + out_runtime_disable: +diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c +index df469aaa7e6e7e..a41c2b13766dc1 100644 +--- a/drivers/leds/rgb/leds-qcom-lpg.c ++++ b/drivers/leds/rgb/leds-qcom-lpg.c +@@ -311,7 +311,7 @@ static int lpg_calc_freq(struct lpg_channel *chan, uint64_t period) + max_res = LPG_RESOLUTION_9BIT; + } + +- min_period = div64_u64((u64)NSEC_PER_SEC * (1 << pwm_resolution_arr[0]), ++ min_period = div64_u64((u64)NSEC_PER_SEC * ((1 << pwm_resolution_arr[0]) - 1), + clk_rate_arr[clk_len - 1]); + if (period <= min_period) + return -EINVAL; +@@ -332,7 +332,7 @@ static int lpg_calc_freq(struct lpg_channel *chan, uint64_t period) + */ + + for (i = 0; i < pwm_resolution_count; i++) { +- resolution = 1 << pwm_resolution_arr[i]; ++ resolution = (1 << pwm_resolution_arr[i]) - 1; + for (clk_sel = 1; clk_sel < clk_len; clk_sel++) { + u64 numerator = period * clk_rate_arr[clk_sel]; + +@@ -379,7 +379,7 @@ static void lpg_calc_duty(struct lpg_channel *chan, uint64_t duty) + unsigned int clk_rate; + + if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { +- max = LPG_RESOLUTION_15BIT - 1; ++ max = BIT(lpg_pwm_resolution_hi_res[chan->pwm_resolution_sel]) - 1; + clk_rate = lpg_clk_rates_hi_res[chan->clk_sel]; + } else { + max = LPG_RESOLUTION_9BIT - 1; +@@ -1060,7 +1060,7 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + if (ret) + return ret; + +- state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * (1 << resolution) * ++ state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * ((1 << resolution) - 1) * + pre_div * (1 << m), refclk); + state->duty_cycle = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * pwm_value * pre_div * (1 << m), refclk); + } else { +diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c +index 694550fdfddddb..5d33cf8ec2ecb9 100644 +--- a/drivers/mailbox/tegra-hsp.c ++++ b/drivers/mailbox/tegra-hsp.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* +- * Copyright (c) 2016-2023, NVIDIA CORPORATION. All rights reserved. ++ * Copyright (c) 2016-2025, NVIDIA CORPORATION. All rights reserved. + */ + + #include +@@ -28,12 +28,6 @@ + #define HSP_INT_FULL_MASK 0xff + + #define HSP_INT_DIMENSIONING 0x380 +-#define HSP_nSM_SHIFT 0 +-#define HSP_nSS_SHIFT 4 +-#define HSP_nAS_SHIFT 8 +-#define HSP_nDB_SHIFT 12 +-#define HSP_nSI_SHIFT 16 +-#define HSP_nINT_MASK 0xf + + #define HSP_DB_TRIGGER 0x0 + #define HSP_DB_ENABLE 0x4 +@@ -97,6 +91,20 @@ struct tegra_hsp_soc { + bool has_per_mb_ie; + bool has_128_bit_mb; + unsigned int reg_stride; ++ ++ /* Shifts for dimensioning register. */ ++ unsigned int si_shift; ++ unsigned int db_shift; ++ unsigned int as_shift; ++ unsigned int ss_shift; ++ unsigned int sm_shift; ++ ++ /* Masks for dimensioning register. */ ++ unsigned int si_mask; ++ unsigned int db_mask; ++ unsigned int as_mask; ++ unsigned int ss_mask; ++ unsigned int sm_mask; + }; + + struct tegra_hsp { +@@ -747,11 +755,11 @@ static int tegra_hsp_probe(struct platform_device *pdev) + return PTR_ERR(hsp->regs); + + value = tegra_hsp_readl(hsp, HSP_INT_DIMENSIONING); +- hsp->num_sm = (value >> HSP_nSM_SHIFT) & HSP_nINT_MASK; +- hsp->num_ss = (value >> HSP_nSS_SHIFT) & HSP_nINT_MASK; +- hsp->num_as = (value >> HSP_nAS_SHIFT) & HSP_nINT_MASK; +- hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK; +- hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK; ++ hsp->num_sm = (value >> hsp->soc->sm_shift) & hsp->soc->sm_mask; ++ hsp->num_ss = (value >> hsp->soc->ss_shift) & hsp->soc->ss_mask; ++ hsp->num_as = (value >> hsp->soc->as_shift) & hsp->soc->as_mask; ++ hsp->num_db = (value >> hsp->soc->db_shift) & hsp->soc->db_mask; ++ hsp->num_si = (value >> hsp->soc->si_shift) & hsp->soc->si_mask; + + err = platform_get_irq_byname_optional(pdev, "doorbell"); + if (err >= 0) +@@ -917,6 +925,16 @@ static const struct tegra_hsp_soc tegra186_hsp_soc = { + .has_per_mb_ie = false, + .has_128_bit_mb = false, + .reg_stride = 0x100, ++ .si_shift = 16, ++ .db_shift = 12, ++ .as_shift = 8, ++ .ss_shift = 4, ++ .sm_shift = 0, ++ .si_mask = 0xf, ++ .db_mask = 0xf, ++ .as_mask = 0xf, ++ .ss_mask = 0xf, ++ .sm_mask = 0xf, + }; + + static const struct tegra_hsp_soc tegra194_hsp_soc = { +@@ -924,6 +942,16 @@ static const struct tegra_hsp_soc tegra194_hsp_soc = { + .has_per_mb_ie = true, + .has_128_bit_mb = false, + .reg_stride = 0x100, ++ .si_shift = 16, ++ .db_shift = 12, ++ .as_shift = 8, ++ .ss_shift = 4, ++ .sm_shift = 0, ++ .si_mask = 0xf, ++ .db_mask = 0xf, ++ .as_mask = 0xf, ++ .ss_mask = 0xf, ++ .sm_mask = 0xf, + }; + + static const struct tegra_hsp_soc tegra234_hsp_soc = { +@@ -931,6 +959,16 @@ static const struct tegra_hsp_soc tegra234_hsp_soc = { + .has_per_mb_ie = false, + .has_128_bit_mb = true, + .reg_stride = 0x100, ++ .si_shift = 16, ++ .db_shift = 12, ++ .as_shift = 8, ++ .ss_shift = 4, ++ .sm_shift = 0, ++ .si_mask = 0xf, ++ .db_mask = 0xf, ++ .as_mask = 0xf, ++ .ss_mask = 0xf, ++ .sm_mask = 0xf, + }; + + static const struct tegra_hsp_soc tegra264_hsp_soc = { +@@ -938,6 +976,16 @@ static const struct tegra_hsp_soc tegra264_hsp_soc = { + .has_per_mb_ie = false, + .has_128_bit_mb = true, + .reg_stride = 0x1000, ++ .si_shift = 17, ++ .db_shift = 12, ++ .as_shift = 8, ++ .ss_shift = 4, ++ .sm_shift = 0, ++ .si_mask = 0x1f, ++ .db_mask = 0x1f, ++ .as_mask = 0xf, ++ .ss_mask = 0xf, ++ .sm_mask = 0xf, + }; + + static const struct of_device_id tegra_hsp_match[] = { +diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c +index 66d9622b684dd4..aead2215d780c2 100644 +--- a/drivers/md/dm-ebs-target.c ++++ b/drivers/md/dm-ebs-target.c +@@ -390,6 +390,12 @@ static int ebs_map(struct dm_target *ti, struct bio *bio) + return DM_MAPIO_REMAPPED; + } + ++static void ebs_postsuspend(struct dm_target *ti) ++{ ++ struct ebs_c *ec = ti->private; ++ dm_bufio_client_reset(ec->bufio); ++} ++ + static void ebs_status(struct dm_target *ti, status_type_t type, + unsigned int status_flags, char *result, unsigned int maxlen) + { +@@ -447,6 +453,7 @@ static struct target_type ebs_target = { + .ctr = ebs_ctr, + .dtr = ebs_dtr, + .map = ebs_map, ++ .postsuspend = ebs_postsuspend, + .status = ebs_status, + .io_hints = ebs_io_hints, + .prepare_ioctl = ebs_prepare_ioctl, +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index a36dd749c688e1..eb2b44f4a61f08 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -4594,16 +4594,19 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv + + ic->recalc_bitmap = dm_integrity_alloc_page_list(n_bitmap_pages); + if (!ic->recalc_bitmap) { ++ ti->error = "Could not allocate memory for bitmap"; + r = -ENOMEM; + goto bad; + } + ic->may_write_bitmap = dm_integrity_alloc_page_list(n_bitmap_pages); + if (!ic->may_write_bitmap) { ++ ti->error = "Could not allocate memory for bitmap"; + r = -ENOMEM; + goto bad; + } + ic->bbs = kvmalloc_array(ic->n_bitmap_blocks, sizeof(struct bitmap_block_status), GFP_KERNEL); + if (!ic->bbs) { ++ ti->error = "Could not allocate memory for bitmap"; + r = -ENOMEM; + goto bad; + } +diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c +index 3636387ce565ae..6ae97da741bba3 100644 +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -836,6 +836,13 @@ static int verity_map(struct dm_target *ti, struct bio *bio) + return DM_MAPIO_SUBMITTED; + } + ++static void verity_postsuspend(struct dm_target *ti) ++{ ++ struct dm_verity *v = ti->private; ++ flush_workqueue(v->verify_wq); ++ dm_bufio_client_reset(v->bufio); ++} ++ + /* + * Status: V (valid) or C (corruption found) + */ +@@ -1557,6 +1564,7 @@ static struct target_type verity_target = { + .ctr = verity_ctr, + .dtr = verity_dtr, + .map = verity_map, ++ .postsuspend = verity_postsuspend, + .status = verity_status, + .prepare_ioctl = verity_prepare_ioctl, + .iterate_devices = verity_iterate_devices, +diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c +index deb40a8ba39995..8317e07b326d0d 100644 +--- a/drivers/md/md-bitmap.c ++++ b/drivers/md/md-bitmap.c +@@ -2119,9 +2119,8 @@ int md_bitmap_get_stats(struct bitmap *bitmap, struct md_bitmap_stats *stats) + + if (!bitmap) + return -ENOENT; +- if (bitmap->mddev->bitmap_info.external) +- return -ENOENT; +- if (!bitmap->storage.sb_page) /* no superblock */ ++ if (!bitmap->mddev->bitmap_info.external && ++ !bitmap->storage.sb_page) + return -EINVAL; + sb = kmap_local_page(bitmap->storage.sb_page); + stats->sync_size = le64_to_cpu(sb->sync_size); +diff --git a/drivers/md/md.c b/drivers/md/md.c +index a8ac4afc51d91d..ca7ae3aad2655f 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -649,6 +649,12 @@ static void __mddev_put(struct mddev *mddev) + queue_work(md_misc_wq, &mddev->del_work); + } + ++static void mddev_put_locked(struct mddev *mddev) ++{ ++ if (atomic_dec_and_test(&mddev->active)) ++ __mddev_put(mddev); ++} ++ + void mddev_put(struct mddev *mddev) + { + if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock)) +@@ -8417,9 +8423,7 @@ static int md_seq_show(struct seq_file *seq, void *v) + if (mddev == list_last_entry(&all_mddevs, struct mddev, all_mddevs)) + status_unused(seq); + +- if (atomic_dec_and_test(&mddev->active)) +- __mddev_put(mddev); +- ++ mddev_put_locked(mddev); + return 0; + } + +@@ -9699,11 +9703,11 @@ EXPORT_SYMBOL_GPL(rdev_clear_badblocks); + static int md_notify_reboot(struct notifier_block *this, + unsigned long code, void *x) + { +- struct mddev *mddev, *n; ++ struct mddev *mddev; + int need_delay = 0; + + spin_lock(&all_mddevs_lock); +- list_for_each_entry_safe(mddev, n, &all_mddevs, all_mddevs) { ++ list_for_each_entry(mddev, &all_mddevs, all_mddevs) { + if (!mddev_get(mddev)) + continue; + spin_unlock(&all_mddevs_lock); +@@ -9715,8 +9719,8 @@ static int md_notify_reboot(struct notifier_block *this, + mddev_unlock(mddev); + } + need_delay = 1; +- mddev_put(mddev); + spin_lock(&all_mddevs_lock); ++ mddev_put_locked(mddev); + } + spin_unlock(&all_mddevs_lock); + +@@ -10039,7 +10043,7 @@ void md_autostart_arrays(int part) + + static __exit void md_exit(void) + { +- struct mddev *mddev, *n; ++ struct mddev *mddev; + int delay = 1; + + unregister_blkdev(MD_MAJOR,"md"); +@@ -10060,7 +10064,7 @@ static __exit void md_exit(void) + remove_proc_entry("mdstat", NULL); + + spin_lock(&all_mddevs_lock); +- list_for_each_entry_safe(mddev, n, &all_mddevs, all_mddevs) { ++ list_for_each_entry(mddev, &all_mddevs, all_mddevs) { + if (!mddev_get(mddev)) + continue; + spin_unlock(&all_mddevs_lock); +@@ -10072,8 +10076,8 @@ static __exit void md_exit(void) + * the mddev for destruction by a workqueue, and the + * destroy_workqueue() below will wait for that to complete. + */ +- mddev_put(mddev); + spin_lock(&all_mddevs_lock); ++ mddev_put_locked(mddev); + } + spin_unlock(&all_mddevs_lock); + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index c300fd609ef08c..36b6bf3f8b29fd 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -1756,6 +1756,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) + * The discard bio returns only first r10bio finishes + */ + if (first_copy) { ++ md_account_bio(mddev, &bio); + r10_bio->master_bio = bio; + set_bit(R10BIO_Discard, &r10_bio->state); + first_copy = false; +diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c +index f80caaa333daf5..67c47e3d671d3d 100644 +--- a/drivers/media/common/siano/smsdvb-main.c ++++ b/drivers/media/common/siano/smsdvb-main.c +@@ -1243,6 +1243,8 @@ static int __init smsdvb_module_init(void) + smsdvb_debugfs_register(); + + rc = smscore_register_hotplug(smsdvb_hotplug); ++ if (rc) ++ smsdvb_debugfs_unregister(); + + pr_debug("\n"); + +diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h +index 6f90f78f58cfac..6e2cb95e86ca59 100644 +--- a/drivers/media/i2c/adv748x/adv748x.h ++++ b/drivers/media/i2c/adv748x/adv748x.h +@@ -322,7 +322,7 @@ struct adv748x_state { + + /* Free run pattern select */ + #define ADV748X_SDP_FRP 0x14 +-#define ADV748X_SDP_FRP_MASK GENMASK(3, 1) ++#define ADV748X_SDP_FRP_MASK GENMASK(2, 0) + + /* Saturation */ + #define ADV748X_SDP_SD_SAT_U 0xe3 /* user_map_rw_reg_e3 */ +diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c +index 92ee86ca80a63d..36402612425779 100644 +--- a/drivers/media/i2c/ccs/ccs-core.c ++++ b/drivers/media/i2c/ccs/ccs-core.c +@@ -3651,6 +3651,7 @@ static int ccs_probe(struct i2c_client *client) + out_disable_runtime_pm: + pm_runtime_put_noidle(&client->dev); + pm_runtime_disable(&client->dev); ++ pm_runtime_set_suspended(&client->dev); + + out_media_entity_cleanup: + media_entity_cleanup(&sensor->src->sd.entity); +@@ -3683,9 +3684,10 @@ static void ccs_remove(struct i2c_client *client) + v4l2_async_unregister_subdev(subdev); + + pm_runtime_disable(&client->dev); +- if (!pm_runtime_status_suspended(&client->dev)) ++ if (!pm_runtime_status_suspended(&client->dev)) { + ccs_power_off(&client->dev); +- pm_runtime_set_suspended(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++ } + + for (i = 0; i < sensor->ssds_used; i++) { + v4l2_device_unregister_subdev(&sensor->ssds[i].sd); +diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c +index a9a8cd148f4fcf..a14e571dc62bc5 100644 +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -1334,21 +1334,23 @@ static int imx219_probe(struct i2c_client *client) + goto error_media_entity; + } + ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ + ret = v4l2_async_register_subdev_sensor(&imx219->sd); + if (ret < 0) { + dev_err(dev, "failed to register sensor sub-device: %d\n", ret); + goto error_subdev_cleanup; + } + +- /* Enable runtime PM and turn off the device */ +- pm_runtime_set_active(dev); +- pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return 0; + + error_subdev_cleanup: + v4l2_subdev_cleanup(&imx219->sd); ++ pm_runtime_disable(dev); ++ pm_runtime_set_suspended(dev); + + error_media_entity: + media_entity_cleanup(&imx219->sd.entity); +@@ -1373,9 +1375,10 @@ static void imx219_remove(struct i2c_client *client) + imx219_free_controls(imx219); + + pm_runtime_disable(&client->dev); +- if (!pm_runtime_status_suspended(&client->dev)) ++ if (!pm_runtime_status_suspended(&client->dev)) { + imx219_power_off(&client->dev); +- pm_runtime_set_suspended(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++ } + } + + static const struct of_device_id imx219_dt_ids[] = { +diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c +index 675fb37a6feaec..2fc52b66154cc4 100644 +--- a/drivers/media/i2c/ov7251.c ++++ b/drivers/media/i2c/ov7251.c +@@ -922,6 +922,8 @@ static int ov7251_set_power_on(struct device *dev) + return ret; + } + ++ usleep_range(1000, 1100); ++ + gpiod_set_value_cansleep(ov7251->enable_gpio, 1); + + /* wait at least 65536 external clock cycles */ +@@ -1675,7 +1677,7 @@ static int ov7251_probe(struct i2c_client *client) + return PTR_ERR(ov7251->analog_regulator); + } + +- ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); ++ ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ov7251->enable_gpio)) { + dev_err(dev, "cannot get enable gpio\n"); + return PTR_ERR(ov7251->enable_gpio); +diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c +index 774487fb72a319..93579a7009a7bc 100644 +--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c ++++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c +@@ -79,8 +79,11 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(void *priv, enum mtk_vcodec_fw_use + } + + fw = devm_kzalloc(&plat_dev->dev, sizeof(*fw), GFP_KERNEL); +- if (!fw) ++ if (!fw) { ++ scp_put(scp); + return ERR_PTR(-ENOMEM); ++ } ++ + fw->type = SCP; + fw->ops = &mtk_vcodec_rproc_msg; + fw->scp = scp; +diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +index e393e3e668f8f5..3fe192a1d5a1de 100644 +--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c ++++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +@@ -1189,7 +1189,8 @@ static int vdec_vp9_slice_setup_lat(struct vdec_vp9_slice_instance *instance, + return ret; + } + +-static ++/* clang stack usage explodes if this is inlined */ ++static noinline_for_stack + void vdec_vp9_slice_map_counts_eob_coef(unsigned int i, unsigned int j, unsigned int k, + struct vdec_vp9_slice_frame_counts *counts, + struct v4l2_vp9_frame_symbol_counts *counts_helper) +diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc/venc_h264_if.c b/drivers/media/platform/mediatek/vcodec/encoder/venc/venc_h264_if.c +index f8145998fcaf78..8522f71fc901d5 100644 +--- a/drivers/media/platform/mediatek/vcodec/encoder/venc/venc_h264_if.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/venc/venc_h264_if.c +@@ -594,7 +594,11 @@ static int h264_enc_init(struct mtk_vcodec_enc_ctx *ctx) + + inst->ctx = ctx; + inst->vpu_inst.ctx = ctx; +- inst->vpu_inst.id = is_ext ? SCP_IPI_VENC_H264 : IPI_VENC_H264; ++ if (is_ext) ++ inst->vpu_inst.id = SCP_IPI_VENC_H264; ++ else ++ inst->vpu_inst.id = IPI_VENC_H264; ++ + inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx->dev->reg_base, VENC_SYS); + + ret = vpu_enc_init(&inst->vpu_inst); +diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c +index c43839539d4dda..8eb9e32031f7f9 100644 +--- a/drivers/media/platform/qcom/venus/hfi_parser.c ++++ b/drivers/media/platform/qcom/venus/hfi_parser.c +@@ -19,6 +19,8 @@ static void init_codecs(struct venus_core *core) + struct hfi_plat_caps *caps = core->caps, *cap; + unsigned long bit; + ++ core->codecs_count = 0; ++ + if (hweight_long(core->dec_codecs) + hweight_long(core->enc_codecs) > MAX_CODEC_NUM) + return; + +@@ -62,7 +64,7 @@ fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num) + cap->cap_bufs_mode_dynamic = true; + } + +-static void ++static int + parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data) + { + struct hfi_buffer_alloc_mode_supported *mode = data; +@@ -70,7 +72,7 @@ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data) + u32 *type; + + if (num_entries > MAX_ALLOC_MODE_ENTRIES) +- return; ++ return -EINVAL; + + type = mode->data; + +@@ -82,6 +84,8 @@ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data) + + type++; + } ++ ++ return sizeof(*mode); + } + + static void fill_profile_level(struct hfi_plat_caps *cap, const void *data, +@@ -96,7 +100,7 @@ static void fill_profile_level(struct hfi_plat_caps *cap, const void *data, + cap->num_pl += num; + } + +-static void ++static int + parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data) + { + struct hfi_profile_level_supported *pl = data; +@@ -104,12 +108,14 @@ parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data) + struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {}; + + if (pl->profile_count > HFI_MAX_PROFILE_COUNT) +- return; ++ return -EINVAL; + + memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel)); + + for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, + fill_profile_level, pl_arr, pl->profile_count); ++ ++ return pl->profile_count * sizeof(*proflevel) + sizeof(u32); + } + + static void +@@ -124,7 +130,7 @@ fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num) + cap->num_caps += num; + } + +-static void ++static int + parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data) + { + struct hfi_capabilities *caps = data; +@@ -133,12 +139,14 @@ parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data) + struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {}; + + if (num_caps > MAX_CAP_ENTRIES) +- return; ++ return -EINVAL; + + memcpy(caps_arr, cap, num_caps * sizeof(*cap)); + + for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, + fill_caps, caps_arr, num_caps); ++ ++ return sizeof(*caps); + } + + static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts, +@@ -153,7 +161,7 @@ static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts, + cap->num_fmts += num_fmts; + } + +-static void ++static int + parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) + { + struct hfi_uncompressed_format_supported *fmt = data; +@@ -162,7 +170,8 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) + struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {}; + u32 entries = fmt->format_entries; + unsigned int i = 0; +- u32 num_planes; ++ u32 num_planes = 0; ++ u32 size; + + while (entries) { + num_planes = pinfo->num_planes; +@@ -172,7 +181,7 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) + i++; + + if (i >= MAX_FMT_ENTRIES) +- return; ++ return -EINVAL; + + if (pinfo->num_planes > MAX_PLANES) + break; +@@ -184,9 +193,13 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) + + for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, + fill_raw_fmts, rawfmts, i); ++ size = fmt->format_entries * (sizeof(*constr) * num_planes + 2 * sizeof(u32)) ++ + 2 * sizeof(u32); ++ ++ return size; + } + +-static void parse_codecs(struct venus_core *core, void *data) ++static int parse_codecs(struct venus_core *core, void *data) + { + struct hfi_codec_supported *codecs = data; + +@@ -198,21 +211,27 @@ static void parse_codecs(struct venus_core *core, void *data) + core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK; + core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC; + } ++ ++ return sizeof(*codecs); + } + +-static void parse_max_sessions(struct venus_core *core, const void *data) ++static int parse_max_sessions(struct venus_core *core, const void *data) + { + const struct hfi_max_sessions_supported *sessions = data; + + core->max_sessions_supported = sessions->max_sessions; ++ ++ return sizeof(*sessions); + } + +-static void parse_codecs_mask(u32 *codecs, u32 *domain, void *data) ++static int parse_codecs_mask(u32 *codecs, u32 *domain, void *data) + { + struct hfi_codec_mask_supported *mask = data; + + *codecs = mask->codecs; + *domain = mask->video_domains; ++ ++ return sizeof(*mask); + } + + static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain) +@@ -281,8 +300,9 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst) + u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf, + u32 size) + { +- unsigned int words_count = size >> 2; +- u32 *word = buf, *data, codecs = 0, domain = 0; ++ u32 *words = buf, *payload, codecs = 0, domain = 0; ++ u32 *frame_size = buf + size; ++ u32 rem_bytes = size; + int ret; + + ret = hfi_platform_parser(core, inst); +@@ -299,38 +319,66 @@ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf, + memset(core->caps, 0, sizeof(core->caps)); + } + +- while (words_count) { +- data = word + 1; ++ while (words < frame_size) { ++ payload = words + 1; + +- switch (*word) { ++ switch (*words) { + case HFI_PROPERTY_PARAM_CODEC_SUPPORTED: +- parse_codecs(core, data); ++ if (rem_bytes <= sizeof(struct hfi_codec_supported)) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ ret = parse_codecs(core, payload); ++ if (ret < 0) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ + init_codecs(core); + break; + case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED: +- parse_max_sessions(core, data); ++ if (rem_bytes <= sizeof(struct hfi_max_sessions_supported)) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ ret = parse_max_sessions(core, payload); + break; + case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: +- parse_codecs_mask(&codecs, &domain, data); ++ if (rem_bytes <= sizeof(struct hfi_codec_mask_supported)) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ ret = parse_codecs_mask(&codecs, &domain, payload); + break; + case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: +- parse_raw_formats(core, codecs, domain, data); ++ if (rem_bytes <= sizeof(struct hfi_uncompressed_format_supported)) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ ret = parse_raw_formats(core, codecs, domain, payload); + break; + case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: +- parse_caps(core, codecs, domain, data); ++ if (rem_bytes <= sizeof(struct hfi_capabilities)) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ ret = parse_caps(core, codecs, domain, payload); + break; + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: +- parse_profile_level(core, codecs, domain, data); ++ if (rem_bytes <= sizeof(struct hfi_profile_level_supported)) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ ret = parse_profile_level(core, codecs, domain, payload); + break; + case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: +- parse_alloc_mode(core, codecs, domain, data); ++ if (rem_bytes <= sizeof(struct hfi_buffer_alloc_mode_supported)) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ ret = parse_alloc_mode(core, codecs, domain, payload); + break; + default: ++ ret = sizeof(u32); + break; + } + +- word++; +- words_count--; ++ if (ret < 0) ++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; ++ ++ words += ret / sizeof(u32); ++ rem_bytes -= ret; + } + + if (!core->max_sessions_supported) +diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c +index f9437b6412b91c..ab93757fff4b31 100644 +--- a/drivers/media/platform/qcom/venus/hfi_venus.c ++++ b/drivers/media/platform/qcom/venus/hfi_venus.c +@@ -187,6 +187,9 @@ static int venus_write_queue(struct venus_hfi_device *hdev, + /* ensure rd/wr indices's are read from memory */ + rmb(); + ++ if (qsize > IFACEQ_QUEUE_SIZE / 4) ++ return -EINVAL; ++ + if (wr_idx >= rd_idx) + empty_space = qsize - (wr_idx - rd_idx); + else +@@ -255,6 +258,9 @@ static int venus_read_queue(struct venus_hfi_device *hdev, + wr_idx = qhdr->write_idx; + qsize = qhdr->q_size; + ++ if (qsize > IFACEQ_QUEUE_SIZE / 4) ++ return -EINVAL; ++ + /* make sure data is valid before using it */ + rmb(); + +@@ -1035,18 +1041,26 @@ static void venus_sfr_print(struct venus_hfi_device *hdev) + { + struct device *dev = hdev->core->dev; + struct hfi_sfr *sfr = hdev->sfr.kva; ++ u32 size; + void *p; + + if (!sfr) + return; + +- p = memchr(sfr->data, '\0', sfr->buf_size); ++ size = sfr->buf_size; ++ if (!size) ++ return; ++ ++ if (size > ALIGNED_SFR_SIZE) ++ size = ALIGNED_SFR_SIZE; ++ ++ p = memchr(sfr->data, '\0', size); + /* + * SFR isn't guaranteed to be NULL terminated since SYS_ERROR indicates + * that Venus is in the process of crashing. + */ + if (!p) +- sfr->data[sfr->buf_size - 1] = '\0'; ++ sfr->data[size - 1] = '\0'; + + dev_err_ratelimited(dev, "SFR message from FW: %s\n", sfr->data); + } +diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c +index 92f1edee58f899..3c64e91260250e 100644 +--- a/drivers/media/platform/st/stm32/dma2d/dma2d.c ++++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c +@@ -492,7 +492,8 @@ static void device_run(void *prv) + dst->sequence = frm_cap->sequence++; + v4l2_m2m_buf_copy_metadata(src, dst, true); + +- clk_enable(dev->gate); ++ if (clk_enable(dev->gate)) ++ goto end; + + dma2d_config_fg(dev, frm_out, + vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0)); +diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c +index 2ce62fe5d60f5a..d3b48a0dd1f474 100644 +--- a/drivers/media/rc/streamzap.c ++++ b/drivers/media/rc/streamzap.c +@@ -138,39 +138,10 @@ static void sz_push_half_space(struct streamzap_ir *sz, + sz_push_full_space(sz, value & SZ_SPACE_MASK); + } + +-/* +- * streamzap_callback - usb IRQ handler callback +- * +- * This procedure is invoked on reception of data from +- * the usb remote. +- */ +-static void streamzap_callback(struct urb *urb) ++static void sz_process_ir_data(struct streamzap_ir *sz, int len) + { +- struct streamzap_ir *sz; + unsigned int i; +- int len; +- +- if (!urb) +- return; +- +- sz = urb->context; +- len = urb->actual_length; +- +- switch (urb->status) { +- case -ECONNRESET: +- case -ENOENT: +- case -ESHUTDOWN: +- /* +- * this urb is terminated, clean up. +- * sz might already be invalid at this point +- */ +- dev_err(sz->dev, "urb terminated, status: %d\n", urb->status); +- return; +- default: +- break; +- } + +- dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); + for (i = 0; i < len; i++) { + dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n", + i, (unsigned char)sz->buf_in[i]); +@@ -219,6 +190,43 @@ static void streamzap_callback(struct urb *urb) + } + + ir_raw_event_handle(sz->rdev); ++} ++ ++/* ++ * streamzap_callback - usb IRQ handler callback ++ * ++ * This procedure is invoked on reception of data from ++ * the usb remote. ++ */ ++static void streamzap_callback(struct urb *urb) ++{ ++ struct streamzap_ir *sz; ++ int len; ++ ++ if (!urb) ++ return; ++ ++ sz = urb->context; ++ len = urb->actual_length; ++ ++ switch (urb->status) { ++ case 0: ++ dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); ++ sz_process_ir_data(sz, len); ++ break; ++ case -ECONNRESET: ++ case -ENOENT: ++ case -ESHUTDOWN: ++ /* ++ * this urb is terminated, clean up. ++ * sz might already be invalid at this point ++ */ ++ dev_err(sz->dev, "urb terminated, status: %d\n", urb->status); ++ return; ++ default: ++ break; ++ } ++ + usb_submit_urb(urb, GFP_ATOMIC); + } + +diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c +index 3e3b424b486058..8ca6459286ba6e 100644 +--- a/drivers/media/test-drivers/vim2m.c ++++ b/drivers/media/test-drivers/vim2m.c +@@ -1316,9 +1316,6 @@ static int vim2m_probe(struct platform_device *pdev) + vfd->v4l2_dev = &dev->v4l2_dev; + + video_set_drvdata(vfd, dev); +- v4l2_info(&dev->v4l2_dev, +- "Device registered as /dev/video%d\n", vfd->num); +- + platform_set_drvdata(pdev, dev); + + dev->m2m_dev = v4l2_m2m_init(&m2m_ops); +@@ -1345,6 +1342,9 @@ static int vim2m_probe(struct platform_device *pdev) + goto error_m2m; + } + ++ v4l2_info(&dev->v4l2_dev, ++ "Device registered as /dev/video%d\n", vfd->num); ++ + #ifdef CONFIG_MEDIA_CONTROLLER + ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, + MEDIA_ENT_F_PROC_VIDEO_SCALER); +diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c +index 9970dc739ca56c..a28bb8ee21e98f 100644 +--- a/drivers/media/test-drivers/visl/visl-core.c ++++ b/drivers/media/test-drivers/visl/visl-core.c +@@ -156,9 +156,15 @@ static const struct visl_ctrl_desc visl_h264_ctrl_descs[] = { + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE, ++ .cfg.min = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED, ++ .cfg.max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, ++ .cfg.def = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED, + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_START_CODE, ++ .cfg.min = V4L2_STATELESS_H264_START_CODE_NONE, ++ .cfg.max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, ++ .cfg.def = V4L2_STATELESS_H264_START_CODE_NONE, + }, + { + .cfg.id = V4L2_CID_STATELESS_H264_SLICE_PARAMS, +@@ -193,9 +199,15 @@ static const struct visl_ctrl_desc visl_hevc_ctrl_descs[] = { + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, ++ .cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, ++ .cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, ++ .cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE, ++ .cfg.min = V4L2_STATELESS_HEVC_START_CODE_NONE, ++ .cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, ++ .cfg.def = V4L2_STATELESS_HEVC_START_CODE_NONE, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, +diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c +index ae2e8bd2b3f73d..02cfa12b9cb902 100644 +--- a/drivers/media/usb/uvc/uvc_driver.c ++++ b/drivers/media/usb/uvc/uvc_driver.c +@@ -3116,6 +3116,15 @@ static const struct usb_device_id uvc_ids[] = { + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX + | UVC_QUIRK_IGNORE_SELECTOR_UNIT) }, ++ /* Actions Microelectronics Co. Display capture-UVC05 */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x1de1, ++ .idProduct = 0xf105, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 0, ++ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_DISABLE_AUTOSUSPEND) }, + /* NXP Semiconductors IR VIDEO */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, +diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c +index 2cf5dcee0ce800..4d05873892c168 100644 +--- a/drivers/media/v4l2-core/v4l2-dv-timings.c ++++ b/drivers/media/v4l2-core/v4l2-dv-timings.c +@@ -764,7 +764,7 @@ bool v4l2_detect_gtf(unsigned int frame_height, + u64 num; + u32 den; + +- num = ((image_width * GTF_D_C_PRIME * (u64)hfreq) - ++ num = (((u64)image_width * GTF_D_C_PRIME * hfreq) - + ((u64)image_width * GTF_D_M_PRIME * 1000)); + den = (hfreq * (100 - GTF_D_C_PRIME) + GTF_D_M_PRIME * 1000) * + (2 * GTF_CELL_GRAN); +@@ -774,7 +774,7 @@ bool v4l2_detect_gtf(unsigned int frame_height, + u64 num; + u32 den; + +- num = ((image_width * GTF_S_C_PRIME * (u64)hfreq) - ++ num = (((u64)image_width * GTF_S_C_PRIME * hfreq) - + ((u64)image_width * GTF_S_M_PRIME * 1000)); + den = (hfreq * (100 - GTF_S_C_PRIME) + GTF_S_M_PRIME * 1000) * + (2 * GTF_CELL_GRAN); +diff --git a/drivers/mfd/ene-kb3930.c b/drivers/mfd/ene-kb3930.c +index fa0ad2f14a3961..9460a67acb0b5e 100644 +--- a/drivers/mfd/ene-kb3930.c ++++ b/drivers/mfd/ene-kb3930.c +@@ -162,7 +162,7 @@ static int kb3930_probe(struct i2c_client *client) + devm_gpiod_get_array_optional(dev, "off", GPIOD_IN); + if (IS_ERR(ddata->off_gpios)) + return PTR_ERR(ddata->off_gpios); +- if (ddata->off_gpios->ndescs < 2) { ++ if (ddata->off_gpios && ddata->off_gpios->ndescs < 2) { + dev_err(dev, "invalid off-gpios property\n"); + return -EINVAL; + } +diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c +index af519088732d9a..c95a2b0b9012c0 100644 +--- a/drivers/misc/pci_endpoint_test.c ++++ b/drivers/misc/pci_endpoint_test.c +@@ -243,7 +243,7 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test) + return true; + + fail: +- switch (irq_type) { ++ switch (test->irq_type) { + case IRQ_TYPE_LEGACY: + dev_err(dev, "Failed to request IRQ %d for Legacy\n", + pci_irq_vector(pdev, i)); +@@ -260,6 +260,9 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test) + break; + } + ++ test->num_irqs = i; ++ pci_endpoint_test_release_irq(test); ++ + return false; + } + +@@ -708,6 +711,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test, + if (!pci_endpoint_test_request_irq(test)) + goto err; + ++ irq_type = test->irq_type; + return true; + + err: +diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c +index 02bee7afab37ef..f97caaa829f707 100644 +--- a/drivers/mmc/host/dw_mmc.c ++++ b/drivers/mmc/host/dw_mmc.c +@@ -2574,6 +2574,91 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) + } + } + ++static void dw_mci_push_data64_32(struct dw_mci *host, void *buf, int cnt) ++{ ++ struct mmc_data *data = host->data; ++ int init_cnt = cnt; ++ ++ /* try and push anything in the part_buf */ ++ if (unlikely(host->part_buf_count)) { ++ int len = dw_mci_push_part_bytes(host, buf, cnt); ++ ++ buf += len; ++ cnt -= len; ++ ++ if (host->part_buf_count == 8) { ++ mci_fifo_l_writeq(host->fifo_reg, host->part_buf); ++ host->part_buf_count = 0; ++ } ++ } ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (unlikely((unsigned long)buf & 0x7)) { ++ while (cnt >= 8) { ++ u64 aligned_buf[16]; ++ int len = min(cnt & -8, (int)sizeof(aligned_buf)); ++ int items = len >> 3; ++ int i; ++ /* memcpy from input buffer into aligned buffer */ ++ memcpy(aligned_buf, buf, len); ++ buf += len; ++ cnt -= len; ++ /* push data from aligned buffer into fifo */ ++ for (i = 0; i < items; ++i) ++ mci_fifo_l_writeq(host->fifo_reg, aligned_buf[i]); ++ } ++ } else ++#endif ++ { ++ u64 *pdata = buf; ++ ++ for (; cnt >= 8; cnt -= 8) ++ mci_fifo_l_writeq(host->fifo_reg, *pdata++); ++ buf = pdata; ++ } ++ /* put anything remaining in the part_buf */ ++ if (cnt) { ++ dw_mci_set_part_bytes(host, buf, cnt); ++ /* Push data if we have reached the expected data length */ ++ if ((data->bytes_xfered + init_cnt) == ++ (data->blksz * data->blocks)) ++ mci_fifo_l_writeq(host->fifo_reg, host->part_buf); ++ } ++} ++ ++static void dw_mci_pull_data64_32(struct dw_mci *host, void *buf, int cnt) ++{ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (unlikely((unsigned long)buf & 0x7)) { ++ while (cnt >= 8) { ++ /* pull data from fifo into aligned buffer */ ++ u64 aligned_buf[16]; ++ int len = min(cnt & -8, (int)sizeof(aligned_buf)); ++ int items = len >> 3; ++ int i; ++ ++ for (i = 0; i < items; ++i) ++ aligned_buf[i] = mci_fifo_l_readq(host->fifo_reg); ++ ++ /* memcpy from aligned buffer into output buffer */ ++ memcpy(buf, aligned_buf, len); ++ buf += len; ++ cnt -= len; ++ } ++ } else ++#endif ++ { ++ u64 *pdata = buf; ++ ++ for (; cnt >= 8; cnt -= 8) ++ *pdata++ = mci_fifo_l_readq(host->fifo_reg); ++ buf = pdata; ++ } ++ if (cnt) { ++ host->part_buf = mci_fifo_l_readq(host->fifo_reg); ++ dw_mci_pull_final_bytes(host, buf, cnt); ++ } ++} ++ + static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) + { + int len; +@@ -3374,8 +3459,13 @@ int dw_mci_probe(struct dw_mci *host) + width = 16; + host->data_shift = 1; + } else if (i == 2) { +- host->push_data = dw_mci_push_data64; +- host->pull_data = dw_mci_pull_data64; ++ if ((host->quirks & DW_MMC_QUIRK_FIFO64_32)) { ++ host->push_data = dw_mci_push_data64_32; ++ host->pull_data = dw_mci_pull_data64_32; ++ } else { ++ host->push_data = dw_mci_push_data64; ++ host->pull_data = dw_mci_pull_data64; ++ } + width = 64; + host->data_shift = 3; + } else { +diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h +index 4ed81f94f7cabd..af16dbb37f2617 100644 +--- a/drivers/mmc/host/dw_mmc.h ++++ b/drivers/mmc/host/dw_mmc.h +@@ -280,6 +280,8 @@ struct dw_mci_board { + + /* Support for longer data read timeout */ + #define DW_MMC_QUIRK_EXTENDED_TMOUT BIT(0) ++/* Force 32-bit access to the FIFO */ ++#define DW_MMC_QUIRK_FIFO64_32 BIT(1) + + #define DW_MMC_240A 0x240a + #define DW_MMC_280A 0x280a +@@ -471,6 +473,31 @@ struct dw_mci_board { + #define mci_fifo_writel(__value, __reg) __raw_writel(__reg, __value) + #define mci_fifo_writeq(__value, __reg) __raw_writeq(__reg, __value) + ++/* ++ * Some dw_mmc devices have 64-bit FIFOs, but expect them to be ++ * accessed using two 32-bit accesses. If such controller is used ++ * with a 64-bit kernel, this has to be done explicitly. ++ */ ++static inline u64 mci_fifo_l_readq(void __iomem *addr) ++{ ++ u64 ans; ++ u32 proxy[2]; ++ ++ proxy[0] = mci_fifo_readl(addr); ++ proxy[1] = mci_fifo_readl(addr + 4); ++ memcpy(&ans, proxy, 8); ++ return ans; ++} ++ ++static inline void mci_fifo_l_writeq(void __iomem *addr, u64 value) ++{ ++ u32 proxy[2]; ++ ++ memcpy(proxy, &value, 8); ++ mci_fifo_writel(addr, proxy[0]); ++ mci_fifo_writel(addr + 4, proxy[1]); ++} ++ + /* Register access macros */ + #define mci_readl(dev, reg) \ + readl_relaxed((dev)->regs + SDMMC_##reg) +diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c +index 9739387cff8c91..58c6e1743f5c65 100644 +--- a/drivers/mtd/inftlcore.c ++++ b/drivers/mtd/inftlcore.c +@@ -482,10 +482,11 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) + silly = MAX_LOOPS; + + while (thisEUN <= inftl->lastEUN) { +- inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + +- blockofs, 8, &retlen, (char *)&bci); +- +- status = bci.Status | bci.Status1; ++ if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + ++ blockofs, 8, &retlen, (char *)&bci) < 0) ++ status = SECTOR_IGNORE; ++ else ++ status = bci.Status | bci.Status1; + pr_debug("INFTL: status of block %d in EUN %d is %x\n", + block , writeEUN, status); + +diff --git a/drivers/mtd/mtdpstore.c b/drivers/mtd/mtdpstore.c +index 7ac8ac90130685..9cf3872e37ae14 100644 +--- a/drivers/mtd/mtdpstore.c ++++ b/drivers/mtd/mtdpstore.c +@@ -417,11 +417,14 @@ static void mtdpstore_notify_add(struct mtd_info *mtd) + } + + longcnt = BITS_TO_LONGS(div_u64(mtd->size, info->kmsg_size)); +- cxt->rmmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL); +- cxt->usedmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL); ++ cxt->rmmap = devm_kcalloc(&mtd->dev, longcnt, sizeof(long), GFP_KERNEL); ++ cxt->usedmap = devm_kcalloc(&mtd->dev, longcnt, sizeof(long), GFP_KERNEL); + + longcnt = BITS_TO_LONGS(div_u64(mtd->size, mtd->erasesize)); +- cxt->badmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL); ++ cxt->badmap = devm_kcalloc(&mtd->dev, longcnt, sizeof(long), GFP_KERNEL); ++ ++ if (!cxt->rmmap || !cxt->usedmap || !cxt->badmap) ++ return; + + /* just support dmesg right now */ + cxt->dev.flags = PSTORE_FLAGS_DMESG; +@@ -527,9 +530,6 @@ static void mtdpstore_notify_remove(struct mtd_info *mtd) + mtdpstore_flush_removed(cxt); + + unregister_pstore_device(&cxt->dev); +- kfree(cxt->badmap); +- kfree(cxt->usedmap); +- kfree(cxt->rmmap); + cxt->mtd = NULL; + cxt->index = -1; + } +diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +index 085a16148a68d4..03d7e26d495375 100644 +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -2974,7 +2974,7 @@ static int brcmnand_resume(struct device *dev) + brcmnand_save_restore_cs_config(host, 1); + + /* Reset the chip, required by some chips after power-up */ +- nand_reset_op(chip); ++ nand_reset(chip, 0); + } + + return 0; +diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c +index ed0cf732d20e40..36cfe03cd4ac3b 100644 +--- a/drivers/mtd/nand/raw/r852.c ++++ b/drivers/mtd/nand/raw/r852.c +@@ -387,6 +387,9 @@ static int r852_wait(struct nand_chip *chip) + static int r852_ready(struct nand_chip *chip) + { + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); ++ if (dev->card_unstable) ++ return 0; ++ + return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY); + } + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index 4a2c9a9134d8c8..cfcda893f1a16d 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -724,6 +724,15 @@ static void b53_enable_mib(struct b53_device *dev) + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); + } + ++static void b53_enable_stp(struct b53_device *dev) ++{ ++ u8 gc; ++ ++ b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); ++ gc |= GC_RX_BPDU_EN; ++ b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); ++} ++ + static u16 b53_default_pvid(struct b53_device *dev) + { + if (is5325(dev) || is5365(dev)) +@@ -863,6 +872,7 @@ static int b53_switch_reset(struct b53_device *dev) + } + + b53_enable_mib(dev); ++ b53_enable_stp(dev); + + return b53_flush_arl(dev, FAST_AGE_STATIC); + } +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 8b01ee3e684a38..da7260e505a2e4 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -1742,6 +1742,8 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, + if (!chip->info->ops->vtu_getnext) + return -EOPNOTSUPP; + ++ memset(entry, 0, sizeof(*entry)); ++ + entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip); + entry->valid = false; + +@@ -1877,7 +1879,16 @@ static int mv88e6xxx_mst_put(struct mv88e6xxx_chip *chip, u8 sid) + struct mv88e6xxx_mst *mst, *tmp; + int err; + +- if (!sid) ++ /* If the SID is zero, it is for a VLAN mapped to the default MSTI, ++ * and mv88e6xxx_stu_setup() made sure it is always present, and thus, ++ * should not be removed here. ++ * ++ * If the chip lacks STU support, numerically the "sid" variable will ++ * happen to also be zero, but we don't want to rely on that fact, so ++ * we explicitly test that first. In that case, there is also nothing ++ * to do here. ++ */ ++ if (!mv88e6xxx_has_stu(chip) || !sid) + return 0; + + list_for_each_entry_safe(mst, tmp, &chip->msts, node) { +@@ -3555,6 +3566,21 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) + return mv88e6xxx_g1_stats_clear(chip); + } + ++static int mv88e6320_setup_errata(struct mv88e6xxx_chip *chip) ++{ ++ u16 dummy; ++ int err; ++ ++ /* Workaround for erratum ++ * 3.3 RGMII timing may be out of spec when transmit delay is enabled ++ */ ++ err = mv88e6xxx_port_hidden_write(chip, 0, 0xf, 0x7, 0xe000); ++ if (err) ++ return err; ++ ++ return mv88e6xxx_port_hidden_read(chip, 0, 0xf, 0x7, &dummy); ++} ++ + /* Check if the errata has already been applied. */ + static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) + { +@@ -5005,6 +5031,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { + + static const struct mv88e6xxx_ops mv88e6320_ops = { + /* MV88E6XXX_FAMILY_6320 */ ++ .setup_errata = mv88e6320_setup_errata, + .ieee_pri_map = mv88e6085_g1_ieee_pri_map, + .ip_pri_map = mv88e6085_g1_ip_pri_map, + .irl_init_all = mv88e6352_g2_irl_init_all, +@@ -5054,6 +5081,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { + + static const struct mv88e6xxx_ops mv88e6321_ops = { + /* MV88E6XXX_FAMILY_6320 */ ++ .setup_errata = mv88e6320_setup_errata, + .ieee_pri_map = mv88e6085_g1_ieee_pri_map, + .ip_pri_map = mv88e6085_g1_ip_pri_map, + .irl_init_all = mv88e6352_g2_irl_init_all, +diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c +index a08dab75e0c0c1..f57fde02077d22 100644 +--- a/drivers/net/dsa/mv88e6xxx/devlink.c ++++ b/drivers/net/dsa/mv88e6xxx/devlink.c +@@ -743,7 +743,8 @@ void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds) + int i; + + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) +- dsa_devlink_region_destroy(chip->regions[i]); ++ if (chip->regions[i]) ++ dsa_devlink_region_destroy(chip->regions[i]); + } + + void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port) +diff --git a/drivers/net/ethernet/amd/pds_core/debugfs.c b/drivers/net/ethernet/amd/pds_core/debugfs.c +index 4e8579ca1c8c71..51f3f73a839a9d 100644 +--- a/drivers/net/ethernet/amd/pds_core/debugfs.c ++++ b/drivers/net/ethernet/amd/pds_core/debugfs.c +@@ -154,8 +154,9 @@ void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq) + debugfs_create_u32("index", 0400, intr_dentry, &intr->index); + debugfs_create_u32("vector", 0400, intr_dentry, &intr->vector); + +- intr_ctrl_regset = kzalloc(sizeof(*intr_ctrl_regset), +- GFP_KERNEL); ++ intr_ctrl_regset = devm_kzalloc(pdsc->dev, ++ sizeof(*intr_ctrl_regset), ++ GFP_KERNEL); + if (!intr_ctrl_regset) + return; + intr_ctrl_regset->regs = intr_ctrl_regs; +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +index 8477a93cee6bd4..b77897aa06c4f5 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +@@ -2273,6 +2273,7 @@ int cxgb4_init_ethtool_filters(struct adapter *adap) + eth_filter->port[i].bmap = bitmap_zalloc(nentries, GFP_KERNEL); + if (!eth_filter->port[i].bmap) { + ret = -ENOMEM; ++ kvfree(eth_filter->port[i].loc_array); + goto free_eth_finfo; + } + } +diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c +index 233e5946905e7d..22317acf16ba4d 100644 +--- a/drivers/net/ethernet/google/gve/gve_ethtool.c ++++ b/drivers/net/ethernet/google/gve/gve_ethtool.c +@@ -356,7 +356,9 @@ gve_get_ethtool_stats(struct net_device *netdev, + */ + data[i++] = 0; + data[i++] = 0; +- data[i++] = tx->dqo_tx.tail - tx->dqo_tx.head; ++ data[i++] = ++ (tx->dqo_tx.tail - tx->dqo_tx.head) & ++ tx->mask; + } + do { + start = +diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h +index 85cc163965062e..49702169a3d8a6 100644 +--- a/drivers/net/ethernet/intel/igc/igc.h ++++ b/drivers/net/ethernet/intel/igc/igc.h +@@ -266,6 +266,7 @@ struct igc_adapter { + struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */ + ktime_t ptp_reset_start; /* Reset time in clock mono */ + struct system_time_snapshot snapshot; ++ struct mutex ptm_lock; /* Only allow one PTM transaction at a time */ + + char fw_version[32]; + +diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h +index a18af5c87cde48..cf8b5ac51caaa7 100644 +--- a/drivers/net/ethernet/intel/igc/igc_defines.h ++++ b/drivers/net/ethernet/intel/igc/igc_defines.h +@@ -562,7 +562,10 @@ + #define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x3f) << 2) + #define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8) + +-#define IGC_PTM_SHORT_CYC_DEFAULT 1 /* Default short cycle interval */ ++/* A short cycle time of 1us theoretically should work, but appears to be too ++ * short in practice. ++ */ ++#define IGC_PTM_SHORT_CYC_DEFAULT 4 /* Default short cycle interval */ + #define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */ + #define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */ + +@@ -581,6 +584,7 @@ + #define IGC_PTM_STAT_T4M1_OVFL BIT(3) /* T4 minus T1 overflow */ + #define IGC_PTM_STAT_ADJUST_1ST BIT(4) /* 1588 timer adjusted during 1st PTM cycle */ + #define IGC_PTM_STAT_ADJUST_CYC BIT(5) /* 1588 timer adjusted during non-1st PTM cycle */ ++#define IGC_PTM_STAT_ALL GENMASK(5, 0) /* Used to clear all status */ + + /* PCIe PTM Cycle Control */ + #define IGC_PTM_CYCLE_CTRL_CYC_TIME(msec) ((msec) & 0x3ff) /* PTM Cycle Time (msec) */ +diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c +index ae93b45cf55e8e..e2f5c4384455e0 100644 +--- a/drivers/net/ethernet/intel/igc/igc_main.c ++++ b/drivers/net/ethernet/intel/igc/igc_main.c +@@ -6951,6 +6951,7 @@ static int igc_probe(struct pci_dev *pdev, + + err_register: + igc_release_hw_control(adapter); ++ igc_ptp_stop(adapter); + err_eeprom: + if (!igc_check_reset_block(hw)) + igc_reset_phy(hw); +diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c +index 928f38792203a6..b6bb01a486d9d8 100644 +--- a/drivers/net/ethernet/intel/igc/igc_ptp.c ++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c +@@ -943,45 +943,62 @@ static void igc_ptm_log_error(struct igc_adapter *adapter, u32 ptm_stat) + } + } + ++/* The PTM lock: adapter->ptm_lock must be held when calling igc_ptm_trigger() */ ++static void igc_ptm_trigger(struct igc_hw *hw) ++{ ++ u32 ctrl; ++ ++ /* To "manually" start the PTM cycle we need to set the ++ * trigger (TRIG) bit ++ */ ++ ctrl = rd32(IGC_PTM_CTRL); ++ ctrl |= IGC_PTM_CTRL_TRIG; ++ wr32(IGC_PTM_CTRL, ctrl); ++ /* Perform flush after write to CTRL register otherwise ++ * transaction may not start ++ */ ++ wrfl(); ++} ++ ++/* The PTM lock: adapter->ptm_lock must be held when calling igc_ptm_reset() */ ++static void igc_ptm_reset(struct igc_hw *hw) ++{ ++ u32 ctrl; ++ ++ ctrl = rd32(IGC_PTM_CTRL); ++ ctrl &= ~IGC_PTM_CTRL_TRIG; ++ wr32(IGC_PTM_CTRL, ctrl); ++ /* Write to clear all status */ ++ wr32(IGC_PTM_STAT, IGC_PTM_STAT_ALL); ++} ++ + static int igc_phc_get_syncdevicetime(ktime_t *device, + struct system_counterval_t *system, + void *ctx) + { +- u32 stat, t2_curr_h, t2_curr_l, ctrl; + struct igc_adapter *adapter = ctx; + struct igc_hw *hw = &adapter->hw; ++ u32 stat, t2_curr_h, t2_curr_l; + int err, count = 100; + ktime_t t1, t2_curr; + +- /* Get a snapshot of system clocks to use as historic value. */ +- ktime_get_snapshot(&adapter->snapshot); +- ++ /* Doing this in a loop because in the event of a ++ * badly timed (ha!) system clock adjustment, we may ++ * get PTM errors from the PCI root, but these errors ++ * are transitory. Repeating the process returns valid ++ * data eventually. ++ */ + do { +- /* Doing this in a loop because in the event of a +- * badly timed (ha!) system clock adjustment, we may +- * get PTM errors from the PCI root, but these errors +- * are transitory. Repeating the process returns valid +- * data eventually. +- */ ++ /* Get a snapshot of system clocks to use as historic value. */ ++ ktime_get_snapshot(&adapter->snapshot); + +- /* To "manually" start the PTM cycle we need to clear and +- * then set again the TRIG bit. +- */ +- ctrl = rd32(IGC_PTM_CTRL); +- ctrl &= ~IGC_PTM_CTRL_TRIG; +- wr32(IGC_PTM_CTRL, ctrl); +- ctrl |= IGC_PTM_CTRL_TRIG; +- wr32(IGC_PTM_CTRL, ctrl); +- +- /* The cycle only starts "for real" when software notifies +- * that it has read the registers, this is done by setting +- * VALID bit. +- */ +- wr32(IGC_PTM_STAT, IGC_PTM_STAT_VALID); ++ igc_ptm_trigger(hw); + + err = readx_poll_timeout(rd32, IGC_PTM_STAT, stat, + stat, IGC_PTM_STAT_SLEEP, + IGC_PTM_STAT_TIMEOUT); ++ igc_ptm_reset(hw); ++ + if (err < 0) { + netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n"); + return err; +@@ -990,15 +1007,7 @@ static int igc_phc_get_syncdevicetime(ktime_t *device, + if ((stat & IGC_PTM_STAT_VALID) == IGC_PTM_STAT_VALID) + break; + +- if (stat & ~IGC_PTM_STAT_VALID) { +- /* An error occurred, log it. */ +- igc_ptm_log_error(adapter, stat); +- /* The STAT register is write-1-to-clear (W1C), +- * so write the previous error status to clear it. +- */ +- wr32(IGC_PTM_STAT, stat); +- continue; +- } ++ igc_ptm_log_error(adapter, stat); + } while (--count); + + if (!count) { +@@ -1030,9 +1039,16 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp, + { + struct igc_adapter *adapter = container_of(ptp, struct igc_adapter, + ptp_caps); ++ int ret; ++ ++ /* This blocks until any in progress PTM transactions complete */ ++ mutex_lock(&adapter->ptm_lock); + +- return get_device_system_crosststamp(igc_phc_get_syncdevicetime, +- adapter, &adapter->snapshot, cts); ++ ret = get_device_system_crosststamp(igc_phc_get_syncdevicetime, ++ adapter, &adapter->snapshot, cts); ++ mutex_unlock(&adapter->ptm_lock); ++ ++ return ret; + } + + /** +@@ -1109,6 +1125,7 @@ void igc_ptp_init(struct igc_adapter *adapter) + + spin_lock_init(&adapter->ptp_tx_lock); + spin_lock_init(&adapter->tmreg_lock); ++ mutex_init(&adapter->ptm_lock); + + adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; +@@ -1121,6 +1138,7 @@ void igc_ptp_init(struct igc_adapter *adapter) + if (IS_ERR(adapter->ptp_clock)) { + adapter->ptp_clock = NULL; + netdev_err(netdev, "ptp_clock_register failed\n"); ++ mutex_destroy(&adapter->ptm_lock); + } else if (adapter->ptp_clock) { + netdev_info(netdev, "PHC added\n"); + adapter->ptp_flags |= IGC_PTP_ENABLED; +@@ -1150,10 +1168,12 @@ static void igc_ptm_stop(struct igc_adapter *adapter) + struct igc_hw *hw = &adapter->hw; + u32 ctrl; + ++ mutex_lock(&adapter->ptm_lock); + ctrl = rd32(IGC_PTM_CTRL); + ctrl &= ~IGC_PTM_CTRL_EN; + + wr32(IGC_PTM_CTRL, ctrl); ++ mutex_unlock(&adapter->ptm_lock); + } + + /** +@@ -1184,13 +1204,18 @@ void igc_ptp_suspend(struct igc_adapter *adapter) + **/ + void igc_ptp_stop(struct igc_adapter *adapter) + { ++ if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) ++ return; ++ + igc_ptp_suspend(adapter); + ++ adapter->ptp_flags &= ~IGC_PTP_ENABLED; + if (adapter->ptp_clock) { + ptp_clock_unregister(adapter->ptp_clock); + netdev_info(adapter->netdev, "PHC removed\n"); + adapter->ptp_flags &= ~IGC_PTP_ENABLED; + } ++ mutex_destroy(&adapter->ptm_lock); + } + + /** +@@ -1202,10 +1227,13 @@ void igc_ptp_stop(struct igc_adapter *adapter) + void igc_ptp_reset(struct igc_adapter *adapter) + { + struct igc_hw *hw = &adapter->hw; +- u32 cycle_ctrl, ctrl; ++ u32 cycle_ctrl, ctrl, stat; + unsigned long flags; + u32 timadj; + ++ if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) ++ return; ++ + /* reset the tstamp_config */ + igc_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); + +@@ -1227,6 +1255,7 @@ void igc_ptp_reset(struct igc_adapter *adapter) + if (!igc_is_crosststamp_supported(adapter)) + break; + ++ mutex_lock(&adapter->ptm_lock); + wr32(IGC_PCIE_DIG_DELAY, IGC_PCIE_DIG_DELAY_DEFAULT); + wr32(IGC_PCIE_PHY_DELAY, IGC_PCIE_PHY_DELAY_DEFAULT); + +@@ -1237,14 +1266,20 @@ void igc_ptp_reset(struct igc_adapter *adapter) + ctrl = IGC_PTM_CTRL_EN | + IGC_PTM_CTRL_START_NOW | + IGC_PTM_CTRL_SHRT_CYC(IGC_PTM_SHORT_CYC_DEFAULT) | +- IGC_PTM_CTRL_PTM_TO(IGC_PTM_TIMEOUT_DEFAULT) | +- IGC_PTM_CTRL_TRIG; ++ IGC_PTM_CTRL_PTM_TO(IGC_PTM_TIMEOUT_DEFAULT); + + wr32(IGC_PTM_CTRL, ctrl); + + /* Force the first cycle to run. */ +- wr32(IGC_PTM_STAT, IGC_PTM_STAT_VALID); ++ igc_ptm_trigger(hw); ++ ++ if (readx_poll_timeout_atomic(rd32, IGC_PTM_STAT, stat, ++ stat, IGC_PTM_STAT_SLEEP, ++ IGC_PTM_STAT_TIMEOUT)) ++ netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n"); + ++ igc_ptm_reset(hw); ++ mutex_unlock(&adapter->ptm_lock); + break; + default: + /* No work to do. */ +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c +index 4995a2d54d7d08..37db19584c1431 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c +@@ -165,6 +165,11 @@ static void __otx2_qos_txschq_cfg(struct otx2_nic *pfvf, + + otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); + } else if (level == NIX_TXSCH_LVL_TL2) { ++ /* configure parent txschq */ ++ cfg->reg[num_regs] = NIX_AF_TL2X_PARENT(node->schq); ++ cfg->regval[num_regs] = (u64)hw->tx_link << 16; ++ num_regs++; ++ + /* configure link cfg */ + if (level == pfvf->qos.link_cfg_lvl) { + cfg->reg[num_regs] = NIX_AF_TL3_TL2X_LINKX_CFG(node->schq, hw->tx_link); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index bdc424123ee6cf..c201ea20e40476 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -724,7 +724,7 @@ static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, + case SPEED_100: + val |= MTK_QTX_SCH_MAX_RATE_EN | + FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) | +- FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 3); ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 3) | + FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1); + break; + case SPEED_1000: +@@ -747,13 +747,13 @@ static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, + case SPEED_100: + val |= MTK_QTX_SCH_MAX_RATE_EN | + FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) | +- FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5); ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5) | + FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1); + break; + case SPEED_1000: + val |= MTK_QTX_SCH_MAX_RATE_EN | +- FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 10) | +- FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 6) | + FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10); + break; + default: +@@ -3244,7 +3244,7 @@ static int mtk_start_dma(struct mtk_eth *eth) + if (mtk_is_netsys_v2_or_greater(eth)) + val |= MTK_MUTLI_CNT | MTK_RESV_BUF | + MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | +- MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN; ++ MTK_CHK_DDONE_EN; + else + val |= MTK_RX_BT_32DWORDS; + mtk_w32(eth, val, reg_map->qdma.glo_cfg); +diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +index 8ffc1fbb036f9f..9c8376b2718916 100644 +--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c ++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +@@ -626,7 +626,7 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev) + /* mac_sl should be configured via phy-link interface */ + am65_cpsw_sl_ctl_reset(port); + +- ret = phylink_of_phy_connect(port->slave.phylink, port->slave.phy_node, 0); ++ ret = phylink_of_phy_connect(port->slave.phylink, port->slave.port_np, 0); + if (ret) + goto error_cleanup; + +@@ -2076,7 +2076,7 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) + of_property_read_bool(port_np, "ti,mac-only"); + + /* get phy/link info */ +- port->slave.phy_node = port_np; ++ port->slave.port_np = of_node_get(port_np); + ret = of_get_phy_mode(port_np, &port->slave.phy_if); + if (ret) { + dev_err(dev, "%pOF read phy-mode err %d\n", +@@ -2134,6 +2134,17 @@ static void am65_cpsw_nuss_phylink_cleanup(struct am65_cpsw_common *common) + } + } + ++static void am65_cpsw_remove_dt(struct am65_cpsw_common *common) ++{ ++ struct am65_cpsw_port *port; ++ int i; ++ ++ for (i = 0; i < common->port_num; i++) { ++ port = &common->ports[i]; ++ of_node_put(port->slave.port_np); ++ } ++} ++ + static int + am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx) + { +@@ -2217,7 +2228,7 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx) + } + + phylink = phylink_create(&port->slave.phylink_config, +- of_node_to_fwnode(port->slave.phy_node), ++ of_node_to_fwnode(port->slave.port_np), + port->slave.phy_if, + &am65_cpsw_phylink_mac_ops); + if (IS_ERR(phylink)) +@@ -3009,6 +3020,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) + err_free_phylink: + am65_cpsw_nuss_phylink_cleanup(common); + am65_cpts_release(common->cpts); ++ am65_cpsw_remove_dt(common); + err_of_clear: + if (common->mdio_dev) + of_platform_device_destroy(common->mdio_dev, NULL); +@@ -3040,6 +3052,7 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev) + am65_cpsw_nuss_phylink_cleanup(common); + am65_cpts_release(common->cpts); + am65_cpsw_disable_serdes_phy(common); ++ am65_cpsw_remove_dt(common); + + if (common->mdio_dev) + of_platform_device_destroy(common->mdio_dev, NULL); +diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h +index f3dad2ab9828be..f107198e25721c 100644 +--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h ++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h +@@ -29,7 +29,7 @@ struct am65_cpts; + struct am65_cpsw_slave_data { + bool mac_only; + struct cpsw_sl *mac_sl; +- struct device_node *phy_node; ++ struct device_node *port_np; + phy_interface_t phy_if; + struct phy *ifphy; + struct phy *serdes_phy; +diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.c b/drivers/net/ethernet/ti/icssg/icss_iep.c +index 3f9a030471fe2f..f3315c65151561 100644 +--- a/drivers/net/ethernet/ti/icssg/icss_iep.c ++++ b/drivers/net/ethernet/ti/icssg/icss_iep.c +@@ -476,66 +476,79 @@ static void icss_iep_update_to_next_boundary(struct icss_iep *iep, u64 start_ns) + static int icss_iep_perout_enable_hw(struct icss_iep *iep, + struct ptp_perout_request *req, int on) + { ++ struct timespec64 ts; ++ u64 ns_start; ++ u64 ns_width; + int ret; + u64 cmp; + ++ if (!on) { ++ /* Disable CMP 1 */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(1), 0); ++ ++ /* clear CMP regs */ ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0); ++ ++ /* Disable sync */ ++ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); ++ ++ return 0; ++ } ++ ++ /* Calculate width of the signal for PPS/PEROUT handling */ ++ ts.tv_sec = req->on.sec; ++ ts.tv_nsec = req->on.nsec; ++ ns_width = timespec64_to_ns(&ts); ++ ++ if (req->flags & PTP_PEROUT_PHASE) { ++ ts.tv_sec = req->phase.sec; ++ ts.tv_nsec = req->phase.nsec; ++ ns_start = timespec64_to_ns(&ts); ++ } else { ++ ns_start = 0; ++ } ++ + if (iep->ops && iep->ops->perout_enable) { + ret = iep->ops->perout_enable(iep->clockops_data, req, on, &cmp); + if (ret) + return ret; + +- if (on) { +- /* Configure CMP */ +- regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp)); +- if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) +- regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp)); +- /* Configure SYNC, 1ms pulse width */ +- regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, 1000000); +- regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); +- regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, 0); +- regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */ +- /* Enable CMP 1 */ +- regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, +- IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1)); +- } else { +- /* Disable CMP 1 */ +- regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, +- IEP_CMP_CFG_CMP_EN(1), 0); +- +- /* clear regs */ +- regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0); +- if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) +- regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0); +- } ++ /* Configure CMP */ ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp)); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp)); ++ /* Configure SYNC, based on req on width */ ++ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, ++ div_u64(ns_width, iep->def_inc)); ++ regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); ++ regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, ++ div_u64(ns_start, iep->def_inc)); ++ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */ ++ /* Enable CMP 1 */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1)); + } else { +- if (on) { +- u64 start_ns; +- +- iep->period = ((u64)req->period.sec * NSEC_PER_SEC) + +- req->period.nsec; +- start_ns = ((u64)req->period.sec * NSEC_PER_SEC) +- + req->period.nsec; +- icss_iep_update_to_next_boundary(iep, start_ns); +- +- /* Enable Sync in single shot mode */ +- regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, +- IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN); +- /* Enable CMP 1 */ +- regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, +- IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1)); +- } else { +- /* Disable CMP 1 */ +- regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, +- IEP_CMP_CFG_CMP_EN(1), 0); +- +- /* clear CMP regs */ +- regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0); +- if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) +- regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0); +- +- /* Disable sync */ +- regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); +- } ++ u64 start_ns; ++ ++ iep->period = ((u64)req->period.sec * NSEC_PER_SEC) + ++ req->period.nsec; ++ start_ns = ((u64)req->period.sec * NSEC_PER_SEC) ++ + req->period.nsec; ++ icss_iep_update_to_next_boundary(iep, start_ns); ++ ++ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, ++ div_u64(ns_width, iep->def_inc)); ++ regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, ++ div_u64(ns_start, iep->def_inc)); ++ /* Enable Sync in single shot mode */ ++ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, ++ IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN); ++ /* Enable CMP 1 */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1)); + } + + return 0; +@@ -544,7 +557,41 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep, + static int icss_iep_perout_enable(struct icss_iep *iep, + struct ptp_perout_request *req, int on) + { +- return -EOPNOTSUPP; ++ int ret = 0; ++ ++ if (!on) ++ goto disable; ++ ++ /* Reject requests with unsupported flags */ ++ if (req->flags & ~(PTP_PEROUT_DUTY_CYCLE | ++ PTP_PEROUT_PHASE)) ++ return -EOPNOTSUPP; ++ ++ /* Set default "on" time (1ms) for the signal if not passed by the app */ ++ if (!(req->flags & PTP_PEROUT_DUTY_CYCLE)) { ++ req->on.sec = 0; ++ req->on.nsec = NSEC_PER_MSEC; ++ } ++ ++disable: ++ mutex_lock(&iep->ptp_clk_mutex); ++ ++ if (iep->pps_enabled) { ++ ret = -EBUSY; ++ goto exit; ++ } ++ ++ if (iep->perout_enabled == !!on) ++ goto exit; ++ ++ ret = icss_iep_perout_enable_hw(iep, req, on); ++ if (!ret) ++ iep->perout_enabled = !!on; ++ ++exit: ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return ret; + } + + static int icss_iep_pps_enable(struct icss_iep *iep, int on) +@@ -568,10 +615,13 @@ static int icss_iep_pps_enable(struct icss_iep *iep, int on) + if (on) { + ns = icss_iep_gettime(iep, NULL); + ts = ns_to_timespec64(ns); ++ rq.perout.flags = 0; + rq.perout.period.sec = 1; + rq.perout.period.nsec = 0; + rq.perout.start.sec = ts.tv_sec + 2; + rq.perout.start.nsec = 0; ++ rq.perout.on.sec = 0; ++ rq.perout.on.nsec = NSEC_PER_MSEC; + ret = icss_iep_perout_enable_hw(iep, &rq.perout, on); + } else { + ret = icss_iep_perout_enable_hw(iep, &rq.perout, on); +diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c +index c37500aa063791..c019fe964eceaf 100644 +--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c ++++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c +@@ -311,7 +311,8 @@ static bool wx_alloc_mapped_page(struct wx_ring *rx_ring, + return true; + + page = page_pool_dev_alloc_pages(rx_ring->page_pool); +- WARN_ON(!page); ++ if (unlikely(!page)) ++ return false; + dma = page_pool_get_dma_addr(page); + + bi->page_dma = dma; +diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +index a4d63d2f3c5bbe..91f0f23c176a09 100644 +--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c ++++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +@@ -589,7 +589,7 @@ static int ngbe_probe(struct pci_dev *pdev, + /* setup the private structure */ + err = ngbe_sw_init(wx); + if (err) +- goto err_free_mac_table; ++ goto err_pci_release_regions; + + /* check if flash load is done after hw power up */ + err = wx_check_flash_load(wx, NGBE_SPI_ILDR_STATUS_PERST); +@@ -687,6 +687,7 @@ static int ngbe_probe(struct pci_dev *pdev, + err_clear_interrupt_scheme: + wx_clear_interrupt_scheme(wx); + err_free_mac_table: ++ kfree(wx->rss_key); + kfree(wx->mac_table); + err_pci_release_regions: + pci_release_selected_regions(pdev, +diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c +index e0e4a68cda3ead..dc62f141f40382 100644 +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -488,6 +488,8 @@ static const struct sfp_quirk sfp_quirks[] = { + + SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), + SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), ++ SFP_QUIRK_M("OEM", "SFP-2.5G-BX10-D", sfp_quirk_2500basex), ++ SFP_QUIRK_M("OEM", "SFP-2.5G-BX10-U", sfp_quirk_2500basex), + SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc), + SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc), + SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball), +diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c +index 52d05ce4a28198..02e1c5bd1892be 100644 +--- a/drivers/net/ppp/ppp_synctty.c ++++ b/drivers/net/ppp/ppp_synctty.c +@@ -506,6 +506,11 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb) + unsigned char *data; + int islcp; + ++ /* Ensure we can safely access protocol field and LCP code */ ++ if (!pskb_may_pull(skb, 3)) { ++ kfree_skb(skb); ++ return NULL; ++ } + data = skb->data; + proto = get_unaligned_be16(data); + +diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c +index f7cff58fe04493..ec4dcf89cbedd2 100644 +--- a/drivers/net/usb/asix_devices.c ++++ b/drivers/net/usb/asix_devices.c +@@ -1421,6 +1421,19 @@ static const struct driver_info hg20f9_info = { + .data = FLAG_EEPROM_MAC, + }; + ++static const struct driver_info lyconsys_fibergecko100_info = { ++ .description = "LyconSys FiberGecko 100 USB 2.0 to SFP Adapter", ++ .bind = ax88178_bind, ++ .status = asix_status, ++ .link_reset = ax88178_link_reset, ++ .reset = ax88178_link_reset, ++ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | ++ FLAG_MULTI_PACKET, ++ .rx_fixup = asix_rx_fixup_common, ++ .tx_fixup = asix_tx_fixup, ++ .data = 0x20061201, ++}; ++ + static const struct usb_device_id products [] = { + { + // Linksys USB200M +@@ -1578,6 +1591,10 @@ static const struct usb_device_id products [] = { + // Linux Automation GmbH USB 10Base-T1L + USB_DEVICE(0x33f7, 0x0004), + .driver_info = (unsigned long) &lxausb_t1l_info, ++}, { ++ /* LyconSys FiberGecko 100 */ ++ USB_DEVICE(0x1d2a, 0x0801), ++ .driver_info = (unsigned long) &lyconsys_fibergecko100_info, + }, + { }, // END + }; +diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c +index 6d61052353f078..a04f758b3ba071 100644 +--- a/drivers/net/usb/cdc_ether.c ++++ b/drivers/net/usb/cdc_ether.c +@@ -782,6 +782,13 @@ static const struct usb_device_id products[] = { + .driver_info = 0, + }, + ++/* Lenovo ThinkPad Hybrid USB-C with USB-A Dock (40af0135eu, based on Realtek RTL8153) */ ++{ ++ USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0xa359, USB_CLASS_COMM, ++ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), ++ .driver_info = 0, ++}, ++ + /* Aquantia AQtion USB to 5GbE Controller (based on AQC111U) */ + { + USB_DEVICE_AND_INTERFACE_INFO(AQUANTIA_VENDOR_ID, 0xc101, +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 3e5998555f9814..bbcefcc7ef8f06 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -784,6 +784,7 @@ enum rtl8152_flags { + #define DEVICE_ID_THINKPAD_USB_C_DONGLE 0x720c + #define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2 0xa387 + #define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN3 0x3062 ++#define DEVICE_ID_THINKPAD_HYBRID_USB_C_DOCK 0xa359 + + struct tally_counter { + __le64 tx_packets; +@@ -9734,6 +9735,7 @@ static bool rtl8152_supports_lenovo_macpassthru(struct usb_device *udev) + case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2: + case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN3: + case DEVICE_ID_THINKPAD_USB_C_DONGLE: ++ case DEVICE_ID_THINKPAD_HYBRID_USB_C_DOCK: + return 1; + } + } else if (vendor_id == VENDOR_ID_REALTEK && parent_vendor_id == VENDOR_ID_LENOVO) { +@@ -10011,6 +10013,8 @@ static const struct usb_device_id rtl8152_table[] = { + { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927) }, + { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0c5e) }, + { USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101) }, ++ ++ /* Lenovo */ + { USB_DEVICE(VENDOR_ID_LENOVO, 0x304f) }, + { USB_DEVICE(VENDOR_ID_LENOVO, 0x3054) }, + { USB_DEVICE(VENDOR_ID_LENOVO, 0x3062) }, +@@ -10021,7 +10025,9 @@ static const struct usb_device_id rtl8152_table[] = { + { USB_DEVICE(VENDOR_ID_LENOVO, 0x720c) }, + { USB_DEVICE(VENDOR_ID_LENOVO, 0x7214) }, + { USB_DEVICE(VENDOR_ID_LENOVO, 0x721e) }, ++ { USB_DEVICE(VENDOR_ID_LENOVO, 0xa359) }, + { USB_DEVICE(VENDOR_ID_LENOVO, 0xa387) }, ++ + { USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041) }, + { USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) }, + { USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) }, +diff --git a/drivers/net/usb/r8153_ecm.c b/drivers/net/usb/r8153_ecm.c +index 20b2df8d74ae1b..8d860dacdf49b2 100644 +--- a/drivers/net/usb/r8153_ecm.c ++++ b/drivers/net/usb/r8153_ecm.c +@@ -135,6 +135,12 @@ static const struct usb_device_id products[] = { + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&r8153_info, + }, ++/* Lenovo ThinkPad Hybrid USB-C with USB-A Dock (40af0135eu, based on Realtek RTL8153) */ ++{ ++ USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID_LENOVO, 0xa359, USB_CLASS_COMM, ++ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), ++ .driver_info = (unsigned long)&r8153_info, ++}, + + { }, /* END */ + }; +diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c +index f1e57e98bdc60d..35f22a4a16cf20 100644 +--- a/drivers/net/wireless/ath/ath12k/dp_mon.c ++++ b/drivers/net/wireless/ath/ath12k/dp_mon.c +@@ -2571,7 +2571,7 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, + dest_idx = 0; + move_next: + ath12k_dp_mon_buf_replenish(ab, buf_ring, 1); +- ath12k_hal_srng_src_get_next_entry(ab, srng); ++ ath12k_hal_srng_dst_get_next_entry(ab, srng); + num_buffs_reaped++; + } + +diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c +index 70ad035acac755..8d9315038a75e4 100644 +--- a/drivers/net/wireless/ath/ath12k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath12k/dp_rx.c +@@ -2484,6 +2484,29 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap + ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + } + ++static bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab, ++ struct hal_rx_desc *rx_desc, ++ struct sk_buff *msdu) ++{ ++ struct ieee80211_hdr *hdr; ++ u8 decap_type; ++ u32 hdr_len; ++ ++ decap_type = ath12k_dp_rx_h_decap_type(ab, rx_desc); ++ if (decap_type != DP_RX_DECAP_TYPE_NATIVE_WIFI) ++ return true; ++ ++ hdr = (struct ieee80211_hdr *)msdu->data; ++ hdr_len = ieee80211_hdrlen(hdr->frame_control); ++ ++ if ((likely(hdr_len <= DP_MAX_NWIFI_HDR_LEN))) ++ return true; ++ ++ ab->soc_stats.invalid_rbm++; ++ WARN_ON_ONCE(1); ++ return false; ++} ++ + static int ath12k_dp_rx_process_msdu(struct ath12k *ar, + struct sk_buff *msdu, + struct sk_buff_head *msdu_list, +@@ -2542,6 +2565,11 @@ static int ath12k_dp_rx_process_msdu(struct ath12k *ar, + } + } + ++ if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) { ++ ret = -EINVAL; ++ goto free_out; ++ } ++ + ath12k_dp_rx_h_ppdu(ar, rx_desc, rx_status); + ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status); + +@@ -2867,6 +2895,9 @@ static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer + RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED; + skb_pull(msdu, hal_rx_desc_sz); + ++ if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) ++ return -EINVAL; ++ + ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs); + ath12k_dp_rx_h_undecap(ar, msdu, rx_desc, + HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true); +@@ -3590,6 +3621,9 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu, + skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); + skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); + } ++ if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu))) ++ return -EINVAL; ++ + ath12k_dp_rx_h_ppdu(ar, desc, status); + + ath12k_dp_rx_h_mpdu(ar, msdu, desc, status); +@@ -3634,7 +3668,7 @@ static bool ath12k_dp_rx_h_reo_err(struct ath12k *ar, struct sk_buff *msdu, + return drop; + } + +-static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, ++static bool ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, + struct ieee80211_rx_status *status) + { + struct ath12k_base *ab = ar->ab; +@@ -3652,6 +3686,9 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, + skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); + skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); + ++ if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu))) ++ return true; ++ + ath12k_dp_rx_h_ppdu(ar, desc, status); + + status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR | +@@ -3659,6 +3696,7 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, + + ath12k_dp_rx_h_undecap(ar, msdu, desc, + HAL_ENCRYPT_TYPE_TKIP_MIC, status, false); ++ return false; + } + + static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu, +@@ -3677,7 +3715,7 @@ static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu, + case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR: + err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc); + if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) { +- ath12k_dp_rx_h_tkip_mic_err(ar, msdu, status); ++ drop = ath12k_dp_rx_h_tkip_mic_err(ar, msdu, status); + break; + } + fallthrough; +diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c +index 447b51cff8f96d..c1a92c7f0f8e88 100644 +--- a/drivers/net/wireless/atmel/at76c50x-usb.c ++++ b/drivers/net/wireless/atmel/at76c50x-usb.c +@@ -2554,7 +2554,7 @@ static void at76_disconnect(struct usb_interface *interface) + + wiphy_info(priv->hw->wiphy, "disconnecting\n"); + at76_delete_device(priv); +- usb_put_dev(priv->udev); ++ usb_put_dev(interface_to_usbdev(interface)); + dev_info(&interface->dev, "disconnected\n"); + } + +diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c +index 1de3c734e136a4..49e6c866a57fc2 100644 +--- a/drivers/net/wireless/mediatek/mt76/eeprom.c ++++ b/drivers/net/wireless/mediatek/mt76/eeprom.c +@@ -95,6 +95,10 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs + + #ifdef CONFIG_NL80211_TESTMODE + dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL); ++ if (!dev->test_mtd.name) { ++ ret = -ENOMEM; ++ goto out_put_node; ++ } + dev->test_mtd.offset = offset; + #endif + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +index 55068f3252ef34..d8043099921966 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +@@ -21,6 +21,7 @@ static const struct usb_device_id mt76x2u_device_table[] = { + { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ + { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ + { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ ++ { USB_DEVICE(0x2357, 0x0137) }, /* TP-Link TL-WDN6200 */ + { }, + }; + +diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c +index 535393eca5641c..d1d8fd812cbf6d 100644 +--- a/drivers/net/wireless/realtek/rtw89/core.c ++++ b/drivers/net/wireless/realtek/rtw89/core.c +@@ -3807,6 +3807,8 @@ static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev) + rtw89_core_setup_phycap(rtwdev); + rtw89_core_setup_rfe_parms(rtwdev); + ++ rtw89_hci_mac_pre_deinit(rtwdev); ++ + rtw89_mac_pwr_off(rtwdev); + + return 0; +diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h +index ee6ae2a0c79815..16aad0f8393ab7 100644 +--- a/drivers/net/wireless/realtek/rtw89/core.h ++++ b/drivers/net/wireless/realtek/rtw89/core.h +@@ -2989,6 +2989,7 @@ struct rtw89_hci_ops { + void (*write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data); + + int (*mac_pre_init)(struct rtw89_dev *rtwdev); ++ int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); + int (*mac_post_init)(struct rtw89_dev *rtwdev); + int (*deinit)(struct rtw89_dev *rtwdev); + +@@ -4515,6 +4516,11 @@ static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) + return rtwdev->hci.ops->tx_kick_off(rtwdev, txch); + } + ++static inline int rtw89_hci_mac_pre_deinit(struct rtw89_dev *rtwdev) ++{ ++ return rtwdev->hci.ops->mac_pre_deinit(rtwdev); ++} ++ + static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues, + bool drop) + { +diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c +index 98af64444d3ebc..30cc6e03c355e8 100644 +--- a/drivers/net/wireless/realtek/rtw89/pci.c ++++ b/drivers/net/wireless/realtek/rtw89/pci.c +@@ -2482,6 +2482,8 @@ static int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev) + { + const struct rtw89_pci_info *info = rtwdev->pci_info; + ++ rtw89_pci_power_wake(rtwdev, false); ++ + if (rtwdev->chip->chip_id == RTL8852A) { + /* ltr sw trigger */ + rtw89_write32_set(rtwdev, R_AX_LTR_CTRL_0, B_AX_APP_LTR_IDLE); +@@ -2568,6 +2570,13 @@ static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) + return 0; + } + ++static int rtw89_pci_ops_mac_pre_deinit(struct rtw89_dev *rtwdev) ++{ ++ rtw89_pci_power_wake(rtwdev, false); ++ ++ return 0; ++} ++ + int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en) + { + u32 val; +@@ -3812,6 +3821,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { + .write32 = rtw89_pci_ops_write32, + + .mac_pre_init = rtw89_pci_ops_mac_pre_init, ++ .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit, + .mac_post_init = rtw89_pci_ops_mac_post_init, + .deinit = rtw89_pci_ops_deinit, + +diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c +index e9dc3c72bb110c..06dc74cc6cb528 100644 +--- a/drivers/net/wireless/ti/wl1251/tx.c ++++ b/drivers/net/wireless/ti/wl1251/tx.c +@@ -342,8 +342,10 @@ void wl1251_tx_work(struct work_struct *work) + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + ret = wl1251_ps_elp_wakeup(wl); +- if (ret < 0) ++ if (ret < 0) { ++ skb_queue_head(&wl->tx_queue, skb); + goto out; ++ } + woken_up = true; + } + +diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c +index c84fadfc63c52c..76cc5b49a5f1ee 100644 +--- a/drivers/ntb/ntb_transport.c ++++ b/drivers/ntb/ntb_transport.c +@@ -1351,7 +1351,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) + qp_count = ilog2(qp_bitmap); + if (nt->use_msi) { + qp_count -= 1; +- nt->msi_db_mask = 1 << qp_count; ++ nt->msi_db_mask = BIT_ULL(qp_count); + ntb_db_clear_mask(ndev, nt->msi_db_mask); + } + +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index c04317a966b387..055b95d2ce9357 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -1083,13 +1083,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new) + nvme_rdma_free_io_queues(ctrl); + } + destroy_admin: +- nvme_quiesce_admin_queue(&ctrl->ctrl); +- blk_sync_queue(ctrl->ctrl.admin_q); +- nvme_rdma_stop_queue(&ctrl->queues[0]); +- nvme_cancel_admin_tagset(&ctrl->ctrl); +- if (new) +- nvme_remove_admin_tag_set(&ctrl->ctrl); +- nvme_rdma_destroy_admin_queue(ctrl); ++ nvme_rdma_teardown_admin_queue(ctrl, new); + return ret; + } + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 8a02ed63b15666..d40d5a4ea932e0 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -173,20 +173,6 @@ struct nvmet_fc_tgt_assoc { + struct rcu_head rcu; + }; + +- +-static inline int +-nvmet_fc_iodnum(struct nvmet_fc_ls_iod *iodptr) +-{ +- return (iodptr - iodptr->tgtport->iod); +-} +- +-static inline int +-nvmet_fc_fodnum(struct nvmet_fc_fcp_iod *fodptr) +-{ +- return (fodptr - fodptr->queue->fod); +-} +- +- + /* + * Association and Connection IDs: + * +diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c +index e6d4226827b527..4b35bdcac185ff 100644 +--- a/drivers/nvme/target/fcloop.c ++++ b/drivers/nvme/target/fcloop.c +@@ -478,7 +478,7 @@ fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport, + if (targetport) { + tport = targetport->private; + spin_lock(&tport->lock); +- list_add_tail(&tport->ls_list, &tls_req->ls_list); ++ list_add_tail(&tls_req->ls_list, &tport->ls_list); + spin_unlock(&tport->lock); + queue_work(nvmet_wq, &tport->ls_work); + } +diff --git a/drivers/of/irq.c b/drivers/of/irq.c +index e54f003c1aaa91..1ec2a198c6692a 100644 +--- a/drivers/of/irq.c ++++ b/drivers/of/irq.c +@@ -16,6 +16,7 @@ + + #define pr_fmt(fmt) "OF: " fmt + ++#include + #include + #include + #include +@@ -38,11 +39,15 @@ + unsigned int irq_of_parse_and_map(struct device_node *dev, int index) + { + struct of_phandle_args oirq; ++ unsigned int ret; + + if (of_irq_parse_one(dev, index, &oirq)) + return 0; + +- return irq_create_of_mapping(&oirq); ++ ret = irq_create_of_mapping(&oirq); ++ of_node_put(oirq.np); ++ ++ return ret; + } + EXPORT_SYMBOL_GPL(irq_of_parse_and_map); + +@@ -165,6 +170,8 @@ const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len, struct of_ph + * the specifier for each map, and then returns the translated map. + * + * Return: 0 on success and a negative number on error ++ * ++ * Note: refcount of node @out_irq->np is increased by 1 on success. + */ + int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) + { +@@ -310,6 +317,12 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) + addrsize = (imap - match_array) - intsize; + + if (ipar == newpar) { ++ /* ++ * We got @ipar's refcount, but the refcount was ++ * gotten again by of_irq_parse_imap_parent() via its ++ * alias @newpar. ++ */ ++ of_node_put(ipar); + pr_debug("%pOF interrupt-map entry to self\n", ipar); + return 0; + } +@@ -339,10 +352,12 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw); + * This function resolves an interrupt for a node by walking the interrupt tree, + * finding which interrupt controller node it is attached to, and returning the + * interrupt specifier that can be used to retrieve a Linux IRQ number. ++ * ++ * Note: refcount of node @out_irq->np is increased by 1 on success. + */ + int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) + { +- struct device_node *p; ++ struct device_node __free(device_node) *p = NULL; + const __be32 *addr; + u32 intsize; + int i, res, addr_len; +@@ -367,41 +382,33 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar + /* Try the new-style interrupts-extended first */ + res = of_parse_phandle_with_args(device, "interrupts-extended", + "#interrupt-cells", index, out_irq); +- if (!res) +- return of_irq_parse_raw(addr_buf, out_irq); +- +- /* Look for the interrupt parent. */ +- p = of_irq_find_parent(device); +- if (p == NULL) +- return -EINVAL; ++ if (!res) { ++ p = out_irq->np; ++ } else { ++ /* Look for the interrupt parent. */ ++ p = of_irq_find_parent(device); ++ /* Get size of interrupt specifier */ ++ if (!p || of_property_read_u32(p, "#interrupt-cells", &intsize)) ++ return -EINVAL; ++ ++ pr_debug(" parent=%pOF, intsize=%d\n", p, intsize); ++ ++ /* Copy intspec into irq structure */ ++ out_irq->np = p; ++ out_irq->args_count = intsize; ++ for (i = 0; i < intsize; i++) { ++ res = of_property_read_u32_index(device, "interrupts", ++ (index * intsize) + i, ++ out_irq->args + i); ++ if (res) ++ return res; ++ } + +- /* Get size of interrupt specifier */ +- if (of_property_read_u32(p, "#interrupt-cells", &intsize)) { +- res = -EINVAL; +- goto out; ++ pr_debug(" intspec=%d\n", *out_irq->args); + } + +- pr_debug(" parent=%pOF, intsize=%d\n", p, intsize); +- +- /* Copy intspec into irq structure */ +- out_irq->np = p; +- out_irq->args_count = intsize; +- for (i = 0; i < intsize; i++) { +- res = of_property_read_u32_index(device, "interrupts", +- (index * intsize) + i, +- out_irq->args + i); +- if (res) +- goto out; +- } +- +- pr_debug(" intspec=%d\n", *out_irq->args); +- +- + /* Check if there are any interrupt-map translations to process */ +- res = of_irq_parse_raw(addr_buf, out_irq); +- out: +- of_node_put(p); +- return res; ++ return of_irq_parse_raw(addr_buf, out_irq); + } + EXPORT_SYMBOL_GPL(of_irq_parse_one); + +@@ -506,8 +513,10 @@ int of_irq_count(struct device_node *dev) + struct of_phandle_args irq; + int nr = 0; + +- while (of_irq_parse_one(dev, nr, &irq) == 0) ++ while (of_irq_parse_one(dev, nr, &irq) == 0) { ++ of_node_put(irq.np); + nr++; ++ } + + return nr; + } +@@ -624,6 +633,8 @@ void __init of_irq_init(const struct of_device_id *matches) + __func__, desc->dev, desc->dev, + desc->interrupt_parent); + of_node_clear_flag(desc->dev, OF_POPULATED); ++ of_node_put(desc->interrupt_parent); ++ of_node_put(desc->dev); + kfree(desc); + continue; + } +@@ -654,6 +665,7 @@ void __init of_irq_init(const struct of_device_id *matches) + err: + list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { + list_del(&desc->list); ++ of_node_put(desc->interrupt_parent); + of_node_put(desc->dev); + kfree(desc); + } +diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c +index 44d385f5c27cd4..940af934ce1bb8 100644 +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -1501,7 +1501,7 @@ static struct pci_ops brcm7425_pcie_ops = { + + static int brcm_pcie_probe(struct platform_device *pdev) + { +- struct device_node *np = pdev->dev.of_node, *msi_np; ++ struct device_node *np = pdev->dev.of_node; + struct pci_host_bridge *bridge; + const struct pcie_cfg_data *data; + struct brcm_pcie *pcie; +@@ -1576,9 +1576,14 @@ static int brcm_pcie_probe(struct platform_device *pdev) + goto fail; + } + +- msi_np = of_parse_phandle(pcie->np, "msi-parent", 0); +- if (pci_msi_enabled() && msi_np == pcie->np) { +- ret = brcm_pcie_enable_msi(pcie); ++ if (pci_msi_enabled()) { ++ struct device_node *msi_np = of_parse_phandle(pcie->np, "msi-parent", 0); ++ ++ if (msi_np == pcie->np) ++ ret = brcm_pcie_enable_msi(pcie); ++ ++ of_node_put(msi_np); ++ + if (ret) { + dev_err(pcie->dev, "probe of internal MSI failed"); + goto fail; +diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c +index 5ff2066aa51643..dfa222e02c4da9 100644 +--- a/drivers/pci/controller/vmd.c ++++ b/drivers/pci/controller/vmd.c +@@ -125,7 +125,7 @@ struct vmd_irq_list { + struct vmd_dev { + struct pci_dev *dev; + +- spinlock_t cfg_lock; ++ raw_spinlock_t cfg_lock; + void __iomem *cfgbar; + + int msix_count; +@@ -402,7 +402,7 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg, + if (!addr) + return -EFAULT; + +- spin_lock_irqsave(&vmd->cfg_lock, flags); ++ raw_spin_lock_irqsave(&vmd->cfg_lock, flags); + switch (len) { + case 1: + *value = readb(addr); +@@ -417,7 +417,7 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg, + ret = -EINVAL; + break; + } +- spin_unlock_irqrestore(&vmd->cfg_lock, flags); ++ raw_spin_unlock_irqrestore(&vmd->cfg_lock, flags); + return ret; + } + +@@ -437,7 +437,7 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg, + if (!addr) + return -EFAULT; + +- spin_lock_irqsave(&vmd->cfg_lock, flags); ++ raw_spin_lock_irqsave(&vmd->cfg_lock, flags); + switch (len) { + case 1: + writeb(value, addr); +@@ -455,7 +455,7 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg, + ret = -EINVAL; + break; + } +- spin_unlock_irqrestore(&vmd->cfg_lock, flags); ++ raw_spin_unlock_irqrestore(&vmd->cfg_lock, flags); + return ret; + } + +@@ -1020,7 +1020,7 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) + if (features & VMD_FEAT_OFFSET_FIRST_VECTOR) + vmd->first_vec = 1; + +- spin_lock_init(&vmd->cfg_lock); ++ raw_spin_lock_init(&vmd->cfg_lock); + pci_set_drvdata(dev, vmd); + err = vmd_enable_domain(vmd, features); + if (err) +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index bcce569a833956..095fa1910d36db 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -5714,8 +5714,6 @@ static bool pci_bus_resettable(struct pci_bus *bus) + return false; + + list_for_each_entry(dev, &bus->devices, bus_list) { +- if (!pci_reset_supported(dev)) +- return false; + if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || + (dev->subordinate && !pci_bus_resettable(dev->subordinate))) + return false; +@@ -5792,8 +5790,6 @@ static bool pci_slot_resettable(struct pci_slot *slot) + list_for_each_entry(dev, &slot->bus->devices, bus_list) { + if (!dev->slot || dev->slot != slot) + continue; +- if (!pci_reset_supported(dev)) +- return false; + if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || + (dev->subordinate && !pci_bus_resettable(dev->subordinate))) + return false; +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index bcd1ba829e1fc1..8e5d818c29a983 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -1145,7 +1145,10 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, + add_dev: + pci_set_bus_msi_domain(child); + ret = device_register(&child->dev); +- WARN_ON(ret < 0); ++ if (WARN_ON(ret < 0)) { ++ put_device(&child->dev); ++ return NULL; ++ } + + pcibios_add_bus(child); + +diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c +index d712a19e47ac15..b3bb4d62f13dcc 100644 +--- a/drivers/perf/arm_pmu.c ++++ b/drivers/perf/arm_pmu.c +@@ -342,12 +342,10 @@ armpmu_add(struct perf_event *event, int flags) + if (idx < 0) + return idx; + +- /* +- * If there is an event in the counter we are going to use then make +- * sure it is disabled. +- */ ++ /* The newly-allocated counter should be empty */ ++ WARN_ON_ONCE(hw_events->events[idx]); ++ + event->hw.idx = idx; +- armpmu->disable(event); + hw_events->events[idx] = event; + + hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; +diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +index e98361dcdeadfe..afd52392cd5301 100644 +--- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c ++++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +@@ -162,6 +162,16 @@ static int imx8_pcie_phy_power_on(struct phy *phy) + return ret; + } + ++static int imx8_pcie_phy_power_off(struct phy *phy) ++{ ++ struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy); ++ ++ reset_control_assert(imx8_phy->reset); ++ reset_control_assert(imx8_phy->perst); ++ ++ return 0; ++} ++ + static int imx8_pcie_phy_init(struct phy *phy) + { + struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy); +@@ -182,6 +192,7 @@ static const struct phy_ops imx8_pcie_phy_ops = { + .init = imx8_pcie_phy_init, + .exit = imx8_pcie_phy_exit, + .power_on = imx8_pcie_phy_power_on, ++ .power_off = imx8_pcie_phy_power_off, + .owner = THIS_MODULE, + }; + +diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c +index 115b83e2d8e65a..b252fc22f64e6b 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -1040,8 +1040,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) + const struct msm_pingroup *g; + u32 intr_target_mask = GENMASK(2, 0); + unsigned long flags; +- bool was_enabled; +- u32 val; ++ u32 val, oldval; + + if (msm_gpio_needs_dual_edge_parent_workaround(d, type)) { + set_bit(d->hwirq, pctrl->dual_edge_irqs); +@@ -1103,8 +1102,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) + * internal circuitry of TLMM, toggling the RAW_STATUS + * could cause the INTR_STATUS to be set for EDGE interrupts. + */ +- val = msm_readl_intr_cfg(pctrl, g); +- was_enabled = val & BIT(g->intr_raw_status_bit); ++ val = oldval = msm_readl_intr_cfg(pctrl, g); + val |= BIT(g->intr_raw_status_bit); + if (g->intr_detection_width == 2) { + val &= ~(3 << g->intr_detection_bit); +@@ -1157,9 +1155,11 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) + /* + * The first time we set RAW_STATUS_EN it could trigger an interrupt. + * Clear the interrupt. This is safe because we have +- * IRQCHIP_SET_TYPE_MASKED. ++ * IRQCHIP_SET_TYPE_MASKED. When changing the interrupt type, we could ++ * also still have a non-matching interrupt latched, so clear whenever ++ * making changes to the interrupt configuration. + */ +- if (!was_enabled) ++ if (val != oldval) + msm_ack_intr_status(pctrl, g); + + if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) +diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c +index 761029f39314a6..c2234657051024 100644 +--- a/drivers/platform/x86/asus-laptop.c ++++ b/drivers/platform/x86/asus-laptop.c +@@ -427,11 +427,14 @@ static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable) + + static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method) + { ++ unsigned long long val = (unsigned long long)curr; ++ acpi_status status; + int i, delta; +- unsigned long long val; +- for (i = 0; i < PEGA_ACC_RETRIES; i++) { +- acpi_evaluate_integer(asus->handle, method, NULL, &val); + ++ for (i = 0; i < PEGA_ACC_RETRIES; i++) { ++ status = acpi_evaluate_integer(asus->handle, method, NULL, &val); ++ if (ACPI_FAILURE(status)) ++ continue; + /* The output is noisy. From reading the ASL + * dissassembly, timeout errors are returned with 1's + * in the high word, and the lack of locking around +diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c +index 13343c31987706..4899fdf9bdf7a2 100644 +--- a/drivers/ptp/ptp_ocp.c ++++ b/drivers/ptp/ptp_ocp.c +@@ -1842,6 +1842,7 @@ ptp_ocp_signal_set(struct ptp_ocp *bp, int gen, struct ptp_ocp_signal *s) + if (!s->start) { + /* roundup() does not work on 32-bit systems */ + s->start = DIV64_U64_ROUND_UP(start_ns, s->period); ++ s->start *= s->period; + s->start = ktime_add(s->start, s->phase); + } + +diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c +index b7c6045c5d0898..2c60d67e9a4a4a 100644 +--- a/drivers/pwm/pwm-fsl-ftm.c ++++ b/drivers/pwm/pwm-fsl-ftm.c +@@ -119,6 +119,9 @@ static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip *fpc, + unsigned long long exval; + + rate = clk_get_rate(fpc->clk[fpc->period.clk_select]); ++ if (rate >> fpc->period.clk_ps == 0) ++ return 0; ++ + exval = ticks; + exval *= 1000000000UL; + do_div(exval, rate >> fpc->period.clk_ps); +@@ -191,6 +194,9 @@ static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc, + unsigned int period = fpc->period.mod_period + 1; + unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period); + ++ if (!period_ns) ++ return 0; ++ + duty = (unsigned long long)duty_ns * period; + do_div(duty, period_ns); + +diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c +index 6adb0ed019066a..6b1a75b6bd12fb 100644 +--- a/drivers/pwm/pwm-mediatek.c ++++ b/drivers/pwm/pwm-mediatek.c +@@ -124,21 +124,25 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); + u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH, + reg_thres = PWMTHRES; ++ unsigned long clk_rate; + u64 resolution; + int ret; + + ret = pwm_mediatek_clk_enable(chip, pwm); +- + if (ret < 0) + return ret; + ++ clk_rate = clk_get_rate(pc->clk_pwms[pwm->hwpwm]); ++ if (!clk_rate) ++ return -EINVAL; ++ + /* Make sure we use the bus clock and not the 26MHz clock */ + if (pc->soc->has_ck_26m_sel) + writel(0, pc->regs + PWM_CK_26M_SEL); + + /* Using resolution in picosecond gets accuracy higher */ + resolution = (u64)NSEC_PER_SEC * 1000; +- do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm])); ++ do_div(resolution, clk_rate); + + cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution); + while (cnt_period > 8191) { +diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c +index 5b5f357c44de61..18fa2d40d93650 100644 +--- a/drivers/pwm/pwm-rcar.c ++++ b/drivers/pwm/pwm-rcar.c +@@ -8,6 +8,7 @@ + * - The hardware cannot generate a 0% duty cycle. + */ + ++#include + #include + #include + #include +@@ -103,23 +104,24 @@ static void rcar_pwm_set_clock_control(struct rcar_pwm_chip *rp, + rcar_pwm_write(rp, value, RCAR_PWMCR); + } + +-static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns, +- int period_ns) ++static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, u64 duty_ns, ++ u64 period_ns) + { +- unsigned long long one_cycle, tmp; /* 0.01 nanoseconds */ ++ unsigned long long tmp; + unsigned long clk_rate = clk_get_rate(rp->clk); + u32 cyc, ph; + +- one_cycle = NSEC_PER_SEC * 100ULL << div; +- do_div(one_cycle, clk_rate); ++ /* div <= 24 == RCAR_PWM_MAX_DIVISION, so the shift doesn't overflow. */ ++ tmp = mul_u64_u64_div_u64(period_ns, clk_rate, (u64)NSEC_PER_SEC << div); ++ if (tmp > FIELD_MAX(RCAR_PWMCNT_CYC0_MASK)) ++ tmp = FIELD_MAX(RCAR_PWMCNT_CYC0_MASK); + +- tmp = period_ns * 100ULL; +- do_div(tmp, one_cycle); +- cyc = (tmp << RCAR_PWMCNT_CYC0_SHIFT) & RCAR_PWMCNT_CYC0_MASK; ++ cyc = FIELD_PREP(RCAR_PWMCNT_CYC0_MASK, tmp); + +- tmp = duty_ns * 100ULL; +- do_div(tmp, one_cycle); +- ph = tmp & RCAR_PWMCNT_PH0_MASK; ++ tmp = mul_u64_u64_div_u64(duty_ns, clk_rate, (u64)NSEC_PER_SEC << div); ++ if (tmp > FIELD_MAX(RCAR_PWMCNT_PH0_MASK)) ++ tmp = FIELD_MAX(RCAR_PWMCNT_PH0_MASK); ++ ph = FIELD_PREP(RCAR_PWMCNT_PH0_MASK, tmp); + + /* Avoid prohibited setting */ + if (cyc == 0 || ph == 0) +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +index 73b378837da7bd..e6bcc3171391ce 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +@@ -2501,6 +2501,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + struct sas_ata_task *ata_task = &task->ata_task; + struct sas_tmf_task *tmf = slot->tmf; ++ int phy_id; + u8 *buf_cmd; + int has_data = 0, hdr_tag = 0; + u32 dw0, dw1 = 0, dw2 = 0; +@@ -2508,10 +2509,14 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, + /* create header */ + /* dw0 */ + dw0 = port->id << CMD_HDR_PORT_OFF; +- if (parent_dev && dev_is_expander(parent_dev->dev_type)) ++ if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + dw0 |= 3 << CMD_HDR_CMD_OFF; +- else ++ } else { ++ phy_id = device->phy->identify.phy_identifier; ++ dw0 |= (1U << phy_id) << CMD_HDR_PHY_ID_OFF; ++ dw0 |= CMD_HDR_FORCE_PHY_MSK; + dw0 |= 4 << CMD_HDR_CMD_OFF; ++ } + + if (tmf && ata_task->force_phy) { + dw0 |= CMD_HDR_FORCE_PHY_MSK; +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +index ff5f86867dbf06..596b5426d99535 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +@@ -358,6 +358,10 @@ + #define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF) + #define CMD_HDR_TLR_CTRL_OFF 6 + #define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF) ++#define CMD_HDR_PHY_ID_OFF 8 ++#define CMD_HDR_PHY_ID_MSK (0x1ff << CMD_HDR_PHY_ID_OFF) ++#define CMD_HDR_FORCE_PHY_OFF 17 ++#define CMD_HDR_FORCE_PHY_MSK (0x1U << CMD_HDR_FORCE_PHY_OFF) + #define CMD_HDR_PORT_OFF 18 + #define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF) + #define CMD_HDR_PRIORITY_OFF 27 +@@ -1425,15 +1429,21 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); ++ int phy_id; + u8 *buf_cmd; + int has_data = 0, hdr_tag = 0; + u32 dw1 = 0, dw2 = 0; + + hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); +- if (parent_dev && dev_is_expander(parent_dev->dev_type)) ++ if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); +- else ++ } else { ++ phy_id = device->phy->identify.phy_identifier; ++ hdr->dw0 |= cpu_to_le32((1U << phy_id) ++ << CMD_HDR_PHY_ID_OFF); ++ hdr->dw0 |= CMD_HDR_FORCE_PHY_MSK; + hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF); ++ } + + switch (task->data_dir) { + case DMA_TO_DEVICE: +diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c +index 4cc93cb79b8b0a..dd3630b09aa241 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_base.c ++++ b/drivers/scsi/megaraid/megaraid_sas_base.c +@@ -2101,6 +2101,9 @@ static int megasas_slave_configure(struct scsi_device *sdev) + /* This sdev property may change post OCR */ + megasas_set_dynamic_target_properties(sdev, is_target_prop); + ++ if (!MEGASAS_IS_LOGICAL(sdev)) ++ sdev->no_vpd_size = 1; ++ + mutex_unlock(&instance->reset_mutex); + + return 0; +@@ -3660,8 +3663,10 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, + + case MFI_STAT_SCSI_IO_FAILED: + case MFI_STAT_LD_INIT_IN_PROGRESS: +- cmd->scmd->result = +- (DID_ERROR << 16) | hdr->scsi_status; ++ if (hdr->scsi_status == 0xf0) ++ cmd->scmd->result = (DID_ERROR << 16) | SAM_STAT_CHECK_CONDITION; ++ else ++ cmd->scmd->result = (DID_ERROR << 16) | hdr->scsi_status; + break; + + case MFI_STAT_SCSI_DONE_WITH_ERROR: +diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c +index 8a83f3fc2b865e..5ebcb582cf0c7f 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c ++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c +@@ -2043,7 +2043,10 @@ map_cmd_status(struct fusion_context *fusion, + + case MFI_STAT_SCSI_IO_FAILED: + case MFI_STAT_LD_INIT_IN_PROGRESS: +- scmd->result = (DID_ERROR << 16) | ext_status; ++ if (ext_status == 0xf0) ++ scmd->result = (DID_ERROR << 16) | SAM_STAT_CHECK_CONDITION; ++ else ++ scmd->result = (DID_ERROR << 16) | ext_status; + break; + + case MFI_STAT_SCSI_DONE_WITH_ERROR: +diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c +index deeb657981a690..0c30fec555475b 100644 +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -3208,11 +3208,14 @@ iscsi_set_host_param(struct iscsi_transport *transport, + } + + /* see similar check in iscsi_if_set_param() */ +- if (strlen(data) > ev->u.set_host_param.len) +- return -EINVAL; ++ if (strlen(data) > ev->u.set_host_param.len) { ++ err = -EINVAL; ++ goto out; ++ } + + err = transport->set_host_param(shost, ev->u.set_host_param.param, + data, ev->u.set_host_param.len); ++out: + scsi_host_put(shost); + return err; + } +diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c +index bdbe94f30f0706..900322bad4f3be 100644 +--- a/drivers/scsi/st.c ++++ b/drivers/scsi/st.c +@@ -4120,7 +4120,7 @@ static void validate_options(void) + */ + static int __init st_setup(char *str) + { +- int i, len, ints[5]; ++ int i, len, ints[ARRAY_SIZE(parms) + 1]; + char *stp; + + stp = get_options(str, ARRAY_SIZE(ints), ints); +diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c +index 7ba45c4aff971c..1307f6d61c986e 100644 +--- a/drivers/soc/samsung/exynos-chipid.c ++++ b/drivers/soc/samsung/exynos-chipid.c +@@ -130,6 +130,8 @@ static int exynos_chipid_probe(struct platform_device *pdev) + + soc_dev_attr->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%x", soc_info.revision); ++ if (!soc_dev_attr->revision) ++ return -ENOMEM; + soc_dev_attr->soc_id = product_id_to_soc_id(soc_info.product_id); + if (!soc_dev_attr->soc_id) { + pr_err("Unknown SoC\n"); +diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c +index 08811577d8f8b2..bf9b816637d02e 100644 +--- a/drivers/spi/spi-cadence-quadspi.c ++++ b/drivers/spi/spi-cadence-quadspi.c +@@ -1576,6 +1576,12 @@ static int cqspi_request_mmap_dma(struct cqspi_st *cqspi) + int ret = PTR_ERR(cqspi->rx_chan); + + cqspi->rx_chan = NULL; ++ if (ret == -ENODEV) { ++ /* DMA support is not mandatory */ ++ dev_info(&cqspi->pdev->dev, "No Rx DMA available\n"); ++ return 0; ++ } ++ + return dev_err_probe(&cqspi->pdev->dev, ret, "No Rx DMA available\n"); + } + init_completion(&cqspi->rx_dma_complete); +diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c +index 50290abc07bc23..f110f932ba0543 100644 +--- a/drivers/target/target_core_spc.c ++++ b/drivers/target/target_core_spc.c +@@ -2243,7 +2243,7 @@ spc_emulate_report_supp_op_codes(struct se_cmd *cmd) + response_length += spc_rsoc_encode_command_descriptor( + &buf[response_length], rctd, descr); + } +- put_unaligned_be32(response_length - 3, buf); ++ put_unaligned_be32(response_length - 4, buf); + } else { + response_length = spc_rsoc_encode_one_command_descriptor( + &buf[response_length], rctd, descr, +diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c +index 77231a9d28ff10..d306ca9a9902da 100644 +--- a/drivers/thermal/rockchip_thermal.c ++++ b/drivers/thermal/rockchip_thermal.c +@@ -386,6 +386,7 @@ static const struct tsadc_table rk3328_code_table[] = { + {296, -40000}, + {304, -35000}, + {313, -30000}, ++ {322, -25000}, + {331, -20000}, + {340, -15000}, + {349, -10000}, +diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c +index 268189f01e15bc..d138b66d5e350b 100644 +--- a/drivers/ufs/host/ufs-exynos.c ++++ b/drivers/ufs/host/ufs-exynos.c +@@ -901,6 +901,12 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs) + } + + phy_set_bus_width(generic_phy, ufs->avail_ln_rx); ++ ++ if (generic_phy->power_count) { ++ phy_power_off(generic_phy); ++ phy_exit(generic_phy); ++ } ++ + ret = phy_init(generic_phy); + if (ret) { + dev_err(hba->dev, "%s: phy init failed, ret = %d\n", +diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c +index 7c7f388aac96b3..35f4c4482fca33 100644 +--- a/drivers/usb/typec/ucsi/ucsi_ccg.c ++++ b/drivers/usb/typec/ucsi/ucsi_ccg.c +@@ -585,6 +585,10 @@ static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, + uc->has_multiple_dp) { + con_index = (uc->last_cmd_sent >> 16) & + UCSI_CMD_CONNECTOR_MASK; ++ if (con_index == 0) { ++ ret = -EINVAL; ++ goto err_put; ++ } + con = &uc->ucsi->connector[con_index - 1]; + ucsi_ccg_update_set_new_cam_cmd(uc, con, (u64 *)val); + } +@@ -599,6 +603,7 @@ static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, + + err_clear_bit: + clear_bit(DEV_CMD_PENDING, &uc->flags); ++err_put: + pm_runtime_put_sync(uc->dev); + mutex_unlock(&uc->lock); + +diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c +index aa4ab4c847fdcc..16573065693452 100644 +--- a/drivers/vdpa/mlx5/core/mr.c ++++ b/drivers/vdpa/mlx5/core/mr.c +@@ -166,9 +166,12 @@ static void fill_indir(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mkey, v + klm->bcount = cpu_to_be32(klm_bcount(dmr->end - dmr->start)); + preve = dmr->end; + } else { ++ u64 bcount = min_t(u64, dmr->start - preve, MAX_KLM_SIZE); ++ + klm->key = cpu_to_be32(mvdev->res.null_mkey); +- klm->bcount = cpu_to_be32(klm_bcount(dmr->start - preve)); +- preve = dmr->start; ++ klm->bcount = cpu_to_be32(klm_bcount(bcount)); ++ preve += bcount; ++ + goto again; + } + } +diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c +index 032f8bddf8721e..0e53e427a91dcb 100644 +--- a/drivers/video/backlight/led_bl.c ++++ b/drivers/video/backlight/led_bl.c +@@ -229,8 +229,11 @@ static void led_bl_remove(struct platform_device *pdev) + backlight_device_unregister(bl); + + led_bl_power_off(priv); +- for (i = 0; i < priv->nb_leds; i++) ++ for (i = 0; i < priv->nb_leds; i++) { ++ mutex_lock(&priv->leds[i]->led_access); + led_sysfs_enable(priv->leds[i]); ++ mutex_unlock(&priv->leds[i]->led_access); ++ } + } + + static const struct of_device_id led_bl_of_match[] = { +diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c +index 21fef9db90d26a..4f09111f8b57e3 100644 +--- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c ++++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c +@@ -2749,9 +2749,13 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, + bool mem_to_mem) + { + int r; +- enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane); ++ enum omap_overlay_caps caps; + enum omap_channel channel; + ++ if (plane == OMAP_DSS_WB) ++ return -EINVAL; ++ ++ caps = dss_feat_get_overlay_caps(plane); + channel = dispc_ovl_get_channel_out(plane); + + DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->" +diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c +index db61bcb3aab176..b0b52fa8fba6da 100644 +--- a/drivers/xen/balloon.c ++++ b/drivers/xen/balloon.c +@@ -671,7 +671,7 @@ void xen_free_ballooned_pages(unsigned int nr_pages, struct page **pages) + } + EXPORT_SYMBOL(xen_free_ballooned_pages); + +-static void __init balloon_add_regions(void) ++static int __init balloon_add_regions(void) + { + unsigned long start_pfn, pages; + unsigned long pfn, extra_pfn_end; +@@ -694,26 +694,38 @@ static void __init balloon_add_regions(void) + for (pfn = start_pfn; pfn < extra_pfn_end; pfn++) + balloon_append(pfn_to_page(pfn)); + +- balloon_stats.total_pages += extra_pfn_end - start_pfn; ++ /* ++ * Extra regions are accounted for in the physmap, but need ++ * decreasing from current_pages to balloon down the initial ++ * allocation, because they are already accounted for in ++ * total_pages. ++ */ ++ if (extra_pfn_end - start_pfn >= balloon_stats.current_pages) { ++ WARN(1, "Extra pages underflow current target"); ++ return -ERANGE; ++ } ++ balloon_stats.current_pages -= extra_pfn_end - start_pfn; + } ++ ++ return 0; + } + + static int __init balloon_init(void) + { + struct task_struct *task; ++ int rc; + + if (!xen_domain()) + return -ENODEV; + + pr_info("Initialising balloon driver\n"); + +-#ifdef CONFIG_XEN_PV +- balloon_stats.current_pages = xen_pv_domain() +- ? min(xen_start_info->nr_pages - xen_released_pages, max_pfn) +- : get_num_physpages(); +-#else +- balloon_stats.current_pages = get_num_physpages(); +-#endif ++ if (xen_released_pages >= get_num_physpages()) { ++ WARN(1, "Released pages underflow current target"); ++ return -ERANGE; ++ } ++ ++ balloon_stats.current_pages = get_num_physpages() - xen_released_pages; + balloon_stats.target_pages = balloon_stats.current_pages; + balloon_stats.balloon_low = 0; + balloon_stats.balloon_high = 0; +@@ -730,7 +742,9 @@ static int __init balloon_init(void) + register_sysctl_init("xen/balloon", balloon_table); + #endif + +- balloon_add_regions(); ++ rc = balloon_add_regions(); ++ if (rc) ++ return rc; + + task = kthread_run(balloon_thread, NULL, "xen-balloon"); + if (IS_ERR(task)) { +diff --git a/drivers/xen/xenfs/xensyms.c b/drivers/xen/xenfs/xensyms.c +index b799bc759c15f4..088b7f02c35866 100644 +--- a/drivers/xen/xenfs/xensyms.c ++++ b/drivers/xen/xenfs/xensyms.c +@@ -48,7 +48,7 @@ static int xensyms_next_sym(struct xensyms *xs) + return -ENOMEM; + + set_xen_guest_handle(symdata->name, xs->name); +- symdata->symnum--; /* Rewind */ ++ symdata->symnum = symnum; /* Rewind */ + + ret = HYPERVISOR_platform_op(&xs->op); + if (ret < 0) +@@ -78,7 +78,7 @@ static void *xensyms_next(struct seq_file *m, void *p, loff_t *pos) + { + struct xensyms *xs = m->private; + +- xs->op.u.symdata.symnum = ++(*pos); ++ *pos = xs->op.u.symdata.symnum; + + if (xensyms_next_sym(xs)) + return NULL; +diff --git a/fs/Kconfig b/fs/Kconfig +index 02a9237807a779..85ae4953f2d7b9 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -365,6 +365,7 @@ config GRACE_PERIOD + config LOCKD + tristate + depends on FILE_LOCKING ++ select CRC32 + select GRACE_PERIOD + + config LOCKD_V4 +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 967c6b5dd0a434..2387210231f236 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -4333,6 +4333,18 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) + */ + btrfs_flush_workqueue(fs_info->delalloc_workers); + ++ /* ++ * When finishing a compressed write bio we schedule a work queue item ++ * to finish an ordered extent - btrfs_finish_compressed_write_work() ++ * calls btrfs_finish_ordered_extent() which in turns does a call to ++ * btrfs_queue_ordered_fn(), and that queues the ordered extent ++ * completion either in the endio_write_workers work queue or in the ++ * fs_info->endio_freespace_worker work queue. We flush those queues ++ * below, so before we flush them we must flush this queue for the ++ * workers of compressed writes. ++ */ ++ flush_workqueue(fs_info->compressed_write_workers); ++ + /* + * After we parked the cleaner kthread, ordered extents may have + * completed and created new delayed iputs. If one of the async reclaim +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index cedffa567a7584..11c4d69177f0ca 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1546,6 +1546,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, + locked_page, + clear_bits, + page_ops); ++ btrfs_qgroup_free_data(inode, NULL, start, cur_alloc_size, NULL); + start += cur_alloc_size; + } + +@@ -1559,6 +1560,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, + clear_bits |= EXTENT_CLEAR_DATA_RESV; + extent_clear_unlock_delalloc(inode, start, end, locked_page, + clear_bits, page_ops); ++ btrfs_qgroup_free_data(inode, NULL, start, end - start + 1, NULL); + } + return ret; + } +@@ -2222,13 +2224,15 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, + */ + if (cow_start != (u64)-1) + cur_offset = cow_start; +- if (cur_offset < end) ++ if (cur_offset < end) { + extent_clear_unlock_delalloc(inode, cur_offset, end, + locked_page, EXTENT_LOCKED | + EXTENT_DELALLOC | EXTENT_DEFRAG | + EXTENT_DO_ACCOUNTING, PAGE_UNLOCK | + PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK); ++ btrfs_qgroup_free_data(inode, NULL, cur_offset, end - cur_offset + 1, NULL); ++ } + btrfs_free_path(path); + return ret; + } +diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c +index fb4992570c2b59..2045ac3d94c4df 100644 +--- a/fs/btrfs/super.c ++++ b/fs/btrfs/super.c +@@ -1336,8 +1336,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) + subvol_name = btrfs_get_subvol_name_from_objectid(info, + BTRFS_I(d_inode(dentry))->root->root_key.objectid); + if (!IS_ERR(subvol_name)) { +- seq_puts(seq, ",subvol="); +- seq_escape(seq, subvol_name, " \t\n\\"); ++ seq_show_option(seq, "subvol", subvol_name); + kfree(subvol_name); + } + return 0; +diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c +index c4463c3f2068dd..197dfafbf40139 100644 +--- a/fs/btrfs/zoned.c ++++ b/fs/btrfs/zoned.c +@@ -2006,6 +2006,9 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group) + physical = map->stripes[i].physical; + zinfo = device->zone_info; + ++ if (!device->bdev) ++ continue; ++ + if (zinfo->max_active_zones == 0) + continue; + +@@ -2165,6 +2168,9 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ + const u64 physical = map->stripes[i].physical; + struct btrfs_zoned_device_info *zinfo = device->zone_info; + ++ if (!device->bdev) ++ continue; ++ + if (zinfo->max_active_zones == 0) + continue; + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 19d7bcf16ebb88..ddfeaf19bff1ba 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4692,22 +4692,43 @@ static inline void ext4_inode_set_iversion_queried(struct inode *inode, u64 val) + inode_set_iversion_queried(inode, val); + } + +-static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags) +- ++static int check_igot_inode(struct inode *inode, ext4_iget_flags flags, ++ const char *function, unsigned int line) + { ++ const char *err_str; ++ + if (flags & EXT4_IGET_EA_INODE) { +- if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) +- return "missing EA_INODE flag"; ++ if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) { ++ err_str = "missing EA_INODE flag"; ++ goto error; ++ } + if (ext4_test_inode_state(inode, EXT4_STATE_XATTR) || +- EXT4_I(inode)->i_file_acl) +- return "ea_inode with extended attributes"; ++ EXT4_I(inode)->i_file_acl) { ++ err_str = "ea_inode with extended attributes"; ++ goto error; ++ } + } else { +- if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) +- return "unexpected EA_INODE flag"; ++ if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) { ++ /* ++ * open_by_handle_at() could provide an old inode number ++ * that has since been reused for an ea_inode; this does ++ * not indicate filesystem corruption ++ */ ++ if (flags & EXT4_IGET_HANDLE) ++ return -ESTALE; ++ err_str = "unexpected EA_INODE flag"; ++ goto error; ++ } ++ } ++ if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) { ++ err_str = "unexpected bad inode w/o EXT4_IGET_BAD"; ++ goto error; + } +- if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) +- return "unexpected bad inode w/o EXT4_IGET_BAD"; +- return NULL; ++ return 0; ++ ++error: ++ ext4_error_inode(inode, function, line, 0, err_str); ++ return -EFSCORRUPTED; + } + + struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, +@@ -4719,7 +4740,6 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, + struct ext4_inode_info *ei; + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + struct inode *inode; +- const char *err_str; + journal_t *journal = EXT4_SB(sb)->s_journal; + long ret; + loff_t size; +@@ -4748,10 +4768,10 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, + if (!inode) + return ERR_PTR(-ENOMEM); + if (!(inode->i_state & I_NEW)) { +- if ((err_str = check_igot_inode(inode, flags)) != NULL) { +- ext4_error_inode(inode, function, line, 0, err_str); ++ ret = check_igot_inode(inode, flags, function, line); ++ if (ret) { + iput(inode); +- return ERR_PTR(-EFSCORRUPTED); ++ return ERR_PTR(ret); + } + return inode; + } +@@ -5023,13 +5043,21 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, + ret = -EFSCORRUPTED; + goto bad_inode; + } +- if ((err_str = check_igot_inode(inode, flags)) != NULL) { +- ext4_error_inode(inode, function, line, 0, err_str); +- ret = -EFSCORRUPTED; +- goto bad_inode; ++ ret = check_igot_inode(inode, flags, function, line); ++ /* ++ * -ESTALE here means there is nothing inherently wrong with the inode, ++ * it's just not an inode we can return for an fhandle lookup. ++ */ ++ if (ret == -ESTALE) { ++ brelse(iloc.bh); ++ unlock_new_inode(inode); ++ iput(inode); ++ return ERR_PTR(-ESTALE); + } +- ++ if (ret) ++ goto bad_inode; + brelse(iloc.bh); ++ + unlock_new_inode(inode); + return inode; + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 96a048d3f51bf5..2e4575becd4fbf 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -2041,7 +2041,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, + * split it in half by count; each resulting block will have at least + * half the space free. + */ +- if (i > 0) ++ if (i >= 0) + split = count - move; + else + split = count/2; +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index a4d7af7495b784..751c879271e05e 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -6933,12 +6933,25 @@ static int ext4_release_dquot(struct dquot *dquot) + { + int ret, err; + handle_t *handle; ++ bool freeze_protected = false; ++ ++ /* ++ * Trying to sb_start_intwrite() in a running transaction ++ * can result in a deadlock. Further, running transactions ++ * are already protected from freezing. ++ */ ++ if (!ext4_journal_current_handle()) { ++ sb_start_intwrite(dquot->dq_sb); ++ freeze_protected = true; ++ } + + handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA, + EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb)); + if (IS_ERR(handle)) { + /* Release dquot anyway to avoid endless cycle in dqput() */ + dquot_release(dquot); ++ if (freeze_protected) ++ sb_end_intwrite(dquot->dq_sb); + return PTR_ERR(handle); + } + ret = dquot_release(dquot); +@@ -6949,6 +6962,10 @@ static int ext4_release_dquot(struct dquot *dquot) + err = ext4_journal_stop(handle); + if (!ret) + ret = err; ++ ++ if (freeze_protected) ++ sb_end_intwrite(dquot->dq_sb); ++ + return ret; + } + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index df5ab1a75fc482..ca22aa9e04b4b1 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1176,15 +1176,24 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent, + { + struct inode *ea_inode; + struct ext4_xattr_entry *entry; ++ struct ext4_iloc iloc; + bool dirty = false; + unsigned int ea_ino; + int err; + int credits; ++ void *end; ++ ++ if (block_csum) ++ end = (void *)bh->b_data + bh->b_size; ++ else { ++ ext4_get_inode_loc(parent, &iloc); ++ end = (void *)ext4_raw_inode(&iloc) + EXT4_SB(parent->i_sb)->s_inode_size; ++ } + + /* One credit for dec ref on ea_inode, one for orphan list addition, */ + credits = 2 + extra_credits; + +- for (entry = first; !IS_LAST_ENTRY(entry); ++ for (entry = first; (void *)entry < end && !IS_LAST_ENTRY(entry); + entry = EXT4_XATTR_NEXT(entry)) { + if (!entry->e_value_inum) + continue; +diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c +index c6317596e695cc..3ec815e615e731 100644 +--- a/fs/f2fs/checkpoint.c ++++ b/fs/f2fs/checkpoint.c +@@ -1327,21 +1327,13 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + unsigned long flags; + +- if (cpc->reason & CP_UMOUNT) { +- if (le32_to_cpu(ckpt->cp_pack_total_block_count) + +- NM_I(sbi)->nat_bits_blocks > BLKS_PER_SEG(sbi)) { +- clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG); +- f2fs_notice(sbi, "Disable nat_bits due to no space"); +- } else if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG) && +- f2fs_nat_bitmap_enabled(sbi)) { +- f2fs_enable_nat_bits(sbi); +- set_ckpt_flags(sbi, CP_NAT_BITS_FLAG); +- f2fs_notice(sbi, "Rebuild and enable nat_bits"); +- } +- } +- + spin_lock_irqsave(&sbi->cp_lock, flags); + ++ if ((cpc->reason & CP_UMOUNT) && ++ le32_to_cpu(ckpt->cp_pack_total_block_count) > ++ sbi->blocks_per_seg - NM_I(sbi)->nat_bits_blocks) ++ disable_nat_bits(sbi, false); ++ + if (cpc->reason & CP_TRIMMED) + __set_ckpt_flags(ckpt, CP_TRIMMED_FLAG); + else +@@ -1524,8 +1516,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) + start_blk = __start_cp_next_addr(sbi); + + /* write nat bits */ +- if ((cpc->reason & CP_UMOUNT) && +- is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG)) { ++ if (enabled_nat_bits(sbi, cpc)) { + __u64 cp_ver = cur_cp_version(ckpt); + block_t blk; + +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index d28e3df61cc4fd..5f6f159be456ea 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -2197,6 +2197,36 @@ static inline void f2fs_up_write(struct f2fs_rwsem *sem) + #endif + } + ++static inline void disable_nat_bits(struct f2fs_sb_info *sbi, bool lock) ++{ ++ unsigned long flags; ++ unsigned char *nat_bits; ++ ++ /* ++ * In order to re-enable nat_bits we need to call fsck.f2fs by ++ * set_sbi_flag(sbi, SBI_NEED_FSCK). But it may give huge cost, ++ * so let's rely on regular fsck or unclean shutdown. ++ */ ++ ++ if (lock) ++ spin_lock_irqsave(&sbi->cp_lock, flags); ++ __clear_ckpt_flags(F2FS_CKPT(sbi), CP_NAT_BITS_FLAG); ++ nat_bits = NM_I(sbi)->nat_bits; ++ NM_I(sbi)->nat_bits = NULL; ++ if (lock) ++ spin_unlock_irqrestore(&sbi->cp_lock, flags); ++ ++ kvfree(nat_bits); ++} ++ ++static inline bool enabled_nat_bits(struct f2fs_sb_info *sbi, ++ struct cp_control *cpc) ++{ ++ bool set = is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG); ++ ++ return (cpc) ? (cpc->reason & CP_UMOUNT) && set : set; ++} ++ + static inline void f2fs_lock_op(struct f2fs_sb_info *sbi) + { + f2fs_down_read(&sbi->cp_rwsem); +@@ -3623,7 +3653,6 @@ int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from); + int f2fs_truncate_xattr_node(struct inode *inode); + int f2fs_wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, + unsigned int seq_id); +-bool f2fs_nat_bitmap_enabled(struct f2fs_sb_info *sbi); + int f2fs_remove_inode_page(struct inode *inode); + struct page *f2fs_new_inode_page(struct inode *inode); + struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs); +@@ -3648,7 +3677,6 @@ int f2fs_recover_xattr_data(struct inode *inode, struct page *page); + int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page); + int f2fs_restore_node_summary(struct f2fs_sb_info *sbi, + unsigned int segno, struct f2fs_summary_block *sum); +-void f2fs_enable_nat_bits(struct f2fs_sb_info *sbi); + int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc); + int f2fs_build_node_manager(struct f2fs_sb_info *sbi); + void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi); +diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c +index 7ad4a924175917..06941705e8939f 100644 +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -35,10 +35,8 @@ void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) + if (f2fs_inode_dirtied(inode, sync)) + return; + +- if (f2fs_is_atomic_file(inode)) { +- set_inode_flag(inode, FI_ATOMIC_DIRTIED); ++ if (f2fs_is_atomic_file(inode)) + return; +- } + + mark_inode_dirty_sync(inode); + } +@@ -764,8 +762,12 @@ void f2fs_update_inode_page(struct inode *inode) + if (err == -ENOENT) + return; + ++ if (err == -EFSCORRUPTED) ++ goto stop_checkpoint; ++ + if (err == -ENOMEM || ++count <= DEFAULT_RETRY_IO_COUNT) + goto retry; ++stop_checkpoint: + f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_UPDATE_INODE); + return; + } +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +index dedba481b66d07..b00d66b953210d 100644 +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -1134,7 +1134,14 @@ int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from) + trace_f2fs_truncate_inode_blocks_enter(inode, from); + + level = get_node_path(inode, from, offset, noffset); +- if (level < 0) { ++ if (level <= 0) { ++ if (!level) { ++ level = -EFSCORRUPTED; ++ f2fs_err(sbi, "%s: inode ino=%lx has corrupted node block, from:%lu addrs:%u", ++ __func__, inode->i_ino, ++ from, ADDRS_PER_INODE(inode)); ++ set_sbi_flag(sbi, SBI_NEED_FSCK); ++ } + trace_f2fs_truncate_inode_blocks_exit(inode, level); + return level; + } +@@ -2258,24 +2265,6 @@ static void __move_free_nid(struct f2fs_sb_info *sbi, struct free_nid *i, + } + } + +-bool f2fs_nat_bitmap_enabled(struct f2fs_sb_info *sbi) +-{ +- struct f2fs_nm_info *nm_i = NM_I(sbi); +- unsigned int i; +- bool ret = true; +- +- f2fs_down_read(&nm_i->nat_tree_lock); +- for (i = 0; i < nm_i->nat_blocks; i++) { +- if (!test_bit_le(i, nm_i->nat_block_bitmap)) { +- ret = false; +- break; +- } +- } +- f2fs_up_read(&nm_i->nat_tree_lock); +- +- return ret; +-} +- + static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, + bool set, bool build) + { +@@ -2954,23 +2943,7 @@ static void __adjust_nat_entry_set(struct nat_entry_set *nes, + list_add_tail(&nes->set_list, head); + } + +-static void __update_nat_bits(struct f2fs_nm_info *nm_i, unsigned int nat_ofs, +- unsigned int valid) +-{ +- if (valid == 0) { +- __set_bit_le(nat_ofs, nm_i->empty_nat_bits); +- __clear_bit_le(nat_ofs, nm_i->full_nat_bits); +- return; +- } +- +- __clear_bit_le(nat_ofs, nm_i->empty_nat_bits); +- if (valid == NAT_ENTRY_PER_BLOCK) +- __set_bit_le(nat_ofs, nm_i->full_nat_bits); +- else +- __clear_bit_le(nat_ofs, nm_i->full_nat_bits); +-} +- +-static void update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid, ++static void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid, + struct page *page) + { + struct f2fs_nm_info *nm_i = NM_I(sbi); +@@ -2979,7 +2952,7 @@ static void update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid, + int valid = 0; + int i = 0; + +- if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG)) ++ if (!enabled_nat_bits(sbi, NULL)) + return; + + if (nat_index == 0) { +@@ -2990,36 +2963,17 @@ static void update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid, + if (le32_to_cpu(nat_blk->entries[i].block_addr) != NULL_ADDR) + valid++; + } +- +- __update_nat_bits(nm_i, nat_index, valid); +-} +- +-void f2fs_enable_nat_bits(struct f2fs_sb_info *sbi) +-{ +- struct f2fs_nm_info *nm_i = NM_I(sbi); +- unsigned int nat_ofs; +- +- f2fs_down_read(&nm_i->nat_tree_lock); +- +- for (nat_ofs = 0; nat_ofs < nm_i->nat_blocks; nat_ofs++) { +- unsigned int valid = 0, nid_ofs = 0; +- +- /* handle nid zero due to it should never be used */ +- if (unlikely(nat_ofs == 0)) { +- valid = 1; +- nid_ofs = 1; +- } +- +- for (; nid_ofs < NAT_ENTRY_PER_BLOCK; nid_ofs++) { +- if (!test_bit_le(nid_ofs, +- nm_i->free_nid_bitmap[nat_ofs])) +- valid++; +- } +- +- __update_nat_bits(nm_i, nat_ofs, valid); ++ if (valid == 0) { ++ __set_bit_le(nat_index, nm_i->empty_nat_bits); ++ __clear_bit_le(nat_index, nm_i->full_nat_bits); ++ return; + } + +- f2fs_up_read(&nm_i->nat_tree_lock); ++ __clear_bit_le(nat_index, nm_i->empty_nat_bits); ++ if (valid == NAT_ENTRY_PER_BLOCK) ++ __set_bit_le(nat_index, nm_i->full_nat_bits); ++ else ++ __clear_bit_le(nat_index, nm_i->full_nat_bits); + } + + static int __flush_nat_entry_set(struct f2fs_sb_info *sbi, +@@ -3038,7 +2992,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi, + * #1, flush nat entries to journal in current hot data summary block. + * #2, flush nat entries to nat page. + */ +- if ((cpc->reason & CP_UMOUNT) || ++ if (enabled_nat_bits(sbi, cpc) || + !__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL)) + to_journal = false; + +@@ -3085,7 +3039,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi, + if (to_journal) { + up_write(&curseg->journal_rwsem); + } else { +- update_nat_bits(sbi, start_nid, page); ++ __update_nat_bits(sbi, start_nid, page); + f2fs_put_page(page, 1); + } + +@@ -3116,7 +3070,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) + * during unmount, let's flush nat_bits before checking + * nat_cnt[DIRTY_NAT]. + */ +- if (cpc->reason & CP_UMOUNT) { ++ if (enabled_nat_bits(sbi, cpc)) { + f2fs_down_write(&nm_i->nat_tree_lock); + remove_nats_in_journal(sbi); + f2fs_up_write(&nm_i->nat_tree_lock); +@@ -3132,7 +3086,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) + * entries, remove all entries from journal and merge them + * into nat entry set. + */ +- if (cpc->reason & CP_UMOUNT || ++ if (enabled_nat_bits(sbi, cpc) || + !__has_cursum_space(journal, + nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL)) + remove_nats_in_journal(sbi); +@@ -3169,18 +3123,15 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) + __u64 cp_ver = cur_cp_version(ckpt); + block_t nat_bits_addr; + ++ if (!enabled_nat_bits(sbi, NULL)) ++ return 0; ++ + nm_i->nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8); + nm_i->nat_bits = f2fs_kvzalloc(sbi, + nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL); + if (!nm_i->nat_bits) + return -ENOMEM; + +- nm_i->full_nat_bits = nm_i->nat_bits + 8; +- nm_i->empty_nat_bits = nm_i->full_nat_bits + nat_bits_bytes; +- +- if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG)) +- return 0; +- + nat_bits_addr = __start_cp_addr(sbi) + BLKS_PER_SEG(sbi) - + nm_i->nat_bits_blocks; + for (i = 0; i < nm_i->nat_bits_blocks; i++) { +@@ -3197,12 +3148,13 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) + + cp_ver |= (cur_cp_crc(ckpt) << 32); + if (cpu_to_le64(cp_ver) != *(__le64 *)nm_i->nat_bits) { +- clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG); +- f2fs_notice(sbi, "Disable nat_bits due to incorrect cp_ver (%llu, %llu)", +- cp_ver, le64_to_cpu(*(__le64 *)nm_i->nat_bits)); ++ disable_nat_bits(sbi, true); + return 0; + } + ++ nm_i->full_nat_bits = nm_i->nat_bits + 8; ++ nm_i->empty_nat_bits = nm_i->full_nat_bits + nat_bits_bytes; ++ + f2fs_notice(sbi, "Found nat_bits in checkpoint"); + return 0; + } +@@ -3213,7 +3165,7 @@ static inline void load_free_nid_bitmap(struct f2fs_sb_info *sbi) + unsigned int i = 0; + nid_t nid, last_nid; + +- if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG)) ++ if (!enabled_nat_bits(sbi, NULL)) + return; + + for (i = 0; i < nm_i->nat_blocks; i++) { +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index aa0e7cc2489ac9..4cc87921aac3ed 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1499,6 +1499,10 @@ int f2fs_inode_dirtied(struct inode *inode, bool sync) + inc_page_count(sbi, F2FS_DIRTY_IMETA); + } + spin_unlock(&sbi->inode_lock[DIRTY_META]); ++ ++ if (!ret && f2fs_is_atomic_file(inode)) ++ set_inode_flag(inode, FI_ATOMIC_DIRTIED); ++ + return ret; + } + +diff --git a/fs/file.c b/fs/file.c +index a178efc8cf4b5c..f8cf6728c6a03f 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -362,17 +362,25 @@ struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_ho + old_fds = old_fdt->fd; + new_fds = new_fdt->fd; + ++ /* ++ * We may be racing against fd allocation from other threads using this ++ * files_struct, despite holding ->file_lock. ++ * ++ * alloc_fd() might have already claimed a slot, while fd_install() ++ * did not populate it yet. Note the latter operates locklessly, so ++ * the file can show up as we are walking the array below. ++ * ++ * At the same time we know no files will disappear as all other ++ * operations take the lock. ++ * ++ * Instead of trying to placate userspace racing with itself, we ++ * ref the file if we see it and mark the fd slot as unused otherwise. ++ */ + for (i = open_files; i != 0; i--) { +- struct file *f = *old_fds++; ++ struct file *f = rcu_dereference_raw(*old_fds++); + if (f) { + get_file(f); + } else { +- /* +- * The fd may be claimed in the fd bitmap but not yet +- * instantiated in the files array if a sibling thread +- * is partway through open(). So make sure that this +- * fd is available to the new process. +- */ + __clear_open_fd(open_files - i, new_fdt); + } + rcu_assign_pointer(*new_fds++, f); +@@ -625,7 +633,7 @@ static struct file *pick_file(struct files_struct *files, unsigned fd) + return NULL; + + fd = array_index_nospec(fd, fdt->max_fds); +- file = fdt->fd[fd]; ++ file = rcu_dereference_raw(fdt->fd[fd]); + if (file) { + rcu_assign_pointer(fdt->fd[fd], NULL); + __put_unused_fd(files, fd); +@@ -1095,7 +1103,7 @@ __releases(&files->file_lock) + */ + fdt = files_fdtable(files); + fd = array_index_nospec(fd, fdt->max_fds); +- tofree = fdt->fd[fd]; ++ tofree = rcu_dereference_raw(fdt->fd[fd]); + if (!tofree && fd_is_open(fd, fdt)) + goto Ebusy; + get_file(file); +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index d84dacbdce2c9d..a6814bea0e0ad8 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -1430,6 +1430,9 @@ static int virtio_fs_get_tree(struct fs_context *fsc) + unsigned int virtqueue_size; + int err = -EIO; + ++ if (!fsc->source) ++ return invalf(fsc, "No source specified"); ++ + /* This gets a reference on virtio_fs object. This ptr gets installed + * in fc->iq->priv. Once fuse_conn is going away, it calls ->put() + * to drop the reference to this object. +diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c +index 6add6ebfef8967..cb823a8a6ba960 100644 +--- a/fs/hfs/bnode.c ++++ b/fs/hfs/bnode.c +@@ -67,6 +67,12 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off) + else + key_len = tree->max_key_len + 1; + ++ if (key_len > sizeof(hfs_btree_key) || key_len < 1) { ++ memset(key, 0, sizeof(hfs_btree_key)); ++ pr_err("hfs: Invalid key length: %d\n", key_len); ++ return; ++ } ++ + hfs_bnode_read(node, key, off, key_len); + } + +diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c +index 87974d5e679156..079ea80534f7de 100644 +--- a/fs/hfsplus/bnode.c ++++ b/fs/hfsplus/bnode.c +@@ -67,6 +67,12 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off) + else + key_len = tree->max_key_len + 2; + ++ if (key_len > sizeof(hfsplus_btree_key) || key_len < 1) { ++ memset(key, 0, sizeof(hfsplus_btree_key)); ++ pr_err("hfsplus: Invalid key length: %d\n", key_len); ++ return; ++ } ++ + hfs_bnode_read(node, key, off, key_len); + } + +diff --git a/fs/isofs/export.c b/fs/isofs/export.c +index 35768a63fb1d23..421d247fae5230 100644 +--- a/fs/isofs/export.c ++++ b/fs/isofs/export.c +@@ -180,7 +180,7 @@ static struct dentry *isofs_fh_to_parent(struct super_block *sb, + return NULL; + + return isofs_export_iget(sb, +- fh_len > 2 ? ifid->parent_block : 0, ++ fh_len > 3 ? ifid->parent_block : 0, + ifid->parent_offset, + fh_len > 4 ? ifid->parent_generation : 0); + } +diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c +index dfbb8f73861f64..ddde73299d6224 100644 +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -1914,7 +1914,6 @@ int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, + + /* Log is no longer empty */ + write_lock(&journal->j_state_lock); +- WARN_ON(!sb->s_sequence); + journal->j_flags &= ~JBD2_FLUSHED; + write_unlock(&journal->j_state_lock); + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index f9009e4f9ffd89..0e1019382cf519 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -204,6 +204,10 @@ int dbMount(struct inode *ipbmap) + bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel); + bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight); + bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth); ++ if (!bmp->db_agwidth) { ++ err = -EINVAL; ++ goto err_release_metapage; ++ } + bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart); + bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size); + if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG || +@@ -3403,7 +3407,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + oldl2agsize = bmp->db_agl2size; + + bmp->db_agl2size = l2agsize; +- bmp->db_agsize = 1 << l2agsize; ++ bmp->db_agsize = (s64)1 << l2agsize; + + /* compute new number of AG */ + agno = bmp->db_numag; +@@ -3666,8 +3670,8 @@ void dbFinalizeBmap(struct inode *ipbmap) + * system size is not a multiple of the group size). + */ + inactfree = (inactags && ag_rem) ? +- ((inactags - 1) << bmp->db_agl2size) + ag_rem +- : inactags << bmp->db_agl2size; ++ (((s64)inactags - 1) << bmp->db_agl2size) + ag_rem ++ : ((s64)inactags << bmp->db_agl2size); + + /* determine how many free blocks are in the active + * allocation groups plus the average number of free blocks +diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c +index b30e4cf2f5794c..9a6d504228e7c5 100644 +--- a/fs/jfs/jfs_imap.c ++++ b/fs/jfs/jfs_imap.c +@@ -102,7 +102,7 @@ int diMount(struct inode *ipimap) + * allocate/initialize the in-memory inode map control structure + */ + /* allocate the in-memory inode map control structure. */ +- imap = kmalloc(sizeof(struct inomap), GFP_KERNEL); ++ imap = kzalloc(sizeof(struct inomap), GFP_KERNEL); + if (imap == NULL) + return -ENOMEM; + +@@ -456,7 +456,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary) + dp += inum % 8; /* 8 inodes per 4K page */ + + /* copy on-disk inode to in-memory inode */ +- if ((copy_from_dinode(dp, ip)) != 0) { ++ if ((copy_from_dinode(dp, ip) != 0) || (ip->i_nlink == 0)) { + /* handle bad return by returning NULL for ip */ + set_nlink(ip, 1); /* Don't want iput() deleting it */ + iput(ip); +diff --git a/fs/namespace.c b/fs/namespace.c +index b4385e2413d599..671e266b8fc5d2 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1869,6 +1869,7 @@ static void warn_mandlock(void) + static int can_umount(const struct path *path, int flags) + { + struct mount *mnt = real_mount(path->mnt); ++ struct super_block *sb = path->dentry->d_sb; + + if (!may_mount()) + return -EPERM; +@@ -1878,7 +1879,7 @@ static int can_umount(const struct path *path, int flags) + return -EINVAL; + if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */ + return -EINVAL; +- if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) ++ if (flags & MNT_FORCE && !ns_capable(sb->s_user_ns, CAP_SYS_ADMIN)) + return -EPERM; + return 0; + } +diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig +index 7df2503cef6c30..2d99f5e7a686b0 100644 +--- a/fs/nfs/Kconfig ++++ b/fs/nfs/Kconfig +@@ -2,6 +2,7 @@ + config NFS_FS + tristate "NFS client support" + depends on INET && FILE_LOCKING && MULTIUSER ++ select CRC32 + select LOCKD + select SUNRPC + select NFS_ACL_SUPPORT if NFS_V3_ACL +@@ -194,7 +195,6 @@ config NFS_USE_KERNEL_DNS + config NFS_DEBUG + bool + depends on NFS_FS && SUNRPC_DEBUG +- select CRC32 + default y + + config NFS_DISABLE_UDP_SUPPORT +diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h +index a92b234ae0870b..ca49d999159eb1 100644 +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -859,18 +859,11 @@ u64 nfs_timespec_to_change_attr(const struct timespec64 *ts) + return ((u64)ts->tv_sec << 30) + ts->tv_nsec; + } + +-#ifdef CONFIG_CRC32 + static inline u32 nfs_stateid_hash(const nfs4_stateid *stateid) + { + return ~crc32_le(0xFFFFFFFF, &stateid->other[0], + NFS4_STATEID_OTHER_SIZE); + } +-#else +-static inline u32 nfs_stateid_hash(nfs4_stateid *stateid) +-{ +- return 0; +-} +-#endif + + static inline bool nfs_error_is_fatal(int err) + { +diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h +index 351616c61df541..f9c291e2165cd8 100644 +--- a/fs/nfs/nfs4session.h ++++ b/fs/nfs/nfs4session.h +@@ -148,16 +148,12 @@ static inline void nfs4_copy_sessionid(struct nfs4_sessionid *dst, + memcpy(dst->data, src->data, NFS4_MAX_SESSIONID_LEN); + } + +-#ifdef CONFIG_CRC32 + /* + * nfs_session_id_hash - calculate the crc32 hash for the session id + * @session - pointer to session + */ + #define nfs_session_id_hash(sess_id) \ + (~crc32_le(0xFFFFFFFF, &(sess_id)->data[0], sizeof((sess_id)->data))) +-#else +-#define nfs_session_id_hash(session) (0) +-#endif + #else /* defined(CONFIG_NFS_V4_1) */ + + static inline int nfs4_init_session(struct nfs_client *clp) +diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig +index 43b88eaf0673ab..05c10f70456ccd 100644 +--- a/fs/nfsd/Kconfig ++++ b/fs/nfsd/Kconfig +@@ -4,6 +4,7 @@ config NFSD + depends on INET + depends on FILE_LOCKING + depends on FSNOTIFY ++ select CRC32 + select LOCKD + select SUNRPC + select EXPORTFS +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 140784446ad220..e2875706e6bfd7 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4938,7 +4938,7 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) + queued = nfsd4_run_cb(&dp->dl_recall); + WARN_ON_ONCE(!queued); + if (!queued) +- nfs4_put_stid(&dp->dl_stid); ++ refcount_dec(&dp->dl_stid.sc_count); + } + + /* Called from break_lease() with flc_lock held. */ +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 40426f899e7601..f1420d3510d2ef 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -263,7 +263,6 @@ static inline bool fh_fsid_match(const struct knfsd_fh *fh1, + return true; + } + +-#ifdef CONFIG_CRC32 + /** + * knfsd_fh_hash - calculate the crc32 hash for the filehandle + * @fh - pointer to filehandle +@@ -275,12 +274,6 @@ static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) + { + return ~crc32_le(0xFFFFFFFF, fh->fh_raw, fh->fh_size); + } +-#else +-static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) +-{ +- return 0; +-} +-#endif + + /** + * fh_clear_pre_post_attrs - Reset pre/post attributes +diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h +index 981967e507b3e1..23b5c5f9c78231 100644 +--- a/fs/overlayfs/overlayfs.h ++++ b/fs/overlayfs/overlayfs.h +@@ -506,8 +506,6 @@ int ovl_set_metacopy_xattr(struct ovl_fs *ofs, struct dentry *d, + bool ovl_is_metacopy_dentry(struct dentry *dentry); + char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding); + int ovl_ensure_verity_loaded(struct path *path); +-int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, +- u8 *digest_buf, int *buf_length); + int ovl_validate_verity(struct ovl_fs *ofs, + struct path *metapath, + struct path *datapath); +diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c +index 2c056d737c27c3..93ee57bc82ade9 100644 +--- a/fs/overlayfs/super.c ++++ b/fs/overlayfs/super.c +@@ -1180,6 +1180,11 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, + return ERR_PTR(-EINVAL); + } + ++ if (ctx->nr == ctx->nr_data) { ++ pr_err("at least one non-data lowerdir is required\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ + err = -EINVAL; + for (i = 0; i < ctx->nr; i++) { + l = &ctx->lower[i]; +diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h +index 85b0a30493a638..7f97e54686524b 100644 +--- a/fs/smb/client/cifsproto.h ++++ b/fs/smb/client/cifsproto.h +@@ -158,6 +158,8 @@ extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, + extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); + extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, + struct cifsFileInfo **ret_file); ++extern int cifs_get_hardlink_path(struct cifs_tcon *tcon, struct inode *inode, ++ struct file *file); + extern unsigned int smbCalcSize(void *buf); + extern int decode_negTokenInit(unsigned char *security_blob, int length, + struct TCP_Server_Info *server); +diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c +index 2d2e41ac9e9d83..54aba8d642ee75 100644 +--- a/fs/smb/client/connect.c ++++ b/fs/smb/client/connect.c +@@ -316,7 +316,6 @@ cifs_abort_connection(struct TCP_Server_Info *server) + server->ssocket->flags); + sock_release(server->ssocket); + server->ssocket = NULL; +- put_net(cifs_net_ns(server)); + } + server->sequence_number = 0; + server->session_estab = false; +@@ -1004,13 +1003,9 @@ clean_demultiplex_info(struct TCP_Server_Info *server) + msleep(125); + if (cifs_rdma_enabled(server)) + smbd_destroy(server); +- + if (server->ssocket) { + sock_release(server->ssocket); + server->ssocket = NULL; +- +- /* Release netns reference for the socket. */ +- put_net(cifs_net_ns(server)); + } + + if (!list_empty(&server->pending_mid_q)) { +@@ -1059,7 +1054,6 @@ clean_demultiplex_info(struct TCP_Server_Info *server) + */ + } + +- /* Release netns reference for this server. */ + put_net(cifs_net_ns(server)); + kfree(server->leaf_fullpath); + kfree(server->hostname); +@@ -1731,8 +1725,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, + + tcp_ses->ops = ctx->ops; + tcp_ses->vals = ctx->vals; +- +- /* Grab netns reference for this server. */ + cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); + + tcp_ses->conn_id = atomic_inc_return(&tcpSesNextId); +@@ -1864,7 +1856,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, + out_err_crypto_release: + cifs_crypto_secmech_release(tcp_ses); + +- /* Release netns reference for this server. */ + put_net(cifs_net_ns(tcp_ses)); + + out_err: +@@ -1873,10 +1864,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, + cifs_put_tcp_session(tcp_ses->primary_server, false); + kfree(tcp_ses->hostname); + kfree(tcp_ses->leaf_fullpath); +- if (tcp_ses->ssocket) { ++ if (tcp_ses->ssocket) + sock_release(tcp_ses->ssocket); +- put_net(cifs_net_ns(tcp_ses)); +- } + kfree(tcp_ses); + } + return ERR_PTR(rc); +@@ -2488,6 +2477,8 @@ static int match_tcon(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + return 0; + if (tcon->nodelete != ctx->nodelete) + return 0; ++ if (tcon->posix_extensions != ctx->linux_ext) ++ return 0; + return 1; + } + +@@ -3138,24 +3129,20 @@ generic_ip_connect(struct TCP_Server_Info *server) + socket = server->ssocket; + } else { + struct net *net = cifs_net_ns(server); ++ struct sock *sk; + +- rc = sock_create_kern(net, sfamily, SOCK_STREAM, IPPROTO_TCP, &server->ssocket); ++ rc = __sock_create(net, sfamily, SOCK_STREAM, ++ IPPROTO_TCP, &server->ssocket, 1); + if (rc < 0) { + cifs_server_dbg(VFS, "Error %d creating socket\n", rc); + return rc; + } + +- /* +- * Grab netns reference for the socket. +- * +- * This reference will be released in several situations: +- * - In the failure path before the cifsd thread is started. +- * - In the all place where server->socket is released, it is +- * also set to NULL. +- * - Ultimately in clean_demultiplex_info(), during the final +- * teardown. +- */ +- get_net(net); ++ sk = server->ssocket->sk; ++ __netns_tracker_free(net, &sk->ns_tracker, false); ++ sk->sk_net_refcnt = 1; ++ get_net_track(net, &sk->ns_tracker, GFP_KERNEL); ++ sock_inuse_add(net, 1); + + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cifs_dbg(FYI, "Socket created\n"); +@@ -3207,7 +3194,6 @@ generic_ip_connect(struct TCP_Server_Info *server) + if (rc < 0) { + cifs_dbg(FYI, "Error %d connecting to server\n", rc); + trace_smb3_connect_err(server->hostname, server->conn_id, &server->dstaddr, rc); +- put_net(cifs_net_ns(server)); + sock_release(socket); + server->ssocket = NULL; + return rc; +diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c +index cb75b95efb7013..d883ed75022c4a 100644 +--- a/fs/smb/client/file.c ++++ b/fs/smb/client/file.c +@@ -816,6 +816,11 @@ int cifs_open(struct inode *inode, struct file *file) + } else { + _cifsFileInfo_put(cfile, true, false); + } ++ } else { ++ /* hard link on the defeered close file */ ++ rc = cifs_get_hardlink_path(tcon, inode, file); ++ if (rc) ++ cifs_close_deferred_file(CIFS_I(inode)); + } + + if (server->oplocks) +@@ -1878,6 +1883,29 @@ cifs_move_llist(struct list_head *source, struct list_head *dest) + list_move(li, dest); + } + ++int ++cifs_get_hardlink_path(struct cifs_tcon *tcon, struct inode *inode, ++ struct file *file) ++{ ++ struct cifsFileInfo *open_file = NULL; ++ struct cifsInodeInfo *cinode = CIFS_I(inode); ++ int rc = 0; ++ ++ spin_lock(&tcon->open_file_lock); ++ spin_lock(&cinode->open_file_lock); ++ ++ list_for_each_entry(open_file, &cinode->openFileList, flist) { ++ if (file->f_flags == open_file->f_flags) { ++ rc = -EINVAL; ++ break; ++ } ++ } ++ ++ spin_unlock(&cinode->open_file_lock); ++ spin_unlock(&tcon->open_file_lock); ++ return rc; ++} ++ + void + cifs_free_llist(struct list_head *llist) + { +diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c +index b90cc918de7a39..d2e291ef104ec0 100644 +--- a/fs/smb/client/fs_context.c ++++ b/fs/smb/client/fs_context.c +@@ -1299,6 +1299,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, + ctx->closetimeo = HZ * result.uint_32; + break; + case Opt_echo_interval: ++ if (result.uint_32 < SMB_ECHO_INTERVAL_MIN || ++ result.uint_32 > SMB_ECHO_INTERVAL_MAX) { ++ cifs_errorf(fc, "echo interval is out of bounds\n"); ++ goto cifs_parse_mount_err; ++ } + ctx->echo_interval = result.uint_32; + break; + case Opt_snapshot: +diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c +index b9cf05e0940d07..d93ebd58ecae16 100644 +--- a/fs/smb/client/inode.c ++++ b/fs/smb/client/inode.c +@@ -1145,6 +1145,16 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data, + cifs_create_junction_fattr(fattr, sb); + goto out; + } ++ /* ++ * If the reparse point is unsupported by the Linux SMB ++ * client then let it process by the SMB server. So mask ++ * the -EOPNOTSUPP error code. This will allow Linux SMB ++ * client to send SMB OPEN request to server. If server ++ * does not support this reparse point too then server ++ * will return error during open the path. ++ */ ++ if (rc == -EOPNOTSUPP) ++ rc = 0; + } + break; + } +diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c +index bb246ef0458fb5..b6556fe3dfa11a 100644 +--- a/fs/smb/client/reparse.c ++++ b/fs/smb/client/reparse.c +@@ -633,8 +633,6 @@ int parse_reparse_point(struct reparse_data_buffer *buf, + const char *full_path, + bool unicode, struct cifs_open_info_data *data) + { +- struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); +- + data->reparse.buf = buf; + + /* See MS-FSCC 2.1.2 */ +@@ -658,8 +656,6 @@ int parse_reparse_point(struct reparse_data_buffer *buf, + } + return 0; + default: +- cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n", +- le32_to_cpu(buf->ReparseTag)); + return -EOPNOTSUPP; + } + } +diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c +index 677ef6f99a5be4..fadc5fc274eb28 100644 +--- a/fs/smb/client/smb2misc.c ++++ b/fs/smb/client/smb2misc.c +@@ -816,11 +816,12 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid, + WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative"); + spin_unlock(&cifs_tcp_ses_lock); + +- if (tcon->ses) ++ if (tcon->ses) { + server = tcon->ses->server; +- +- cifs_server_dbg(FYI, "tid=0x%x: tcon is closing, skipping async close retry of fid %llu %llu\n", +- tcon->tid, persistent_fid, volatile_fid); ++ cifs_server_dbg(FYI, ++ "tid=0x%x: tcon is closing, skipping async close retry of fid %llu %llu\n", ++ tcon->tid, persistent_fid, volatile_fid); ++ } + + return 0; + } +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index 371a5ead86635d..5a5277b4b53b11 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -129,14 +129,6 @@ static void free_opinfo(struct oplock_info *opinfo) + kfree(opinfo); + } + +-static inline void opinfo_free_rcu(struct rcu_head *rcu_head) +-{ +- struct oplock_info *opinfo; +- +- opinfo = container_of(rcu_head, struct oplock_info, rcu_head); +- free_opinfo(opinfo); +-} +- + struct oplock_info *opinfo_get(struct ksmbd_file *fp) + { + struct oplock_info *opinfo; +@@ -157,8 +149,8 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) + if (list_empty(&ci->m_op_list)) + return NULL; + +- rcu_read_lock(); +- opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info, ++ down_read(&ci->m_lock); ++ opinfo = list_first_entry(&ci->m_op_list, struct oplock_info, + op_entry); + if (opinfo) { + if (opinfo->conn == NULL || +@@ -171,8 +163,7 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) + } + } + } +- +- rcu_read_unlock(); ++ up_read(&ci->m_lock); + + return opinfo; + } +@@ -185,7 +176,7 @@ void opinfo_put(struct oplock_info *opinfo) + if (!atomic_dec_and_test(&opinfo->refcount)) + return; + +- call_rcu(&opinfo->rcu_head, opinfo_free_rcu); ++ free_opinfo(opinfo); + } + + static void opinfo_add(struct oplock_info *opinfo) +@@ -193,7 +184,7 @@ static void opinfo_add(struct oplock_info *opinfo) + struct ksmbd_inode *ci = opinfo->o_fp->f_ci; + + down_write(&ci->m_lock); +- list_add_rcu(&opinfo->op_entry, &ci->m_op_list); ++ list_add(&opinfo->op_entry, &ci->m_op_list); + up_write(&ci->m_lock); + } + +@@ -207,7 +198,7 @@ static void opinfo_del(struct oplock_info *opinfo) + write_unlock(&lease_list_lock); + } + down_write(&ci->m_lock); +- list_del_rcu(&opinfo->op_entry); ++ list_del(&opinfo->op_entry); + up_write(&ci->m_lock); + } + +@@ -1347,8 +1338,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, + ci = fp->f_ci; + op = opinfo_get(fp); + +- rcu_read_lock(); +- list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) { ++ down_read(&ci->m_lock); ++ list_for_each_entry(brk_op, &ci->m_op_list, op_entry) { + if (brk_op->conn == NULL) + continue; + +@@ -1358,7 +1349,6 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, + if (ksmbd_conn_releasing(brk_op->conn)) + continue; + +- rcu_read_unlock(); + if (brk_op->is_lease && (brk_op->o_lease->state & + (~(SMB2_LEASE_READ_CACHING_LE | + SMB2_LEASE_HANDLE_CACHING_LE)))) { +@@ -1388,9 +1378,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, + oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE, NULL); + next: + opinfo_put(brk_op); +- rcu_read_lock(); + } +- rcu_read_unlock(); ++ up_read(&ci->m_lock); + + if (op) + opinfo_put(op); +diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h +index 59554b73f60c26..0fe931485465ac 100644 +--- a/fs/smb/server/oplock.h ++++ b/fs/smb/server/oplock.h +@@ -78,7 +78,6 @@ struct oplock_info { + struct list_head lease_entry; + wait_queue_head_t oplock_q; /* Other server threads */ + wait_queue_head_t oplock_brk; /* oplock breaking wait */ +- struct rcu_head rcu_head; + }; + + struct lease_break_info { +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 8877f9e900b2fb..d41d67ec5ee51a 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -1599,8 +1599,10 @@ static int krb5_authenticate(struct ksmbd_work *work, + if (prev_sess_id && prev_sess_id != sess->id) + destroy_previous_session(conn, sess->user, prev_sess_id); + +- if (sess->state == SMB2_SESSION_VALID) ++ if (sess->state == SMB2_SESSION_VALID) { + ksmbd_free_user(sess->user); ++ sess->user = NULL; ++ } + + retval = ksmbd_krb5_authenticate(sess, in_blob, in_len, + out_blob, &out_len); +diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c +index 2d7cd7f42f2785..281101fd1f76f1 100644 +--- a/fs/smb/server/transport_ipc.c ++++ b/fs/smb/server/transport_ipc.c +@@ -296,7 +296,11 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req) + server_conf.signing = req->signing; + server_conf.tcp_port = req->tcp_port; + server_conf.ipc_timeout = req->ipc_timeout * HZ; +- server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL; ++ if (check_mul_overflow(req->deadtime, SMB_ECHO_INTERVAL, ++ &server_conf.deadtime)) { ++ ret = -EINVAL; ++ goto out; ++ } + server_conf.share_fake_fscaps = req->share_fake_fscaps; + ksmbd_init_domain(req->sub_auth); + +@@ -322,6 +326,7 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req) + ret |= ksmbd_set_work_group(req->work_group); + ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req), + req->ifc_list_sz); ++out: + if (ret) { + pr_err("Server configuration error: %s %s %s\n", + req->netbios_name, req->server_string, +diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c +index d0c19ad9d0145c..fa5b7e63eb832e 100644 +--- a/fs/smb/server/vfs.c ++++ b/fs/smb/server/vfs.c +@@ -496,7 +496,8 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, + int err = 0; + + if (work->conn->connection_type) { +- if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) { ++ if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE)) || ++ S_ISDIR(file_inode(fp->filp)->i_mode)) { + pr_err("no right to write(%pD)\n", fp->filp); + err = -EACCES; + goto out; +diff --git a/fs/udf/inode.c b/fs/udf/inode.c +index e98c198f85b964..2f73119c7ec98a 100644 +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -814,6 +814,7 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) + } + map->oflags = UDF_BLK_MAPPED; + map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc, offset); ++ ret = 0; + goto out_free; + } + +diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c +index 5d3e595f9da96a..5ceb1fa8eb1149 100644 +--- a/fs/userfaultfd.c ++++ b/fs/userfaultfd.c +@@ -451,32 +451,6 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason) + if (!(vmf->flags & FAULT_FLAG_USER) && (ctx->flags & UFFD_USER_MODE_ONLY)) + goto out; + +- /* +- * If it's already released don't get it. This avoids to loop +- * in __get_user_pages if userfaultfd_release waits on the +- * caller of handle_userfault to release the mmap_lock. +- */ +- if (unlikely(READ_ONCE(ctx->released))) { +- /* +- * Don't return VM_FAULT_SIGBUS in this case, so a non +- * cooperative manager can close the uffd after the +- * last UFFDIO_COPY, without risking to trigger an +- * involuntary SIGBUS if the process was starting the +- * userfaultfd while the userfaultfd was still armed +- * (but after the last UFFDIO_COPY). If the uffd +- * wasn't already closed when the userfault reached +- * this point, that would normally be solved by +- * userfaultfd_must_wait returning 'false'. +- * +- * If we were to return VM_FAULT_SIGBUS here, the non +- * cooperative manager would be instead forced to +- * always call UFFDIO_UNREGISTER before it can safely +- * close the uffd. +- */ +- ret = VM_FAULT_NOPAGE; +- goto out; +- } +- + /* + * Check that we can return VM_FAULT_RETRY. + * +@@ -513,6 +487,31 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason) + if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT) + goto out; + ++ if (unlikely(READ_ONCE(ctx->released))) { ++ /* ++ * If a concurrent release is detected, do not return ++ * VM_FAULT_SIGBUS or VM_FAULT_NOPAGE, but instead always ++ * return VM_FAULT_RETRY with lock released proactively. ++ * ++ * If we were to return VM_FAULT_SIGBUS here, the non ++ * cooperative manager would be instead forced to ++ * always call UFFDIO_UNREGISTER before it can safely ++ * close the uffd, to avoid involuntary SIGBUS triggered. ++ * ++ * If we were to return VM_FAULT_NOPAGE, it would work for ++ * the fault path, in which the lock will be released ++ * later. However for GUP, faultin_page() does nothing ++ * special on NOPAGE, so GUP would spin retrying without ++ * releasing the mmap read lock, causing possible livelock. ++ * ++ * Here only VM_FAULT_RETRY would make sure the mmap lock ++ * be released immediately, so that the thread concurrently ++ * releasing the userfault would always make progress. ++ */ ++ release_fault_lock(vmf); ++ goto out; ++ } ++ + /* take the reference before dropping the mmap_lock */ + userfaultfd_ctx_get(ctx); + +diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h +index 3ae19892229db2..07e9a451262b66 100644 +--- a/include/drm/drm_kunit_helpers.h ++++ b/include/drm/drm_kunit_helpers.h +@@ -9,7 +9,11 @@ + + #include + ++struct drm_crtc_funcs; ++struct drm_crtc_helper_funcs; + struct drm_device; ++struct drm_plane_funcs; ++struct drm_plane_helper_funcs; + struct kunit; + + struct device *drm_kunit_helper_alloc_device(struct kunit *test); +@@ -99,4 +103,28 @@ drm_kunit_helper_atomic_state_alloc(struct kunit *test, + struct drm_device *drm, + struct drm_modeset_acquire_ctx *ctx); + ++struct drm_plane * ++drm_kunit_helper_create_primary_plane(struct kunit *test, ++ struct drm_device *drm, ++ const struct drm_plane_funcs *funcs, ++ const struct drm_plane_helper_funcs *helper_funcs, ++ const uint32_t *formats, ++ unsigned int num_formats, ++ const uint64_t *modifiers); ++ ++struct drm_crtc * ++drm_kunit_helper_create_crtc(struct kunit *test, ++ struct drm_device *drm, ++ struct drm_plane *primary, ++ struct drm_plane *cursor, ++ const struct drm_crtc_funcs *funcs, ++ const struct drm_crtc_helper_funcs *helper_funcs); ++ ++int drm_kunit_add_mode_destroy_action(struct kunit *test, ++ struct drm_display_mode *mode); ++ ++struct drm_display_mode * ++drm_kunit_display_mode_from_cea_vic(struct kunit *test, struct drm_device *dev, ++ u8 video_code); ++ + #endif // DRM_KUNIT_HELPERS_H_ +diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h +index 1a97277f99b1b8..ae8c46ad92222e 100644 +--- a/include/linux/backing-dev.h ++++ b/include/linux/backing-dev.h +@@ -250,6 +250,7 @@ static inline struct bdi_writeback *inode_to_wb(const struct inode *inode) + { + #ifdef CONFIG_LOCKDEP + WARN_ON_ONCE(debug_locks && ++ (inode->i_sb->s_iflags & SB_I_CGROUPWB) && + (!lockdep_is_held(&inode->i_lock) && + !lockdep_is_held(&inode->i_mapping->i_pages.xa_lock) && + !lockdep_is_held(&inode->i_wb->list_lock))); +diff --git a/include/linux/hid.h b/include/linux/hid.h +index 774cb25dec34c5..38e161a827bde9 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -1214,10 +1214,19 @@ void hid_quirks_exit(__u16 bus); + + #ifdef CONFIG_HID_PID + int hid_pidff_init(struct hid_device *hid); ++int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks); + #else + #define hid_pidff_init NULL ++#define hid_pidff_init_with_quirks NULL + #endif + ++/* HID PIDFF quirks */ ++#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0) ++#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1) ++#define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2) ++#define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(3) ++#define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY BIT(4) ++ + #define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__) + + #define hid_err(hid, fmt, ...) \ +diff --git a/include/linux/nfs.h b/include/linux/nfs.h +index ceb70a926b95e8..095a95c1fae826 100644 +--- a/include/linux/nfs.h ++++ b/include/linux/nfs.h +@@ -46,7 +46,6 @@ enum nfs3_stable_how { + NFS_INVALID_STABLE_HOW = -1 + }; + +-#ifdef CONFIG_CRC32 + /** + * nfs_fhandle_hash - calculate the crc32 hash for the filehandle + * @fh - pointer to filehandle +@@ -58,10 +57,4 @@ static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh) + { + return ~crc32_le(0xFFFFFFFF, &fh->data[0], fh->size); + } +-#else /* CONFIG_CRC32 */ +-static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh) +-{ +- return 0; +-} +-#endif /* CONFIG_CRC32 */ + #endif /* _LINUX_NFS_H */ +diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h +index 3c3a7dede0ef5b..e2c9a0c259df3b 100644 +--- a/include/linux/pgtable.h ++++ b/include/linux/pgtable.h +@@ -194,10 +194,14 @@ static inline int pmd_young(pmd_t pmd) + * hazard could result in the direct mode hypervisor case, since the actual + * write to the page tables may not yet have taken place, so reads though + * a raw PTE pointer after it has been modified are not guaranteed to be +- * up to date. This mode can only be entered and left under the protection of +- * the page table locks for all page tables which may be modified. In the UP +- * case, this is required so that preemption is disabled, and in the SMP case, +- * it must synchronize the delayed page table writes properly on other CPUs. ++ * up to date. ++ * ++ * In the general case, no lock is guaranteed to be held between entry and exit ++ * of the lazy mode. So the implementation must assume preemption may be enabled ++ * and cpu migration is possible; it must take steps to be robust against this. ++ * (In practice, for user PTE updates, the appropriate page table lock(s) are ++ * held, but for kernel PTE updates, no lock is held). Nesting is not permitted ++ * and the mode cannot be used in interrupt context. + */ + #ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE + #define arch_enter_lazy_mmu_mode() do {} while (0) +@@ -233,7 +237,6 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, + { + page_table_check_ptes_set(mm, ptep, pte, nr); + +- arch_enter_lazy_mmu_mode(); + for (;;) { + set_pte(ptep, pte); + if (--nr == 0) +@@ -241,7 +244,6 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, + ptep++; + pte = pte_next_pfn(pte); + } +- arch_leave_lazy_mmu_mode(); + } + #endif + #define set_pte_at(mm, addr, ptep, pte) set_ptes(mm, addr, ptep, pte, 1) +diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h +index 3d6cf306cd55e9..0cbbbded033194 100644 +--- a/include/linux/rtnetlink.h ++++ b/include/linux/rtnetlink.h +@@ -130,4 +130,26 @@ extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + + extern void rtnl_offload_xstats_notify(struct net_device *dev); + ++static inline int rtnl_has_listeners(const struct net *net, u32 group) ++{ ++ struct sock *rtnl = net->rtnl; ++ ++ return netlink_has_listeners(rtnl, group); ++} ++ ++/** ++ * rtnl_notify_needed - check if notification is needed ++ * @net: Pointer to the net namespace ++ * @nlflags: netlink ingress message flags ++ * @group: rtnl group ++ * ++ * Based on the ingress message flags and rtnl group, returns true ++ * if a notification is needed, false otherwise. ++ */ ++static inline bool ++rtnl_notify_needed(const struct net *net, u16 nlflags, u32 group) ++{ ++ return (nlflags & NLM_F_ECHO) || rtnl_has_listeners(net, group); ++} ++ + #endif /* __LINUX_RTNETLINK_H */ +diff --git a/include/linux/tpm.h b/include/linux/tpm.h +index 4ee9d13749adc1..5f4998626a9889 100644 +--- a/include/linux/tpm.h ++++ b/include/linux/tpm.h +@@ -272,6 +272,7 @@ enum tpm2_cc_attrs { + #define TPM_VID_WINBOND 0x1050 + #define TPM_VID_STM 0x104A + #define TPM_VID_ATML 0x1114 ++#define TPM_VID_IFX 0x15D1 + + enum tpm_chip_flags { + TPM_CHIP_FLAG_BOOTSTRAPPED = BIT(0), +diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h +index 5a24d6d8522af9..d943bb454b1769 100644 +--- a/include/net/sctp/structs.h ++++ b/include/net/sctp/structs.h +@@ -778,6 +778,7 @@ struct sctp_transport { + + /* Reference counting. */ + refcount_t refcnt; ++ __u32 dead:1, + /* RTO-Pending : A flag used to track if one of the DATA + * chunks sent to this address is currently being + * used to compute a RTT. If this flag is 0, +@@ -787,7 +788,7 @@ struct sctp_transport { + * calculation completes (i.e. the DATA chunk + * is SACK'd) clear this flag. + */ +- __u32 rto_pending:1, ++ rto_pending:1, + + /* + * hb_sent : a flag that signals that we have a pending +diff --git a/include/net/xdp.h b/include/net/xdp.h +index de08c8e0d13483..b39ac83618a550 100644 +--- a/include/net/xdp.h ++++ b/include/net/xdp.h +@@ -486,7 +486,14 @@ static __always_inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog, + * under local_bh_disable(), which provides the needed RCU protection + * for accessing map entries. + */ +- u32 act = __bpf_prog_run(prog, xdp, BPF_DISPATCHER_FUNC(xdp)); ++ struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); ++ u32 act; ++ ++ if (ri->map_id || ri->map_type) { ++ ri->map_id = 0; ++ ri->map_type = BPF_MAP_TYPE_UNSPEC; ++ } ++ act = __bpf_prog_run(prog, xdp, BPF_DISPATCHER_FUNC(xdp)); + + if (static_branch_unlikely(&bpf_master_redirect_enabled_key)) { + if (act == XDP_TX && netif_is_bond_slave(xdp->rxq->dev)) +diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h +index cd924c959d7327..1f753e72fa2c24 100644 +--- a/include/uapi/linux/kfd_ioctl.h ++++ b/include/uapi/linux/kfd_ioctl.h +@@ -58,6 +58,8 @@ struct kfd_ioctl_get_version_args { + #define KFD_MAX_QUEUE_PERCENTAGE 100 + #define KFD_MAX_QUEUE_PRIORITY 15 + ++#define KFD_MIN_QUEUE_RING_SIZE 1024 ++ + struct kfd_ioctl_create_queue_args { + __u64 ring_base_address; /* to KFD */ + __u64 write_pointer_address; /* from KFD */ +diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h +index 81d09ef9aa50e9..f82a66361a1ed5 100644 +--- a/include/uapi/linux/landlock.h ++++ b/include/uapi/linux/landlock.h +@@ -38,9 +38,11 @@ struct landlock_ruleset_attr { + * + * - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI + * version. ++ * - %LANDLOCK_CREATE_RULESET_ERRATA: Get a bitmask of fixed issues. + */ + /* clang-format off */ + #define LANDLOCK_CREATE_RULESET_VERSION (1U << 0) ++#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1) + /* clang-format on */ + + /** +diff --git a/include/xen/interface/xen-mca.h b/include/xen/interface/xen-mca.h +index 464aa6b3a5f928..1c9afbe8cc2600 100644 +--- a/include/xen/interface/xen-mca.h ++++ b/include/xen/interface/xen-mca.h +@@ -372,7 +372,7 @@ struct xen_mce { + #define XEN_MCE_LOG_LEN 32 + + struct xen_mce_log { +- char signature[12]; /* "MACHINECHECK" */ ++ char signature[12] __nonstring; /* "MACHINECHECK" */ + unsigned len; /* = XEN_MCE_LOG_LEN */ + unsigned next; + unsigned flags; +diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c +index 0d9b8a8b42c278..8c6611fe4f4633 100644 +--- a/io_uring/kbuf.c ++++ b/io_uring/kbuf.c +@@ -321,6 +321,8 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe + p->nbufs = tmp; + p->addr = READ_ONCE(sqe->addr); + p->len = READ_ONCE(sqe->len); ++ if (!p->len) ++ return -EINVAL; + + if (check_mul_overflow((unsigned long)p->len, (unsigned long)p->nbufs, + &size)) +diff --git a/io_uring/net.c b/io_uring/net.c +index 1a0e98e19dc0ed..4948a67bbac480 100644 +--- a/io_uring/net.c ++++ b/io_uring/net.c +@@ -1438,6 +1438,8 @@ int io_accept(struct io_kiocb *req, unsigned int issue_flags) + goto retry; + + io_req_set_res(req, ret, 0); ++ if (!(issue_flags & IO_URING_F_MULTISHOT)) ++ return IOU_OK; + return IOU_STOP_MULTISHOT; + } + +diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index 3468d8230e5f75..9419a79e8833ff 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -6141,6 +6141,9 @@ static void zap_class(struct pending_free *pf, struct lock_class *class) + hlist_del_rcu(&class->hash_entry); + WRITE_ONCE(class->key, NULL); + WRITE_ONCE(class->name, NULL); ++ /* Class allocated but not used, -1 in nr_unused_locks */ ++ if (class->usage_mask == 0) ++ debug_atomic_dec(nr_unused_locks); + nr_lock_classes--; + __clear_bit(class - lock_classes, lock_classes_in_use); + if (class - lock_classes == max_lock_class_idx) +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index a49f136014ce6b..259521b179aa11 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -83,7 +83,7 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) + + if (unlikely(sg_policy->limits_changed)) { + sg_policy->limits_changed = false; +- sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS); ++ sg_policy->need_freq_update = true; + return true; + } + +@@ -95,10 +95,22 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) + static bool sugov_update_next_freq(struct sugov_policy *sg_policy, u64 time, + unsigned int next_freq) + { +- if (sg_policy->need_freq_update) ++ if (sg_policy->need_freq_update) { + sg_policy->need_freq_update = false; +- else if (sg_policy->next_freq == next_freq) ++ /* ++ * The policy limits have changed, but if the return value of ++ * cpufreq_driver_resolve_freq() after applying the new limits ++ * is still equal to the previously selected frequency, the ++ * driver callback need not be invoked unless the driver ++ * specifically wants that to happen on every update of the ++ * policy limits. ++ */ ++ if (sg_policy->next_freq == next_freq && ++ !cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS)) ++ return false; ++ } else if (sg_policy->next_freq == next_freq) { + return false; ++ } + + sg_policy->next_freq = next_freq; + sg_policy->last_freq_update_time = time; +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 99fdeee3bcd87a..650493ed76cd40 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -5420,9 +5420,10 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr) + + /* Make a copy hash to place the new and the old entries in */ + size = hash->count + direct_functions->count; +- if (size > 32) +- size = 32; +- new_hash = alloc_ftrace_hash(fls(size)); ++ size = fls(size); ++ if (size > FTRACE_HASH_MAX_BITS) ++ size = FTRACE_HASH_MAX_BITS; ++ new_hash = alloc_ftrace_hash(size); + if (!new_hash) + goto out_unlock; + +@@ -6325,6 +6326,7 @@ ftrace_graph_set_hash(struct ftrace_hash *hash, char *buffer) + } + } + } ++ cond_resched(); + } while_for_each_ftrace_rec(); + out: + mutex_unlock(&ftrace_lock); +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 562efd66857267..1a936978c2b1a6 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -790,7 +790,9 @@ static int __ftrace_event_enable_disable(struct trace_event_file *file, + clear_bit(EVENT_FILE_FL_RECORDED_TGID_BIT, &file->flags); + } + +- call->class->reg(call, TRACE_REG_UNREGISTER, file); ++ ret = call->class->reg(call, TRACE_REG_UNREGISTER, file); ++ ++ WARN_ON_ONCE(ret); + } + /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT, else clear it */ + if (file->flags & EVENT_FILE_FL_SOFT_MODE) +diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c +index 0c611b281a5b5f..f50c2ad43f3d82 100644 +--- a/kernel/trace/trace_events_filter.c ++++ b/kernel/trace/trace_events_filter.c +@@ -808,7 +808,7 @@ static __always_inline char *test_string(char *str) + kstr = ubuf->buffer; + + /* For safety, do not trust the string pointer */ +- if (!strncpy_from_kernel_nofault(kstr, str, USTRING_BUF_SIZE)) ++ if (strncpy_from_kernel_nofault(kstr, str, USTRING_BUF_SIZE) < 0) + return NULL; + return kstr; + } +@@ -827,7 +827,7 @@ static __always_inline char *test_ustring(char *str) + + /* user space address? */ + ustr = (char __user *)str; +- if (!strncpy_from_user_nofault(kstr, ustr, USTRING_BUF_SIZE)) ++ if (strncpy_from_user_nofault(kstr, ustr, USTRING_BUF_SIZE) < 0) + return NULL; + + return kstr; +diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c +index ccd6703ac50b71..794e72dbb12d33 100644 +--- a/kernel/trace/trace_events_synth.c ++++ b/kernel/trace/trace_events_synth.c +@@ -377,7 +377,6 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, + union trace_synth_field *data = &entry->fields[n_u64]; + + trace_seq_printf(s, print_fmt, se->fields[i]->name, +- STR_VAR_LEN_MAX, + (char *)entry + data->as_dynamic.offset, + i == se->n_fields - 1 ? "" : " "); + n_u64++; +diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c +index 8c73156a7eb94c..606190239c8776 100644 +--- a/kernel/trace/trace_probe.c ++++ b/kernel/trace/trace_probe.c +@@ -769,6 +769,10 @@ static int check_prepare_btf_string_fetch(char *typename, + + #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API + ++/* ++ * Add the entry code to store the 'argnum'th parameter and return the offset ++ * in the entry data buffer where the data will be stored. ++ */ + static int __store_entry_arg(struct trace_probe *tp, int argnum) + { + struct probe_entry_arg *earg = tp->entry_arg; +@@ -792,6 +796,20 @@ static int __store_entry_arg(struct trace_probe *tp, int argnum) + tp->entry_arg = earg; + } + ++ /* ++ * The entry code array is repeating the pair of ++ * [FETCH_OP_ARG(argnum)][FETCH_OP_ST_EDATA(offset of entry data buffer)] ++ * and the rest of entries are filled with [FETCH_OP_END]. ++ * ++ * To reduce the redundant function parameter fetching, we scan the entry ++ * code array to find the FETCH_OP_ARG which already fetches the 'argnum' ++ * parameter. If it doesn't match, update 'offset' to find the last ++ * offset. ++ * If we find the FETCH_OP_END without matching FETCH_OP_ARG entry, we ++ * will save the entry with FETCH_OP_ARG and FETCH_OP_ST_EDATA, and ++ * return data offset so that caller can find the data offset in the entry ++ * data buffer. ++ */ + offset = 0; + for (i = 0; i < earg->size - 1; i++) { + switch (earg->code[i].op) { +@@ -825,6 +843,16 @@ int traceprobe_get_entry_data_size(struct trace_probe *tp) + if (!earg) + return 0; + ++ /* ++ * earg->code[] array has an operation sequence which is run in ++ * the entry handler. ++ * The sequence stopped by FETCH_OP_END and each data stored in ++ * the entry data buffer by FETCH_OP_ST_EDATA. The FETCH_OP_ST_EDATA ++ * stores the data at the data buffer + its offset, and all data are ++ * "unsigned long" size. The offset must be increased when a data is ++ * stored. Thus we need to find the last FETCH_OP_ST_EDATA in the ++ * code array. ++ */ + for (i = 0; i < earg->size; i++) { + switch (earg->code[i].op) { + case FETCH_OP_END: +diff --git a/lib/sg_split.c b/lib/sg_split.c +index 60a0babebf2efc..0f89aab5c6715b 100644 +--- a/lib/sg_split.c ++++ b/lib/sg_split.c +@@ -88,8 +88,6 @@ static void sg_split_phys(struct sg_splitter *splitters, const int nb_splits) + if (!j) { + out_sg->offset += split->skip_sg0; + out_sg->length -= split->skip_sg0; +- } else { +- out_sg->offset = 0; + } + sg_dma_address(out_sg) = 0; + sg_dma_len(out_sg) = 0; +diff --git a/lib/string.c b/lib/string.c +index be26623953d2e6..d49243af5bf215 100644 +--- a/lib/string.c ++++ b/lib/string.c +@@ -128,6 +128,7 @@ ssize_t strscpy(char *dest, const char *src, size_t count) + if (count == 0 || WARN_ON_ONCE(count > INT_MAX)) + return -E2BIG; + ++#ifndef CONFIG_DCACHE_WORD_ACCESS + #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + /* + * If src is unaligned, don't cross a page boundary, +@@ -142,12 +143,14 @@ ssize_t strscpy(char *dest, const char *src, size_t count) + /* If src or dest is unaligned, don't do word-at-a-time. */ + if (((long) dest | (long) src) & (sizeof(long) - 1)) + max = 0; ++#endif + #endif + + /* +- * read_word_at_a_time() below may read uninitialized bytes after the +- * trailing zero and use them in comparisons. Disable this optimization +- * under KMSAN to prevent false positive reports. ++ * load_unaligned_zeropad() or read_word_at_a_time() below may read ++ * uninitialized bytes after the trailing zero and use them in ++ * comparisons. Disable this optimization under KMSAN to prevent ++ * false positive reports. + */ + if (IS_ENABLED(CONFIG_KMSAN)) + max = 0; +@@ -155,7 +158,11 @@ ssize_t strscpy(char *dest, const char *src, size_t count) + while (max >= sizeof(unsigned long)) { + unsigned long c, data; + ++#ifdef CONFIG_DCACHE_WORD_ACCESS ++ c = load_unaligned_zeropad(src+res); ++#else + c = read_word_at_a_time(src+res); ++#endif + if (has_zero(c, &data, &constants)) { + data = prep_zero_mask(c, data, &constants); + data = create_zero_mask(data); +diff --git a/lib/zstd/common/portability_macros.h b/lib/zstd/common/portability_macros.h +index 0e3b2c0a527db7..0dde8bf56595ea 100644 +--- a/lib/zstd/common/portability_macros.h ++++ b/lib/zstd/common/portability_macros.h +@@ -55,7 +55,7 @@ + #ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ +- && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ ++ && (__GNUC__ >= 11))) \ + && (defined(__x86_64__) || defined(_M_X64)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 +diff --git a/mm/filemap.c b/mm/filemap.c +index d7c79a69afc88f..05eb77623a1063 100644 +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2256,6 +2256,7 @@ unsigned filemap_get_folios_contig(struct address_space *mapping, + *start = folio->index + nr; + goto out; + } ++ xas_advance(&xas, folio_next_index(folio) - 1); + continue; + put_folio: + folio_put(folio); +diff --git a/mm/gup.c b/mm/gup.c +index 69d259f7bf37ec..29c719b3ab31e1 100644 +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -1871,8 +1871,8 @@ size_t fault_in_safe_writeable(const char __user *uaddr, size_t size) + } while (start != end); + mmap_read_unlock(mm); + +- if (size > (unsigned long)uaddr - start) +- return size - ((unsigned long)uaddr - start); ++ if (size > start - (unsigned long)uaddr) ++ return size - (start - (unsigned long)uaddr); + return 0; + } + EXPORT_SYMBOL(fault_in_safe_writeable); +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index faded25b19be83..7c196b754071bd 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -4695,7 +4695,7 @@ static struct ctl_table hugetlb_table[] = { + { } + }; + +-static void hugetlb_sysctl_init(void) ++static void __init hugetlb_sysctl_init(void) + { + register_sysctl_init("vm", hugetlb_table); + } +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index 9018a1162efc9d..a96840c4158165 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -869,12 +869,17 @@ static int kill_accessing_process(struct task_struct *p, unsigned long pfn, + mmap_read_lock(p->mm); + ret = walk_page_range(p->mm, 0, TASK_SIZE, &hwpoison_walk_ops, + (void *)&priv); ++ /* ++ * ret = 1 when CMCI wins, regardless of whether try_to_unmap() ++ * succeeds or fails, then kill the process with SIGBUS. ++ * ret = 0 when poison page is a clean page and it's dropped, no ++ * SIGBUS is needed. ++ */ + if (ret == 1 && priv.tk.addr) + kill_proc(&priv.tk, pfn, flags); +- else +- ret = 0; + mmap_read_unlock(p->mm); +- return ret > 0 ? -EHWPOISON : -EFAULT; ++ ++ return ret > 0 ? -EHWPOISON : 0; + } + + static const char *action_name[] = { +diff --git a/mm/memory.c b/mm/memory.c +index d04faa09eaf6cc..8b80db7115e5fe 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2600,11 +2600,11 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, + if (fn) { + do { + if (create || !pte_none(ptep_get(pte))) { +- err = fn(pte++, addr, data); ++ err = fn(pte, addr, data); + if (err) + break; + } +- } while (addr += PAGE_SIZE, addr != end); ++ } while (pte++, addr += PAGE_SIZE, addr != end); + } + *mask |= PGTBL_PTE_MODIFIED; + +diff --git a/mm/mremap.c b/mm/mremap.c +index df71010baabe7e..d458ef218a3725 100644 +--- a/mm/mremap.c ++++ b/mm/mremap.c +@@ -599,8 +599,8 @@ static unsigned long move_vma(struct vm_area_struct *vma, + unsigned long vm_flags = vma->vm_flags; + unsigned long new_pgoff; + unsigned long moved_len; +- unsigned long account_start = 0; +- unsigned long account_end = 0; ++ bool account_start = false; ++ bool account_end = false; + unsigned long hiwater_vm; + int err = 0; + bool need_rmap_locks; +@@ -684,9 +684,9 @@ static unsigned long move_vma(struct vm_area_struct *vma, + if (vm_flags & VM_ACCOUNT && !(flags & MREMAP_DONTUNMAP)) { + vm_flags_clear(vma, VM_ACCOUNT); + if (vma->vm_start < old_addr) +- account_start = vma->vm_start; ++ account_start = true; + if (vma->vm_end > old_addr + old_len) +- account_end = vma->vm_end; ++ account_end = true; + } + + /* +@@ -726,7 +726,7 @@ static unsigned long move_vma(struct vm_area_struct *vma, + /* OOM: unable to split vma, just get accounts right */ + if (vm_flags & VM_ACCOUNT && !(flags & MREMAP_DONTUNMAP)) + vm_acct_memory(old_len >> PAGE_SHIFT); +- account_start = account_end = 0; ++ account_start = account_end = false; + } + + if (vm_flags & VM_LOCKED) { +diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c +index e0b368e545ed00..dcc1ee3d059e92 100644 +--- a/mm/page_vma_mapped.c ++++ b/mm/page_vma_mapped.c +@@ -77,6 +77,7 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw, spinlock_t **ptlp) + * mapped at the @pvmw->pte + * @pvmw: page_vma_mapped_walk struct, includes a pair pte and pfn range + * for checking ++ * @pte_nr: the number of small pages described by @pvmw->pte. + * + * page_vma_mapped_walk() found a place where pfn range is *potentially* + * mapped. check_pte() has to validate this. +@@ -93,7 +94,7 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw, spinlock_t **ptlp) + * Otherwise, return false. + * + */ +-static bool check_pte(struct page_vma_mapped_walk *pvmw) ++static bool check_pte(struct page_vma_mapped_walk *pvmw, unsigned long pte_nr) + { + unsigned long pfn; + pte_t ptent = ptep_get(pvmw->pte); +@@ -126,7 +127,11 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw) + pfn = pte_pfn(ptent); + } + +- return (pfn - pvmw->pfn) < pvmw->nr_pages; ++ if ((pfn + pte_nr - 1) < pvmw->pfn) ++ return false; ++ if (pfn > (pvmw->pfn + pvmw->nr_pages - 1)) ++ return false; ++ return true; + } + + /* Returns true if the two ranges overlap. Careful to not overflow. */ +@@ -201,7 +206,7 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw) + return false; + + pvmw->ptl = huge_pte_lock(hstate, mm, pvmw->pte); +- if (!check_pte(pvmw)) ++ if (!check_pte(pvmw, pages_per_huge_page(hstate))) + return not_found(pvmw); + return true; + } +@@ -283,7 +288,7 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw) + goto next_pte; + } + this_pte: +- if (check_pte(pvmw)) ++ if (check_pte(pvmw, 1)) + return true; + next_pte: + do { +diff --git a/mm/rmap.c b/mm/rmap.c +index 9f795b93cf40f5..968b85a67b1a11 100644 +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -2296,7 +2296,7 @@ static bool folio_make_device_exclusive(struct folio *folio, + * Restrict to anonymous folios for now to avoid potential writeback + * issues. + */ +- if (!folio_test_anon(folio)) ++ if (!folio_test_anon(folio) || folio_test_hugetlb(folio)) + return false; + + rmap_walk(folio, &rwc); +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 49456b72575529..258f5472f1e900 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -8115,7 +8115,7 @@ int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) + return NODE_RECLAIM_NOSCAN; + + ret = __node_reclaim(pgdat, gfp_mask, order); +- clear_bit(PGDAT_RECLAIM_LOCKED, &pgdat->flags); ++ clear_bit_unlock(PGDAT_RECLAIM_LOCKED, &pgdat->flags); + + if (!ret) + count_vm_event(PGSCAN_ZONE_RECLAIM_FAILED); +diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c +index 2a7f1b15714ab9..e9326f322d7a27 100644 +--- a/net/8021q/vlan_dev.c ++++ b/net/8021q/vlan_dev.c +@@ -273,17 +273,6 @@ static int vlan_dev_open(struct net_device *dev) + goto out; + } + +- if (dev->flags & IFF_ALLMULTI) { +- err = dev_set_allmulti(real_dev, 1); +- if (err < 0) +- goto del_unicast; +- } +- if (dev->flags & IFF_PROMISC) { +- err = dev_set_promiscuity(real_dev, 1); +- if (err < 0) +- goto clear_allmulti; +- } +- + ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr); + + if (vlan->flags & VLAN_FLAG_GVRP) +@@ -297,12 +286,6 @@ static int vlan_dev_open(struct net_device *dev) + netif_carrier_on(dev); + return 0; + +-clear_allmulti: +- if (dev->flags & IFF_ALLMULTI) +- dev_set_allmulti(real_dev, -1); +-del_unicast: +- if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) +- dev_uc_del(real_dev, dev->dev_addr); + out: + netif_carrier_off(dev); + return err; +@@ -315,10 +298,6 @@ static int vlan_dev_stop(struct net_device *dev) + + dev_mc_unsync(real_dev, dev); + dev_uc_unsync(real_dev, dev); +- if (dev->flags & IFF_ALLMULTI) +- dev_set_allmulti(real_dev, -1); +- if (dev->flags & IFF_PROMISC) +- dev_set_promiscuity(real_dev, -1); + + if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) + dev_uc_del(real_dev, dev->dev_addr); +@@ -490,12 +469,10 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change) + { + struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; + +- if (dev->flags & IFF_UP) { +- if (change & IFF_ALLMULTI) +- dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); +- if (change & IFF_PROMISC) +- dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); +- } ++ if (change & IFF_ALLMULTI) ++ dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); ++ if (change & IFF_PROMISC) ++ dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); + } + + static void vlan_dev_set_rx_mode(struct net_device *vlan_dev) +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 1e689d8c00a509..4029330e29a998 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -6149,11 +6149,12 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, + * event or send an immediate device found event if the data + * should not be stored for later. + */ +- if (!ext_adv && !has_pending_adv_report(hdev)) { ++ if (!has_pending_adv_report(hdev)) { + /* If the report will trigger a SCAN_REQ store it for + * later merging. + */ +- if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { ++ if (!ext_adv && (type == LE_ADV_IND || ++ type == LE_ADV_SCAN_IND)) { + store_pending_adv_report(hdev, bdaddr, bdaddr_type, + rssi, flags, data, len); + return; +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 8d6fc186950334..d4dcdb2370cc98 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -3954,7 +3954,8 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, + + /* Check if the ACL is secure enough (if not SDP) */ + if (psm != cpu_to_le16(L2CAP_PSM_SDP) && +- !hci_conn_check_link_mode(conn->hcon)) { ++ (!hci_conn_check_link_mode(conn->hcon) || ++ !l2cap_check_enc_key_size(conn->hcon))) { + conn->disc_reason = HCI_ERROR_AUTH_FAILURE; + result = L2CAP_CR_SEC_BLOCK; + goto response; +@@ -7509,8 +7510,24 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) + if (skb->len > len) { + BT_ERR("Frame is too long (len %u, expected len %d)", + skb->len, len); ++ /* PTS test cases L2CAP/COS/CED/BI-14-C and BI-15-C ++ * (Multiple Signaling Command in one PDU, Data ++ * Truncated, BR/EDR) send a C-frame to the IUT with ++ * PDU Length set to 8 and Channel ID set to the ++ * correct signaling channel for the logical link. ++ * The Information payload contains one L2CAP_ECHO_REQ ++ * packet with Data Length set to 0 with 0 octets of ++ * echo data and one invalid command packet due to ++ * data truncated in PDU but present in HCI packet. ++ * ++ * Shorter the socket buffer to the PDU length to ++ * allow to process valid commands from the PDU before ++ * setting the socket unreliable. ++ */ ++ skb->len = len; ++ l2cap_recv_frame(conn, skb); + l2cap_conn_unreliable(conn, ECOMM); +- goto drop; ++ goto unlock; + } + + /* Append fragment into frame (with header) */ +diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c +index be714b4d7b4307..a1c22eab71ffec 100644 +--- a/net/bridge/br_vlan.c ++++ b/net/bridge/br_vlan.c +@@ -715,8 +715,8 @@ static int br_vlan_add_existing(struct net_bridge *br, + u16 flags, bool *changed, + struct netlink_ext_ack *extack) + { +- bool would_change = __vlan_flags_would_change(vlan, flags); + bool becomes_brentry = false; ++ bool would_change = false; + int err; + + if (!br_vlan_is_brentry(vlan)) { +@@ -725,6 +725,8 @@ static int br_vlan_add_existing(struct net_bridge *br, + return -EINVAL; + + becomes_brentry = true; ++ } else { ++ would_change = __vlan_flags_would_change(vlan, flags); + } + + /* Master VLANs that aren't brentries weren't notified before, +diff --git a/net/core/filter.c b/net/core/filter.c +index 84992279f4b10e..39eef3370d800e 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -211,24 +211,36 @@ BPF_CALL_3(bpf_skb_get_nlattr_nest, struct sk_buff *, skb, u32, a, u32, x) + return 0; + } + ++static int bpf_skb_load_helper_convert_offset(const struct sk_buff *skb, int offset) ++{ ++ if (likely(offset >= 0)) ++ return offset; ++ ++ if (offset >= SKF_NET_OFF) ++ return offset - SKF_NET_OFF + skb_network_offset(skb); ++ ++ if (offset >= SKF_LL_OFF && skb_mac_header_was_set(skb)) ++ return offset - SKF_LL_OFF + skb_mac_offset(skb); ++ ++ return INT_MIN; ++} ++ + BPF_CALL_4(bpf_skb_load_helper_8, const struct sk_buff *, skb, const void *, + data, int, headlen, int, offset) + { +- u8 tmp, *ptr; ++ u8 tmp; + const int len = sizeof(tmp); + +- if (offset >= 0) { +- if (headlen - offset >= len) +- return *(u8 *)(data + offset); +- if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) +- return tmp; +- } else { +- ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len); +- if (likely(ptr)) +- return *(u8 *)ptr; +- } ++ offset = bpf_skb_load_helper_convert_offset(skb, offset); ++ if (offset == INT_MIN) ++ return -EFAULT; + +- return -EFAULT; ++ if (headlen - offset >= len) ++ return *(u8 *)(data + offset); ++ if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) ++ return tmp; ++ else ++ return -EFAULT; + } + + BPF_CALL_2(bpf_skb_load_helper_8_no_cache, const struct sk_buff *, skb, +@@ -241,21 +253,19 @@ BPF_CALL_2(bpf_skb_load_helper_8_no_cache, const struct sk_buff *, skb, + BPF_CALL_4(bpf_skb_load_helper_16, const struct sk_buff *, skb, const void *, + data, int, headlen, int, offset) + { +- __be16 tmp, *ptr; ++ __be16 tmp; + const int len = sizeof(tmp); + +- if (offset >= 0) { +- if (headlen - offset >= len) +- return get_unaligned_be16(data + offset); +- if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) +- return be16_to_cpu(tmp); +- } else { +- ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len); +- if (likely(ptr)) +- return get_unaligned_be16(ptr); +- } ++ offset = bpf_skb_load_helper_convert_offset(skb, offset); ++ if (offset == INT_MIN) ++ return -EFAULT; + +- return -EFAULT; ++ if (headlen - offset >= len) ++ return get_unaligned_be16(data + offset); ++ if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) ++ return be16_to_cpu(tmp); ++ else ++ return -EFAULT; + } + + BPF_CALL_2(bpf_skb_load_helper_16_no_cache, const struct sk_buff *, skb, +@@ -268,21 +278,19 @@ BPF_CALL_2(bpf_skb_load_helper_16_no_cache, const struct sk_buff *, skb, + BPF_CALL_4(bpf_skb_load_helper_32, const struct sk_buff *, skb, const void *, + data, int, headlen, int, offset) + { +- __be32 tmp, *ptr; ++ __be32 tmp; + const int len = sizeof(tmp); + +- if (likely(offset >= 0)) { +- if (headlen - offset >= len) +- return get_unaligned_be32(data + offset); +- if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) +- return be32_to_cpu(tmp); +- } else { +- ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len); +- if (likely(ptr)) +- return get_unaligned_be32(ptr); +- } ++ offset = bpf_skb_load_helper_convert_offset(skb, offset); ++ if (offset == INT_MIN) ++ return -EFAULT; + +- return -EFAULT; ++ if (headlen - offset >= len) ++ return get_unaligned_be32(data + offset); ++ if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) ++ return be32_to_cpu(tmp); ++ else ++ return -EFAULT; + } + + BPF_CALL_2(bpf_skb_load_helper_32_no_cache, const struct sk_buff *, skb, +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 31f923e7b5c40c..2f2f63c8cf4b07 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -865,7 +865,13 @@ static void page_pool_release_retry(struct work_struct *wq) + int inflight; + + inflight = page_pool_release(pool); +- if (!inflight) ++ /* In rare cases, a driver bug may cause inflight to go negative. ++ * Don't reschedule release if inflight is 0 or negative. ++ * - If 0, the page_pool has been destroyed ++ * - if negative, we will never recover ++ * in both cases no reschedule is necessary. ++ */ ++ if (inflight <= 0) + return; + + /* Periodic warning */ +diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c +index ccbdb98109f806..07736edc8b6a5d 100644 +--- a/net/dsa/dsa.c ++++ b/net/dsa/dsa.c +@@ -867,6 +867,16 @@ static void dsa_tree_teardown_lags(struct dsa_switch_tree *dst) + kfree(dst->lags); + } + ++static void dsa_tree_teardown_routing_table(struct dsa_switch_tree *dst) ++{ ++ struct dsa_link *dl, *next; ++ ++ list_for_each_entry_safe(dl, next, &dst->rtable, list) { ++ list_del(&dl->list); ++ kfree(dl); ++ } ++} ++ + static int dsa_tree_setup(struct dsa_switch_tree *dst) + { + bool complete; +@@ -884,7 +894,7 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst) + + err = dsa_tree_setup_cpu_ports(dst); + if (err) +- return err; ++ goto teardown_rtable; + + err = dsa_tree_setup_switches(dst); + if (err) +@@ -916,14 +926,14 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst) + dsa_tree_teardown_switches(dst); + teardown_cpu_ports: + dsa_tree_teardown_cpu_ports(dst); ++teardown_rtable: ++ dsa_tree_teardown_routing_table(dst); + + return err; + } + + static void dsa_tree_teardown(struct dsa_switch_tree *dst) + { +- struct dsa_link *dl, *next; +- + if (!dst->setup) + return; + +@@ -937,10 +947,7 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst) + + dsa_tree_teardown_cpu_ports(dst); + +- list_for_each_entry_safe(dl, next, &dst->rtable, list) { +- list_del(&dl->list); +- kfree(dl); +- } ++ dsa_tree_teardown_routing_table(dst); + + pr_info("DSA: tree %d torn down\n", dst->index); + +@@ -1483,12 +1490,44 @@ static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd) + + static void dsa_switch_release_ports(struct dsa_switch *ds) + { ++ struct dsa_mac_addr *a, *tmp; + struct dsa_port *dp, *next; ++ struct dsa_vlan *v, *n; + + dsa_switch_for_each_port_safe(dp, next, ds) { +- WARN_ON(!list_empty(&dp->fdbs)); +- WARN_ON(!list_empty(&dp->mdbs)); +- WARN_ON(!list_empty(&dp->vlans)); ++ /* These are either entries that upper layers lost track of ++ * (probably due to bugs), or installed through interfaces ++ * where one does not necessarily have to remove them, like ++ * ndo_dflt_fdb_add(). ++ */ ++ list_for_each_entry_safe(a, tmp, &dp->fdbs, list) { ++ dev_info(ds->dev, ++ "Cleaning up unicast address %pM vid %u from port %d\n", ++ a->addr, a->vid, dp->index); ++ list_del(&a->list); ++ kfree(a); ++ } ++ ++ list_for_each_entry_safe(a, tmp, &dp->mdbs, list) { ++ dev_info(ds->dev, ++ "Cleaning up multicast address %pM vid %u from port %d\n", ++ a->addr, a->vid, dp->index); ++ list_del(&a->list); ++ kfree(a); ++ } ++ ++ /* These are entries that upper layers have lost track of, ++ * probably due to bugs, but also due to dsa_port_do_vlan_del() ++ * having failed and the VLAN entry still lingering on. ++ */ ++ list_for_each_entry_safe(v, n, &dp->vlans, list) { ++ dev_info(ds->dev, ++ "Cleaning up vid %u from port %d\n", ++ v->vid, dp->index); ++ list_del(&v->list); ++ kfree(v); ++ } ++ + list_del(&dp->list); + kfree(dp); + } +diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c +index cbdfc392f7e0d9..a5420421e462ef 100644 +--- a/net/dsa/tag_8021q.c ++++ b/net/dsa/tag_8021q.c +@@ -197,7 +197,7 @@ static int dsa_port_do_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid) + + err = ds->ops->tag_8021q_vlan_del(ds, port, vid); + if (err) { +- refcount_inc(&v->refcount); ++ refcount_set(&v->refcount, 1); + return err; + } + +diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c +index c1ad63bee8eade..7a9d8fe78ae9db 100644 +--- a/net/ethtool/netlink.c ++++ b/net/ethtool/netlink.c +@@ -402,7 +402,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info) + ret = ops->prepare_data(req_info, reply_data, info); + rtnl_unlock(); + if (ret < 0) +- goto err_cleanup; ++ goto err_dev; + ret = ops->reply_size(req_info, reply_data); + if (ret < 0) + goto err_cleanup; +@@ -460,7 +460,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev, + ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info); + rtnl_unlock(); + if (ret < 0) +- goto out; ++ goto out_cancel; + ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr); + if (ret < 0) + goto out; +@@ -469,6 +469,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev, + out: + if (ctx->ops->cleanup_data) + ctx->ops->cleanup_data(ctx->reply_data); ++out_cancel: + ctx->reply_data->dev = NULL; + if (ret < 0) + genlmsg_cancel(skb, ehdr); +@@ -676,7 +677,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd, + ethnl_init_reply_data(reply_data, ops, dev); + ret = ops->prepare_data(req_info, reply_data, &info); + if (ret < 0) +- goto err_cleanup; ++ goto err_rep; + ret = ops->reply_size(req_info, reply_data); + if (ret < 0) + goto err_cleanup; +@@ -711,6 +712,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd, + err_cleanup: + if (ops->cleanup_data) + ops->cleanup_data(reply_data); ++err_rep: + kfree(reply_data); + kfree(req_info); + return; +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 2e98531fa51a31..53197087353a7b 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -472,10 +472,10 @@ void fib6_select_path(const struct net *net, struct fib6_result *res, + goto out; + + hash = fl6->mp_hash; +- if (hash <= atomic_read(&first->fib6_nh->fib_nh_upper_bound) && +- rt6_score_route(first->fib6_nh, first->fib6_flags, oif, +- strict) >= 0) { +- match = first; ++ if (hash <= atomic_read(&first->fib6_nh->fib_nh_upper_bound)) { ++ if (rt6_score_route(first->fib6_nh, first->fib6_flags, oif, ++ strict) >= 0) ++ match = first; + goto out; + } + +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index fae701248f0580..eaa4e5c6a5c3ac 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -682,6 +682,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + ieee80211_txq_remove_vlan(local, sdata); + ++ if (sdata->vif.txq) ++ ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq)); ++ + sdata->bss = NULL; + + if (local->open_count == 0) +diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c +index 51369072984ee1..c6395551f5df08 100644 +--- a/net/mac80211/mesh_hwmp.c ++++ b/net/mac80211/mesh_hwmp.c +@@ -365,6 +365,12 @@ u32 airtime_link_metric_get(struct ieee80211_local *local, + return (u32)result; + } + ++/* Check that the first metric is at least 10% better than the second one */ ++static bool is_metric_better(u32 x, u32 y) ++{ ++ return (x < y) && (x < (y - x / 10)); ++} ++ + /** + * hwmp_route_info_get - Update routing info to originator and transmitter + * +@@ -456,8 +462,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, + (mpath->sn == orig_sn && + (rcu_access_pointer(mpath->next_hop) != + sta ? +- mult_frac(new_metric, 10, 9) : +- new_metric) >= mpath->metric)) { ++ !is_metric_better(new_metric, mpath->metric) : ++ new_metric >= mpath->metric))) { + process = false; + fresh_info = false; + } +@@ -531,8 +537,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, + if ((mpath->flags & MESH_PATH_FIXED) || + ((mpath->flags & MESH_PATH_ACTIVE) && + ((rcu_access_pointer(mpath->next_hop) != sta ? +- mult_frac(last_hop_metric, 10, 9) : +- last_hop_metric) > mpath->metric))) ++ !is_metric_better(last_hop_metric, mpath->metric) : ++ last_hop_metric > mpath->metric)))) + fresh_info = false; + } else { + mpath = mesh_path_add(sdata, ta); +diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c +index 28be85d055330b..8032cfba22d1c5 100644 +--- a/net/mctp/af_mctp.c ++++ b/net/mctp/af_mctp.c +@@ -550,6 +550,9 @@ static int mctp_sk_hash(struct sock *sk) + { + struct net *net = sock_net(sk); + ++ /* Bind lookup runs under RCU, remain live during that. */ ++ sock_set_flag(sk, SOCK_RCU_FREE); ++ + mutex_lock(&net->mctp.bind_lock); + sk_add_node_rcu(sk, &net->mctp.binds); + mutex_unlock(&net->mctp.bind_lock); +diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c +index d0f73b9180c7c0..31f6899ef71aac 100644 +--- a/net/mptcp/sockopt.c ++++ b/net/mptcp/sockopt.c +@@ -1388,6 +1388,32 @@ static int mptcp_getsockopt_v4(struct mptcp_sock *msk, int optname, + switch (optname) { + case IP_TOS: + return mptcp_put_int_option(msk, optval, optlen, inet_sk(sk)->tos); ++ case IP_FREEBIND: ++ return mptcp_put_int_option(msk, optval, optlen, ++ inet_test_bit(FREEBIND, sk)); ++ case IP_TRANSPARENT: ++ return mptcp_put_int_option(msk, optval, optlen, ++ inet_test_bit(TRANSPARENT, sk)); ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++static int mptcp_getsockopt_v6(struct mptcp_sock *msk, int optname, ++ char __user *optval, int __user *optlen) ++{ ++ struct sock *sk = (void *)msk; ++ ++ switch (optname) { ++ case IPV6_V6ONLY: ++ return mptcp_put_int_option(msk, optval, optlen, ++ sk->sk_ipv6only); ++ case IPV6_TRANSPARENT: ++ return mptcp_put_int_option(msk, optval, optlen, ++ inet_test_bit(TRANSPARENT, sk)); ++ case IPV6_FREEBIND: ++ return mptcp_put_int_option(msk, optval, optlen, ++ inet_test_bit(FREEBIND, sk)); + } + + return -EOPNOTSUPP; +@@ -1432,6 +1458,8 @@ int mptcp_getsockopt(struct sock *sk, int level, int optname, + + if (level == SOL_IP) + return mptcp_getsockopt_v4(msk, optname, optval, option); ++ if (level == SOL_IPV6) ++ return mptcp_getsockopt_v6(msk, optname, optval, option); + if (level == SOL_TCP) + return mptcp_getsockopt_sol_tcp(msk, optname, optval, option); + if (level == SOL_MPTCP) +diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c +index b3eeeb948b6132..f4b8ca8be81e8a 100644 +--- a/net/mptcp/subflow.c ++++ b/net/mptcp/subflow.c +@@ -731,8 +731,6 @@ static bool subflow_hmac_valid(const struct request_sock *req, + + subflow_req = mptcp_subflow_rsk(req); + msk = subflow_req->msk; +- if (!msk) +- return false; + + subflow_generate_hmac(msk->remote_key, msk->local_key, + subflow_req->remote_nonce, +@@ -828,12 +826,8 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, + + } else if (subflow_req->mp_join) { + mptcp_get_options(skb, &mp_opt); +- if (!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK) || +- !subflow_hmac_valid(req, &mp_opt) || +- !mptcp_can_accept_new_subflow(subflow_req->msk)) { +- SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC); ++ if (!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK)) + fallback = true; +- } + } + + create_child: +@@ -883,6 +877,17 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, + goto dispose_child; + } + ++ if (!subflow_hmac_valid(req, &mp_opt)) { ++ SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC); ++ subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT); ++ goto dispose_child; ++ } ++ ++ if (!mptcp_can_accept_new_subflow(owner)) { ++ subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT); ++ goto dispose_child; ++ } ++ + /* move the msk reference ownership to the subflow */ + subflow_req->msk = NULL; + ctx->conn = (struct sock *)owner; +diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c +index b8d3c3213efee5..c15db28c5ebc43 100644 +--- a/net/netfilter/nft_set_pipapo_avx2.c ++++ b/net/netfilter/nft_set_pipapo_avx2.c +@@ -994,8 +994,9 @@ static int nft_pipapo_avx2_lookup_8b_16(unsigned long *map, unsigned long *fill, + NFT_PIPAPO_AVX2_BUCKET_LOAD8(5, lt, 8, pkt[8], bsize); + + NFT_PIPAPO_AVX2_AND(6, 2, 3); ++ NFT_PIPAPO_AVX2_AND(3, 4, 7); + NFT_PIPAPO_AVX2_BUCKET_LOAD8(7, lt, 9, pkt[9], bsize); +- NFT_PIPAPO_AVX2_AND(0, 4, 5); ++ NFT_PIPAPO_AVX2_AND(0, 3, 5); + NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt, 10, pkt[10], bsize); + NFT_PIPAPO_AVX2_AND(2, 6, 7); + NFT_PIPAPO_AVX2_BUCKET_LOAD8(3, lt, 11, pkt[11], bsize); +diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c +index 9c13e14034d3b6..089ab1826e1d5e 100644 +--- a/net/openvswitch/flow_netlink.c ++++ b/net/openvswitch/flow_netlink.c +@@ -2862,7 +2862,8 @@ static int validate_set(const struct nlattr *a, + size_t key_len; + + /* There can be only one key in a action */ +- if (nla_total_size(nla_len(ovs_key)) != nla_len(a)) ++ if (!nla_ok(ovs_key, nla_len(a)) || ++ nla_total_size(nla_len(ovs_key)) != nla_len(a)) + return -EINVAL; + + key_len = nla_len(ovs_key); +diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c +index 96c39e9a873c75..7245f39d1e6529 100644 +--- a/net/sched/cls_api.c ++++ b/net/sched/cls_api.c +@@ -1977,6 +1977,7 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb, + struct tcmsg *tcm; + struct nlmsghdr *nlh; + unsigned char *b = skb_tail_pointer(skb); ++ int ret = -EMSGSIZE; + + nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); + if (!nlh) +@@ -2021,11 +2022,45 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb, + + return skb->len; + ++cls_op_not_supp: ++ ret = -EOPNOTSUPP; + out_nlmsg_trim: + nla_put_failure: +-cls_op_not_supp: + nlmsg_trim(skb, b); +- return -1; ++ return ret; ++} ++ ++static struct sk_buff *tfilter_notify_prep(struct net *net, ++ struct sk_buff *oskb, ++ struct nlmsghdr *n, ++ struct tcf_proto *tp, ++ struct tcf_block *block, ++ struct Qdisc *q, u32 parent, ++ void *fh, int event, ++ u32 portid, bool rtnl_held, ++ struct netlink_ext_ack *extack) ++{ ++ unsigned int size = oskb ? max(NLMSG_GOODSIZE, oskb->len) : NLMSG_GOODSIZE; ++ struct sk_buff *skb; ++ int ret; ++ ++retry: ++ skb = alloc_skb(size, GFP_KERNEL); ++ if (!skb) ++ return ERR_PTR(-ENOBUFS); ++ ++ ret = tcf_fill_node(net, skb, tp, block, q, parent, fh, portid, ++ n->nlmsg_seq, n->nlmsg_flags, event, false, ++ rtnl_held, extack); ++ if (ret <= 0) { ++ kfree_skb(skb); ++ if (ret == -EMSGSIZE) { ++ size += NLMSG_GOODSIZE; ++ goto retry; ++ } ++ return ERR_PTR(-EINVAL); ++ } ++ return skb; + } + + static int tfilter_notify(struct net *net, struct sk_buff *oskb, +@@ -2038,16 +2073,13 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb, + u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; + int err = 0; + +- skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); +- if (!skb) +- return -ENOBUFS; ++ if (!unicast && !rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC)) ++ return 0; + +- if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid, +- n->nlmsg_seq, n->nlmsg_flags, event, +- false, rtnl_held, extack) <= 0) { +- kfree_skb(skb); +- return -EINVAL; +- } ++ skb = tfilter_notify_prep(net, oskb, n, tp, block, q, parent, fh, event, ++ portid, rtnl_held, extack); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); + + if (unicast) + err = rtnl_unicast(skb, net, portid); +@@ -2067,16 +2099,14 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb, + u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; + int err; + +- skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); +- if (!skb) +- return -ENOBUFS; ++ if (!rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC)) ++ return tp->ops->delete(tp, fh, last, rtnl_held, extack); + +- if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid, +- n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER, +- false, rtnl_held, extack) <= 0) { ++ skb = tfilter_notify_prep(net, oskb, n, tp, block, q, parent, fh, ++ RTM_DELTFILTER, portid, rtnl_held, extack); ++ if (IS_ERR(skb)) { + NL_SET_ERR_MSG(extack, "Failed to build del event notification"); +- kfree_skb(skb); +- return -EINVAL; ++ return PTR_ERR(skb); + } + + err = tp->ops->delete(tp, fh, last, rtnl_held, extack); +@@ -2891,6 +2921,9 @@ static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb, + struct sk_buff *skb; + int err = 0; + ++ if (!unicast && !rtnl_notify_needed(net, flags, RTNLGRP_TC)) ++ return 0; ++ + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) + return -ENOBUFS; +@@ -2920,6 +2953,9 @@ static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops, + struct net *net = block->net; + struct sk_buff *skb; + ++ if (!rtnl_notify_needed(net, flags, RTNLGRP_TC)) ++ return 0; ++ + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) + return -ENOBUFS; +diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c +index d7a4874543de5d..5f2e0681574567 100644 +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -95,10 +95,7 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) + &q->stats, qdisc_pkt_len, codel_get_enqueue_time, + drop_func, dequeue_func); + +- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, +- * or HTB crashes. Defer it for next round. +- */ +- if (q->stats.drop_count && sch->q.qlen) { ++ if (q->stats.drop_count) { + qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len); + q->stats.drop_count = 0; + q->stats.drop_len = 0; +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 8c4fee0634366e..9330923a624c02 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -314,10 +314,8 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch) + } + qdisc_bstats_update(sch, skb); + flow->deficit -= qdisc_pkt_len(skb); +- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, +- * or HTB crashes. Defer it for next round. +- */ +- if (q->cstats.drop_count && sch->q.qlen) { ++ ++ if (q->cstats.drop_count) { + qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, + q->cstats.drop_len); + q->cstats.drop_count = 0; +diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c +index 60754f366ab7bc..002941d35b643c 100644 +--- a/net/sched/sch_sfq.c ++++ b/net/sched/sch_sfq.c +@@ -631,6 +631,15 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt, + struct red_parms *p = NULL; + struct sk_buff *to_free = NULL; + struct sk_buff *tail = NULL; ++ unsigned int maxflows; ++ unsigned int quantum; ++ unsigned int divisor; ++ int perturb_period; ++ u8 headdrop; ++ u8 maxdepth; ++ int limit; ++ u8 flags; ++ + + if (opt->nla_len < nla_attr_size(sizeof(*ctl))) + return -EINVAL; +@@ -652,39 +661,64 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt, + if (!p) + return -ENOMEM; + } +- if (ctl->limit == 1) { +- NL_SET_ERR_MSG_MOD(extack, "invalid limit"); +- return -EINVAL; +- } ++ + sch_tree_lock(sch); ++ ++ limit = q->limit; ++ divisor = q->divisor; ++ headdrop = q->headdrop; ++ maxdepth = q->maxdepth; ++ maxflows = q->maxflows; ++ perturb_period = q->perturb_period; ++ quantum = q->quantum; ++ flags = q->flags; ++ ++ /* update and validate configuration */ + if (ctl->quantum) +- q->quantum = ctl->quantum; +- WRITE_ONCE(q->perturb_period, ctl->perturb_period * HZ); ++ quantum = ctl->quantum; ++ perturb_period = ctl->perturb_period * HZ; + if (ctl->flows) +- q->maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS); ++ maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS); + if (ctl->divisor) { +- q->divisor = ctl->divisor; +- q->maxflows = min_t(u32, q->maxflows, q->divisor); ++ divisor = ctl->divisor; ++ maxflows = min_t(u32, maxflows, divisor); + } + if (ctl_v1) { + if (ctl_v1->depth) +- q->maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH); ++ maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH); + if (p) { +- swap(q->red_parms, p); +- red_set_parms(q->red_parms, ++ red_set_parms(p, + ctl_v1->qth_min, ctl_v1->qth_max, + ctl_v1->Wlog, + ctl_v1->Plog, ctl_v1->Scell_log, + NULL, + ctl_v1->max_P); + } +- q->flags = ctl_v1->flags; +- q->headdrop = ctl_v1->headdrop; ++ flags = ctl_v1->flags; ++ headdrop = ctl_v1->headdrop; + } + if (ctl->limit) { +- q->limit = min_t(u32, ctl->limit, q->maxdepth * q->maxflows); +- q->maxflows = min_t(u32, q->maxflows, q->limit); ++ limit = min_t(u32, ctl->limit, maxdepth * maxflows); ++ maxflows = min_t(u32, maxflows, limit); + } ++ if (limit == 1) { ++ sch_tree_unlock(sch); ++ kfree(p); ++ NL_SET_ERR_MSG_MOD(extack, "invalid limit"); ++ return -EINVAL; ++ } ++ ++ /* commit configuration */ ++ q->limit = limit; ++ q->divisor = divisor; ++ q->headdrop = headdrop; ++ q->maxdepth = maxdepth; ++ q->maxflows = maxflows; ++ WRITE_ONCE(q->perturb_period, perturb_period); ++ q->quantum = quantum; ++ q->flags = flags; ++ if (p) ++ swap(q->red_parms, p); + + qlen = sch->q.qlen; + while (sch->q.qlen > q->limit) { +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 108a0745c0c3ca..b84c5e0a76f52d 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -71,8 +71,9 @@ + /* Forward declarations for internal helper functions. */ + static bool sctp_writeable(const struct sock *sk); + static void sctp_wfree(struct sk_buff *skb); +-static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, +- size_t msg_len); ++static int sctp_wait_for_sndbuf(struct sctp_association *asoc, ++ struct sctp_transport *transport, ++ long *timeo_p, size_t msg_len); + static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); + static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); + static int sctp_wait_for_accept(struct sock *sk, long timeo); +@@ -1827,7 +1828,7 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, + + if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) { + timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); +- err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); ++ err = sctp_wait_for_sndbuf(asoc, transport, &timeo, msg_len); + if (err) + goto err; + if (unlikely(sinfo->sinfo_stream >= asoc->stream.outcnt)) { +@@ -9208,8 +9209,9 @@ void sctp_sock_rfree(struct sk_buff *skb) + + + /* Helper function to wait for space in the sndbuf. */ +-static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, +- size_t msg_len) ++static int sctp_wait_for_sndbuf(struct sctp_association *asoc, ++ struct sctp_transport *transport, ++ long *timeo_p, size_t msg_len) + { + struct sock *sk = asoc->base.sk; + long current_timeo = *timeo_p; +@@ -9219,7 +9221,9 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, + pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc, + *timeo_p, msg_len); + +- /* Increment the association's refcnt. */ ++ /* Increment the transport and association's refcnt. */ ++ if (transport) ++ sctp_transport_hold(transport); + sctp_association_hold(asoc); + + /* Wait on the association specific sndbuf space. */ +@@ -9228,7 +9232,7 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, + TASK_INTERRUPTIBLE); + if (asoc->base.dead) + goto do_dead; +- if (!*timeo_p) ++ if ((!*timeo_p) || (transport && transport->dead)) + goto do_nonblock; + if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING) + goto do_error; +@@ -9253,7 +9257,9 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, + out: + finish_wait(&asoc->wait, &wait); + +- /* Release the association's refcnt. */ ++ /* Release the transport and association's refcnt. */ ++ if (transport) ++ sctp_transport_put(transport); + sctp_association_put(asoc); + + return err; +diff --git a/net/sctp/transport.c b/net/sctp/transport.c +index 2abe45af98e7c6..31eca29b6cfbfb 100644 +--- a/net/sctp/transport.c ++++ b/net/sctp/transport.c +@@ -117,6 +117,8 @@ struct sctp_transport *sctp_transport_new(struct net *net, + */ + void sctp_transport_free(struct sctp_transport *transport) + { ++ transport->dead = 1; ++ + /* Try to delete the heartbeat timer. */ + if (del_timer(&transport->hb_timer)) + sctp_transport_put(transport); +diff --git a/net/tipc/link.c b/net/tipc/link.c +index d0143823658d58..6c6d8546c57861 100644 +--- a/net/tipc/link.c ++++ b/net/tipc/link.c +@@ -1068,6 +1068,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list, + if (unlikely(l->backlog[imp].len >= l->backlog[imp].limit)) { + if (imp == TIPC_SYSTEM_IMPORTANCE) { + pr_warn("%s<%s>, link overflow", link_rst_msg, l->name); ++ __skb_queue_purge(list); + return -ENOBUFS; + } + rc = link_schedule_user(l, hdr); +diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c +index 0a67b93a52ec25..d7dea82bcf5653 100644 +--- a/net/tls/tls_main.c ++++ b/net/tls/tls_main.c +@@ -804,6 +804,11 @@ static int tls_setsockopt(struct sock *sk, int level, int optname, + return do_tls_setsockopt(sk, optname, optval, optlen); + } + ++static int tls_disconnect(struct sock *sk, int flags) ++{ ++ return -EOPNOTSUPP; ++} ++ + struct tls_context *tls_ctx_create(struct sock *sk) + { + struct inet_connection_sock *icsk = inet_csk(sk); +@@ -899,6 +904,7 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], + prot[TLS_BASE][TLS_BASE] = *base; + prot[TLS_BASE][TLS_BASE].setsockopt = tls_setsockopt; + prot[TLS_BASE][TLS_BASE].getsockopt = tls_getsockopt; ++ prot[TLS_BASE][TLS_BASE].disconnect = tls_disconnect; + prot[TLS_BASE][TLS_BASE].close = tls_sk_proto_close; + + prot[TLS_SW][TLS_BASE] = prot[TLS_BASE][TLS_BASE]; +diff --git a/scripts/sign-file.c b/scripts/sign-file.c +index 3edb156ae52c30..7070245edfc121 100644 +--- a/scripts/sign-file.c ++++ b/scripts/sign-file.c +@@ -27,14 +27,17 @@ + #include + #include + #include +-#include +- +-/* +- * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API. +- * +- * Remove this if/when that API is no longer used +- */ +-#pragma GCC diagnostic ignored "-Wdeprecated-declarations" ++#if OPENSSL_VERSION_MAJOR >= 3 ++# define USE_PKCS11_PROVIDER ++# include ++# include ++#else ++# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0) ++# define USE_PKCS11_ENGINE ++# include ++# endif ++#endif ++#include "ssl-common.h" + + /* + * Use CMS if we have openssl-1.0.0 or newer available - otherwise we have to +@@ -83,41 +86,6 @@ void format(void) + exit(2); + } + +-static void display_openssl_errors(int l) +-{ +- const char *file; +- char buf[120]; +- int e, line; +- +- if (ERR_peek_error() == 0) +- return; +- fprintf(stderr, "At main.c:%d:\n", l); +- +- while ((e = ERR_get_error_line(&file, &line))) { +- ERR_error_string(e, buf); +- fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); +- } +-} +- +-static void drain_openssl_errors(void) +-{ +- const char *file; +- int line; +- +- if (ERR_peek_error() == 0) +- return; +- while (ERR_get_error_line(&file, &line)) {} +-} +- +-#define ERR(cond, fmt, ...) \ +- do { \ +- bool __cond = (cond); \ +- display_openssl_errors(__LINE__); \ +- if (__cond) { \ +- errx(1, fmt, ## __VA_ARGS__); \ +- } \ +- } while(0) +- + static const char *key_pass; + + static int pem_pw_cb(char *buf, int len, int w, void *v) +@@ -139,28 +107,64 @@ static int pem_pw_cb(char *buf, int len, int w, void *v) + return pwlen; + } + +-static EVP_PKEY *read_private_key(const char *private_key_name) ++static EVP_PKEY *read_private_key_pkcs11(const char *private_key_name) + { +- EVP_PKEY *private_key; ++ EVP_PKEY *private_key = NULL; ++#ifdef USE_PKCS11_PROVIDER ++ OSSL_STORE_CTX *store; + ++ if (!OSSL_PROVIDER_try_load(NULL, "pkcs11", true)) ++ ERR(1, "OSSL_PROVIDER_try_load(pkcs11)"); ++ if (!OSSL_PROVIDER_try_load(NULL, "default", true)) ++ ERR(1, "OSSL_PROVIDER_try_load(default)"); ++ ++ store = OSSL_STORE_open(private_key_name, NULL, NULL, NULL, NULL); ++ ERR(!store, "OSSL_STORE_open"); ++ ++ while (!OSSL_STORE_eof(store)) { ++ OSSL_STORE_INFO *info = OSSL_STORE_load(store); ++ ++ if (!info) { ++ drain_openssl_errors(__LINE__, 0); ++ continue; ++ } ++ if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY) { ++ private_key = OSSL_STORE_INFO_get1_PKEY(info); ++ ERR(!private_key, "OSSL_STORE_INFO_get1_PKEY"); ++ } ++ OSSL_STORE_INFO_free(info); ++ if (private_key) ++ break; ++ } ++ OSSL_STORE_close(store); ++#elif defined(USE_PKCS11_ENGINE) ++ ENGINE *e; ++ ++ ENGINE_load_builtin_engines(); ++ drain_openssl_errors(__LINE__, 1); ++ e = ENGINE_by_id("pkcs11"); ++ ERR(!e, "Load PKCS#11 ENGINE"); ++ if (ENGINE_init(e)) ++ drain_openssl_errors(__LINE__, 1); ++ else ++ ERR(1, "ENGINE_init"); ++ if (key_pass) ++ ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); ++ private_key = ENGINE_load_private_key(e, private_key_name, NULL, NULL); ++ ERR(!private_key, "%s", private_key_name); ++#else ++ fprintf(stderr, "no pkcs11 engine/provider available\n"); ++ exit(1); ++#endif ++ return private_key; ++} ++ ++static EVP_PKEY *read_private_key(const char *private_key_name) ++{ + if (!strncmp(private_key_name, "pkcs11:", 7)) { +- ENGINE *e; +- +- ENGINE_load_builtin_engines(); +- drain_openssl_errors(); +- e = ENGINE_by_id("pkcs11"); +- ERR(!e, "Load PKCS#11 ENGINE"); +- if (ENGINE_init(e)) +- drain_openssl_errors(); +- else +- ERR(1, "ENGINE_init"); +- if (key_pass) +- ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), +- "Set PKCS#11 PIN"); +- private_key = ENGINE_load_private_key(e, private_key_name, +- NULL, NULL); +- ERR(!private_key, "%s", private_key_name); ++ return read_private_key_pkcs11(private_key_name); + } else { ++ EVP_PKEY *private_key; + BIO *b; + + b = BIO_new_file(private_key_name, "rb"); +@@ -169,9 +173,9 @@ static EVP_PKEY *read_private_key(const char *private_key_name) + NULL); + ERR(!private_key, "%s", private_key_name); + BIO_free(b); +- } + +- return private_key; ++ return private_key; ++ } + } + + static X509 *read_x509(const char *x509_name) +@@ -306,7 +310,7 @@ int main(int argc, char **argv) + + /* Digest the module data. */ + OpenSSL_add_all_digests(); +- display_openssl_errors(__LINE__); ++ drain_openssl_errors(__LINE__, 0); + digest_algo = EVP_get_digestbyname(hash_algo); + ERR(!digest_algo, "EVP_get_digestbyname"); + +diff --git a/scripts/ssl-common.h b/scripts/ssl-common.h +new file mode 100644 +index 00000000000000..2db0e181143cf4 +--- /dev/null ++++ b/scripts/ssl-common.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++/* ++ * SSL helper functions shared by sign-file and extract-cert. ++ */ ++ ++static void drain_openssl_errors(int l, int silent) ++{ ++ const char *file; ++ char buf[120]; ++ int e, line; ++ ++ if (ERR_peek_error() == 0) ++ return; ++ if (!silent) ++ fprintf(stderr, "At main.c:%d:\n", l); ++ ++ while ((e = ERR_peek_error_line(&file, &line))) { ++ ERR_error_string(e, buf); ++ if (!silent) ++ fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); ++ ERR_get_error(); ++ } ++} ++ ++#define ERR(cond, fmt, ...) \ ++ do { \ ++ bool __cond = (cond); \ ++ drain_openssl_errors(__LINE__, 0); \ ++ if (__cond) { \ ++ errx(1, fmt, ## __VA_ARGS__); \ ++ } \ ++ } while (0) +diff --git a/security/landlock/errata.h b/security/landlock/errata.h +new file mode 100644 +index 00000000000000..fe91ef0e6f72db +--- /dev/null ++++ b/security/landlock/errata.h +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Landlock - Errata information ++ * ++ * Copyright © 2025 Microsoft Corporation ++ */ ++ ++#ifndef _SECURITY_LANDLOCK_ERRATA_H ++#define _SECURITY_LANDLOCK_ERRATA_H ++ ++#include ++ ++struct landlock_erratum { ++ const int abi; ++ const u8 number; ++}; ++ ++/* clang-format off */ ++#define LANDLOCK_ERRATUM(NUMBER) \ ++ { \ ++ .abi = LANDLOCK_ERRATA_ABI, \ ++ .number = NUMBER, \ ++ }, ++/* clang-format on */ ++ ++/* ++ * Some fixes may require user space to check if they are applied on the running ++ * kernel before using a specific feature. For instance, this applies when a ++ * restriction was previously too restrictive and is now getting relaxed (for ++ * compatibility or semantic reasons). However, non-visible changes for ++ * legitimate use (e.g. security fixes) do not require an erratum. ++ */ ++static const struct landlock_erratum landlock_errata_init[] __initconst = { ++ ++/* ++ * Only Sparse may not implement __has_include. If a compiler does not ++ * implement __has_include, a warning will be printed at boot time (see ++ * setup.c). ++ */ ++#ifdef __has_include ++ ++#define LANDLOCK_ERRATA_ABI 1 ++#if __has_include("errata/abi-1.h") ++#include "errata/abi-1.h" ++#endif ++#undef LANDLOCK_ERRATA_ABI ++ ++#define LANDLOCK_ERRATA_ABI 2 ++#if __has_include("errata/abi-2.h") ++#include "errata/abi-2.h" ++#endif ++#undef LANDLOCK_ERRATA_ABI ++ ++#define LANDLOCK_ERRATA_ABI 3 ++#if __has_include("errata/abi-3.h") ++#include "errata/abi-3.h" ++#endif ++#undef LANDLOCK_ERRATA_ABI ++ ++#define LANDLOCK_ERRATA_ABI 4 ++#if __has_include("errata/abi-4.h") ++#include "errata/abi-4.h" ++#endif ++#undef LANDLOCK_ERRATA_ABI ++ ++/* ++ * For each new erratum, we need to include all the ABI files up to the impacted ++ * ABI to make all potential future intermediate errata easy to backport. ++ * ++ * If such change involves more than one ABI addition, then it must be in a ++ * dedicated commit with the same Fixes tag as used for the actual fix. ++ * ++ * Each commit creating a new security/landlock/errata/abi-*.h file must have a ++ * Depends-on tag to reference the commit that previously added the line to ++ * include this new file, except if the original Fixes tag is enough. ++ * ++ * Each erratum must be documented in its related ABI file, and a dedicated ++ * commit must update Documentation/userspace-api/landlock.rst to include this ++ * erratum. This commit will not be backported. ++ */ ++ ++#endif ++ ++ {} ++}; ++ ++#endif /* _SECURITY_LANDLOCK_ERRATA_H */ +diff --git a/security/landlock/setup.c b/security/landlock/setup.c +index 0f6113528fa4a8..8b46e8748b8a42 100644 +--- a/security/landlock/setup.c ++++ b/security/landlock/setup.c +@@ -6,11 +6,13 @@ + * Copyright © 2018-2020 ANSSI + */ + ++#include + #include + #include + + #include "common.h" + #include "cred.h" ++#include "errata.h" + #include "fs.h" + #include "ptrace.h" + #include "setup.h" +@@ -24,8 +26,36 @@ struct lsm_blob_sizes landlock_blob_sizes __ro_after_init = { + .lbs_superblock = sizeof(struct landlock_superblock_security), + }; + ++int landlock_errata __ro_after_init; ++ ++static void __init compute_errata(void) ++{ ++ size_t i; ++ ++#ifndef __has_include ++ /* ++ * This is a safeguard to make sure the compiler implements ++ * __has_include (see errata.h). ++ */ ++ WARN_ON_ONCE(1); ++ return; ++#endif ++ ++ for (i = 0; landlock_errata_init[i].number; i++) { ++ const int prev_errata = landlock_errata; ++ ++ if (WARN_ON_ONCE(landlock_errata_init[i].abi > ++ landlock_abi_version)) ++ continue; ++ ++ landlock_errata |= BIT(landlock_errata_init[i].number - 1); ++ WARN_ON_ONCE(prev_errata == landlock_errata); ++ } ++} ++ + static int __init landlock_init(void) + { ++ compute_errata(); + landlock_add_cred_hooks(); + landlock_add_ptrace_hooks(); + landlock_add_fs_hooks(); +diff --git a/security/landlock/setup.h b/security/landlock/setup.h +index 1daffab1ab4bda..420dceca35d271 100644 +--- a/security/landlock/setup.h ++++ b/security/landlock/setup.h +@@ -11,7 +11,10 @@ + + #include + ++extern const int landlock_abi_version; ++ + extern bool landlock_initialized; ++extern int landlock_errata; + + extern struct lsm_blob_sizes landlock_blob_sizes; + +diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c +index 336bedaa3af689..eb23df4e836cba 100644 +--- a/security/landlock/syscalls.c ++++ b/security/landlock/syscalls.c +@@ -150,7 +150,9 @@ static const struct file_operations ruleset_fops = { + * the new ruleset. + * @size: Size of the pointed &struct landlock_ruleset_attr (needed for + * backward and forward compatibility). +- * @flags: Supported value: %LANDLOCK_CREATE_RULESET_VERSION. ++ * @flags: Supported value: ++ * - %LANDLOCK_CREATE_RULESET_VERSION ++ * - %LANDLOCK_CREATE_RULESET_ERRATA + * + * This system call enables to create a new Landlock ruleset, and returns the + * related file descriptor on success. +@@ -159,6 +161,10 @@ static const struct file_operations ruleset_fops = { + * 0, then the returned value is the highest supported Landlock ABI version + * (starting at 1). + * ++ * If @flags is %LANDLOCK_CREATE_RULESET_ERRATA and @attr is NULL and @size is ++ * 0, then the returned value is a bitmask of fixed issues for the current ++ * Landlock ABI version. ++ * + * Possible returned errors are: + * + * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; +@@ -181,9 +187,15 @@ SYSCALL_DEFINE3(landlock_create_ruleset, + return -EOPNOTSUPP; + + if (flags) { +- if ((flags == LANDLOCK_CREATE_RULESET_VERSION) && !attr && +- !size) +- return LANDLOCK_ABI_VERSION; ++ if (attr || size) ++ return -EINVAL; ++ ++ if (flags == LANDLOCK_CREATE_RULESET_VERSION) ++ return landlock_abi_version; ++ ++ if (flags == LANDLOCK_CREATE_RULESET_ERRATA) ++ return landlock_errata; ++ + return -EINVAL; + } + +@@ -213,6 +225,8 @@ SYSCALL_DEFINE3(landlock_create_ruleset, + return ruleset_fd; + } + ++const int landlock_abi_version = LANDLOCK_ABI_VERSION; ++ + /* + * Returns an owned ruleset from a FD. It is thus needed to call + * landlock_put_ruleset() on the return value. +diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +index d90151910bee90..3a0df631d25d91 100644 +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_X86 + /* for snoop control */ +@@ -1363,8 +1364,21 @@ static void azx_free(struct azx *chip) + if (use_vga_switcheroo(hda)) { + if (chip->disabled && hda->probe_continued) + snd_hda_unlock_devices(&chip->bus); +- if (hda->vga_switcheroo_registered) ++ if (hda->vga_switcheroo_registered) { + vga_switcheroo_unregister_client(chip->pci); ++ ++ /* Some GPUs don't have sound, and azx_first_init fails, ++ * leaving the device probed but non-functional. As long ++ * as it's probed, the PCI subsystem keeps its runtime ++ * PM status as active. Force it to suspended (as we ++ * actually stop the chip) to allow GPU to suspend via ++ * vga_switcheroo, and print a warning. ++ */ ++ dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n"); ++ pm_runtime_disable(&pci->dev); ++ pm_runtime_set_suspended(&pci->dev); ++ pm_runtime_enable(&pci->dev); ++ } + } + + if (bus->chip_init) { +@@ -2079,6 +2093,27 @@ static const struct pci_device_id driver_denylist[] = { + {} + }; + ++static struct pci_device_id driver_denylist_ideapad_z570[] = { ++ { PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) }, /* NVIDIA GF108 HDA */ ++ {} ++}; ++ ++/* DMI-based denylist, to be used when: ++ * - PCI subsystem IDs are zero, impossible to distinguish from valid sound cards. ++ * - Different modifications of the same laptop use different GPU models. ++ */ ++static const struct dmi_system_id driver_denylist_dmi[] = { ++ { ++ /* No HDA in NVIDIA DGPU. BIOS disables it, but quirk_nvidia_hda() reenables. */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"), ++ }, ++ .driver_data = &driver_denylist_ideapad_z570, ++ }, ++ {} ++}; ++ + static const struct hda_controller_ops pci_hda_ops = { + .disable_msi_reset_irq = disable_msi_reset_irq, + .position_check = azx_position_check, +@@ -2089,6 +2124,7 @@ static DECLARE_BITMAP(probed_devs, SNDRV_CARDS); + static int azx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) + { ++ const struct dmi_system_id *dmi; + struct snd_card *card; + struct hda_intel *hda; + struct azx *chip; +@@ -2101,6 +2137,12 @@ static int azx_probe(struct pci_dev *pci, + return -ENODEV; + } + ++ dmi = dmi_first_match(driver_denylist_dmi); ++ if (dmi && pci_match_id(dmi->driver_data, pci)) { ++ dev_info(&pci->dev, "Skipping the device on the DMI denylist\n"); ++ return -ENODEV; ++ } ++ + dev = find_first_zero_bit(probed_devs, SNDRV_CARDS); + if (dev >= SNDRV_CARDS) + return -ENODEV; +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 5179061f57b573..2f3f295f2b0cb5 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10238,6 +10238,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1c33, "ASUS UX5304MA", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), ++ SND_PCI_QUIRK(0x1043, 0x1c80, "ASUS VivoBook TP401", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS), + SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index 2981bd1c3530d0..622df58a969421 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -339,6 +339,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "83Q3"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83J2"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +@@ -584,6 +591,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_VERSION, "pang13"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7UCX"), ++ } ++ }, + {} + }; + +diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c +index 9f5f1a92561d1e..0b8e88b19888ec 100644 +--- a/sound/soc/codecs/cs42l43-jack.c ++++ b/sound/soc/codecs/cs42l43-jack.c +@@ -690,6 +690,9 @@ static void cs42l43_clear_jack(struct cs42l43_codec *priv) + CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL, + CS42L43_JACK_STEREO_CONFIG_MASK, 0); ++ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK, + 0x2 << CS42L43_HSDET_MODE_SHIFT); +diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c +index 6ce309980cd10e..e29815535929d5 100644 +--- a/sound/soc/codecs/lpass-wsa-macro.c ++++ b/sound/soc/codecs/lpass-wsa-macro.c +@@ -66,6 +66,10 @@ + #define CDC_WSA_TX_SPKR_PROT_CLK_DISABLE 0 + #define CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK GENMASK(3, 0) + #define CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K 0 ++#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_16K 1 ++#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_24K 2 ++#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_32K 3 ++#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_48K 4 + #define CDC_WSA_TX0_SPKR_PROT_PATH_CFG0 (0x0248) + #define CDC_WSA_TX1_SPKR_PROT_PATH_CTL (0x0264) + #define CDC_WSA_TX1_SPKR_PROT_PATH_CFG0 (0x0268) +@@ -347,6 +351,7 @@ struct wsa_macro { + int ear_spkr_gain; + int spkr_gain_offset; + int spkr_mode; ++ u32 pcm_rate_vi; + int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX]; + int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX]; + struct regmap *regmap; +@@ -974,6 +979,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { + struct snd_soc_component *component = dai->component; ++ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + int ret; + + switch (substream->stream) { +@@ -985,6 +991,11 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream, + __func__, params_rate(params)); + return ret; + } ++ break; ++ case SNDRV_PCM_STREAM_CAPTURE: ++ if (dai->id == WSA_MACRO_AIF_VI) ++ wsa->pcm_rate_vi = params_rate(params); ++ + break; + default: + break; +@@ -1142,35 +1153,11 @@ static void wsa_macro_mclk_enable(struct wsa_macro *wsa, bool mclk_enable) + } + } + +-static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w, +- struct snd_kcontrol *kcontrol, int event) ++static void wsa_macro_enable_disable_vi_sense(struct snd_soc_component *component, bool enable, ++ u32 tx_reg0, u32 tx_reg1, u32 val) + { +- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); +- struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); +- +- wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU); +- return 0; +-} +- +-static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, +- struct snd_kcontrol *kcontrol, +- int event) +-{ +- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); +- struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); +- u32 tx_reg0, tx_reg1; +- +- if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { +- tx_reg0 = CDC_WSA_TX0_SPKR_PROT_PATH_CTL; +- tx_reg1 = CDC_WSA_TX1_SPKR_PROT_PATH_CTL; +- } else if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { +- tx_reg0 = CDC_WSA_TX2_SPKR_PROT_PATH_CTL; +- tx_reg1 = CDC_WSA_TX3_SPKR_PROT_PATH_CTL; +- } +- +- switch (event) { +- case SND_SOC_DAPM_POST_PMU: +- /* Enable V&I sensing */ ++ if (enable) { ++ /* Enable V&I sensing */ + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_RESET); +@@ -1179,10 +1166,10 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, + CDC_WSA_TX_SPKR_PROT_RESET); + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK, +- CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K); ++ val); + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK, +- CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K); ++ val); + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK, + CDC_WSA_TX_SPKR_PROT_CLK_ENABLE); +@@ -1195,9 +1182,7 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_NO_RESET); +- break; +- case SND_SOC_DAPM_POST_PMD: +- /* Disable V&I sensing */ ++ } else { + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_RESET); +@@ -1210,6 +1195,72 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK, + CDC_WSA_TX_SPKR_PROT_CLK_DISABLE); ++ } ++} ++ ++static void wsa_macro_enable_disable_vi_feedback(struct snd_soc_component *component, ++ bool enable, u32 rate) ++{ ++ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); ++ ++ if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) ++ wsa_macro_enable_disable_vi_sense(component, enable, ++ CDC_WSA_TX0_SPKR_PROT_PATH_CTL, ++ CDC_WSA_TX1_SPKR_PROT_PATH_CTL, rate); ++ ++ if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) ++ wsa_macro_enable_disable_vi_sense(component, enable, ++ CDC_WSA_TX2_SPKR_PROT_PATH_CTL, ++ CDC_WSA_TX3_SPKR_PROT_PATH_CTL, rate); ++} ++ ++static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); ++ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); ++ ++ wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU); ++ return 0; ++} ++ ++static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, ++ int event) ++{ ++ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); ++ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); ++ u32 rate_val; ++ ++ switch (wsa->pcm_rate_vi) { ++ case 8000: ++ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K; ++ break; ++ case 16000: ++ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_16K; ++ break; ++ case 24000: ++ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_24K; ++ break; ++ case 32000: ++ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_32K; ++ break; ++ case 48000: ++ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_48K; ++ break; ++ default: ++ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K; ++ break; ++ } ++ ++ switch (event) { ++ case SND_SOC_DAPM_POST_PMU: ++ /* Enable V&I sensing */ ++ wsa_macro_enable_disable_vi_feedback(component, true, rate_val); ++ break; ++ case SND_SOC_DAPM_POST_PMD: ++ /* Disable V&I sensing */ ++ wsa_macro_enable_disable_vi_feedback(component, false, rate_val); + break; + } + +diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c +index 9ea4be56d3b709..43edad6c887dcb 100644 +--- a/sound/soc/dwc/dwc-i2s.c ++++ b/sound/soc/dwc/dwc-i2s.c +@@ -199,12 +199,10 @@ static void i2s_start(struct dw_i2s_dev *dev, + else + i2s_write_reg(dev->i2s_base, IRER, 1); + +- /* I2S needs to enable IRQ to make a handshake with DMAC on the JH7110 SoC */ +- if (dev->use_pio || dev->is_jh7110) +- i2s_enable_irqs(dev, substream->stream, config->chan_nr); +- else ++ if (!(dev->use_pio || dev->is_jh7110)) + i2s_enable_dma(dev, substream->stream); + ++ i2s_enable_irqs(dev, substream->stream, config->chan_nr); + i2s_write_reg(dev->i2s_base, CER, 1); + } + +@@ -218,11 +216,12 @@ static void i2s_stop(struct dw_i2s_dev *dev, + else + i2s_write_reg(dev->i2s_base, IRER, 0); + +- if (dev->use_pio || dev->is_jh7110) +- i2s_disable_irqs(dev, substream->stream, 8); +- else ++ if (!(dev->use_pio || dev->is_jh7110)) + i2s_disable_dma(dev, substream->stream); + ++ i2s_disable_irqs(dev, substream->stream, 8); ++ ++ + if (!dev->active) { + i2s_write_reg(dev->i2s_base, CER, 0); + i2s_write_reg(dev->i2s_base, IER, 0); +diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c +index 0ab2c19621175e..d8e44470f501e7 100644 +--- a/sound/soc/fsl/fsl_audmix.c ++++ b/sound/soc/fsl/fsl_audmix.c +@@ -492,11 +492,17 @@ static int fsl_audmix_probe(struct platform_device *pdev) + goto err_disable_pm; + } + +- priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0); +- if (IS_ERR(priv->pdev)) { +- ret = PTR_ERR(priv->pdev); +- dev_err(dev, "failed to register platform: %d\n", ret); +- goto err_disable_pm; ++ /* ++ * If dais property exist, then register the imx-audmix card driver. ++ * otherwise, it should be linked by audio graph card. ++ */ ++ if (of_find_property(pdev->dev.of_node, "dais", NULL)) { ++ priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0); ++ if (IS_ERR(priv->pdev)) { ++ ret = PTR_ERR(priv->pdev); ++ dev_err(dev, "failed to register platform: %d\n", ret); ++ goto err_disable_pm; ++ } + } + + return 0; +diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c +index bb1e77ac78e047..781019685b941f 100644 +--- a/sound/soc/intel/avs/pcm.c ++++ b/sound/soc/intel/avs/pcm.c +@@ -808,7 +808,8 @@ static int avs_component_probe(struct snd_soc_component *component) + else + mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, + "hda-generic-tplg.bin"); +- ++ if (!mach->tplg_filename) ++ return -ENOMEM; + filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, + mach->tplg_filename); + if (!filename) +diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h +index bdfe66ec3314f9..ea12f02eca55f6 100644 +--- a/sound/soc/qcom/lpass.h ++++ b/sound/soc/qcom/lpass.h +@@ -13,10 +13,11 @@ + #include + #include + #include ++#include + #include "lpass-hdmi.h" + + #define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 +-#define LPASS_MAX_PORTS (LPASS_CDC_DMA_VA_TX8 + 1) ++#define LPASS_MAX_PORTS (DISPLAY_PORT_RX_7 + 1) + #define LPASS_MAX_MI2S_PORTS (8) + #define LPASS_MAX_DMA_CHANNELS (8) + #define LPASS_MAX_HDMI_DMA_CHANNELS (4) +diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c +index 739856a00017c5..def05ce58d176e 100644 +--- a/sound/soc/qcom/qdsp6/q6apm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6apm-dai.c +@@ -24,8 +24,8 @@ + #define PLAYBACK_MIN_PERIOD_SIZE 128 + #define CAPTURE_MIN_NUM_PERIODS 2 + #define CAPTURE_MAX_NUM_PERIODS 8 +-#define CAPTURE_MAX_PERIOD_SIZE 4096 +-#define CAPTURE_MIN_PERIOD_SIZE 320 ++#define CAPTURE_MAX_PERIOD_SIZE 65536 ++#define CAPTURE_MIN_PERIOD_SIZE 6144 + #define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE) + #define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE) + #define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024) +@@ -380,13 +380,14 @@ static int q6apm_dai_open(struct snd_soc_component *component, + } + } + +- ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); ++ /* setup 10ms latency to accommodate DSP restrictions */ ++ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480); + if (ret < 0) { + dev_err(dev, "constraint for period bytes step ret = %d\n", ret); + goto err; + } + +- ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); ++ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480); + if (ret < 0) { + dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret); + goto err; +diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c +index 2a2a5bd98110bc..ca57413cb7847a 100644 +--- a/sound/soc/qcom/qdsp6/q6apm.c ++++ b/sound/soc/qcom/qdsp6/q6apm.c +@@ -494,6 +494,19 @@ int q6apm_read(struct q6apm_graph *graph) + } + EXPORT_SYMBOL_GPL(q6apm_read); + ++int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir) ++{ ++ struct audioreach_graph_data *data; ++ ++ if (dir == SNDRV_PCM_STREAM_PLAYBACK) ++ data = &graph->rx_data; ++ else ++ data = &graph->tx_data; ++ ++ return (int)atomic_read(&data->hw_ptr); ++} ++EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer); ++ + static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op) + { + struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done; +@@ -520,7 +533,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op) + done = data->payload; + phys = graph->rx_data.buf[token].phys; + mutex_unlock(&graph->lock); +- ++ /* token numbering starts at 0 */ ++ atomic_set(&graph->rx_data.hw_ptr, token + 1); + if (lower_32_bits(phys) == done->buf_addr_lsw && + upper_32_bits(phys) == done->buf_addr_msw) { + graph->result.opcode = hdr->opcode; +@@ -553,6 +567,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op) + rd_done = data->payload; + phys = graph->tx_data.buf[hdr->token].phys; + mutex_unlock(&graph->lock); ++ /* token numbering starts at 0 */ ++ atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1); + + if (upper_32_bits(phys) == rd_done->buf_addr_msw && + lower_32_bits(phys) == rd_done->buf_addr_lsw) { +diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h +index f486bd639b9f0d..74fa4fed881bf9 100644 +--- a/sound/soc/qcom/qdsp6/q6apm.h ++++ b/sound/soc/qcom/qdsp6/q6apm.h +@@ -2,6 +2,7 @@ + #ifndef __Q6APM_H__ + #define __Q6APM_H__ + #include ++#include + #include + #include + #include +@@ -78,6 +79,7 @@ struct audioreach_graph_data { + uint32_t num_periods; + uint32_t dsp_buf; + uint32_t mem_map_handle; ++ atomic_t hw_ptr; + }; + + struct audioreach_graph { +@@ -151,4 +153,5 @@ int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, + int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples); + int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples); + int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id); ++int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir); + #endif /* __APM_GRAPH_ */ +diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c +index 5e14cd0a38deb6..82ef8fdb914e3b 100644 +--- a/sound/soc/qcom/qdsp6/q6asm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6asm-dai.c +@@ -902,9 +902,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, + + if (ret < 0) { + dev_err(dev, "q6asm_open_write failed\n"); +- q6asm_audio_client_free(prtd->audio_client); +- prtd->audio_client = NULL; +- return ret; ++ goto open_err; + } + } + +@@ -913,7 +911,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, + prtd->session_id, dir); + if (ret) { + dev_err(dev, "Stream reg failed ret:%d\n", ret); +- return ret; ++ goto q6_err; + } + + ret = __q6asm_dai_compr_set_codec_params(component, stream, +@@ -921,7 +919,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, + prtd->stream_id); + if (ret) { + dev_err(dev, "codec param setup failed ret:%d\n", ret); +- return ret; ++ goto q6_err; + } + + ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, +@@ -930,12 +928,21 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, + + if (ret < 0) { + dev_err(dev, "Buffer Mapping failed ret:%d\n", ret); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto q6_err; + } + + prtd->state = Q6ASM_STREAM_RUNNING; + + return 0; ++ ++q6_err: ++ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); ++ ++open_err: ++ q6asm_audio_client_free(prtd->audio_client); ++ prtd->audio_client = NULL; ++ return ret; + } + + static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component, +diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c +index cf1e63daad86bf..7afded323150c8 100644 +--- a/sound/soc/sof/topology.c ++++ b/sound/soc/sof/topology.c +@@ -1267,8 +1267,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s + struct snd_sof_tuple *new_tuples; + + num_tuples += token_list[object_token_list[i]].count * (num_sets - 1); +- new_tuples = krealloc(swidget->tuples, +- sizeof(*new_tuples) * num_tuples, GFP_KERNEL); ++ new_tuples = krealloc_array(swidget->tuples, ++ num_tuples, sizeof(*new_tuples), GFP_KERNEL); + if (!new_tuples) { + ret = -ENOMEM; + goto err; +diff --git a/sound/usb/midi.c b/sound/usb/midi.c +index 6d861046b582b5..3059f814eb5c2d 100644 +--- a/sound/usb/midi.c ++++ b/sound/usb/midi.c +@@ -489,16 +489,84 @@ static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep, + + /* + * CME protocol: like the standard protocol, but SysEx commands are sent as a +- * single USB packet preceded by a 0x0F byte. ++ * single USB packet preceded by a 0x0F byte, as are system realtime ++ * messages and MIDI Active Sensing. ++ * Also, multiple messages can be sent in the same packet. + */ + static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) + { +- if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) +- snd_usbmidi_standard_input(ep, buffer, buffer_length); +- else +- snd_usbmidi_input_data(ep, buffer[0] >> 4, +- &buffer[1], buffer_length - 1); ++ int remaining = buffer_length; ++ ++ /* ++ * CME send sysex, song position pointer, system realtime ++ * and active sensing using CIN 0x0f, which in the standard ++ * is only intended for single byte unparsed data. ++ * So we need to interpret these here before sending them on. ++ * By default, we assume single byte data, which is true ++ * for system realtime (midi clock, start, stop and continue) ++ * and active sensing, and handle the other (known) cases ++ * separately. ++ * In contrast to the standard, CME does not split sysex ++ * into multiple 4-byte packets, but lumps everything together ++ * into one. In addition, CME can string multiple messages ++ * together in the same packet; pressing the Record button ++ * on an UF6 sends a sysex message directly followed ++ * by a song position pointer in the same packet. ++ * For it to have any reasonable meaning, a sysex message ++ * needs to be at least 3 bytes in length (0xf0, id, 0xf7), ++ * corresponding to a packet size of 4 bytes, and the ones sent ++ * by CME devices are 6 or 7 bytes, making the packet fragments ++ * 7 or 8 bytes long (six or seven bytes plus preceding CN+CIN byte). ++ * For the other types, the packet size is always 4 bytes, ++ * as per the standard, with the data size being 3 for SPP ++ * and 1 for the others. ++ * Thus all packet fragments are at least 4 bytes long, so we can ++ * skip anything that is shorter; this also conveniantly skips ++ * packets with size 0, which CME devices continuously send when ++ * they have nothing better to do. ++ * Another quirk is that sometimes multiple messages are sent ++ * in the same packet. This has been observed for midi clock ++ * and active sensing i.e. 0x0f 0xf8 0x00 0x00 0x0f 0xfe 0x00 0x00, ++ * but also multiple note ons/offs, and control change together ++ * with MIDI clock. Similarly, some sysex messages are followed by ++ * the song position pointer in the same packet, and occasionally ++ * additionally by a midi clock or active sensing. ++ * We handle this by looping over all data and parsing it along the way. ++ */ ++ while (remaining >= 4) { ++ int source_length = 4; /* default */ ++ ++ if ((buffer[0] & 0x0f) == 0x0f) { ++ int data_length = 1; /* default */ ++ ++ if (buffer[1] == 0xf0) { ++ /* Sysex: Find EOX and send on whole message. */ ++ /* To kick off the search, skip the first ++ * two bytes (CN+CIN and SYSEX (0xf0). ++ */ ++ uint8_t *tmp_buf = buffer + 2; ++ int tmp_length = remaining - 2; ++ ++ while (tmp_length > 1 && *tmp_buf != 0xf7) { ++ tmp_buf++; ++ tmp_length--; ++ } ++ data_length = tmp_buf - buffer; ++ source_length = data_length + 1; ++ } else if (buffer[1] == 0xf2) { ++ /* Three byte song position pointer */ ++ data_length = 3; ++ } ++ snd_usbmidi_input_data(ep, buffer[0] >> 4, ++ &buffer[1], data_length); ++ } else { ++ /* normal channel events */ ++ snd_usbmidi_standard_input(ep, buffer, source_length); ++ } ++ buffer += source_length; ++ remaining -= source_length; ++ } + } + + /* +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 9102ad5985cc0f..8ba5bcfd5cd572 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -3926,6 +3926,11 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) + WARN_INSN(insn, "RET before UNTRAIN"); + return 1; + ++ case INSN_CONTEXT_SWITCH: ++ if (insn_func(insn)) ++ break; ++ return 0; ++ + case INSN_NOP: + if (insn->retpoline_safe) + return 0; +diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c +index e63dc11fa3a533..48e25be6e16356 100644 +--- a/tools/power/cpupower/bench/parse.c ++++ b/tools/power/cpupower/bench/parse.c +@@ -120,6 +120,10 @@ FILE *prepare_output(const char *dirname) + struct config *prepare_default_config() + { + struct config *config = malloc(sizeof(struct config)); ++ if (!config) { ++ perror("malloc"); ++ return NULL; ++ } + + dprintf("loading defaults\n"); + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 83d65c2abaf010..3316015757433a 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4289,6 +4289,14 @@ if (defined($opt{"LOG_FILE"})) { + if ($opt{"CLEAR_LOG"}) { + unlink $opt{"LOG_FILE"}; + } ++ ++ if (! -e $opt{"LOG_FILE"} && $opt{"LOG_FILE"} =~ m,^(.*/),) { ++ my $dir = $1; ++ if (! -d $dir) { ++ mkpath($dir) or die "Failed to create directories '$dir': $!"; ++ print "\nThe log directory $dir did not exist, so it was created.\n"; ++ } ++ } + open(LOG, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; + LOG->autoflush(1); + } +diff --git a/tools/testing/kunit/qemu_configs/sh.py b/tools/testing/kunit/qemu_configs/sh.py +index 78a474a5b95f3a..f00cb89fdef6aa 100644 +--- a/tools/testing/kunit/qemu_configs/sh.py ++++ b/tools/testing/kunit/qemu_configs/sh.py +@@ -7,7 +7,9 @@ CONFIG_CPU_SUBTYPE_SH7751R=y + CONFIG_MEMORY_START=0x0c000000 + CONFIG_SH_RTS7751R2D=y + CONFIG_RTS7751R2D_PLUS=y +-CONFIG_SERIAL_SH_SCI=y''', ++CONFIG_SERIAL_SH_SCI=y ++CONFIG_CMDLINE_EXTEND=y ++''', + qemu_arch='sh4', + kernel_path='arch/sh/boot/zImage', + kernel_command_line='console=ttySC1', +diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c +index d587a558997f8c..11149bd12a1f79 100644 +--- a/tools/testing/radix-tree/linux.c ++++ b/tools/testing/radix-tree/linux.c +@@ -121,7 +121,7 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp) + void kmem_cache_free_bulk(struct kmem_cache *cachep, size_t size, void **list) + { + if (kmalloc_verbose) +- pr_debug("Bulk free %p[0-%lu]\n", list, size - 1); ++ pr_debug("Bulk free %p[0-%zu]\n", list, size - 1); + + pthread_mutex_lock(&cachep->lock); + for (int i = 0; i < size; i++) +@@ -139,7 +139,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, + size_t i; + + if (kmalloc_verbose) +- pr_debug("Bulk alloc %lu\n", size); ++ pr_debug("Bulk alloc %zu\n", size); + + if (!(gfp & __GFP_DIRECT_RECLAIM)) { + if (cachep->non_kernel < size) +diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c +index 7d7a6a06cdb75b..2d8230da906429 100644 +--- a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c ++++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c +@@ -98,7 +98,7 @@ int main(int argc, char *argv[]) + info("Calling futex_waitv on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); + res = futex_waitv(&waitv, 1, 0, &to, CLOCK_MONOTONIC); + if (!res || errno != EWOULDBLOCK) { +- ksft_test_result_pass("futex_waitv returned: %d %s\n", ++ ksft_test_result_fail("futex_waitv returned: %d %s\n", + res ? errno : res, + res ? strerror(errno) : ""); + ret = RET_FAIL; +diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c +index 5aa7d2feab100d..b06410bd1aa14e 100644 +--- a/tools/testing/selftests/landlock/base_test.c ++++ b/tools/testing/selftests/landlock/base_test.c +@@ -98,10 +98,54 @@ TEST(abi_version) + ASSERT_EQ(EINVAL, errno); + } + ++/* ++ * Old source trees might not have the set of Kselftest fixes related to kernel ++ * UAPI headers. ++ */ ++#ifndef LANDLOCK_CREATE_RULESET_ERRATA ++#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1) ++#endif ++ ++TEST(errata) ++{ ++ const struct landlock_ruleset_attr ruleset_attr = { ++ .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, ++ }; ++ int errata; ++ ++ errata = landlock_create_ruleset(NULL, 0, ++ LANDLOCK_CREATE_RULESET_ERRATA); ++ /* The errata bitmask will not be backported to tests. */ ++ ASSERT_LE(0, errata); ++ TH_LOG("errata: 0x%x", errata); ++ ++ ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, ++ LANDLOCK_CREATE_RULESET_ERRATA)); ++ ASSERT_EQ(EINVAL, errno); ++ ++ ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr), ++ LANDLOCK_CREATE_RULESET_ERRATA)); ++ ASSERT_EQ(EINVAL, errno); ++ ++ ASSERT_EQ(-1, ++ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), ++ LANDLOCK_CREATE_RULESET_ERRATA)); ++ ASSERT_EQ(EINVAL, errno); ++ ++ ASSERT_EQ(-1, landlock_create_ruleset( ++ NULL, 0, ++ LANDLOCK_CREATE_RULESET_VERSION | ++ LANDLOCK_CREATE_RULESET_ERRATA)); ++ ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, ++ LANDLOCK_CREATE_RULESET_ERRATA | ++ 1 << 31)); ++ ASSERT_EQ(EINVAL, errno); ++} ++ + /* Tests ordering of syscall argument checks. */ + TEST(create_ruleset_checks_ordering) + { +- const int last_flag = LANDLOCK_CREATE_RULESET_VERSION; ++ const int last_flag = LANDLOCK_CREATE_RULESET_ERRATA; + const int invalid_flag = last_flag << 1; + int ruleset_fd; + const struct landlock_ruleset_attr ruleset_attr = { +diff --git a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh +index 8e00276b4e69be..dc3fc438b3d9e1 100755 +--- a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh ++++ b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh +@@ -27,7 +27,7 @@ fi + if [[ $cgroup2 ]]; then + cgroup_path=$(mount -t cgroup2 | head -1 | awk '{print $3}') + if [[ -z "$cgroup_path" ]]; then +- cgroup_path=/dev/cgroup/memory ++ cgroup_path=$(mktemp -d) + mount -t cgroup2 none $cgroup_path + do_umount=1 + fi +@@ -35,7 +35,7 @@ if [[ $cgroup2 ]]; then + else + cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}') + if [[ -z "$cgroup_path" ]]; then +- cgroup_path=/dev/cgroup/memory ++ cgroup_path=$(mktemp -d) + mount -t cgroup memory,hugetlb $cgroup_path + do_umount=1 + fi +diff --git a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh +index 14d26075c8635f..302f2c7003f034 100755 +--- a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh ++++ b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh +@@ -22,7 +22,7 @@ fi + if [[ $cgroup2 ]]; then + CGROUP_ROOT=$(mount -t cgroup2 | head -1 | awk '{print $3}') + if [[ -z "$CGROUP_ROOT" ]]; then +- CGROUP_ROOT=/dev/cgroup/memory ++ CGROUP_ROOT=$(mktemp -d) + mount -t cgroup2 none $CGROUP_ROOT + do_umount=1 + fi +diff --git a/tools/testing/selftests/net/mptcp/diag.sh b/tools/testing/selftests/net/mptcp/diag.sh +index 7f89623f1080e1..f00c97b2a6b5f6 100755 +--- a/tools/testing/selftests/net/mptcp/diag.sh ++++ b/tools/testing/selftests/net/mptcp/diag.sh +@@ -186,23 +186,6 @@ chk_msk_inuse() + __chk_nr get_msk_inuse $expected "${msg}" 0 + } + +-# $1: ns, $2: port +-wait_local_port_listen() +-{ +- local listener_ns="${1}" +- local port="${2}" +- +- local port_hex i +- +- port_hex="$(printf "%04X" "${port}")" +- for i in $(seq 10); do +- ip netns exec "${listener_ns}" cat /proc/net/tcp | \ +- awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && +- break +- sleep 0.1 +- done +-} +- + # $1: cestab nr + chk_msk_cestab() + { +@@ -240,7 +223,7 @@ echo "a" | \ + ip netns exec $ns \ + ./mptcp_connect -p 10000 -l -t ${timeout_poll} -w 20 \ + 0.0.0.0 >/dev/null & +-wait_local_port_listen $ns 10000 ++mptcp_lib_wait_local_port_listen $ns 10000 + chk_msk_nr 0 "no msk on netns creation" + chk_msk_listen 10000 + +@@ -265,7 +248,7 @@ echo "a" | \ + ip netns exec $ns \ + ./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} -w 20 \ + 0.0.0.0 >/dev/null & +-wait_local_port_listen $ns 10001 ++mptcp_lib_wait_local_port_listen $ns 10001 + echo "b" | \ + timeout ${timeout_test} \ + ip netns exec $ns \ +@@ -288,7 +271,7 @@ for I in `seq 1 $NR_CLIENTS`; do + ./mptcp_connect -p $((I+10001)) -l -w 20 \ + -t ${timeout_poll} 0.0.0.0 >/dev/null & + done +-wait_local_port_listen $ns $((NR_CLIENTS + 10001)) ++mptcp_lib_wait_local_port_listen $ns $((NR_CLIENTS + 10001)) + + for I in `seq 1 $NR_CLIENTS`; do + echo "b" | \ +diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c +index d240d02fa443a1..c83a8b47bbdfa5 100644 +--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c ++++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c +@@ -1270,7 +1270,7 @@ int main_loop(void) + + if (cfg_input && cfg_sockopt_types.mptfo) { + fd_in = open(cfg_input, O_RDONLY); +- if (fd < 0) ++ if (fd_in < 0) + xerror("can't open %s:%d", cfg_input, errno); + } + +@@ -1293,13 +1293,13 @@ int main_loop(void) + + if (cfg_input && !cfg_sockopt_types.mptfo) { + fd_in = open(cfg_input, O_RDONLY); +- if (fd < 0) ++ if (fd_in < 0) + xerror("can't open %s:%d", cfg_input, errno); + } + + ret = copyfd_io(fd_in, fd, 1, 0, &winfo); + if (ret) +- return ret; ++ goto out; + + if (cfg_truncate > 0) { + shutdown(fd, SHUT_WR); +@@ -1320,7 +1320,10 @@ int main_loop(void) + close(fd); + } + +- return 0; ++out: ++ if (cfg_input) ++ close(fd_in); ++ return ret; + } + + int parse_proto(const char *proto) +diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh +index d203d314b7b265..3763ffa214d53f 100755 +--- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh +@@ -342,23 +342,6 @@ do_ping() + return 0 + } + +-# $1: ns, $2: port +-wait_local_port_listen() +-{ +- local listener_ns="${1}" +- local port="${2}" +- +- local port_hex i +- +- port_hex="$(printf "%04X" "${port}")" +- for i in $(seq 10); do +- ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ +- awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && +- break +- sleep 0.1 +- done +-} +- + do_transfer() + { + local listener_ns="$1" +@@ -448,7 +431,7 @@ do_transfer() + $extra_args $local_addr < "$sin" > "$sout" & + local spid=$! + +- wait_local_port_listen "${listener_ns}" "${port}" ++ mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}" + + local start + start=$(date +%s%3N) +diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh +index 497dc187387f8d..442b7220468afc 100755 +--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh +@@ -598,24 +598,6 @@ link_failure() + done + } + +-# $1: ns, $2: port +-wait_local_port_listen() +-{ +- local listener_ns="${1}" +- local port="${2}" +- +- local port_hex +- port_hex="$(printf "%04X" "${port}")" +- +- local i +- for i in $(seq 10); do +- ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ +- awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && +- break +- sleep 0.1 +- done +-} +- + rm_addr_count() + { + mptcp_lib_get_counter "${1}" "MPTcpExtRmAddr" +@@ -1117,7 +1099,7 @@ do_transfer() + fi + local spid=$! + +- wait_local_port_listen "${listener_ns}" "${port}" ++ mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}" + + extra_cl_args="$extra_args $extra_cl_args" + if [ "$test_linkfail" -eq 0 ];then +diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh +index d98c89f31afe8a..919f4f1018eb71 100644 +--- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh +@@ -274,3 +274,21 @@ mptcp_lib_events() { + ip netns exec "${ns}" ./pm_nl_ctl events >> "${evts}" 2>&1 & + pid=$! + } ++ ++# $1: ns, $2: port ++mptcp_lib_wait_local_port_listen() { ++ local listener_ns="${1}" ++ local port="${2}" ++ ++ local port_hex ++ port_hex="$(printf "%04X" "${port}")" ++ ++ local _ ++ for _ in $(seq 10); do ++ ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ ++ awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) \ ++ {rc=0; exit}} END {exit rc}" && ++ break ++ sleep 0.1 ++ done ++} +diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh +index f24bd2bf083111..214a89fce8b803 100755 +--- a/tools/testing/selftests/net/mptcp/simult_flows.sh ++++ b/tools/testing/selftests/net/mptcp/simult_flows.sh +@@ -123,23 +123,6 @@ setup() + grep -q ' kmemleak_init$\| lockdep_init$\| kasan_init$\| prove_locking$' /proc/kallsyms && slack=$((slack+550)) + } + +-# $1: ns, $2: port +-wait_local_port_listen() +-{ +- local listener_ns="${1}" +- local port="${2}" +- +- local port_hex i +- +- port_hex="$(printf "%04X" "${port}")" +- for i in $(seq 10); do +- ip netns exec "${listener_ns}" cat /proc/net/tcp* | \ +- awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" && +- break +- sleep 0.1 +- done +-} +- + do_transfer() + { + local cin=$1 +@@ -179,7 +162,7 @@ do_transfer() + 0.0.0.0 < "$sin" > "$sout" & + local spid=$! + +- wait_local_port_listen "${ns3}" "${port}" ++ mptcp_lib_wait_local_port_listen "${ns3}" "${port}" + + timeout ${timeout_test} \ + ip netns exec ${ns1} \ diff --git a/patch/kernel/archive/spacemit-6.6/patch-6.6.88-89.patch b/patch/kernel/archive/spacemit-6.6/patch-6.6.88-89.patch new file mode 100644 index 000000000000..56b336c43150 --- /dev/null +++ b/patch/kernel/archive/spacemit-6.6/patch-6.6.88-89.patch @@ -0,0 +1,6884 @@ +diff --git a/Documentation/scheduler/sched-capacity.rst b/Documentation/scheduler/sched-capacity.rst +index e2c1cf7431588e..de414b33dd2abd 100644 +--- a/Documentation/scheduler/sched-capacity.rst ++++ b/Documentation/scheduler/sched-capacity.rst +@@ -39,14 +39,15 @@ per Hz, leading to:: + ------------------- + + Two different capacity values are used within the scheduler. A CPU's +-``capacity_orig`` is its maximum attainable capacity, i.e. its maximum +-attainable performance level. A CPU's ``capacity`` is its ``capacity_orig`` to +-which some loss of available performance (e.g. time spent handling IRQs) is +-subtracted. ++``original capacity`` is its maximum attainable capacity, i.e. its maximum ++attainable performance level. This original capacity is returned by ++the function arch_scale_cpu_capacity(). A CPU's ``capacity`` is its ``original ++capacity`` to which some loss of available performance (e.g. time spent ++handling IRQs) is subtracted. + + Note that a CPU's ``capacity`` is solely intended to be used by the CFS class, +-while ``capacity_orig`` is class-agnostic. The rest of this document will use +-the term ``capacity`` interchangeably with ``capacity_orig`` for the sake of ++while ``original capacity`` is class-agnostic. The rest of this document will use ++the term ``capacity`` interchangeably with ``original capacity`` for the sake of + brevity. + + 1.3 Platform examples +diff --git a/Makefile b/Makefile +index b1dfe3df7dfc9d..23e90df5785c84 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 88 ++SUBLEVEL = 89 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi +index 39110c1232e0da..db10b4b46cca9d 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi +@@ -196,13 +196,6 @@ key-power { + wakeup-event-action = ; + wakeup-source; + }; +- +- key-suspend { +- label = "Suspend"; +- gpios = <&gpio TEGRA234_MAIN_GPIO(G, 2) GPIO_ACTIVE_LOW>; +- linux,input-type = ; +- linux,code = ; +- }; + }; + + fan: pwm-fan { +diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig +index 623cf80639decc..25aa993abebcea 100644 +--- a/arch/loongarch/Kconfig ++++ b/arch/loongarch/Kconfig +@@ -59,6 +59,7 @@ config LOONGARCH + select ARCH_SUPPORTS_NUMA_BALANCING + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_CMPXCHG_LOCKREF ++ select ARCH_USE_MEMTEST + select ARCH_USE_QUEUED_RWLOCKS + select ARCH_USE_QUEUED_SPINLOCKS + select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT +diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h +index f3ddaed9ef7f08..a5b63c84f8541a 100644 +--- a/arch/loongarch/include/asm/ptrace.h ++++ b/arch/loongarch/include/asm/ptrace.h +@@ -33,9 +33,9 @@ struct pt_regs { + unsigned long __last[]; + } __aligned(8); + +-static inline int regs_irqs_disabled(struct pt_regs *regs) ++static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) + { +- return arch_irqs_disabled_flags(regs->csr_prmd); ++ return !(regs->csr_prmd & CSR_PRMD_PIE); + } + + static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c +index d59052c03d9b7e..2b4b99b4e6c94e 100644 +--- a/arch/loongarch/kernel/traps.c ++++ b/arch/loongarch/kernel/traps.c +@@ -527,9 +527,10 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs) + die_if_kernel("Kernel ale access", regs); + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr); + #else ++ bool pie = regs_irqs_disabled(regs); + unsigned int *pc; + +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr); +@@ -556,7 +557,7 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs) + die_if_kernel("Kernel ale access", regs); + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr); + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + #endif + irqentry_exit(regs, state); +@@ -588,12 +589,13 @@ static void bug_handler(struct pt_regs *regs) + asmlinkage void noinstr do_bce(struct pt_regs *regs) + { + bool user = user_mode(regs); ++ bool pie = regs_irqs_disabled(regs); + unsigned long era = exception_era(regs); + u64 badv = 0, lower = 0, upper = ULONG_MAX; + union loongarch_instruction insn; + irqentry_state_t state = irqentry_enter(regs); + +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + current->thread.trap_nr = read_csr_excode(); +@@ -659,7 +661,7 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs) + force_sig_bnderr((void __user *)badv, (void __user *)lower, (void __user *)upper); + + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + + irqentry_exit(regs, state); +@@ -677,11 +679,12 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs) + asmlinkage void noinstr do_bp(struct pt_regs *regs) + { + bool user = user_mode(regs); ++ bool pie = regs_irqs_disabled(regs); + unsigned int opcode, bcode; + unsigned long era = exception_era(regs); + irqentry_state_t state = irqentry_enter(regs); + +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + if (__get_inst(&opcode, (u32 *)era, user)) +@@ -747,7 +750,7 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs) + } + + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + + irqentry_exit(regs, state); +@@ -982,6 +985,7 @@ static void init_restore_lbt(void) + + asmlinkage void noinstr do_lbt(struct pt_regs *regs) + { ++ bool pie = regs_irqs_disabled(regs); + irqentry_state_t state = irqentry_enter(regs); + + /* +@@ -991,7 +995,7 @@ asmlinkage void noinstr do_lbt(struct pt_regs *regs) + * (including the user using 'MOVGR2GCSR' to turn on TM, which + * will not trigger the BTE), we need to check PRMD first. + */ +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_enable(); + + if (!cpu_has_lbt) { +@@ -1005,7 +1009,7 @@ asmlinkage void noinstr do_lbt(struct pt_regs *regs) + preempt_enable(); + + out: +- if (regs->csr_prmd & CSR_PRMD_PIE) ++ if (!pie) + local_irq_disable(); + + irqentry_exit(regs, state); +diff --git a/arch/loongarch/mm/hugetlbpage.c b/arch/loongarch/mm/hugetlbpage.c +index 1e76fcb83093dd..41308429f44612 100644 +--- a/arch/loongarch/mm/hugetlbpage.c ++++ b/arch/loongarch/mm/hugetlbpage.c +@@ -47,7 +47,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr, + pmd = pmd_offset(pud, addr); + } + } +- return (pte_t *) pmd; ++ return pmd_none(pmdp_get(pmd)) ? NULL : (pte_t *) pmd; + } + + int pmd_huge(pmd_t pmd) +diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c +index 4dd53427f65785..a5bf96993bb1a6 100644 +--- a/arch/loongarch/mm/init.c ++++ b/arch/loongarch/mm/init.c +@@ -64,9 +64,6 @@ void __init paging_init(void) + { + unsigned long max_zone_pfns[MAX_NR_ZONES]; + +-#ifdef CONFIG_ZONE_DMA +- max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; +-#endif + #ifdef CONFIG_ZONE_DMA32 + max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; + #endif +diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h +index 696b40beb774f5..8494466740ccad 100644 +--- a/arch/mips/include/asm/mips-cm.h ++++ b/arch/mips/include/asm/mips-cm.h +@@ -47,6 +47,16 @@ extern phys_addr_t __mips_cm_phys_base(void); + */ + extern int mips_cm_is64; + ++/* ++ * mips_cm_is_l2_hci_broken - determine if HCI is broken ++ * ++ * Some CM reports show that Hardware Cache Initialization is ++ * complete, but in reality it's not the case. They also incorrectly ++ * indicate that Hardware Cache Initialization is supported. This ++ * flags allows warning about this broken feature. ++ */ ++extern bool mips_cm_is_l2_hci_broken; ++ + /** + * mips_cm_error_report - Report CM cache errors + */ +@@ -85,6 +95,18 @@ static inline bool mips_cm_present(void) + #endif + } + ++/** ++ * mips_cm_update_property - update property from the device tree ++ * ++ * Retrieve the properties from the device tree if a CM node exist and ++ * update the internal variable based on this. ++ */ ++#ifdef CONFIG_MIPS_CM ++extern void mips_cm_update_property(void); ++#else ++static inline void mips_cm_update_property(void) {} ++#endif ++ + /** + * mips_cm_has_l2sync - determine whether an L2-only sync region is present + * +diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c +index 3f00788b08718d..4f75160f08949f 100644 +--- a/arch/mips/kernel/mips-cm.c ++++ b/arch/mips/kernel/mips-cm.c +@@ -5,6 +5,7 @@ + */ + + #include ++#include + #include + #include + +@@ -14,6 +15,7 @@ + void __iomem *mips_gcr_base; + void __iomem *mips_cm_l2sync_base; + int mips_cm_is64; ++bool mips_cm_is_l2_hci_broken; + + static char *cm2_tr[8] = { + "mem", "gcr", "gic", "mmio", +@@ -243,6 +245,18 @@ static void mips_cm_probe_l2sync(void) + mips_cm_l2sync_base = ioremap(addr, MIPS_CM_L2SYNC_SIZE); + } + ++void mips_cm_update_property(void) ++{ ++ struct device_node *cm_node; ++ ++ cm_node = of_find_compatible_node(of_root, NULL, "mobileye,eyeq6-cm"); ++ if (!cm_node) ++ return; ++ pr_info("HCI (Hardware Cache Init for the L2 cache) in GCR_L2_RAM_CONFIG from the CM3 is broken"); ++ mips_cm_is_l2_hci_broken = true; ++ of_node_put(cm_node); ++} ++ + int mips_cm_probe(void) + { + phys_addr_t addr; +diff --git a/arch/parisc/kernel/pdt.c b/arch/parisc/kernel/pdt.c +index 0f9b3b5914cf69..b70b67adb855f6 100644 +--- a/arch/parisc/kernel/pdt.c ++++ b/arch/parisc/kernel/pdt.c +@@ -63,6 +63,7 @@ static unsigned long pdt_entry[MAX_PDT_ENTRIES] __page_aligned_bss; + #define PDT_ADDR_PERM_ERR (pdt_type != PDT_PDC ? 2UL : 0UL) + #define PDT_ADDR_SINGLE_ERR 1UL + ++#ifdef CONFIG_PROC_FS + /* report PDT entries via /proc/meminfo */ + void arch_report_meminfo(struct seq_file *m) + { +@@ -74,6 +75,7 @@ void arch_report_meminfo(struct seq_file *m) + seq_printf(m, "PDT_cur_entries: %7lu\n", + pdt_status.pdt_entries); + } ++#endif + + static int get_info_pat_new(void) + { +diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h +index 721ec275ce57e3..231d777d936c2d 100644 +--- a/arch/riscv/include/asm/alternative-macros.h ++++ b/arch/riscv/include/asm/alternative-macros.h +@@ -115,24 +115,19 @@ + \old_c + .endm + +-#define _ALTERNATIVE_CFG(old_c, ...) \ +- ALTERNATIVE_CFG old_c +- +-#define _ALTERNATIVE_CFG_2(old_c, ...) \ +- ALTERNATIVE_CFG old_c ++#define __ALTERNATIVE_CFG(old_c, ...) ALTERNATIVE_CFG old_c ++#define __ALTERNATIVE_CFG_2(old_c, ...) ALTERNATIVE_CFG old_c + + #else /* !__ASSEMBLY__ */ + +-#define __ALTERNATIVE_CFG(old_c) \ +- old_c "\n" ++#define __ALTERNATIVE_CFG(old_c, ...) old_c "\n" ++#define __ALTERNATIVE_CFG_2(old_c, ...) old_c "\n" + +-#define _ALTERNATIVE_CFG(old_c, ...) \ +- __ALTERNATIVE_CFG(old_c) ++#endif /* __ASSEMBLY__ */ + +-#define _ALTERNATIVE_CFG_2(old_c, ...) \ +- __ALTERNATIVE_CFG(old_c) ++#define _ALTERNATIVE_CFG(old_c, ...) __ALTERNATIVE_CFG(old_c) ++#define _ALTERNATIVE_CFG_2(old_c, ...) __ALTERNATIVE_CFG_2(old_c) + +-#endif /* __ASSEMBLY__ */ + #endif /* CONFIG_RISCV_ALTERNATIVE */ + + /* +diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c +index b16352083ff987..f0be263b334ced 100644 +--- a/arch/s390/kvm/intercept.c ++++ b/arch/s390/kvm/intercept.c +@@ -94,7 +94,7 @@ static int handle_validity(struct kvm_vcpu *vcpu) + + vcpu->stat.exit_validity++; + trace_kvm_s390_intercept_validity(vcpu, viwhy); +- KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy, ++ KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%p)", viwhy, + current->pid, vcpu->kvm); + + /* do not warn on invalid runtime instrumentation mode */ +diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c +index efaebba5ee19c7..fe4841104ed924 100644 +--- a/arch/s390/kvm/interrupt.c ++++ b/arch/s390/kvm/interrupt.c +@@ -3161,7 +3161,7 @@ void kvm_s390_gisa_clear(struct kvm *kvm) + if (!gi->origin) + return; + gisa_clear_ipm(gi->origin); +- VM_EVENT(kvm, 3, "gisa 0x%pK cleared", gi->origin); ++ VM_EVENT(kvm, 3, "gisa 0x%p cleared", gi->origin); + } + + void kvm_s390_gisa_init(struct kvm *kvm) +@@ -3178,7 +3178,7 @@ void kvm_s390_gisa_init(struct kvm *kvm) + gi->timer.function = gisa_vcpu_kicker; + memset(gi->origin, 0, sizeof(struct kvm_s390_gisa)); + gi->origin->next_alert = (u32)virt_to_phys(gi->origin); +- VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin); ++ VM_EVENT(kvm, 3, "gisa 0x%p initialized", gi->origin); + } + + void kvm_s390_gisa_enable(struct kvm *kvm) +@@ -3219,7 +3219,7 @@ void kvm_s390_gisa_destroy(struct kvm *kvm) + process_gib_alert_list(); + hrtimer_cancel(&gi->timer); + gi->origin = NULL; +- VM_EVENT(kvm, 3, "gisa 0x%pK destroyed", gisa); ++ VM_EVENT(kvm, 3, "gisa 0x%p destroyed", gisa); + } + + void kvm_s390_gisa_disable(struct kvm *kvm) +@@ -3468,7 +3468,7 @@ int __init kvm_s390_gib_init(u8 nisc) + } + } + +- KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc); ++ KVM_EVENT(3, "gib 0x%p (nisc=%d) initialized", gib, gib->nisc); + goto out; + + out_unreg_gal: +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index 348d030d2660ca..890d850f51f076 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -990,7 +990,7 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att + } + mutex_unlock(&kvm->lock); + VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit); +- VM_EVENT(kvm, 3, "New guest asce: 0x%pK", ++ VM_EVENT(kvm, 3, "New guest asce: 0x%p", + (void *) kvm->arch.gmap->asce); + break; + } +@@ -3418,7 +3418,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) + kvm_s390_gisa_init(kvm); + INIT_LIST_HEAD(&kvm->arch.pv.need_cleanup); + kvm->arch.pv.set_aside = NULL; +- KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid); ++ KVM_EVENT(3, "vm 0x%p created by pid %u", kvm, current->pid); + + return 0; + out_err: +@@ -3481,7 +3481,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) + kvm_s390_destroy_adapters(kvm); + kvm_s390_clear_float_irqs(kvm); + kvm_s390_vsie_destroy(kvm); +- KVM_EVENT(3, "vm 0x%pK destroyed", kvm); ++ KVM_EVENT(3, "vm 0x%p destroyed", kvm); + } + + /* Section: vcpu related */ +@@ -3602,7 +3602,7 @@ static int sca_switch_to_extended(struct kvm *kvm) + + free_page((unsigned long)old_sca); + +- VM_EVENT(kvm, 2, "Switched to ESCA (0x%pK -> 0x%pK)", ++ VM_EVENT(kvm, 2, "Switched to ESCA (0x%p -> 0x%p)", + old_sca, kvm->arch.sca); + return 0; + } +@@ -3974,7 +3974,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) + goto out_free_sie_block; + } + +- VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK", ++ VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%p, sie block at 0x%p", + vcpu->vcpu_id, vcpu, vcpu->arch.sie_block); + trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block); + +diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h +index 6f0209d45164f0..9c5f546a2e1a3c 100644 +--- a/arch/s390/kvm/trace-s390.h ++++ b/arch/s390/kvm/trace-s390.h +@@ -56,7 +56,7 @@ TRACE_EVENT(kvm_s390_create_vcpu, + __entry->sie_block = sie_block; + ), + +- TP_printk("create cpu %d at 0x%pK, sie block at 0x%pK", ++ TP_printk("create cpu %d at 0x%p, sie block at 0x%p", + __entry->id, __entry->vcpu, __entry->sie_block) + ); + +@@ -255,7 +255,7 @@ TRACE_EVENT(kvm_s390_enable_css, + __entry->kvm = kvm; + ), + +- TP_printk("enabling channel I/O support (kvm @ %pK)\n", ++ TP_printk("enabling channel I/O support (kvm @ %p)\n", + __entry->kvm) + ); + +diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S +index 2143358d0c4c74..78fd2442b49dcd 100644 +--- a/arch/x86/entry/entry.S ++++ b/arch/x86/entry/entry.S +@@ -16,7 +16,7 @@ + + SYM_FUNC_START(entry_ibpb) + movl $MSR_IA32_PRED_CMD, %ecx +- movl $PRED_CMD_IBPB, %eax ++ movl _ASM_RIP(x86_pred_cmd), %eax + xorl %edx, %edx + wrmsr + +diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c +index 1458ccaa6a0579..ad63bd408cd900 100644 +--- a/arch/x86/events/core.c ++++ b/arch/x86/events/core.c +@@ -623,7 +623,7 @@ int x86_pmu_hw_config(struct perf_event *event) + if (event->attr.type == event->pmu->type) + event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK; + +- if (!event->attr.freq && x86_pmu.limit_period) { ++ if (is_sampling_event(event) && !event->attr.freq && x86_pmu.limit_period) { + s64 left = event->attr.sample_period; + x86_pmu.limit_period(event, &left); + if (left > event->attr.sample_period) +diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h +index ca8eed1d496ab4..2bec0c89a95c27 100644 +--- a/arch/x86/include/asm/asm.h ++++ b/arch/x86/include/asm/asm.h +@@ -229,9 +229,6 @@ register unsigned long current_stack_pointer asm(_ASM_SP); + #define _ASM_EXTABLE_UA(from, to) \ + _ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS) + +-#define _ASM_EXTABLE_CPY(from, to) \ +- _ASM_EXTABLE_TYPE(from, to, EX_TYPE_COPY) +- + #define _ASM_EXTABLE_FAULT(from, to) \ + _ASM_EXTABLE_TYPE(from, to, EX_TYPE_FAULT) + +diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h +index 991e31cfde94cc..afad9c0b07e0c8 100644 +--- a/arch/x86/include/asm/extable_fixup_types.h ++++ b/arch/x86/include/asm/extable_fixup_types.h +@@ -36,7 +36,7 @@ + #define EX_TYPE_DEFAULT 1 + #define EX_TYPE_FAULT 2 + #define EX_TYPE_UACCESS 3 +-#define EX_TYPE_COPY 4 ++/* unused, was: #define EX_TYPE_COPY 4 */ + #define EX_TYPE_CLEAR_FS 5 + #define EX_TYPE_FPU_RESTORE 6 + #define EX_TYPE_BPF 7 +diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h +index f81a851c46dca5..652c0137e909f3 100644 +--- a/arch/x86/include/asm/intel-family.h ++++ b/arch/x86/include/asm/intel-family.h +@@ -159,6 +159,8 @@ + #define INTEL_FAM6_GRANITERAPIDS_D 0xAE + #define INTEL_GRANITERAPIDS_D IFM(6, 0xAE) + ++#define INTEL_BARTLETTLAKE IFM(6, 0xD7) /* Raptor Cove */ ++ + /* "Hybrid" Processors (P-Core/E-Core) */ + + #define INTEL_FAM6_LAKEFIELD 0x8A /* Sunny Cove / Tremont */ +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 7df458a6553eb2..78545f7e9cc6ca 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -1574,7 +1574,7 @@ static void __init spec_ctrl_disable_kernel_rrsba(void) + rrsba_disabled = true; + } + +-static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_mitigation mode) ++static void __init spectre_v2_select_rsb_mitigation(enum spectre_v2_mitigation mode) + { + /* + * Similar to context switches, there are two types of RSB attacks +@@ -1598,27 +1598,30 @@ static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_ + */ + switch (mode) { + case SPECTRE_V2_NONE: +- return; ++ break; + +- case SPECTRE_V2_EIBRS_LFENCE: + case SPECTRE_V2_EIBRS: ++ case SPECTRE_V2_EIBRS_LFENCE: ++ case SPECTRE_V2_EIBRS_RETPOLINE: + if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) { +- setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT_LITE); + pr_info("Spectre v2 / PBRSB-eIBRS: Retire a single CALL on VMEXIT\n"); ++ setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT_LITE); + } +- return; ++ break; + +- case SPECTRE_V2_EIBRS_RETPOLINE: + case SPECTRE_V2_RETPOLINE: + case SPECTRE_V2_LFENCE: + case SPECTRE_V2_IBRS: ++ pr_info("Spectre v2 / SpectreRSB: Filling RSB on context switch and VMEXIT\n"); ++ setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); + setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT); +- pr_info("Spectre v2 / SpectreRSB : Filling RSB on VMEXIT\n"); +- return; +- } ++ break; + +- pr_warn_once("Unknown Spectre v2 mode, disabling RSB mitigation at VM exit"); +- dump_stack(); ++ default: ++ pr_warn_once("Unknown Spectre v2 mode, disabling RSB mitigation\n"); ++ dump_stack(); ++ break; ++ } + } + + /* +@@ -1844,10 +1847,7 @@ static void __init spectre_v2_select_mitigation(void) + * + * FIXME: Is this pointless for retbleed-affected AMD? + */ +- setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); +- pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n"); +- +- spectre_v2_determine_rsb_fill_type_at_vmexit(mode); ++ spectre_v2_select_rsb_mitigation(mode); + + /* + * Retpoline protects the kernel, but doesn't protect firmware. IBRS +diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c +index c4477162c07d13..9c5754229d6ed3 100644 +--- a/arch/x86/kernel/cpu/mce/severity.c ++++ b/arch/x86/kernel/cpu/mce/severity.c +@@ -288,14 +288,12 @@ static noinstr int error_context(struct mce *m, struct pt_regs *regs) + copy_user = is_copy_from_user(regs); + instrumentation_end(); + +- switch (fixup_type) { +- case EX_TYPE_UACCESS: +- case EX_TYPE_COPY: +- if (!copy_user) +- return IN_KERNEL; +- m->kflags |= MCE_IN_KERNEL_COPYIN; +- fallthrough; ++ if (copy_user) { ++ m->kflags |= MCE_IN_KERNEL_COPYIN | MCE_IN_KERNEL_RECOV; ++ return IN_KERNEL_RECOV; ++ } + ++ switch (fixup_type) { + case EX_TYPE_FAULT_MCE_SAFE: + case EX_TYPE_DEFAULT_MCE_SAFE: + m->kflags |= MCE_IN_KERNEL_RECOV; +diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c +index 80e262bb627fe1..cb9852ad609893 100644 +--- a/arch/x86/kernel/i8253.c ++++ b/arch/x86/kernel/i8253.c +@@ -46,7 +46,8 @@ bool __init pit_timer_init(void) + * VMMs otherwise steal CPU time just to pointlessly waggle + * the (masked) IRQ. + */ +- clockevent_i8253_disable(); ++ scoped_guard(irq) ++ clockevent_i8253_disable(); + return false; + } + clockevent_i8253_init(true); +diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c +index 4b74ea91f4e6bb..6970b11a6b4c62 100644 +--- a/arch/x86/kvm/svm/avic.c ++++ b/arch/x86/kvm/svm/avic.c +@@ -820,7 +820,7 @@ static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi) + * Allocating new amd_iommu_pi_data, which will get + * add to the per-vcpu ir_list. + */ +- ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_KERNEL_ACCOUNT); ++ ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_ATOMIC | __GFP_ACCOUNT); + if (!ir) { + ret = -ENOMEM; + goto out; +@@ -896,6 +896,7 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + { + struct kvm_kernel_irq_routing_entry *e; + struct kvm_irq_routing_table *irq_rt; ++ bool enable_remapped_mode = true; + int idx, ret = 0; + + if (!kvm_arch_has_assigned_device(kvm) || +@@ -933,6 +934,8 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + kvm_vcpu_apicv_active(&svm->vcpu)) { + struct amd_iommu_pi_data pi; + ++ enable_remapped_mode = false; ++ + /* Try to enable guest_mode in IRTE */ + pi.base = __sme_set(page_to_phys(svm->avic_backing_page) & + AVIC_HPA_MASK); +@@ -951,33 +954,6 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + */ + if (!ret && pi.is_guest_mode) + svm_ir_list_add(svm, &pi); +- } else { +- /* Use legacy mode in IRTE */ +- struct amd_iommu_pi_data pi; +- +- /** +- * Here, pi is used to: +- * - Tell IOMMU to use legacy mode for this interrupt. +- * - Retrieve ga_tag of prior interrupt remapping data. +- */ +- pi.prev_ga_tag = 0; +- pi.is_guest_mode = false; +- ret = irq_set_vcpu_affinity(host_irq, &pi); +- +- /** +- * Check if the posted interrupt was previously +- * setup with the guest_mode by checking if the ga_tag +- * was cached. If so, we need to clean up the per-vcpu +- * ir_list. +- */ +- if (!ret && pi.prev_ga_tag) { +- int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag); +- struct kvm_vcpu *vcpu; +- +- vcpu = kvm_get_vcpu_by_id(kvm, id); +- if (vcpu) +- svm_ir_list_del(to_svm(vcpu), &pi); +- } + } + + if (!ret && svm) { +@@ -993,6 +969,34 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + } + + ret = 0; ++ if (enable_remapped_mode) { ++ /* Use legacy mode in IRTE */ ++ struct amd_iommu_pi_data pi; ++ ++ /** ++ * Here, pi is used to: ++ * - Tell IOMMU to use legacy mode for this interrupt. ++ * - Retrieve ga_tag of prior interrupt remapping data. ++ */ ++ pi.prev_ga_tag = 0; ++ pi.is_guest_mode = false; ++ ret = irq_set_vcpu_affinity(host_irq, &pi); ++ ++ /** ++ * Check if the posted interrupt was previously ++ * setup with the guest_mode by checking if the ga_tag ++ * was cached. If so, we need to clean up the per-vcpu ++ * ir_list. ++ */ ++ if (!ret && pi.prev_ga_tag) { ++ int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag); ++ struct kvm_vcpu *vcpu; ++ ++ vcpu = kvm_get_vcpu_by_id(kvm, id); ++ if (vcpu) ++ svm_ir_list_del(to_svm(vcpu), &pi); ++ } ++ } + out: + srcu_read_unlock(&kvm->irq_srcu, idx); + return ret; +diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c +index af662312fd0778..b54e0cb86e5d61 100644 +--- a/arch/x86/kvm/vmx/posted_intr.c ++++ b/arch/x86/kvm/vmx/posted_intr.c +@@ -274,6 +274,7 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + { + struct kvm_kernel_irq_routing_entry *e; + struct kvm_irq_routing_table *irq_rt; ++ bool enable_remapped_mode = true; + struct kvm_lapic_irq irq; + struct kvm_vcpu *vcpu; + struct vcpu_data vcpu_info; +@@ -312,21 +313,8 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + + kvm_set_msi_irq(kvm, e, &irq); + if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) || +- !kvm_irq_is_postable(&irq)) { +- /* +- * Make sure the IRTE is in remapped mode if +- * we don't handle it in posted mode. +- */ +- ret = irq_set_vcpu_affinity(host_irq, NULL); +- if (ret < 0) { +- printk(KERN_INFO +- "failed to back to remapped mode, irq: %u\n", +- host_irq); +- goto out; +- } +- ++ !kvm_irq_is_postable(&irq)) + continue; +- } + + vcpu_info.pi_desc_addr = __pa(vcpu_to_pi_desc(vcpu)); + vcpu_info.vector = irq.vector; +@@ -334,11 +322,12 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + trace_kvm_pi_irte_update(host_irq, vcpu->vcpu_id, e->gsi, + vcpu_info.vector, vcpu_info.pi_desc_addr, set); + +- if (set) +- ret = irq_set_vcpu_affinity(host_irq, &vcpu_info); +- else +- ret = irq_set_vcpu_affinity(host_irq, NULL); ++ if (!set) ++ continue; + ++ enable_remapped_mode = false; ++ ++ ret = irq_set_vcpu_affinity(host_irq, &vcpu_info); + if (ret < 0) { + printk(KERN_INFO "%s: failed to update PI IRTE\n", + __func__); +@@ -346,6 +335,9 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + } + } + ++ if (enable_remapped_mode) ++ ret = irq_set_vcpu_affinity(host_irq, NULL); ++ + ret = 0; + out: + srcu_read_unlock(&kvm->irq_srcu, idx); +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 2a2dbeb56897d8..f67fe8a65820c8 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -13297,7 +13297,8 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq, + bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old, + struct kvm_kernel_irq_routing_entry *new) + { +- if (new->type != KVM_IRQ_ROUTING_MSI) ++ if (old->type != KVM_IRQ_ROUTING_MSI || ++ new->type != KVM_IRQ_ROUTING_MSI) + return true; + + return !!memcmp(&old->msi, &new->msi, sizeof(new->msi)); +diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c +index 271dcb2deabc31..2354c0156e51c9 100644 +--- a/arch/x86/mm/extable.c ++++ b/arch/x86/mm/extable.c +@@ -163,13 +163,6 @@ static bool ex_handler_uaccess(const struct exception_table_entry *fixup, + return ex_handler_default(fixup, regs); + } + +-static bool ex_handler_copy(const struct exception_table_entry *fixup, +- struct pt_regs *regs, int trapnr) +-{ +- WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?"); +- return ex_handler_fault(fixup, regs, trapnr); +-} +- + static bool ex_handler_msr(const struct exception_table_entry *fixup, + struct pt_regs *regs, bool wrmsr, bool safe, int reg) + { +@@ -267,8 +260,6 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, + return ex_handler_fault(e, regs, trapnr); + case EX_TYPE_UACCESS: + return ex_handler_uaccess(e, regs, trapnr, fault_addr); +- case EX_TYPE_COPY: +- return ex_handler_copy(e, regs, trapnr); + case EX_TYPE_CLEAR_FS: + return ex_handler_clear_fs(e, regs); + case EX_TYPE_FPU_RESTORE: +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index df1794a5e38a57..4872bb082b1935 100644 +--- a/arch/x86/mm/tlb.c ++++ b/arch/x86/mm/tlb.c +@@ -392,9 +392,9 @@ static void cond_mitigation(struct task_struct *next) + prev_mm = this_cpu_read(cpu_tlbstate.last_user_mm_spec); + + /* +- * Avoid user/user BTB poisoning by flushing the branch predictor +- * when switching between processes. This stops one process from +- * doing Spectre-v2 attacks on another. ++ * Avoid user->user BTB/RSB poisoning by flushing them when switching ++ * between processes. This stops one process from doing Spectre-v2 ++ * attacks on another. + * + * Both, the conditional and the always IBPB mode use the mm + * pointer to avoid the IBPB when switching between tasks of the +diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S +index c4365a05ab83b3..fc46b4dfbd7475 100644 +--- a/arch/x86/platform/pvh/head.S ++++ b/arch/x86/platform/pvh/head.S +@@ -100,7 +100,12 @@ SYM_CODE_START_LOCAL(pvh_start_xen) + xor %edx, %edx + wrmsr + +- call xen_prepare_pvh ++ /* Call xen_prepare_pvh() via the kernel virtual mapping */ ++ leaq xen_prepare_pvh(%rip), %rax ++ subq phys_base(%rip), %rax ++ addq $__START_KERNEL_map, %rax ++ ANNOTATE_RETPOLINE_SAFE ++ call *%rax + + /* startup_64 expects boot_params in %rsi. */ + mov $_pa(pvh_bootparams), %rsi +diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c +index 5b84b0f7cc178f..3378670286535a 100644 +--- a/crypto/crypto_null.c ++++ b/crypto/crypto_null.c +@@ -17,10 +17,10 @@ + #include + #include + #include +-#include ++#include + #include + +-static DEFINE_MUTEX(crypto_default_null_skcipher_lock); ++static DEFINE_SPINLOCK(crypto_default_null_skcipher_lock); + static struct crypto_sync_skcipher *crypto_default_null_skcipher; + static int crypto_default_null_skcipher_refcnt; + +@@ -152,23 +152,32 @@ MODULE_ALIAS_CRYPTO("cipher_null"); + + struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void) + { ++ struct crypto_sync_skcipher *ntfm = NULL; + struct crypto_sync_skcipher *tfm; + +- mutex_lock(&crypto_default_null_skcipher_lock); ++ spin_lock_bh(&crypto_default_null_skcipher_lock); + tfm = crypto_default_null_skcipher; + + if (!tfm) { +- tfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0); +- if (IS_ERR(tfm)) +- goto unlock; +- +- crypto_default_null_skcipher = tfm; ++ spin_unlock_bh(&crypto_default_null_skcipher_lock); ++ ++ ntfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0); ++ if (IS_ERR(ntfm)) ++ return ntfm; ++ ++ spin_lock_bh(&crypto_default_null_skcipher_lock); ++ tfm = crypto_default_null_skcipher; ++ if (!tfm) { ++ tfm = ntfm; ++ ntfm = NULL; ++ crypto_default_null_skcipher = tfm; ++ } + } + + crypto_default_null_skcipher_refcnt++; ++ spin_unlock_bh(&crypto_default_null_skcipher_lock); + +-unlock: +- mutex_unlock(&crypto_default_null_skcipher_lock); ++ crypto_free_sync_skcipher(ntfm); + + return tfm; + } +@@ -176,12 +185,16 @@ EXPORT_SYMBOL_GPL(crypto_get_default_null_skcipher); + + void crypto_put_default_null_skcipher(void) + { +- mutex_lock(&crypto_default_null_skcipher_lock); ++ struct crypto_sync_skcipher *tfm = NULL; ++ ++ spin_lock_bh(&crypto_default_null_skcipher_lock); + if (!--crypto_default_null_skcipher_refcnt) { +- crypto_free_sync_skcipher(crypto_default_null_skcipher); ++ tfm = crypto_default_null_skcipher; + crypto_default_null_skcipher = NULL; + } +- mutex_unlock(&crypto_default_null_skcipher_lock); ++ spin_unlock_bh(&crypto_default_null_skcipher_lock); ++ ++ crypto_free_sync_skcipher(tfm); + } + EXPORT_SYMBOL_GPL(crypto_put_default_null_skcipher); + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index 115994dfefec1e..77d6af61158936 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -2301,6 +2301,34 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "103C_5336AN HP ZHAN 66 Pro"), + }, + }, ++ /* ++ * Lenovo Legion Go S; touchscreen blocks HW sleep when woken up from EC ++ * https://gitlab.freedesktop.org/drm/amd/-/issues/3929 ++ */ ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83L3"), ++ } ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83N6"), ++ } ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83Q2"), ++ } ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83Q3"), ++ } ++ }, + { }, + }; + +diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c +index a35dd0e41c2704..f73ce6e13065dd 100644 +--- a/drivers/acpi/pptt.c ++++ b/drivers/acpi/pptt.c +@@ -229,7 +229,7 @@ static int acpi_pptt_leaf_node(struct acpi_table_header *table_hdr, + node_entry = ACPI_PTR_DIFF(node, table_hdr); + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, + sizeof(struct acpi_table_pptt)); +- proc_sz = sizeof(struct acpi_pptt_processor *); ++ proc_sz = sizeof(struct acpi_pptt_processor); + + while ((unsigned long)entry + proc_sz < table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; +@@ -270,7 +270,7 @@ static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_he + table_end = (unsigned long)table_hdr + table_hdr->length; + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, + sizeof(struct acpi_table_pptt)); +- proc_sz = sizeof(struct acpi_pptt_processor *); ++ proc_sz = sizeof(struct acpi_pptt_processor); + + /* find the processor structure associated with this cpuid */ + while ((unsigned long)entry + proc_sz < table_end) { +diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c +index 5377d094bf7548..6a1460d35447cc 100644 +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -2354,8 +2354,8 @@ static unsigned int ata_msense_control_ata_feature(struct ata_device *dev, + */ + put_unaligned_be16(ATA_FEATURE_SUB_MPAGE_LEN - 4, &buf[2]); + +- if (dev->flags & ATA_DFLAG_CDL) +- buf[4] = 0x02; /* Support T2A and T2B pages */ ++ if (dev->flags & ATA_DFLAG_CDL_ENABLED) ++ buf[4] = 0x02; /* T2A and T2B pages enabled */ + else + buf[4] = 0; + +@@ -3764,12 +3764,11 @@ static int ata_mselect_control_spg0(struct ata_queued_cmd *qc, + } + + /* +- * Translate MODE SELECT control mode page, sub-pages f2h (ATA feature mode ++ * Translate MODE SELECT control mode page, sub-page f2h (ATA feature mode + * page) into a SET FEATURES command. + */ +-static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, +- const u8 *buf, int len, +- u16 *fp) ++static int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, ++ const u8 *buf, int len, u16 *fp) + { + struct ata_device *dev = qc->dev; + struct ata_taskfile *tf = &qc->tf; +@@ -3787,17 +3786,27 @@ static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, + /* Check cdl_ctrl */ + switch (buf[0] & 0x03) { + case 0: +- /* Disable CDL */ ++ /* Disable CDL if it is enabled */ ++ if (!(dev->flags & ATA_DFLAG_CDL_ENABLED)) ++ return 0; ++ ata_dev_dbg(dev, "Disabling CDL\n"); + cdl_action = 0; + dev->flags &= ~ATA_DFLAG_CDL_ENABLED; + break; + case 0x02: +- /* Enable CDL T2A/T2B: NCQ priority must be disabled */ ++ /* ++ * Enable CDL if not already enabled. Since this is mutually ++ * exclusive with NCQ priority, allow this only if NCQ priority ++ * is disabled. ++ */ ++ if (dev->flags & ATA_DFLAG_CDL_ENABLED) ++ return 0; + if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) { + ata_dev_err(dev, + "NCQ priority must be disabled to enable CDL\n"); + return -EINVAL; + } ++ ata_dev_dbg(dev, "Enabling CDL\n"); + cdl_action = 1; + dev->flags |= ATA_DFLAG_CDL_ENABLED; + break; +diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c +index d56a5d508ccd7b..8b690f59df27d6 100644 +--- a/drivers/auxdisplay/hd44780.c ++++ b/drivers/auxdisplay/hd44780.c +@@ -313,13 +313,13 @@ static int hd44780_probe(struct platform_device *pdev) + fail3: + kfree(hd); + fail2: +- kfree(lcd); ++ charlcd_free(lcd); + fail1: + kfree(hdc); + return ret; + } + +-static int hd44780_remove(struct platform_device *pdev) ++static void hd44780_remove(struct platform_device *pdev) + { + struct charlcd *lcd = platform_get_drvdata(pdev); + struct hd44780_common *hdc = lcd->drvdata; +@@ -328,8 +328,7 @@ static int hd44780_remove(struct platform_device *pdev) + kfree(hdc->hd44780); + kfree(lcd->drvdata); + +- kfree(lcd); +- return 0; ++ charlcd_free(lcd); + } + + static const struct of_device_id hd44780_of_match[] = { +@@ -340,7 +339,7 @@ MODULE_DEVICE_TABLE(of, hd44780_of_match); + + static struct platform_driver hd44780_driver = { + .probe = hd44780_probe, +- .remove = hd44780_remove, ++ .remove_new = hd44780_remove, + .driver = { + .name = "hd44780", + .of_match_table = hd44780_of_match, +diff --git a/drivers/base/base.h b/drivers/base/base.h +index a8e3d8165232fd..0b491449b022a1 100644 +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -73,6 +73,7 @@ static inline void subsys_put(struct subsys_private *sp) + kset_put(&sp->subsys); + } + ++struct subsys_private *bus_to_subsys(const struct bus_type *bus); + struct subsys_private *class_to_subsys(const struct class *class); + + struct driver_private { +@@ -179,6 +180,22 @@ int driver_add_groups(struct device_driver *drv, const struct attribute_group ** + void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups); + void device_driver_detach(struct device *dev); + ++static inline void device_set_driver(struct device *dev, const struct device_driver *drv) ++{ ++ /* ++ * Majority (all?) read accesses to dev->driver happens either ++ * while holding device lock or in bus/driver code that is only ++ * invoked when the device is bound to a driver and there is no ++ * concern of the pointer being changed while it is being read. ++ * However when reading device's uevent file we read driver pointer ++ * without taking device lock (so we do not block there for ++ * arbitrary amount of time). We use WRITE_ONCE() here to prevent ++ * tearing so that READ_ONCE() can safely be used in uevent code. ++ */ ++ // FIXME - this cast should not be needed "soon" ++ WRITE_ONCE(dev->driver, (struct device_driver *)drv); ++} ++ + int devres_release_all(struct device *dev); + void device_block_probing(void); + void device_unblock_probing(void); +diff --git a/drivers/base/bus.c b/drivers/base/bus.c +index d4361ad3b433f5..b97e13a52c3308 100644 +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -57,7 +57,7 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, + * NULL. A call to subsys_put() must be done when finished with the pointer in + * order for it to be properly freed. + */ +-static struct subsys_private *bus_to_subsys(const struct bus_type *bus) ++struct subsys_private *bus_to_subsys(const struct bus_type *bus) + { + struct subsys_private *sp = NULL; + struct kobject *kobj; +diff --git a/drivers/base/core.c b/drivers/base/core.c +index 8e2caa9eb5cd41..a192ce5bb8f902 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -2570,6 +2570,35 @@ static const char *dev_uevent_name(const struct kobject *kobj) + return NULL; + } + ++/* ++ * Try filling "DRIVER=" uevent variable for a device. Because this ++ * function may race with binding and unbinding the device from a driver, ++ * we need to be careful. Binding is generally safe, at worst we miss the ++ * fact that the device is already bound to a driver (but the driver ++ * information that is delivered through uevents is best-effort, it may ++ * become obsolete as soon as it is generated anyways). Unbinding is more ++ * risky as driver pointer is transitioning to NULL, so READ_ONCE() should ++ * be used to make sure we are dealing with the same pointer, and to ++ * ensure that driver structure is not going to disappear from under us ++ * we take bus' drivers klist lock. The assumption that only registered ++ * driver can be bound to a device, and to unregister a driver bus code ++ * will take the same lock. ++ */ ++static void dev_driver_uevent(const struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct subsys_private *sp = bus_to_subsys(dev->bus); ++ ++ if (sp) { ++ scoped_guard(spinlock, &sp->klist_drivers.k_lock) { ++ struct device_driver *drv = READ_ONCE(dev->driver); ++ if (drv) ++ add_uevent_var(env, "DRIVER=%s", drv->name); ++ } ++ ++ subsys_put(sp); ++ } ++} ++ + static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) + { + const struct device *dev = kobj_to_dev(kobj); +@@ -2601,8 +2630,8 @@ static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) + if (dev->type && dev->type->name) + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); + +- if (dev->driver) +- add_uevent_var(env, "DRIVER=%s", dev->driver->name); ++ /* Add "DRIVER=%s" variable if the device is bound to a driver */ ++ dev_driver_uevent(dev, env); + + /* Add common DT information about the device */ + of_device_uevent(dev, env); +@@ -2672,11 +2701,8 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, + if (!env) + return -ENOMEM; + +- /* Synchronize with really_probe() */ +- device_lock(dev); + /* let the kset specific function add its keys */ + retval = kset->uevent_ops->uevent(&dev->kobj, env); +- device_unlock(dev); + if (retval) + goto out; + +@@ -3691,7 +3717,7 @@ int device_add(struct device *dev) + device_pm_remove(dev); + dpm_sysfs_remove(dev); + DPMError: +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + bus_remove_device(dev); + BusError: + device_remove_attrs(dev); +diff --git a/drivers/base/dd.c b/drivers/base/dd.c +index 0c3725c3eefa46..7e2fb159bb895b 100644 +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -550,7 +550,7 @@ static void device_unbind_cleanup(struct device *dev) + arch_teardown_dma_ops(dev); + kfree(dev->dma_range_map); + dev->dma_range_map = NULL; +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + dev_set_drvdata(dev, NULL); + if (dev->pm_domain && dev->pm_domain->dismiss) + dev->pm_domain->dismiss(dev); +@@ -629,7 +629,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) + } + + re_probe: +- dev->driver = drv; ++ device_set_driver(dev, drv); + + /* If using pinctrl, bind pins now before probing */ + ret = pinctrl_bind_pins(dev); +@@ -1014,7 +1014,7 @@ static int __device_attach(struct device *dev, bool allow_async) + if (ret == 0) + ret = 1; + else { +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + ret = 0; + } + } else { +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 8a6c1146df00fd..455e2a2b149f4b 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -441,7 +441,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, + cmd->iocb.ki_filp = file; + cmd->iocb.ki_complete = lo_rw_aio_complete; + cmd->iocb.ki_flags = IOCB_DIRECT; +- cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0); ++ cmd->iocb.ki_ioprio = req_get_ioprio(rq); + + if (rw == ITER_SOURCE) + ret = call_write_iter(file, &cmd->iocb, &iter); +diff --git a/drivers/char/misc.c b/drivers/char/misc.c +index f7dd455dd0dd3c..dda466f9181acf 100644 +--- a/drivers/char/misc.c ++++ b/drivers/char/misc.c +@@ -315,7 +315,7 @@ static int __init misc_init(void) + goto fail_remove; + + err = -EIO; +- if (register_chrdev(MISC_MAJOR, "misc", &misc_fops)) ++ if (__register_chrdev(MISC_MAJOR, 0, MINORMASK + 1, "misc", &misc_fops)) + goto fail_printk; + return 0; + +diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c +index 796ab9a4e48fa1..80e0f485170a8f 100644 +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -1612,8 +1612,8 @@ static void handle_control_message(struct virtio_device *vdev, + break; + case VIRTIO_CONSOLE_RESIZE: { + struct { +- __u16 rows; +- __u16 cols; ++ __virtio16 rows; ++ __virtio16 cols; + } size; + + if (!is_console_port(port)) +@@ -1621,7 +1621,8 @@ static void handle_control_message(struct virtio_device *vdev, + + memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), + sizeof(size)); +- set_console_size(port, size.rows, size.cols); ++ set_console_size(port, virtio16_to_cpu(vdev, size.rows), ++ virtio16_to_cpu(vdev, size.cols)); + + port->cons.hvc->irq_requested = 1; + resize_console(port); +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 5bbd036f5295f5..8474099e2cac19 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -5216,6 +5216,10 @@ of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec) + if (!clkspec) + return ERR_PTR(-EINVAL); + ++ /* Check if node in clkspec is in disabled/fail state */ ++ if (!of_device_is_available(clkspec->np)) ++ return ERR_PTR(-ENOENT); ++ + mutex_lock(&of_clk_mutex); + list_for_each_entry(provider, &of_clk_providers, link) { + if (provider->node == clkspec->np) { +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 6c6bc79b2e9cec..865d47800791bd 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -14,6 +14,17 @@ + + #include "rzg2l-cpg.h" + ++/* Specific registers. */ ++#define CPG_PL2SDHI_DSEL (0x218) ++ ++/* Clock select configuration. */ ++#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) ++#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) ++ ++/* Clock status configuration. */ ++#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) ++#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G043_CLK_P0_DIV2, +@@ -75,8 +86,12 @@ static const struct clk_div_table dtable_1_32[] = { + + /* Mux clock tables */ + static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; ++#ifdef CONFIG_ARM64 + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; +-static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++#endif ++static const char * const sel_sdhi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++ ++static const u32 mtable_sdhi[] = { 1, 2, 3 }; + + static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + /* External Clock Inputs */ +@@ -120,11 +135,18 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + DEF_DIV("P2", R9A07G043_CLK_P2, CLK_PLL3_DIV2_4_2, DIVPL3A, dtable_1_32), + DEF_FIXED("M0", R9A07G043_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), + DEF_FIXED("ZT", R9A07G043_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1), ++#ifdef CONFIG_ARM64 + DEF_MUX("HP", R9A07G043_CLK_HP, SEL_PLL6_2, sel_pll6_2), ++#endif ++#ifdef CONFIG_RISCV ++ DEF_FIXED("HP", R9A07G043_CLK_HP, CLK_PLL6_250, 1, 1), ++#endif + DEF_FIXED("SPI0", R9A07G043_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, sel_shdi), +- DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, sel_shdi), ++ DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), ++ DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), + }; +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index c597414a94d8a0..48404cafea3f51 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -15,6 +15,17 @@ + + #include "rzg2l-cpg.h" + ++/* Specific registers. */ ++#define CPG_PL2SDHI_DSEL (0x218) ++ ++/* Clock select configuration. */ ++#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) ++#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) ++ ++/* Clock status configuration. */ ++#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) ++#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A, +@@ -95,9 +106,11 @@ static const struct clk_div_table dtable_16_128[] = { + static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; + static const char * const sel_pll5_4[] = { ".pll5_foutpostdiv", ".pll5_fout1ph0" }; + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; +-static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++static const char * const sel_sdhi[] = { ".clk_533", ".clk_400", ".clk_266" }; + static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" }; + ++static const u32 mtable_sdhi[] = { 1, 2, 3 }; ++ + static const struct { + struct cpg_core_clk common[56]; + #ifdef CONFIG_CLK_R9A07G054 +@@ -163,8 +176,10 @@ static const struct { + DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, sel_pll6_2), + DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, sel_shdi), +- DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, sel_shdi), ++ DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), ++ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), + DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8), +diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c +index f8dbb092b9f1b2..77eefb6ee4538a 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.c ++++ b/drivers/clk/renesas/rzg2l-cpg.c +@@ -56,15 +56,37 @@ + #define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff) + #define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff) + ++#define CPG_WEN_BIT BIT(16) ++ + #define MAX_VCLK_FREQ (148500000) + +-struct sd_hw_data { ++/** ++ * struct clk_hw_data - clock hardware data ++ * @hw: clock hw ++ * @conf: clock configuration (register offset, shift, width) ++ * @sconf: clock status configuration (register offset, shift, width) ++ * @priv: CPG private data structure ++ */ ++struct clk_hw_data { + struct clk_hw hw; + u32 conf; ++ u32 sconf; + struct rzg2l_cpg_priv *priv; + }; + +-#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw) ++#define to_clk_hw_data(_hw) container_of(_hw, struct clk_hw_data, hw) ++ ++/** ++ * struct sd_mux_hw_data - SD MUX clock hardware data ++ * @hw_data: clock hw data ++ * @mtable: clock mux table ++ */ ++struct sd_mux_hw_data { ++ struct clk_hw_data hw_data; ++ const u32 *mtable; ++}; ++ ++#define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data) + + struct rzg2l_pll5_param { + u32 pl5_fracin; +@@ -121,6 +143,76 @@ static void rzg2l_cpg_del_clk_provider(void *data) + of_clk_del_provider(data); + } + ++/* Must be called in atomic context. */ ++static int rzg2l_cpg_wait_clk_update_done(void __iomem *base, u32 conf) ++{ ++ u32 bitmask = GENMASK(GET_WIDTH(conf) - 1, 0) << GET_SHIFT(conf); ++ u32 off = GET_REG_OFFSET(conf); ++ u32 val; ++ ++ return readl_poll_timeout_atomic(base + off, val, !(val & bitmask), 10, 200); ++} ++ ++int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, ++ void *data) ++{ ++ struct clk_notifier_data *cnd = data; ++ struct clk_hw *hw = __clk_get_hw(cnd->clk); ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 off = GET_REG_OFFSET(clk_hw_data->conf); ++ u32 shift = GET_SHIFT(clk_hw_data->conf); ++ const u32 clk_src_266 = 3; ++ unsigned long flags; ++ int ret; ++ ++ if (event != PRE_RATE_CHANGE || (cnd->new_rate / MEGA == 266)) ++ return NOTIFY_DONE; ++ ++ spin_lock_irqsave(&priv->rmw_lock, flags); ++ ++ /* ++ * As per the HW manual, we should not directly switch from 533 MHz to ++ * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) ++ * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, ++ * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 ++ * (400 MHz)). ++ * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock ++ * switching register is prohibited. ++ * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and ++ * the index to value mapping is done by adding 1 to the index. ++ */ ++ ++ writel((CPG_WEN_BIT | clk_src_266) << shift, priv->base + off); ++ ++ /* Wait for the update done. */ ++ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); ++ ++ spin_unlock_irqrestore(&priv->rmw_lock, flags); ++ ++ if (ret) ++ dev_err(priv->dev, "failed to switch to safe clk source\n"); ++ ++ return notifier_from_errno(ret); ++} ++ ++static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core, ++ struct rzg2l_cpg_priv *priv) ++{ ++ struct notifier_block *nb; ++ ++ if (!core->notifier) ++ return 0; ++ ++ nb = devm_kzalloc(priv->dev, sizeof(*nb), GFP_KERNEL); ++ if (!nb) ++ return -ENOMEM; ++ ++ nb->notifier_call = core->notifier; ++ ++ return clk_notifier_register(hw->clk, nb); ++} ++ + static struct clk * __init + rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, + struct clk **clks, +@@ -183,63 +275,44 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, + + static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + { +- struct sd_hw_data *hwdata = to_sd_hw_data(hw); +- struct rzg2l_cpg_priv *priv = hwdata->priv; +- u32 off = GET_REG_OFFSET(hwdata->conf); +- u32 shift = GET_SHIFT(hwdata->conf); +- const u32 clk_src_266 = 2; +- u32 msk, val, bitmask; ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 off = GET_REG_OFFSET(clk_hw_data->conf); ++ u32 shift = GET_SHIFT(clk_hw_data->conf); + unsigned long flags; ++ u32 val; + int ret; + +- /* +- * As per the HW manual, we should not directly switch from 533 MHz to +- * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) +- * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, +- * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 +- * (400 MHz)). +- * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock +- * switching register is prohibited. +- * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and +- * the index to value mapping is done by adding 1 to the index. +- */ +- bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; +- msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; ++ val = clk_mux_index_to_val(sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, index); ++ + spin_lock_irqsave(&priv->rmw_lock, flags); +- if (index != clk_src_266) { +- writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); +- +- ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, +- !(val & msk), 10, +- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +- if (ret) +- goto unlock; +- } + +- writel(bitmask | ((index + 1) << shift), priv->base + off); ++ writel((CPG_WEN_BIT | val) << shift, priv->base + off); ++ ++ /* Wait for the update done. */ ++ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); + +- ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, +- !(val & msk), 10, +- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +-unlock: + spin_unlock_irqrestore(&priv->rmw_lock, flags); + + if (ret) +- dev_err(priv->dev, "failed to switch clk source\n"); ++ dev_err(priv->dev, "Failed to switch parent\n"); + + return ret; + } + + static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) + { +- struct sd_hw_data *hwdata = to_sd_hw_data(hw); +- struct rzg2l_cpg_priv *priv = hwdata->priv; +- u32 val = readl(priv->base + GET_REG_OFFSET(hwdata->conf)); ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 val; + +- val >>= GET_SHIFT(hwdata->conf); +- val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0); ++ val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); ++ val >>= GET_SHIFT(clk_hw_data->conf); ++ val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); + +- return val ? val - 1 : 0; ++ return clk_mux_val_to_index(hw, sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, val); + } + + static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { +@@ -253,31 +326,40 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, + void __iomem *base, + struct rzg2l_cpg_priv *priv) + { +- struct sd_hw_data *clk_hw_data; ++ struct sd_mux_hw_data *sd_mux_hw_data; + struct clk_init_data init; + struct clk_hw *clk_hw; + int ret; + +- clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); +- if (!clk_hw_data) ++ sd_mux_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_mux_hw_data), GFP_KERNEL); ++ if (!sd_mux_hw_data) + return ERR_PTR(-ENOMEM); + +- clk_hw_data->priv = priv; +- clk_hw_data->conf = core->conf; ++ sd_mux_hw_data->hw_data.priv = priv; ++ sd_mux_hw_data->hw_data.conf = core->conf; ++ sd_mux_hw_data->hw_data.sconf = core->sconf; ++ sd_mux_hw_data->mtable = core->mtable; + + init.name = GET_SHIFT(core->conf) ? "sd1" : "sd0"; + init.ops = &rzg2l_cpg_sd_clk_mux_ops; +- init.flags = 0; ++ init.flags = core->flag; + init.num_parents = core->num_parents; + init.parent_names = core->parent_names; + +- clk_hw = &clk_hw_data->hw; ++ clk_hw = &sd_mux_hw_data->hw_data.hw; + clk_hw->init = &init; + + ret = devm_clk_hw_register(priv->dev, clk_hw); + if (ret) + return ERR_PTR(ret); + ++ ret = rzg2l_register_notifier(clk_hw, core, priv); ++ if (ret) { ++ dev_err(priv->dev, "Failed to register notifier for %s\n", ++ core->name); ++ return ERR_PTR(ret); ++ } ++ + return clk_hw->clk; + } + +diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h +index 91e9c2569f801b..e662459cc6d963 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.h ++++ b/drivers/clk/renesas/rzg2l-cpg.h +@@ -9,6 +9,8 @@ + #ifndef __RENESAS_RZG2L_CPG_H__ + #define __RENESAS_RZG2L_CPG_H__ + ++#include ++ + #define CPG_SIPLL5_STBY (0x140) + #define CPG_SIPLL5_CLK1 (0x144) + #define CPG_SIPLL5_CLK3 (0x14C) +@@ -19,7 +21,6 @@ + #define CPG_PL2_DDIV (0x204) + #define CPG_PL3A_DDIV (0x208) + #define CPG_PL6_DDIV (0x210) +-#define CPG_PL2SDHI_DSEL (0x218) + #define CPG_CLKSTATUS (0x280) + #define CPG_PL3_SSEL (0x408) + #define CPG_PL6_SSEL (0x414) +@@ -43,8 +44,6 @@ + #define CPG_CLKSTATUS_SELSDHI0_STS BIT(28) + #define CPG_CLKSTATUS_SELSDHI1_STS BIT(29) + +-#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 200 +- + /* n = 0/1/2 for PLL1/4/6 */ + #define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n)) + #define CPG_SAMPLL_CLK2(n) (0x08 + (16 * n)) +@@ -69,9 +68,6 @@ + #define SEL_PLL6_2 SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1) + #define SEL_GPU2 SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1) + +-#define SEL_SDHI0 DDIV_PACK(CPG_PL2SDHI_DSEL, 0, 2) +-#define SEL_SDHI1 DDIV_PACK(CPG_PL2SDHI_DSEL, 4, 2) +- + #define EXTAL_FREQ_IN_MEGA_HZ (24) + + /** +@@ -90,10 +86,13 @@ struct cpg_core_clk { + unsigned int mult; + unsigned int type; + unsigned int conf; ++ unsigned int sconf; + const struct clk_div_table *dtable; ++ const u32 *mtable; + const char * const *parent_names; +- int flag; +- int mux_flags; ++ notifier_fn_t notifier; ++ u32 flag; ++ u32 mux_flags; + int num_parents; + }; + +@@ -151,10 +150,11 @@ enum clk_types { + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .mux_flags = CLK_MUX_READ_ONLY) +-#define DEF_SD_MUX(_name, _id, _conf, _parent_names) \ +- DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, \ ++#define DEF_SD_MUX(_name, _id, _conf, _sconf, _parent_names, _mtable, _clk_flags, _notifier) \ ++ DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \ + .parent_names = _parent_names, \ +- .num_parents = ARRAY_SIZE(_parent_names)) ++ .num_parents = ARRAY_SIZE(_parent_names), \ ++ .mtable = _mtable, .flag = _clk_flags, .notifier = _notifier) + #define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \ + DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent) + #define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names) \ +@@ -273,4 +273,6 @@ extern const struct rzg2l_cpg_info r9a07g044_cpg_info; + extern const struct rzg2l_cpg_info r9a07g054_cpg_info; + extern const struct rzg2l_cpg_info r9a09g011_cpg_info; + ++int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, void *data); ++ + #endif +diff --git a/drivers/comedi/drivers/jr3_pci.c b/drivers/comedi/drivers/jr3_pci.c +index 951c23fa0369ea..75dce1ff24193b 100644 +--- a/drivers/comedi/drivers/jr3_pci.c ++++ b/drivers/comedi/drivers/jr3_pci.c +@@ -758,7 +758,7 @@ static void jr3_pci_detach(struct comedi_device *dev) + struct jr3_pci_dev_private *devpriv = dev->private; + + if (devpriv) +- del_timer_sync(&devpriv->timer); ++ timer_shutdown_sync(&devpriv->timer); + + comedi_pci_detach(dev); + } +diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c +index 021f423705e1b1..9ba6b09775f617 100644 +--- a/drivers/cpufreq/apple-soc-cpufreq.c ++++ b/drivers/cpufreq/apple-soc-cpufreq.c +@@ -103,11 +103,17 @@ static const struct of_device_id apple_soc_cpufreq_of_match[] = { + + static unsigned int apple_soc_cpufreq_get_rate(unsigned int cpu) + { +- struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); +- struct apple_cpu_priv *priv = policy->driver_data; ++ struct cpufreq_policy *policy; ++ struct apple_cpu_priv *priv; + struct cpufreq_frequency_table *p; + unsigned int pstate; + ++ policy = cpufreq_cpu_get_raw(cpu); ++ if (unlikely(!policy)) ++ return 0; ++ ++ priv = policy->driver_data; ++ + if (priv->info->cur_pstate_mask) { + u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS); + +diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c +index c8447ecad797e7..aa34af940cb53b 100644 +--- a/drivers/cpufreq/cppc_cpufreq.c ++++ b/drivers/cpufreq/cppc_cpufreq.c +@@ -773,7 +773,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) + int ret; + + if (!policy) +- return -ENODEV; ++ return 0; + + cpu_data = policy->driver_data; + +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 079940c69ee0ba..e4989764efe2a8 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -33,11 +33,17 @@ static const struct scmi_perf_proto_ops *perf_ops; + + static unsigned int scmi_cpufreq_get_rate(unsigned int cpu) + { +- struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); +- struct scmi_data *priv = policy->driver_data; ++ struct cpufreq_policy *policy; ++ struct scmi_data *priv; + unsigned long rate; + int ret; + ++ policy = cpufreq_cpu_get_raw(cpu); ++ if (unlikely(!policy)) ++ return 0; ++ ++ priv = policy->driver_data; ++ + ret = perf_ops->freq_get(ph, priv->domain_id, &rate, false); + if (ret) + return 0; +diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c +index bfc2e65e1e5022..2aef39bff7d6f5 100644 +--- a/drivers/cpufreq/scpi-cpufreq.c ++++ b/drivers/cpufreq/scpi-cpufreq.c +@@ -29,9 +29,16 @@ static struct scpi_ops *scpi_ops; + + static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) + { +- struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); +- struct scpi_data *priv = policy->driver_data; +- unsigned long rate = clk_get_rate(priv->clk); ++ struct cpufreq_policy *policy; ++ struct scpi_data *priv; ++ unsigned long rate; ++ ++ policy = cpufreq_cpu_get_raw(cpu); ++ if (unlikely(!policy)) ++ return 0; ++ ++ priv = policy->driver_data; ++ rate = clk_get_rate(priv->clk); + + return rate / 1000; + } +diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c +index c77f482d2a97e9..5bc809146ffea0 100644 +--- a/drivers/crypto/atmel-sha204a.c ++++ b/drivers/crypto/atmel-sha204a.c +@@ -107,6 +107,12 @@ static int atmel_sha204a_probe(struct i2c_client *client) + i2c_priv->hwrng.name = dev_name(&client->dev); + i2c_priv->hwrng.read = atmel_sha204a_rng_read; + ++ /* ++ * According to review by Bill Cox [1], this HWRNG has very low entropy. ++ * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html ++ */ ++ i2c_priv->hwrng.quality = 1; ++ + ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng); + if (ret) + dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); +diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c +index 0caa57dafc525a..b1e60542351a66 100644 +--- a/drivers/crypto/ccp/sp-pci.c ++++ b/drivers/crypto/ccp/sp-pci.c +@@ -577,6 +577,7 @@ static const struct pci_device_id sp_pci_table[] = { + { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, + { PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] }, + { PCI_VDEVICE(AMD, 0x1649), (kernel_ulong_t)&dev_vdata[6] }, ++ { PCI_VDEVICE(AMD, 0x1134), (kernel_ulong_t)&dev_vdata[7] }, + { PCI_VDEVICE(AMD, 0x17E0), (kernel_ulong_t)&dev_vdata[7] }, + { PCI_VDEVICE(AMD, 0x156E), (kernel_ulong_t)&dev_vdata[8] }, + /* Last entry must be zero */ +diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c +index bab4592db647f7..92ef68849fbea8 100644 +--- a/drivers/cxl/core/regs.c ++++ b/drivers/cxl/core/regs.c +@@ -478,7 +478,6 @@ resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri + resource_size_t rcrb = ri->base; + void __iomem *addr; + u32 bar0, bar1; +- u16 cmd; + u32 id; + + if (which == CXL_RCRB_UPSTREAM) +@@ -500,7 +499,6 @@ resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri + } + + id = readl(addr + PCI_VENDOR_ID); +- cmd = readw(addr + PCI_COMMAND); + bar0 = readl(addr + PCI_BASE_ADDRESS_0); + bar1 = readl(addr + PCI_BASE_ADDRESS_1); + iounmap(addr); +@@ -515,8 +513,6 @@ resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri + dev_err(dev, "Failed to access Downstream Port RCRB\n"); + return CXL_RESOURCE_NONE; + } +- if (!(cmd & PCI_COMMAND_MEMORY)) +- return CXL_RESOURCE_NONE; + /* The RCRB is a Memory Window, and the MEM_TYPE_1M bit is obsolete */ + if (bar0 & (PCI_BASE_ADDRESS_MEM_TYPE_1M | PCI_BASE_ADDRESS_SPACE_IO)) + return CXL_RESOURCE_NONE; +diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c +index d1fcdd1f9aaed3..373282beeb6068 100644 +--- a/drivers/dma-buf/udmabuf.c ++++ b/drivers/dma-buf/udmabuf.c +@@ -214,7 +214,7 @@ static long udmabuf_create(struct miscdevice *device, + if (!ubuf) + return -ENOMEM; + +- pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; ++ pglimit = ((u64)size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; + for (i = 0; i < head->count; i++) { + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) + goto err; +diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c +index ffe621695e472b..78b8a97b236376 100644 +--- a/drivers/dma/dmatest.c ++++ b/drivers/dma/dmatest.c +@@ -827,9 +827,9 @@ static int dmatest_func(void *data) + } else { + dma_async_issue_pending(chan); + +- wait_event_freezable_timeout(thread->done_wait, +- done->done, +- msecs_to_jiffies(params->timeout)); ++ wait_event_timeout(thread->done_wait, ++ done->done, ++ msecs_to_jiffies(params->timeout)); + + status = dma_async_is_tx_complete(chan, cookie, NULL, + NULL); +diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c +index cec9e8f29bbdfe..a0a2a0f75bba46 100644 +--- a/drivers/gpio/gpiolib-of.c ++++ b/drivers/gpio/gpiolib-of.c +@@ -247,6 +247,9 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np, + { "fsl,imx8qm-fec", "phy-reset-gpios", "phy-reset-active-high" }, + { "fsl,s32v234-fec", "phy-reset-gpios", "phy-reset-active-high" }, + #endif ++#if IS_ENABLED(CONFIG_MMC_ATMELMCI) ++ { "atmel,hsmci", "cd-gpios", "cd-inverted" }, ++#endif + #if IS_ENABLED(CONFIG_PCI_IMX6) + { "fsl,imx6q-pcie", "reset-gpio", "reset-gpio-active-high" }, + { "fsl,imx6sx-pcie", "reset-gpio", "reset-gpio-active-high" }, +@@ -272,9 +275,6 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np, + #if IS_ENABLED(CONFIG_REGULATOR_GPIO) + { "regulator-gpio", "enable-gpio", "enable-active-high" }, + { "regulator-gpio", "enable-gpios", "enable-active-high" }, +-#endif +-#if IS_ENABLED(CONFIG_MMC_ATMELMCI) +- { "atmel,hsmci", "cd-gpios", "cd-inverted" }, + #endif + }; + unsigned int i; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 28f2b4022d34e3..e6bc590533194d 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -2789,16 +2789,16 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state, + for (k = 0; k < dc_state->stream_count; k++) { + bundle->stream_update.stream = dc_state->streams[k]; + +- for (m = 0; m < dc_state->stream_status->plane_count; m++) { ++ for (m = 0; m < dc_state->stream_status[k].plane_count; m++) { + bundle->surface_updates[m].surface = +- dc_state->stream_status->plane_states[m]; ++ dc_state->stream_status[k].plane_states[m]; + bundle->surface_updates[m].surface->force_full_update = + true; + } + + update_planes_and_stream_adapter(dm->dc, + UPDATE_TYPE_FULL, +- dc_state->stream_status->plane_count, ++ dc_state->stream_status[k].plane_count, + dc_state->streams[k], + &bundle->stream_update, + bundle->surface_updates); +@@ -9590,6 +9590,9 @@ static bool should_reset_plane(struct drm_atomic_state *state, + if (adev->ip_versions[DCE_HWIP][0] < IP_VERSION(3, 2, 0) && state->allow_modeset) + return true; + ++ if (amdgpu_in_reset(adev) && state->allow_modeset) ++ return true; ++ + /* Exit early if we know that we're adding or removing the plane. */ + if (old_plane_state->crtc != new_plane_state->crtc) + return true; +diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c +index 70a25949142c0d..74b0c85944bd61 100644 +--- a/drivers/iio/adc/ad7768-1.c ++++ b/drivers/iio/adc/ad7768-1.c +@@ -142,7 +142,7 @@ static const struct iio_chan_spec ad7768_channels[] = { + .channel = 0, + .scan_index = 0, + .scan_type = { +- .sign = 'u', ++ .sign = 's', + .realbits = 24, + .storagebits = 32, + .shift = 8, +@@ -370,12 +370,11 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, + return ret; + + ret = ad7768_scan_direct(indio_dev); +- if (ret >= 0) +- *val = ret; + + iio_device_release_direct_mode(indio_dev); + if (ret < 0) + return ret; ++ *val = sign_extend32(ret, chan->scan_type.realbits - 1); + + return IIO_VAL_INT; + +diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c +index 11155e0fb8395c..35d777976c2952 100644 +--- a/drivers/infiniband/hw/qib/qib_fs.c ++++ b/drivers/infiniband/hw/qib/qib_fs.c +@@ -55,6 +55,7 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry, + struct inode *inode = new_inode(dir->i_sb); + + if (!inode) { ++ dput(dentry); + error = -EPERM; + goto bail; + } +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 95bd7c25ba6f36..83c5d786686d07 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -3619,7 +3619,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) + * we should not modify the IRTE + */ + if (!dev_data || !dev_data->use_vapic) +- return 0; ++ return -EINVAL; + + ir_data->cfg = irqd_cfg(data); + pi_data->ir_data = ir_data; +diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c +index d83c2c85962c37..683e8721e3b498 100644 +--- a/drivers/irqchip/irq-gic-v2m.c ++++ b/drivers/irqchip/irq-gic-v2m.c +@@ -454,7 +454,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, + #ifdef CONFIG_ACPI + static int acpi_num_msi; + +-static __init struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) ++static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) + { + struct v2m_data *data; + +diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c +index 82102a4c5d6883..f8215a8f656a46 100644 +--- a/drivers/mailbox/pcc.c ++++ b/drivers/mailbox/pcc.c +@@ -313,6 +313,10 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + int ret; + + pchan = chan->con_priv; ++ ++ if (pcc_chan_reg_read_modify_write(&pchan->plat_irq_ack)) ++ return IRQ_NONE; ++ + if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE && + !pchan->chan_in_use) + return IRQ_NONE; +@@ -330,13 +334,16 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) + return IRQ_NONE; + } + +- if (pcc_chan_reg_read_modify_write(&pchan->plat_irq_ack)) +- return IRQ_NONE; +- ++ /* ++ * Clear this flag after updating interrupt ack register and just ++ * before mbox_chan_received_data() which might call pcc_send_data() ++ * where the flag is set again to start new transfer. This is ++ * required to avoid any possible race in updatation of this flag. ++ */ ++ pchan->chan_in_use = false; + mbox_chan_received_data(chan, NULL); + + check_and_ack(pchan, chan); +- pchan->chan_in_use = false; + + return IRQ_HANDLED; + } +diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c +index 1ae37e693de045..d080e21df666d9 100644 +--- a/drivers/mcb/mcb-parse.c ++++ b/drivers/mcb/mcb-parse.c +@@ -101,7 +101,7 @@ static int chameleon_parse_gdd(struct mcb_bus *bus, + + ret = mcb_device_register(bus, mdev); + if (ret < 0) +- goto err; ++ return ret; + + return 0; + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 65309da1dca340..8b25287c89ed6d 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -2061,14 +2061,9 @@ static int fix_sync_read_error(struct r1bio *r1_bio) + if (!rdev_set_badblocks(rdev, sect, s, 0)) + abort = 1; + } +- if (abort) { +- conf->recovery_disabled = +- mddev->recovery_disabled; +- set_bit(MD_RECOVERY_INTR, &mddev->recovery); +- md_done_sync(mddev, r1_bio->sectors, 0); +- put_buf(r1_bio); ++ if (abort) + return 0; +- } ++ + /* Try next page */ + sectors -= s; + sect += s; +@@ -2207,10 +2202,21 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio) + int disks = conf->raid_disks * 2; + struct bio *wbio; + +- if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) +- /* ouch - failed to read all of that. */ +- if (!fix_sync_read_error(r1_bio)) ++ if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) { ++ /* ++ * ouch - failed to read all of that. ++ * No need to fix read error for check/repair ++ * because all member disks are read. ++ */ ++ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) || ++ !fix_sync_read_error(r1_bio)) { ++ conf->recovery_disabled = mddev->recovery_disabled; ++ set_bit(MD_RECOVERY_INTR, &mddev->recovery); ++ md_done_sync(mddev, r1_bio->sectors, 0); ++ put_buf(r1_bio); + return; ++ } ++ } + + if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) + process_checks(r1_bio); +diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c +index 807551a5143b78..15d863f97cbf96 100644 +--- a/drivers/media/test-drivers/vimc/vimc-streamer.c ++++ b/drivers/media/test-drivers/vimc/vimc-streamer.c +@@ -59,6 +59,12 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) + continue; + + sd = media_entity_to_v4l2_subdev(ved->ent); ++ /* ++ * Do not call .s_stream() to stop an already ++ * stopped/unstarted subdev. ++ */ ++ if (!v4l2_subdev_is_streaming(sd)) ++ continue; + v4l2_subdev_call(sd, video, s_stream, 0); + } + } +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index a32ef739eb4490..5f115438d07228 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -363,12 +363,8 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) + * The .s_stream() operation must never be called to start or stop an + * already started or stopped subdev. Catch offenders but don't return + * an error yet to avoid regressions. +- * +- * As .s_stream() is mutually exclusive with the .enable_streams() and +- * .disable_streams() operation, we can use the enabled_streams field +- * to store the subdev streaming state. + */ +- if (WARN_ON(!!sd->enabled_streams == !!enable)) ++ if (WARN_ON(sd->s_stream_enabled == !!enable)) + return 0; + + ret = sd->ops->video->s_stream(sd, enable); +@@ -379,7 +375,7 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) + } + + if (!ret) { +- sd->enabled_streams = enable ? BIT(0) : 0; ++ sd->s_stream_enabled = enable; + + #if IS_REACHABLE(CONFIG_LEDS_CLASS) + if (!IS_ERR_OR_NULL(sd->privacy_led)) { +@@ -1929,37 +1925,43 @@ static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) + { + struct device *dev = sd->entity.graph_obj.mdev->dev; +- unsigned int i; + int ret; + + /* + * The subdev doesn't implement pad-based stream enable, fall back +- * on the .s_stream() operation. This can only be done for subdevs that +- * have a single source pad, as sd->enabled_streams is global to the +- * subdev. ++ * to the .s_stream() operation. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + +- for (i = 0; i < sd->entity.num_pads; ++i) { +- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) +- return -EOPNOTSUPP; +- } ++ /* ++ * .s_stream() means there is no streams support, so the only allowed ++ * stream is the implicit stream 0. ++ */ ++ if (streams_mask != BIT_ULL(0)) ++ return -EOPNOTSUPP; ++ ++ /* ++ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices ++ * with 64 pads or less can be supported. ++ */ ++ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE) ++ return -EOPNOTSUPP; + +- if (sd->enabled_streams & streams_mask) { +- dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n", +- streams_mask, sd->entity.name, pad); ++ if (sd->enabled_pads & BIT_ULL(pad)) { ++ dev_dbg(dev, "pad %u already enabled on %s\n", ++ pad, sd->entity.name); + return -EALREADY; + } + +- /* Start streaming when the first streams are enabled. */ +- if (!sd->enabled_streams) { ++ /* Start streaming when the first pad is enabled. */ ++ if (!sd->enabled_pads) { + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret) + return ret; + } + +- sd->enabled_streams |= streams_mask; ++ sd->enabled_pads |= BIT_ULL(pad); + + return 0; + } +@@ -2046,37 +2048,43 @@ static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) + { + struct device *dev = sd->entity.graph_obj.mdev->dev; +- unsigned int i; + int ret; + + /* +- * If the subdev doesn't implement pad-based stream enable, fall back +- * on the .s_stream() operation. This can only be done for subdevs that +- * have a single source pad, as sd->enabled_streams is global to the +- * subdev. ++ * If the subdev doesn't implement pad-based stream enable, fall back ++ * to the .s_stream() operation. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + +- for (i = 0; i < sd->entity.num_pads; ++i) { +- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) +- return -EOPNOTSUPP; +- } ++ /* ++ * .s_stream() means there is no streams support, so the only allowed ++ * stream is the implicit stream 0. ++ */ ++ if (streams_mask != BIT_ULL(0)) ++ return -EOPNOTSUPP; ++ ++ /* ++ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices ++ * with 64 pads or less can be supported. ++ */ ++ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE) ++ return -EOPNOTSUPP; + +- if ((sd->enabled_streams & streams_mask) != streams_mask) { +- dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n", +- streams_mask, sd->entity.name, pad); ++ if (!(sd->enabled_pads & BIT_ULL(pad))) { ++ dev_dbg(dev, "pad %u already disabled on %s\n", ++ pad, sd->entity.name); + return -EALREADY; + } + + /* Stop streaming when the last streams are disabled. */ +- if (!(sd->enabled_streams & ~streams_mask)) { ++ if (!(sd->enabled_pads & ~BIT_ULL(pad))) { + ret = v4l2_subdev_call(sd, video, s_stream, 0); + if (ret) + return ret; + } + +- sd->enabled_streams &= ~streams_mask; ++ sd->enabled_pads &= ~BIT_ULL(pad); + + return 0; + } +@@ -2232,6 +2240,31 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + } + EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event); + ++bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd) ++{ ++ struct v4l2_subdev_state *state; ++ ++ if (!v4l2_subdev_has_op(sd, pad, enable_streams)) ++ return sd->s_stream_enabled; ++ ++ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) ++ return !!sd->enabled_pads; ++ ++ state = v4l2_subdev_get_locked_active_state(sd); ++ ++ for (unsigned int i = 0; i < state->stream_configs.num_configs; ++i) { ++ const struct v4l2_subdev_stream_config *cfg; ++ ++ cfg = &state->stream_configs.configs[i]; ++ ++ if (cfg->enabled) ++ return true; ++ } ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(v4l2_subdev_is_streaming); ++ + int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd) + { + #if IS_REACHABLE(CONFIG_LEDS_CLASS) +diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c +index 5b861dbff27e9a..6c24426104ba6f 100644 +--- a/drivers/misc/lkdtm/perms.c ++++ b/drivers/misc/lkdtm/perms.c +@@ -28,6 +28,13 @@ static const unsigned long rodata = 0xAA55AA55; + /* This is marked __ro_after_init, so it should ultimately be .rodata. */ + static unsigned long ro_after_init __ro_after_init = 0x55AA5500; + ++/* ++ * This is a pointer to do_nothing() which is initialized at runtime rather ++ * than build time to avoid objtool IBT validation warnings caused by an ++ * inlined unrolled memcpy() in execute_location(). ++ */ ++static void __ro_after_init *do_nothing_ptr; ++ + /* + * This just returns to the caller. It is designed to be copied into + * non-executable memory regions. +@@ -65,13 +72,12 @@ static noinline __nocfi void execute_location(void *dst, bool write) + { + void (*func)(void); + func_desc_t fdesc; +- void *do_nothing_text = dereference_function_descriptor(do_nothing); + +- pr_info("attempting ok execution at %px\n", do_nothing_text); ++ pr_info("attempting ok execution at %px\n", do_nothing_ptr); + do_nothing(); + + if (write == CODE_WRITE) { +- memcpy(dst, do_nothing_text, EXEC_SIZE); ++ memcpy(dst, do_nothing_ptr, EXEC_SIZE); + flush_icache_range((unsigned long)dst, + (unsigned long)dst + EXEC_SIZE); + } +@@ -267,6 +273,8 @@ static void lkdtm_ACCESS_NULL(void) + + void __init lkdtm_perms_init(void) + { ++ do_nothing_ptr = dereference_function_descriptor(do_nothing); ++ + /* Make sure we can write to __ro_after_init values during __init */ + ro_after_init |= 0xAA; + } +diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +index 3c1359d8d4e692..55b892f982e93e 100644 +--- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c ++++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +@@ -37,6 +37,7 @@ + struct pci1xxxx_gpio { + struct auxiliary_device *aux_dev; + void __iomem *reg_base; ++ raw_spinlock_t wa_lock; + struct gpio_chip gpio; + spinlock_t lock; + int irq_base; +@@ -164,7 +165,7 @@ static void pci1xxxx_gpio_irq_ack(struct irq_data *data) + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); +- pci1xxx_assign_bit(priv->reg_base, INTR_STAT_OFFSET(gpio), (gpio % 32), true); ++ writel(BIT(gpio % 32), priv->reg_base + INTR_STAT_OFFSET(gpio)); + spin_unlock_irqrestore(&priv->lock, flags); + } + +@@ -254,6 +255,7 @@ static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) + struct pci1xxxx_gpio *priv = dev_id; + struct gpio_chip *gc = &priv->gpio; + unsigned long int_status = 0; ++ unsigned long wa_flags; + unsigned long flags; + u8 pincount; + int bit; +@@ -277,7 +279,9 @@ static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) + writel(BIT(bit), priv->reg_base + INTR_STATUS_OFFSET(gpiobank)); + spin_unlock_irqrestore(&priv->lock, flags); + irq = irq_find_mapping(gc->irq.domain, (bit + (gpiobank * 32))); +- handle_nested_irq(irq); ++ raw_spin_lock_irqsave(&priv->wa_lock, wa_flags); ++ generic_handle_irq(irq); ++ raw_spin_unlock_irqrestore(&priv->wa_lock, wa_flags); + } + } + spin_lock_irqsave(&priv->lock, flags); +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index a4668ddd94551a..4adfa5af162f1d 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -117,6 +117,7 @@ + + #define MEI_DEV_ID_LNL_M 0xA870 /* Lunar Lake Point M */ + ++#define MEI_DEV_ID_PTL_H 0xE370 /* Panther Lake H */ + #define MEI_DEV_ID_PTL_P 0xE470 /* Panther Lake P */ + + /* +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 6826cc50d29f36..93b98a7f4c7fd9 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -124,6 +124,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + + {MEI_PCI_DEVICE(MEI_DEV_ID_LNL_M, MEI_ME_PCH15_CFG)}, + ++ {MEI_PCI_DEVICE(MEI_DEV_ID_PTL_H, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_PTL_P, MEI_ME_PCH15_CFG)}, + + /* required last entry */ +diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c +index 945d08531de376..82808cc373f68b 100644 +--- a/drivers/mmc/host/sdhci-msm.c ++++ b/drivers/mmc/host/sdhci-msm.c +@@ -1866,7 +1866,7 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, + if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS)) + return 0; + +- ice = of_qcom_ice_get(dev); ++ ice = devm_of_qcom_ice_get(dev); + if (ice == ERR_PTR(-EOPNOTSUPP)) { + dev_warn(dev, "Disabling inline encryption support\n"); + ice = NULL; +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +index 90ab2f1058ce0e..2d18a03d927421 100644 +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2596,6 +2596,9 @@ mt7531_setup_common(struct dsa_switch *ds) + struct mt7530_priv *priv = ds->priv; + int ret, i; + ++ ds->assisted_learning_on_cpu_port = true; ++ ds->mtu_enforcement_ingress = true; ++ + mt753x_trap_frames(priv); + + /* Enable and reset MIB counters */ +@@ -2735,9 +2738,6 @@ mt7531_setup(struct dsa_switch *ds) + + mt7531_setup_common(ds); + +- ds->assisted_learning_on_cpu_port = true; +- ds->mtu_enforcement_ingress = true; +- + return 0; + } + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index da7260e505a2e4..ef52d1ae27d694 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -5047,6 +5047,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { + .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, + .port_tag_remap = mv88e6095_port_tag_remap, ++ .port_set_policy = mv88e6352_port_set_policy, + .port_set_frame_mode = mv88e6351_port_set_frame_mode, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, +@@ -5071,8 +5072,10 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, +- .vtu_getnext = mv88e6185_g1_vtu_getnext, +- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, ++ .vtu_getnext = mv88e6352_g1_vtu_getnext, ++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, ++ .stu_getnext = mv88e6352_g1_stu_getnext, ++ .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, +@@ -5097,6 +5100,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { + .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, + .port_tag_remap = mv88e6095_port_tag_remap, ++ .port_set_policy = mv88e6352_port_set_policy, + .port_set_frame_mode = mv88e6351_port_set_frame_mode, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, +@@ -5120,8 +5124,10 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, +- .vtu_getnext = mv88e6185_g1_vtu_getnext, +- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, ++ .vtu_getnext = mv88e6352_g1_vtu_getnext, ++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, ++ .stu_getnext = mv88e6352_g1_stu_getnext, ++ .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, +@@ -5713,7 +5719,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .global1_addr = 0x1b, + .global2_addr = 0x1c, + .age_time_coeff = 3750, +- .atu_move_port_mask = 0x1f, ++ .atu_move_port_mask = 0xf, + .g1_irqs = 9, + .g2_irqs = 10, + .pvt = true, +@@ -6114,9 +6120,11 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .num_databases = 4096, + .num_macs = 8192, + .num_ports = 7, +- .num_internal_phys = 5, ++ .num_internal_phys = 2, ++ .internal_phys_offset = 3, + .num_gpio = 15, + .max_vid = 4095, ++ .max_sid = 63, + .port_base_addr = 0x10, + .phy_base_addr = 0x0, + .global1_addr = 0x1b, +@@ -6139,9 +6147,11 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .num_databases = 4096, + .num_macs = 8192, + .num_ports = 7, +- .num_internal_phys = 5, ++ .num_internal_phys = 2, ++ .internal_phys_offset = 3, + .num_gpio = 15, + .max_vid = 4095, ++ .max_sid = 63, + .port_base_addr = 0x10, + .phy_base_addr = 0x0, + .global1_addr = 0x1b, +@@ -6150,6 +6160,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .g1_irqs = 8, + .g2_irqs = 10, + .atu_move_port_mask = 0xf, ++ .pvt = true, + .multi_chip = true, + .edsa_support = MV88E6XXX_EDSA_SUPPORTED, + .ptp_support = true, +@@ -6172,7 +6183,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .global1_addr = 0x1b, + .global2_addr = 0x1c, + .age_time_coeff = 3750, +- .atu_move_port_mask = 0x1f, ++ .atu_move_port_mask = 0xf, + .g1_irqs = 9, + .g2_irqs = 10, + .pvt = true, +diff --git a/drivers/net/ethernet/amd/pds_core/adminq.c b/drivers/net/ethernet/amd/pds_core/adminq.c +index ea773cfa0af67b..733f133d69e75f 100644 +--- a/drivers/net/ethernet/amd/pds_core/adminq.c ++++ b/drivers/net/ethernet/amd/pds_core/adminq.c +@@ -5,11 +5,6 @@ + + #include "core.h" + +-struct pdsc_wait_context { +- struct pdsc_qcq *qcq; +- struct completion wait_completion; +-}; +- + static int pdsc_process_notifyq(struct pdsc_qcq *qcq) + { + union pds_core_notifyq_comp *comp; +@@ -110,10 +105,10 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq) + q_info = &q->info[q->tail_idx]; + q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); + +- /* Copy out the completion data */ +- memcpy(q_info->dest, comp, sizeof(*comp)); +- +- complete_all(&q_info->wc->wait_completion); ++ if (!completion_done(&q_info->completion)) { ++ memcpy(q_info->dest, comp, sizeof(*comp)); ++ complete(&q_info->completion); ++ } + + if (cq->tail_idx == cq->num_descs - 1) + cq->done_color = !cq->done_color; +@@ -166,8 +161,7 @@ irqreturn_t pdsc_adminq_isr(int irq, void *data) + static int __pdsc_adminq_post(struct pdsc *pdsc, + struct pdsc_qcq *qcq, + union pds_core_adminq_cmd *cmd, +- union pds_core_adminq_comp *comp, +- struct pdsc_wait_context *wc) ++ union pds_core_adminq_comp *comp) + { + struct pdsc_queue *q = &qcq->q; + struct pdsc_q_info *q_info; +@@ -209,9 +203,9 @@ static int __pdsc_adminq_post(struct pdsc *pdsc, + /* Post the request */ + index = q->head_idx; + q_info = &q->info[index]; +- q_info->wc = wc; + q_info->dest = comp; + memcpy(q_info->desc, cmd, sizeof(*cmd)); ++ reinit_completion(&q_info->completion); + + dev_dbg(pdsc->dev, "head_idx %d tail_idx %d\n", + q->head_idx, q->tail_idx); +@@ -235,16 +229,13 @@ int pdsc_adminq_post(struct pdsc *pdsc, + union pds_core_adminq_comp *comp, + bool fast_poll) + { +- struct pdsc_wait_context wc = { +- .wait_completion = +- COMPLETION_INITIALIZER_ONSTACK(wc.wait_completion), +- }; + unsigned long poll_interval = 1; + unsigned long poll_jiffies; + unsigned long time_limit; + unsigned long time_start; + unsigned long time_done; + unsigned long remaining; ++ struct completion *wc; + int err = 0; + int index; + +@@ -254,20 +245,19 @@ int pdsc_adminq_post(struct pdsc *pdsc, + return -ENXIO; + } + +- wc.qcq = &pdsc->adminqcq; +- index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp, &wc); ++ index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp); + if (index < 0) { + err = index; + goto err_out; + } + ++ wc = &pdsc->adminqcq.q.info[index].completion; + time_start = jiffies; + time_limit = time_start + HZ * pdsc->devcmd_timeout; + do { + /* Timeslice the actual wait to catch IO errors etc early */ + poll_jiffies = msecs_to_jiffies(poll_interval); +- remaining = wait_for_completion_timeout(&wc.wait_completion, +- poll_jiffies); ++ remaining = wait_for_completion_timeout(wc, poll_jiffies); + if (remaining) + break; + +@@ -296,9 +286,11 @@ int pdsc_adminq_post(struct pdsc *pdsc, + dev_dbg(pdsc->dev, "%s: elapsed %d msecs\n", + __func__, jiffies_to_msecs(time_done - time_start)); + +- /* Check the results */ +- if (time_after_eq(time_done, time_limit)) ++ /* Check the results and clear an un-completed timeout */ ++ if (time_after_eq(time_done, time_limit) && !completion_done(wc)) { + err = -ETIMEDOUT; ++ complete(wc); ++ } + + dev_dbg(pdsc->dev, "read admin queue completion idx %d:\n", index); + dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1, +diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c +index fd1a5149c00319..fb7a5403e630db 100644 +--- a/drivers/net/ethernet/amd/pds_core/auxbus.c ++++ b/drivers/net/ethernet/amd/pds_core/auxbus.c +@@ -107,9 +107,6 @@ int pds_client_adminq_cmd(struct pds_auxiliary_dev *padev, + dev_dbg(pf->dev, "%s: %s opcode %d\n", + __func__, dev_name(&padev->aux_dev.dev), req->opcode); + +- if (pf->state) +- return -ENXIO; +- + /* Wrap the client's request */ + cmd.client_request.opcode = PDS_AQ_CMD_CLIENT_CMD; + cmd.client_request.client_id = cpu_to_le16(padev->client_id); +diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c +index eb73c921dc1ed9..b3fa867c8ccd91 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.c ++++ b/drivers/net/ethernet/amd/pds_core/core.c +@@ -169,8 +169,10 @@ static void pdsc_q_map(struct pdsc_queue *q, void *base, dma_addr_t base_pa) + q->base = base; + q->base_pa = base_pa; + +- for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) ++ for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) { + cur->desc = base + (i * q->desc_size); ++ init_completion(&cur->completion); ++ } + } + + static void pdsc_cq_map(struct pdsc_cq *cq, void *base, dma_addr_t base_pa) +diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h +index f410f7d132056b..858bebf7977624 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.h ++++ b/drivers/net/ethernet/amd/pds_core/core.h +@@ -96,7 +96,7 @@ struct pdsc_q_info { + unsigned int bytes; + unsigned int nbufs; + struct pdsc_buf_info bufs[PDS_CORE_MAX_FRAGS]; +- struct pdsc_wait_context *wc; ++ struct completion completion; + void *dest; + }; + +diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c +index 971d4278280d65..0032e8e3518117 100644 +--- a/drivers/net/ethernet/amd/pds_core/devlink.c ++++ b/drivers/net/ethernet/amd/pds_core/devlink.c +@@ -101,7 +101,7 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, + .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL, + .fw_control.oper = PDS_CORE_FW_GET_LIST, + }; +- struct pds_core_fw_list_info fw_list; ++ struct pds_core_fw_list_info fw_list = {}; + struct pdsc *pdsc = devlink_priv(dl); + union pds_core_dev_comp comp; + char buf[32]; +@@ -114,8 +114,6 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, + if (!err) + memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list)); + mutex_unlock(&pdsc->devcmd_lock); +- if (err && err != -EIO) +- return err; + + listlen = min(fw_list.num_fw_slots, ARRAY_SIZE(fw_list.fw_names)); + for (i = 0; i < listlen; i++) { +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c201ea20e40476..dc89dbc13b251f 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3949,11 +3949,27 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset) + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + + if (mtk_is_netsys_v3_or_greater(eth)) { +- /* PSE should not drop port1, port8 and port9 packets */ +- mtk_w32(eth, 0x00000302, PSE_DROP_CFG); ++ /* PSE dummy page mechanism */ ++ mtk_w32(eth, PSE_DUMMY_WORK_GDM(1) | PSE_DUMMY_WORK_GDM(2) | ++ PSE_DUMMY_WORK_GDM(3) | DUMMY_PAGE_THR, PSE_DUMY_REQ); ++ ++ /* PSE free buffer drop threshold */ ++ mtk_w32(eth, 0x00600009, PSE_IQ_REV(8)); ++ ++ /* PSE should not drop port8, port9 and port13 packets from ++ * WDMA Tx ++ */ ++ mtk_w32(eth, 0x00002300, PSE_DROP_CFG); ++ ++ /* PSE should drop packets to port8, port9 and port13 on WDMA Rx ++ * ring full ++ */ ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(0)); ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(1)); ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(2)); + + /* GDM and CDM Threshold */ +- mtk_w32(eth, 0x00000707, MTK_CDMW0_THRES); ++ mtk_w32(eth, 0x08000707, MTK_CDMW0_THRES); + mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES); + + /* Disable GDM1 RX CRC stripping */ +@@ -3970,7 +3986,7 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset) + mtk_w32(eth, 0x00000300, PSE_DROP_CFG); + + /* PSE should drop packets to port 8/9 on WDMA Rx ring full */ +- mtk_w32(eth, 0x00000300, PSE_PPE0_DROP); ++ mtk_w32(eth, 0x00000300, PSE_PPE_DROP(0)); + + /* PSE Free Queue Flow Control */ + mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 403219d987eff5..d1c7b5f1ee4a9c 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -149,7 +149,15 @@ + #define PSE_FQFC_CFG1 0x100 + #define PSE_FQFC_CFG2 0x104 + #define PSE_DROP_CFG 0x108 +-#define PSE_PPE0_DROP 0x110 ++#define PSE_PPE_DROP(x) (0x110 + ((x) * 0x4)) ++ ++/* PSE Last FreeQ Page Request Control */ ++#define PSE_DUMY_REQ 0x10C ++/* PSE_DUMY_REQ is not a typo but actually called like that also in ++ * MediaTek's datasheet ++ */ ++#define PSE_DUMMY_WORK_GDM(x) BIT(16 + (x)) ++#define DUMMY_PAGE_THR 0x1 + + /* PSE Input Queue Reservation Register*/ + #define PSE_IQ_REV(x) (0x140 + (((x) - 1) << 2)) +diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c +index 0b88635f4fbca9..623607fd2cefd3 100644 +--- a/drivers/net/phy/microchip.c ++++ b/drivers/net/phy/microchip.c +@@ -31,47 +31,6 @@ static int lan88xx_write_page(struct phy_device *phydev, int page) + return __phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, page); + } + +-static int lan88xx_phy_config_intr(struct phy_device *phydev) +-{ +- int rc; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- /* unmask all source and clear them before enable */ +- rc = phy_write(phydev, LAN88XX_INT_MASK, 0x7FFF); +- rc = phy_read(phydev, LAN88XX_INT_STS); +- rc = phy_write(phydev, LAN88XX_INT_MASK, +- LAN88XX_INT_MASK_MDINTPIN_EN_ | +- LAN88XX_INT_MASK_LINK_CHANGE_); +- } else { +- rc = phy_write(phydev, LAN88XX_INT_MASK, 0); +- if (rc) +- return rc; +- +- /* Ack interrupts after they have been disabled */ +- rc = phy_read(phydev, LAN88XX_INT_STS); +- } +- +- return rc < 0 ? rc : 0; +-} +- +-static irqreturn_t lan88xx_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read(phydev, LAN88XX_INT_STS); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & LAN88XX_INT_STS_LINK_CHANGE_)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- + static int lan88xx_suspend(struct phy_device *phydev) + { + struct lan88xx_priv *priv = phydev->priv; +@@ -392,8 +351,9 @@ static struct phy_driver microchip_phy_driver[] = { + .config_aneg = lan88xx_config_aneg, + .link_change_notify = lan88xx_link_change_notify, + +- .config_intr = lan88xx_phy_config_intr, +- .handle_interrupt = lan88xx_handle_interrupt, ++ /* Interrupt handling is broken, do not define related ++ * functions to force polling. ++ */ + + .suspend = lan88xx_suspend, + .resume = genphy_resume, +diff --git a/drivers/net/phy/phy_led_triggers.c b/drivers/net/phy/phy_led_triggers.c +index f550576eb9dae7..6f9d8da76c4dfb 100644 +--- a/drivers/net/phy/phy_led_triggers.c ++++ b/drivers/net/phy/phy_led_triggers.c +@@ -91,9 +91,8 @@ int phy_led_triggers_register(struct phy_device *phy) + if (!phy->phy_num_led_triggers) + return 0; + +- phy->led_link_trigger = devm_kzalloc(&phy->mdio.dev, +- sizeof(*phy->led_link_trigger), +- GFP_KERNEL); ++ phy->led_link_trigger = kzalloc(sizeof(*phy->led_link_trigger), ++ GFP_KERNEL); + if (!phy->led_link_trigger) { + err = -ENOMEM; + goto out_clear; +@@ -103,10 +102,9 @@ int phy_led_triggers_register(struct phy_device *phy) + if (err) + goto out_free_link; + +- phy->phy_led_triggers = devm_kcalloc(&phy->mdio.dev, +- phy->phy_num_led_triggers, +- sizeof(struct phy_led_trigger), +- GFP_KERNEL); ++ phy->phy_led_triggers = kcalloc(phy->phy_num_led_triggers, ++ sizeof(struct phy_led_trigger), ++ GFP_KERNEL); + if (!phy->phy_led_triggers) { + err = -ENOMEM; + goto out_unreg_link; +@@ -127,11 +125,11 @@ int phy_led_triggers_register(struct phy_device *phy) + out_unreg: + while (i--) + phy_led_trigger_unregister(&phy->phy_led_triggers[i]); +- devm_kfree(&phy->mdio.dev, phy->phy_led_triggers); ++ kfree(phy->phy_led_triggers); + out_unreg_link: + phy_led_trigger_unregister(phy->led_link_trigger); + out_free_link: +- devm_kfree(&phy->mdio.dev, phy->led_link_trigger); ++ kfree(phy->led_link_trigger); + phy->led_link_trigger = NULL; + out_clear: + phy->phy_num_led_triggers = 0; +@@ -145,8 +143,13 @@ void phy_led_triggers_unregister(struct phy_device *phy) + + for (i = 0; i < phy->phy_num_led_triggers; i++) + phy_led_trigger_unregister(&phy->phy_led_triggers[i]); ++ kfree(phy->phy_led_triggers); ++ phy->phy_led_triggers = NULL; + +- if (phy->led_link_trigger) ++ if (phy->led_link_trigger) { + phy_led_trigger_unregister(phy->led_link_trigger); ++ kfree(phy->led_link_trigger); ++ phy->led_link_trigger = NULL; ++ } + } + EXPORT_SYMBOL_GPL(phy_led_triggers_unregister); +diff --git a/drivers/net/vmxnet3/vmxnet3_xdp.c b/drivers/net/vmxnet3/vmxnet3_xdp.c +index 616ecc38d1726c..5f470499e60024 100644 +--- a/drivers/net/vmxnet3/vmxnet3_xdp.c ++++ b/drivers/net/vmxnet3/vmxnet3_xdp.c +@@ -397,7 +397,7 @@ vmxnet3_process_xdp(struct vmxnet3_adapter *adapter, + + xdp_init_buff(&xdp, PAGE_SIZE, &rq->xdp_rxq); + xdp_prepare_buff(&xdp, page_address(page), rq->page_pool->p.offset, +- rbi->len, false); ++ rcd->len, false); + xdp_buff_clear_frags_flag(&xdp); + + xdp_prog = rcu_dereference(rq->adapter->xdp_bpf_prog); +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index bcb5651f18e0f5..0115f8f5b7245f 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -985,20 +985,27 @@ static u32 xennet_run_xdp(struct netfront_queue *queue, struct page *pdata, + act = bpf_prog_run_xdp(prog, xdp); + switch (act) { + case XDP_TX: +- get_page(pdata); + xdpf = xdp_convert_buff_to_frame(xdp); ++ if (unlikely(!xdpf)) { ++ trace_xdp_exception(queue->info->netdev, prog, act); ++ break; ++ } ++ get_page(pdata); + err = xennet_xdp_xmit(queue->info->netdev, 1, &xdpf, 0); +- if (unlikely(!err)) ++ if (unlikely(err <= 0)) { ++ if (err < 0) ++ trace_xdp_exception(queue->info->netdev, prog, act); + xdp_return_frame_rx_napi(xdpf); +- else if (unlikely(err < 0)) +- trace_xdp_exception(queue->info->netdev, prog, act); ++ } + break; + case XDP_REDIRECT: + get_page(pdata); + err = xdp_do_redirect(queue->info->netdev, xdp, prog); + *need_xdp_flush = true; +- if (unlikely(err)) ++ if (unlikely(err)) { + trace_xdp_exception(queue->info->netdev, prog, act); ++ xdp_return_buff(xdp); ++ } + break; + case XDP_PASS: + case XDP_DROP: +diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c +index d687e8c2cc78dc..63ceed89b62ef9 100644 +--- a/drivers/ntb/hw/amd/ntb_hw_amd.c ++++ b/drivers/ntb/hw/amd/ntb_hw_amd.c +@@ -1318,6 +1318,7 @@ static const struct pci_device_id amd_ntb_pci_tbl[] = { + { PCI_VDEVICE(AMD, 0x148b), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(AMD, 0x14c0), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(AMD, 0x14c3), (kernel_ulong_t)&dev_data[1] }, ++ { PCI_VDEVICE(AMD, 0x155a), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(HYGON, 0x145b), (kernel_ulong_t)&dev_data[0] }, + { 0, } + }; +diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c +index 48823b53ede3e9..22aaa60d2d3846 100644 +--- a/drivers/ntb/hw/idt/ntb_hw_idt.c ++++ b/drivers/ntb/hw/idt/ntb_hw_idt.c +@@ -1041,7 +1041,7 @@ static inline char *idt_get_mw_name(enum idt_mw_type mw_type) + static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, + unsigned char *mw_cnt) + { +- struct idt_mw_cfg mws[IDT_MAX_NR_MWS], *ret_mws; ++ struct idt_mw_cfg *mws; + const struct idt_ntb_bar *bars; + enum idt_mw_type mw_type; + unsigned char widx, bidx, en_cnt; +@@ -1049,6 +1049,11 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, + int aprt_size; + u32 data; + ++ mws = devm_kcalloc(&ndev->ntb.pdev->dev, IDT_MAX_NR_MWS, ++ sizeof(*mws), GFP_KERNEL); ++ if (!mws) ++ return ERR_PTR(-ENOMEM); ++ + /* Retrieve the array of the BARs registers */ + bars = portdata_tbl[port].bars; + +@@ -1103,16 +1108,7 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, + } + } + +- /* Allocate memory for memory window descriptors */ +- ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws), +- GFP_KERNEL); +- if (!ret_mws) +- return ERR_PTR(-ENOMEM); +- +- /* Copy the info of detected memory windows */ +- memcpy(ret_mws, mws, (*mw_cnt)*sizeof(*ret_mws)); +- +- return ret_mws; ++ return mws; + } + + /* +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index f00665ad0c11a3..c6b0637e61debd 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -3972,6 +3972,15 @@ static void nvme_scan_work(struct work_struct *work) + nvme_scan_ns_sequential(ctrl); + } + mutex_unlock(&ctrl->scan_lock); ++ ++ /* Requeue if we have missed AENs */ ++ if (test_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events)) ++ nvme_queue_scan(ctrl); ++#ifdef CONFIG_NVME_MULTIPATH ++ else if (ctrl->ana_log_buf) ++ /* Re-read the ANA log page to not miss updates */ ++ queue_work(nvme_wq, &ctrl->ana_work); ++#endif + } + + /* +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index 32283301199f01..119afdfe4b91e9 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -426,7 +426,7 @@ static bool nvme_available_path(struct nvme_ns_head *head) + struct nvme_ns *ns; + + if (!test_bit(NVME_NSHEAD_DISK_LIVE, &head->flags)) +- return NULL; ++ return false; + + list_for_each_entry_srcu(ns, &head->list, siblings, + srcu_read_lock_held(&head->srcu)) { +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index d40d5a4ea932e0..570c58d2b5a585 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -1030,33 +1030,24 @@ nvmet_fc_alloc_hostport(struct nvmet_fc_tgtport *tgtport, void *hosthandle) + struct nvmet_fc_hostport *newhost, *match = NULL; + unsigned long flags; + ++ /* ++ * Caller holds a reference on tgtport. ++ */ ++ + /* if LLDD not implemented, leave as NULL */ + if (!hosthandle) + return NULL; + +- /* +- * take reference for what will be the newly allocated hostport if +- * we end up using a new allocation +- */ +- if (!nvmet_fc_tgtport_get(tgtport)) +- return ERR_PTR(-EINVAL); +- + spin_lock_irqsave(&tgtport->lock, flags); + match = nvmet_fc_match_hostport(tgtport, hosthandle); + spin_unlock_irqrestore(&tgtport->lock, flags); + +- if (match) { +- /* no new allocation - release reference */ +- nvmet_fc_tgtport_put(tgtport); ++ if (match) + return match; +- } + + newhost = kzalloc(sizeof(*newhost), GFP_KERNEL); +- if (!newhost) { +- /* no new allocation - release reference */ +- nvmet_fc_tgtport_put(tgtport); ++ if (!newhost) + return ERR_PTR(-ENOMEM); +- } + + spin_lock_irqsave(&tgtport->lock, flags); + match = nvmet_fc_match_hostport(tgtport, hosthandle); +@@ -1065,6 +1056,7 @@ nvmet_fc_alloc_hostport(struct nvmet_fc_tgtport *tgtport, void *hosthandle) + kfree(newhost); + newhost = match; + } else { ++ nvmet_fc_tgtport_get(tgtport); + newhost->tgtport = tgtport; + newhost->hosthandle = hosthandle; + INIT_LIST_HEAD(&newhost->host_list); +@@ -1099,7 +1091,8 @@ static void + nvmet_fc_schedule_delete_assoc(struct nvmet_fc_tgt_assoc *assoc) + { + nvmet_fc_tgtport_get(assoc->tgtport); +- queue_work(nvmet_wq, &assoc->del_work); ++ if (!queue_work(nvmet_wq, &assoc->del_work)) ++ nvmet_fc_tgtport_put(assoc->tgtport); + } + + static struct nvmet_fc_tgt_assoc * +diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c +index b278ab4338ceb5..d5c1b2a126a560 100644 +--- a/drivers/of/resolver.c ++++ b/drivers/of/resolver.c +@@ -262,25 +262,22 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, + */ + int of_resolve_phandles(struct device_node *overlay) + { +- struct device_node *child, *local_fixups, *refnode; +- struct device_node *tree_symbols, *overlay_fixups; ++ struct device_node *child, *refnode; ++ struct device_node *overlay_fixups; ++ struct device_node __free(device_node) *local_fixups = NULL; + struct property *prop; + const char *refpath; + phandle phandle, phandle_delta; + int err; + +- tree_symbols = NULL; +- + if (!overlay) { + pr_err("null overlay\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + if (!of_node_check_flag(overlay, OF_DETACHED)) { + pr_err("overlay not detached\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + phandle_delta = live_tree_max_phandle() + 1; +@@ -292,7 +289,7 @@ int of_resolve_phandles(struct device_node *overlay) + + err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); + if (err) +- goto out; ++ return err; + + overlay_fixups = NULL; + +@@ -301,16 +298,13 @@ int of_resolve_phandles(struct device_node *overlay) + overlay_fixups = child; + } + +- if (!overlay_fixups) { +- err = 0; +- goto out; +- } ++ if (!overlay_fixups) ++ return 0; + +- tree_symbols = of_find_node_by_path("/__symbols__"); ++ struct device_node __free(device_node) *tree_symbols = of_find_node_by_path("/__symbols__"); + if (!tree_symbols) { + pr_err("no symbols in root of device tree.\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + for_each_property_of_node(overlay_fixups, prop) { +@@ -324,14 +318,12 @@ int of_resolve_phandles(struct device_node *overlay) + if (err) { + pr_err("node label '%s' not found in live devicetree symbols table\n", + prop->name); +- goto out; ++ return err; + } + + refnode = of_find_node_by_path(refpath); +- if (!refnode) { +- err = -ENOENT; +- goto out; +- } ++ if (!refnode) ++ return -ENOENT; + + phandle = refnode->phandle; + of_node_put(refnode); +@@ -341,11 +333,8 @@ int of_resolve_phandles(struct device_node *overlay) + break; + } + +-out: + if (err) + pr_err("overlay phandle fixup failed: %d\n", err); +- of_node_put(tree_symbols); +- + return err; + } + EXPORT_SYMBOL_GPL(of_resolve_phandles); +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 8e5d818c29a983..b7cec139d816ba 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -885,6 +885,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + resource_size_t offset, next_offset; + LIST_HEAD(resources); + struct resource *res, *next_res; ++ bool bus_registered = false; + char addr[64], *fmt; + const char *name; + int err; +@@ -948,6 +949,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + name = dev_name(&bus->dev); + + err = device_register(&bus->dev); ++ bus_registered = true; + if (err) + goto unregister; + +@@ -1031,12 +1033,15 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + unregister: + put_device(&bridge->dev); + device_del(&bridge->dev); +- + free: + #ifdef CONFIG_PCI_DOMAINS_GENERIC + pci_bus_release_domain_nr(bus, parent); + #endif +- kfree(bus); ++ if (bus_registered) ++ put_device(&bus->dev); ++ else ++ kfree(bus); ++ + return err; + } + +diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c +index c5d733216508e8..df660b7e1300ca 100644 +--- a/drivers/pinctrl/renesas/pinctrl-rza2.c ++++ b/drivers/pinctrl/renesas/pinctrl-rza2.c +@@ -243,6 +243,9 @@ static int rza2_gpio_register(struct rza2_pinctrl_priv *priv) + int ret; + + chip.label = devm_kasprintf(priv->dev, GFP_KERNEL, "%pOFn", np); ++ if (!chip.label) ++ return -ENOMEM; ++ + chip.parent = priv->dev; + chip.ngpio = priv->npins; + +diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c +index 374d80dc6d17ab..bec22a001a5dd5 100644 +--- a/drivers/regulator/rk808-regulator.c ++++ b/drivers/regulator/rk808-regulator.c +@@ -267,8 +267,8 @@ static const unsigned int rk817_buck1_4_ramp_table[] = { + + static int rk806_set_mode_dcdc(struct regulator_dev *rdev, unsigned int mode) + { +- int rid = rdev_get_id(rdev); +- int ctr_bit, reg; ++ unsigned int rid = rdev_get_id(rdev); ++ unsigned int ctr_bit, reg; + + reg = RK806_POWER_FPWM_EN0 + rid / 8; + ctr_bit = rid % 8; +diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c +index 905986c616559b..73848f764559b4 100644 +--- a/drivers/rtc/rtc-pcf85063.c ++++ b/drivers/rtc/rtc-pcf85063.c +@@ -35,6 +35,7 @@ + #define PCF85063_REG_CTRL1_CAP_SEL BIT(0) + #define PCF85063_REG_CTRL1_STOP BIT(5) + #define PCF85063_REG_CTRL1_EXT_TEST BIT(7) ++#define PCF85063_REG_CTRL1_SWR 0x58 + + #define PCF85063_REG_CTRL2 0x01 + #define PCF85063_CTRL2_AF BIT(6) +@@ -589,7 +590,7 @@ static int pcf85063_probe(struct i2c_client *client) + + i2c_set_clientdata(client, pcf85063); + +- err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp); ++ err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp); + if (err) { + dev_err(&client->dev, "RTC chip is not present\n"); + return err; +@@ -599,6 +600,22 @@ static int pcf85063_probe(struct i2c_client *client) + if (IS_ERR(pcf85063->rtc)) + return PTR_ERR(pcf85063->rtc); + ++ /* ++ * If a Power loss is detected, SW reset the device. ++ * From PCF85063A datasheet: ++ * There is a low probability that some devices will have corruption ++ * of the registers after the automatic power-on reset... ++ */ ++ if (tmp & PCF85063_REG_SC_OS) { ++ dev_warn(&client->dev, ++ "POR issue detected, sending a SW reset\n"); ++ err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1, ++ PCF85063_REG_CTRL1_SWR); ++ if (err < 0) ++ dev_warn(&client->dev, ++ "SW reset failed, trying to continue\n"); ++ } ++ + err = pcf85063_load_capacitance(pcf85063, client->dev.of_node, + config->force_cap_7000 ? 7000 : 0); + if (err < 0) +diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c +index e5d947c763ea5d..6a030ba38bf360 100644 +--- a/drivers/s390/char/sclp_con.c ++++ b/drivers/s390/char/sclp_con.c +@@ -263,6 +263,19 @@ static struct console sclp_console = + .index = 0 /* ttyS0 */ + }; + ++/* ++ * Release allocated pages. ++ */ ++static void __init __sclp_console_free_pages(void) ++{ ++ struct list_head *page, *p; ++ ++ list_for_each_safe(page, p, &sclp_con_pages) { ++ list_del(page); ++ free_page((unsigned long)page); ++ } ++} ++ + /* + * called by console_init() in drivers/char/tty_io.c at boot-time. + */ +@@ -282,6 +295,10 @@ sclp_console_init(void) + /* Allocate pages for output buffering */ + for (i = 0; i < sclp_console_pages; i++) { + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); ++ if (!page) { ++ __sclp_console_free_pages(); ++ return -ENOMEM; ++ } + list_add_tail(page, &sclp_con_pages); + } + sclp_conbuf = NULL; +diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c +index 892c18d2f87e90..d3edacb6ee148b 100644 +--- a/drivers/s390/char/sclp_tty.c ++++ b/drivers/s390/char/sclp_tty.c +@@ -490,6 +490,17 @@ static const struct tty_operations sclp_ops = { + .flush_buffer = sclp_tty_flush_buffer, + }; + ++/* Release allocated pages. */ ++static void __init __sclp_tty_free_pages(void) ++{ ++ struct list_head *page, *p; ++ ++ list_for_each_safe(page, p, &sclp_tty_pages) { ++ list_del(page); ++ free_page((unsigned long)page); ++ } ++} ++ + static int __init + sclp_tty_init(void) + { +@@ -516,6 +527,7 @@ sclp_tty_init(void) + for (i = 0; i < MAX_KMEM_PAGES; i++) { + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (page == NULL) { ++ __sclp_tty_free_pages(); + tty_driver_kref_put(driver); + return -ENOMEM; + } +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index f78c5f8a49ffac..7e64661d215bd2 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -911,8 +911,28 @@ static void hisi_sas_phyup_work_common(struct work_struct *work, + container_of(work, typeof(*phy), works[event]); + struct hisi_hba *hisi_hba = phy->hisi_hba; + struct asd_sas_phy *sas_phy = &phy->sas_phy; ++ struct asd_sas_port *sas_port = sas_phy->port; ++ struct hisi_sas_port *port = phy->port; ++ struct device *dev = hisi_hba->dev; ++ struct domain_device *port_dev; + int phy_no = sas_phy->id; + ++ if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) && ++ sas_port && port && (port->id != phy->port_id)) { ++ dev_info(dev, "phy%d's hw port id changed from %d to %llu\n", ++ phy_no, port->id, phy->port_id); ++ port_dev = sas_port->port_dev; ++ if (port_dev && !dev_is_expander(port_dev->dev_type)) { ++ /* ++ * Set the device state to gone to block ++ * sending IO to the device. ++ */ ++ set_bit(SAS_DEV_GONE, &port_dev->state); ++ hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); ++ return; ++ } ++ } ++ + phy->wait_phyup_cnt = 0; + if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP) + hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no); +diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c +index ee2da8e49d4cfb..a9d6dac4133466 100644 +--- a/drivers/scsi/pm8001/pm8001_sas.c ++++ b/drivers/scsi/pm8001/pm8001_sas.c +@@ -719,6 +719,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) + spin_lock_irqsave(&pm8001_ha->lock, flags); + } + PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id); ++ pm8001_ha->phy[pm8001_dev->attached_phy].phy_attached = 0; + pm8001_free_dev(pm8001_dev); + } else { + pm8001_dbg(pm8001_ha, DISC, "Found dev has gone.\n"); +diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c +index 22bdce0bc32792..9c0142a010bac1 100644 +--- a/drivers/scsi/scsi.c ++++ b/drivers/scsi/scsi.c +@@ -693,26 +693,23 @@ void scsi_cdl_check(struct scsi_device *sdev) + */ + int scsi_cdl_enable(struct scsi_device *sdev, bool enable) + { +- struct scsi_mode_data data; +- struct scsi_sense_hdr sshdr; +- struct scsi_vpd *vpd; +- bool is_ata = false; + char buf[64]; ++ bool is_ata; + int ret; + + if (!sdev->cdl_supported) + return -EOPNOTSUPP; + + rcu_read_lock(); +- vpd = rcu_dereference(sdev->vpd_pg89); +- if (vpd) +- is_ata = true; ++ is_ata = rcu_dereference(sdev->vpd_pg89); + rcu_read_unlock(); + + /* + * For ATA devices, CDL needs to be enabled with a SET FEATURES command. + */ + if (is_ata) { ++ struct scsi_mode_data data; ++ struct scsi_sense_hdr sshdr; + char *buf_data; + int len; + +@@ -721,16 +718,30 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) + if (ret) + return -EINVAL; + +- /* Enable CDL using the ATA feature page */ ++ /* Enable or disable CDL using the ATA feature page */ + len = min_t(size_t, sizeof(buf), + data.length - data.header_length - + data.block_descriptor_length); + buf_data = buf + data.header_length + + data.block_descriptor_length; +- if (enable) +- buf_data[4] = 0x02; +- else +- buf_data[4] = 0; ++ ++ /* ++ * If we want to enable CDL and CDL is already enabled on the ++ * device, do nothing. This avoids needlessly resetting the CDL ++ * statistics on the device as that is implied by the CDL enable ++ * action. Similar to this, there is no need to do anything if ++ * we want to disable CDL and CDL is already disabled. ++ */ ++ if (enable) { ++ if ((buf_data[4] & 0x03) == 0x02) ++ goto out; ++ buf_data[4] &= ~0x03; ++ buf_data[4] |= 0x02; ++ } else { ++ if ((buf_data[4] & 0x03) == 0x00) ++ goto out; ++ buf_data[4] &= ~0x03; ++ } + + ret = scsi_mode_select(sdev, 1, 0, buf_data, len, 5 * HZ, 3, + &data, &sshdr); +@@ -742,6 +753,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) + } + } + ++out: + sdev->cdl_enable = enable; + + return 0; +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index e6dc2c556fde9e..bd75e3ebc14da3 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1152,8 +1152,12 @@ EXPORT_SYMBOL_GPL(scsi_alloc_request); + */ + static void scsi_cleanup_rq(struct request *rq) + { ++ struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); ++ ++ cmd->flags = 0; ++ + if (rq->rq_flags & RQF_DONTPREP) { +- scsi_mq_uninit_cmd(blk_mq_rq_to_pdu(rq)); ++ scsi_mq_uninit_cmd(cmd); + rq->rq_flags &= ~RQF_DONTPREP; + } + } +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index fbab7fe5c652b9..d6e205e3812a96 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -328,6 +329,53 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) + } + EXPORT_SYMBOL_GPL(of_qcom_ice_get); + ++static void qcom_ice_put(const struct qcom_ice *ice) ++{ ++ struct platform_device *pdev = to_platform_device(ice->dev); ++ ++ if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice")) ++ platform_device_put(pdev); ++} ++ ++static void devm_of_qcom_ice_put(struct device *dev, void *res) ++{ ++ qcom_ice_put(*(struct qcom_ice **)res); ++} ++ ++/** ++ * devm_of_qcom_ice_get() - Devres managed helper to get an ICE instance from ++ * a DT node. ++ * @dev: device pointer for the consumer device. ++ * ++ * This function will provide an ICE instance either by creating one for the ++ * consumer device if its DT node provides the 'ice' reg range and the 'ice' ++ * clock (for legacy DT style). On the other hand, if consumer provides a ++ * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already ++ * be created and so this function will return that instead. ++ * ++ * Return: ICE pointer on success, NULL if there is no ICE data provided by the ++ * consumer or ERR_PTR() on error. ++ */ ++struct qcom_ice *devm_of_qcom_ice_get(struct device *dev) ++{ ++ struct qcom_ice *ice, **dr; ++ ++ dr = devres_alloc(devm_of_qcom_ice_put, sizeof(*dr), GFP_KERNEL); ++ if (!dr) ++ return ERR_PTR(-ENOMEM); ++ ++ ice = of_qcom_ice_get(dev); ++ if (!IS_ERR_OR_NULL(ice)) { ++ *dr = ice; ++ devres_add(dev, dr); ++ } else { ++ devres_free(dr); ++ } ++ ++ return ice; ++} ++EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get); ++ + static int qcom_ice_probe(struct platform_device *pdev) + { + struct qcom_ice *engine; +diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c +index daa32bde615561..da4442954375b1 100644 +--- a/drivers/spi/spi-imx.c ++++ b/drivers/spi/spi-imx.c +@@ -1614,10 +1614,13 @@ static int spi_imx_transfer_one(struct spi_controller *controller, + struct spi_device *spi, + struct spi_transfer *transfer) + { ++ int ret; + struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); + unsigned long hz_per_byte, byte_limit; + +- spi_imx_setupxfer(spi, transfer); ++ ret = spi_imx_setupxfer(spi, transfer); ++ if (ret < 0) ++ return ret; + transfer->effective_speed_hz = spi_imx->spi_bus_clk; + + /* flush rxfifo before transfer */ +diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c +index d1afa4140e8a26..e3c236025a7b3b 100644 +--- a/drivers/spi/spi-tegra210-quad.c ++++ b/drivers/spi/spi-tegra210-quad.c +@@ -1117,9 +1117,9 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, + (&tqspi->xfer_completion, + QSPI_DMA_TIMEOUT); + +- if (WARN_ON(ret == 0)) { +- dev_err(tqspi->dev, "QSPI Transfer failed with timeout: %d\n", +- ret); ++ if (WARN_ON_ONCE(ret == 0)) { ++ dev_err_ratelimited(tqspi->dev, ++ "QSPI Transfer failed with timeout\n"); + if (tqspi->is_curr_dma_xfer && + (tqspi->cur_direction & DATA_DIR_TX)) + dmaengine_terminate_all +diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c +index 7c3310a2b28a41..b92a8a5b2e8c97 100644 +--- a/drivers/thunderbolt/tb.c ++++ b/drivers/thunderbolt/tb.c +@@ -1370,11 +1370,15 @@ static void tb_scan_port(struct tb_port *port) + goto out_rpm_put; + } + +- tb_retimer_scan(port, true); +- + sw = tb_switch_alloc(port->sw->tb, &port->sw->dev, + tb_downstream_route(port)); + if (IS_ERR(sw)) { ++ /* ++ * Make the downstream retimers available even if there ++ * is no router connected. ++ */ ++ tb_retimer_scan(port, true); ++ + /* + * If there is an error accessing the connected switch + * it may be connected to another domain. Also we allow +@@ -1424,6 +1428,14 @@ static void tb_scan_port(struct tb_port *port) + upstream_port = tb_upstream_port(sw); + tb_configure_link(port, upstream_port, sw); + ++ /* ++ * Scan for downstream retimers. We only scan them after the ++ * router has been enumerated to avoid issues with certain ++ * Pluggable devices that expect the host to enumerate them ++ * within certain timeout. ++ */ ++ tb_retimer_scan(port, true); ++ + /* + * CL0s and CL1 are enabled and supported together. + * Silently ignore CLx enabling in case CLx is not supported. +diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c +index 90953e679e386a..76b6429fb9e92e 100644 +--- a/drivers/tty/serial/msm_serial.c ++++ b/drivers/tty/serial/msm_serial.c +@@ -1741,6 +1741,12 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device, + if (!device->port.membase) + return -ENODEV; + ++ /* Disable DM / single-character modes */ ++ msm_write(&device->port, 0, UARTDM_DMEN); ++ msm_write(&device->port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); ++ msm_write(&device->port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); ++ msm_write(&device->port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR); ++ + device->con->write = msm_serial_early_write_dm; + return 0; + } +diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c +index d195c5de52e78f..e86b00873d0ea6 100644 +--- a/drivers/tty/serial/sifive.c ++++ b/drivers/tty/serial/sifive.c +@@ -562,8 +562,11 @@ static void sifive_serial_break_ctl(struct uart_port *port, int break_state) + static int sifive_serial_startup(struct uart_port *port) + { + struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); ++ unsigned long flags; + ++ uart_port_lock_irqsave(&ssp->port, &flags); + __ssp_enable_rxwm(ssp); ++ uart_port_unlock_irqrestore(&ssp->port, flags); + + return 0; + } +@@ -571,9 +574,12 @@ static int sifive_serial_startup(struct uart_port *port) + static void sifive_serial_shutdown(struct uart_port *port) + { + struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); ++ unsigned long flags; + ++ uart_port_lock_irqsave(&ssp->port, &flags); + __ssp_disable_rxwm(ssp); + __ssp_disable_txwm(ssp); ++ uart_port_unlock_irqrestore(&ssp->port, flags); + } + + /** +diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c +index da8c1734d33358..411109a5ebbffd 100644 +--- a/drivers/ufs/core/ufs-mcq.c ++++ b/drivers/ufs/core/ufs-mcq.c +@@ -632,13 +632,6 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) + unsigned long flags; + int err; + +- if (!ufshcd_cmd_inflight(lrbp->cmd)) { +- dev_err(hba->dev, +- "%s: skip abort. cmd at tag %d already completed.\n", +- __func__, tag); +- return FAILED; +- } +- + /* Skip task abort in case previous aborts failed and report failure */ + if (lrbp->req_abort_skip) { + dev_err(hba->dev, "%s: skip abort. tag %d failed earlier\n", +@@ -647,6 +640,11 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) + } + + hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd)); ++ if (!hwq) { ++ dev_err(hba->dev, "%s: skip abort. cmd at tag %d already completed.\n", ++ __func__, tag); ++ return FAILED; ++ } + + if (ufshcd_mcq_sqe_search(hba, hwq, tag)) { + /* +diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c +index d138b66d5e350b..f61126189876e9 100644 +--- a/drivers/ufs/host/ufs-exynos.c ++++ b/drivers/ufs/host/ufs-exynos.c +@@ -990,9 +990,14 @@ static int exynos_ufs_pre_link(struct ufs_hba *hba) + exynos_ufs_config_intr(ufs, DFES_DEF_L4_ERRS, UNIPRO_L4); + exynos_ufs_set_unipro_pclk_div(ufs); + ++ exynos_ufs_setup_clocks(hba, true, PRE_CHANGE); ++ + /* unipro */ + exynos_ufs_config_unipro(ufs); + ++ if (ufs->drv_data->pre_link) ++ ufs->drv_data->pre_link(ufs); ++ + /* m-phy */ + exynos_ufs_phy_init(ufs); + if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR)) { +@@ -1000,11 +1005,6 @@ static int exynos_ufs_pre_link(struct ufs_hba *hba) + exynos_ufs_config_phy_cap_attr(ufs); + } + +- exynos_ufs_setup_clocks(hba, true, PRE_CHANGE); +- +- if (ufs->drv_data->pre_link) +- ufs->drv_data->pre_link(ufs); +- + return 0; + } + +diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c +index 51ed40529f9a7b..c6417ef074a478 100644 +--- a/drivers/ufs/host/ufs-qcom.c ++++ b/drivers/ufs/host/ufs-qcom.c +@@ -121,7 +121,7 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) + struct device *dev = hba->dev; + struct qcom_ice *ice; + +- ice = of_qcom_ice_get(dev); ++ ice = devm_of_qcom_ice_get(dev); + if (ice == ERR_PTR(-EOPNOTSUPP)) { + dev_warn(dev, "Disabling inline encryption support\n"); + ice = NULL; +diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c +index b1b46c7c63f8b3..05e8414c31df4c 100644 +--- a/drivers/usb/cdns3/cdns3-gadget.c ++++ b/drivers/usb/cdns3/cdns3-gadget.c +@@ -1962,6 +1962,7 @@ static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) + unsigned int bit; + unsigned long reg; + ++ local_bh_disable(); + spin_lock_irqsave(&priv_dev->lock, flags); + + reg = readl(&priv_dev->regs->usb_ists); +@@ -2003,6 +2004,7 @@ static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) + irqend: + writel(~0, &priv_dev->regs->ep_ien); + spin_unlock_irqrestore(&priv_dev->lock, flags); ++ local_bh_enable(); + + return ret; + } +diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c +index b3cbca361a9696..73d5b9466676c4 100644 +--- a/drivers/usb/chipidea/ci_hdrc_imx.c ++++ b/drivers/usb/chipidea/ci_hdrc_imx.c +@@ -328,6 +328,13 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) + return ret; + } + ++static void ci_hdrc_imx_disable_regulator(void *arg) ++{ ++ struct ci_hdrc_imx_data *data = arg; ++ ++ regulator_disable(data->hsic_pad_regulator); ++} ++ + static int ci_hdrc_imx_probe(struct platform_device *pdev) + { + struct ci_hdrc_imx_data *data; +@@ -386,6 +393,13 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + "Failed to enable HSIC pad regulator\n"); + goto err_put; + } ++ ret = devm_add_action_or_reset(dev, ++ ci_hdrc_imx_disable_regulator, data); ++ if (ret) { ++ dev_err(dev, ++ "Failed to add regulator devm action\n"); ++ goto err_put; ++ } + } + } + +@@ -424,11 +438,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + + ret = imx_get_clks(dev); + if (ret) +- goto disable_hsic_regulator; ++ goto qos_remove_request; + + ret = imx_prepare_enable_clks(dev); + if (ret) +- goto disable_hsic_regulator; ++ goto qos_remove_request; + + data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0); + if (IS_ERR(data->phy)) { +@@ -458,7 +472,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) { + pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL; + data->override_phy_control = true; +- usb_phy_init(pdata.usb_phy); ++ ret = usb_phy_init(pdata.usb_phy); ++ if (ret) { ++ dev_err(dev, "Failed to init phy\n"); ++ goto err_clk; ++ } + } + + if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) +@@ -467,7 +485,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + ret = imx_usbmisc_init(data->usbmisc_data); + if (ret) { + dev_err(dev, "usbmisc init failed, ret=%d\n", ret); +- goto err_clk; ++ goto phy_shutdown; + } + + data->ci_pdev = ci_hdrc_add_device(dev, +@@ -476,7 +494,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + if (IS_ERR(data->ci_pdev)) { + ret = PTR_ERR(data->ci_pdev); + dev_err_probe(dev, ret, "ci_hdrc_add_device failed\n"); +- goto err_clk; ++ goto phy_shutdown; + } + + if (data->usbmisc_data) { +@@ -510,17 +528,18 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) + + disable_device: + ci_hdrc_remove_device(data->ci_pdev); ++phy_shutdown: ++ if (data->override_phy_control) ++ usb_phy_shutdown(data->phy); + err_clk: + imx_disable_unprepare_clks(dev); +-disable_hsic_regulator: +- if (data->hsic_pad_regulator) +- /* don't overwrite original ret (cf. EPROBE_DEFER) */ +- regulator_disable(data->hsic_pad_regulator); ++qos_remove_request: + if (pdata.flags & CI_HDRC_PMQOS) + cpu_latency_qos_remove_request(&data->pm_qos_req); + data->ci_pdev = NULL; + err_put: +- put_device(data->usbmisc_data->dev); ++ if (data->usbmisc_data) ++ put_device(data->usbmisc_data->dev); + return ret; + } + +@@ -541,10 +560,9 @@ static void ci_hdrc_imx_remove(struct platform_device *pdev) + imx_disable_unprepare_clks(&pdev->dev); + if (data->plat_data->flags & CI_HDRC_PMQOS) + cpu_latency_qos_remove_request(&data->pm_qos_req); +- if (data->hsic_pad_regulator) +- regulator_disable(data->hsic_pad_regulator); + } +- put_device(data->usbmisc_data->dev); ++ if (data->usbmisc_data) ++ put_device(data->usbmisc_data->dev); + } + + static void ci_hdrc_imx_shutdown(struct platform_device *pdev) +diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c +index 6830be4419e20a..559c121f092300 100644 +--- a/drivers/usb/class/cdc-wdm.c ++++ b/drivers/usb/class/cdc-wdm.c +@@ -726,7 +726,7 @@ static int wdm_open(struct inode *inode, struct file *file) + rv = -EBUSY; + goto out; + } +- ++ smp_rmb(); /* ordered against wdm_wwan_port_stop() */ + rv = usb_autopm_get_interface(desc->intf); + if (rv < 0) { + dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); +@@ -829,6 +829,7 @@ static struct usb_class_driver wdm_class = { + static int wdm_wwan_port_start(struct wwan_port *port) + { + struct wdm_device *desc = wwan_port_get_drvdata(port); ++ int rv; + + /* The interface is both exposed via the WWAN framework and as a + * legacy usbmisc chardev. If chardev is already open, just fail +@@ -848,7 +849,15 @@ static int wdm_wwan_port_start(struct wwan_port *port) + wwan_port_txon(port); + + /* Start getting events */ +- return usb_submit_urb(desc->validity, GFP_KERNEL); ++ rv = usb_submit_urb(desc->validity, GFP_KERNEL); ++ if (rv < 0) { ++ wwan_port_txoff(port); ++ desc->manage_power(desc->intf, 0); ++ /* this must be last lest we race with chardev open */ ++ clear_bit(WDM_WWAN_IN_USE, &desc->flags); ++ } ++ ++ return rv; + } + + static void wdm_wwan_port_stop(struct wwan_port *port) +@@ -859,8 +868,10 @@ static void wdm_wwan_port_stop(struct wwan_port *port) + poison_urbs(desc); + desc->manage_power(desc->intf, 0); + clear_bit(WDM_READ, &desc->flags); +- clear_bit(WDM_WWAN_IN_USE, &desc->flags); + unpoison_urbs(desc); ++ smp_wmb(); /* ordered against wdm_open() */ ++ /* this must be last lest we open a poisoned device */ ++ clear_bit(WDM_WWAN_IN_USE, &desc->flags); + } + + static void wdm_wwan_port_tx_complete(struct urb *urb) +@@ -868,7 +879,7 @@ static void wdm_wwan_port_tx_complete(struct urb *urb) + struct sk_buff *skb = urb->context; + struct wdm_device *desc = skb_shinfo(skb)->destructor_arg; + +- usb_autopm_put_interface(desc->intf); ++ usb_autopm_put_interface_async(desc->intf); + wwan_port_txon(desc->wwanp); + kfree_skb(skb); + } +@@ -898,7 +909,7 @@ static int wdm_wwan_port_tx(struct wwan_port *port, struct sk_buff *skb) + req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); + req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; + req->wValue = 0; +- req->wIndex = desc->inum; ++ req->wIndex = desc->inum; /* already converted */ + req->wLength = cpu_to_le16(skb->len); + + skb_shinfo(skb)->destructor_arg = desc; +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 6926bd639ec6ff..4903c733d37ae7 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -369,6 +369,9 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM }, + { USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* SanDisk Corp. SanDisk 3.2Gen1 */ ++ { USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Realforce 87U Keyboard */ + { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM }, + +@@ -383,6 +386,9 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x0904, 0x6103), .driver_info = + USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL }, + ++ /* Silicon Motion Flash Drive */ ++ { USB_DEVICE(0x090c, 0x1000), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Sound Devices USBPre2 */ + { USB_DEVICE(0x0926, 0x0202), .driver_info = + USB_QUIRK_ENDPOINT_IGNORE }, +@@ -536,6 +542,9 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x2040, 0x7200), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + ++ /* VLI disk */ ++ { USB_DEVICE(0x2109, 0x0711), .driver_info = USB_QUIRK_NO_LPM }, ++ + /* Raydium Touchscreen */ + { USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM }, + +diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c +index 052852f8014676..54a4ee2b90b7f4 100644 +--- a/drivers/usb/dwc3/dwc3-pci.c ++++ b/drivers/usb/dwc3/dwc3-pci.c +@@ -148,11 +148,21 @@ static const struct property_entry dwc3_pci_intel_byt_properties[] = { + {} + }; + ++/* ++ * Intel Merrifield SoC uses these endpoints for tracing and they cannot ++ * be re-allocated if being used because the side band flow control signals ++ * are hard wired to certain endpoints: ++ * - 1 High BW Bulk IN (IN#1) (RTIT) ++ * - 1 1KB BW Bulk IN (IN#8) + 1 1KB BW Bulk OUT (Run Control) (OUT#8) ++ */ ++static const u8 dwc3_pci_mrfld_reserved_endpoints[] = { 3, 16, 17 }; ++ + static const struct property_entry dwc3_pci_mrfld_properties[] = { + PROPERTY_ENTRY_STRING("dr_mode", "otg"), + PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"), + PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"), + PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"), ++ PROPERTY_ENTRY_U8_ARRAY("snps,reserved-endpoints", dwc3_pci_mrfld_reserved_endpoints), + PROPERTY_ENTRY_BOOL("snps,usb2-gadget-lpm-disable"), + PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), + {} +diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c +index d19a5d2d65adb9..ae30aa50a58257 100644 +--- a/drivers/usb/dwc3/dwc3-xilinx.c ++++ b/drivers/usb/dwc3/dwc3-xilinx.c +@@ -207,15 +207,13 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) + + skip_usb3_phy: + /* ulpi reset via gpio-modepin or gpio-framework driver */ +- reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); ++ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) { + return dev_err_probe(dev, PTR_ERR(reset_gpio), + "Failed to request reset GPIO\n"); + } + + if (reset_gpio) { +- /* Toggle ulpi to reset the phy. */ +- gpiod_set_value_cansleep(reset_gpio, 1); + usleep_range(5000, 10000); + gpiod_set_value_cansleep(reset_gpio, 0); + usleep_range(5000, 10000); +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index fdaace1564f96f..f51d743bb3ecc6 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -548,6 +548,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep) + int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index) + { + struct dwc3_gadget_ep_cmd_params params; ++ struct dwc3_ep *dep; + u32 cmd; + int i; + int ret; +@@ -564,8 +565,13 @@ int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index) + return ret; + + /* Reset resource allocation flags */ +- for (i = resource_index; i < dwc->num_eps && dwc->eps[i]; i++) +- dwc->eps[i]->flags &= ~DWC3_EP_RESOURCE_ALLOCATED; ++ for (i = resource_index; i < dwc->num_eps; i++) { ++ dep = dwc->eps[i]; ++ if (!dep) ++ continue; ++ ++ dep->flags &= ~DWC3_EP_RESOURCE_ALLOCATED; ++ } + + return 0; + } +@@ -752,9 +758,11 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) + + dwc->last_fifo_depth = fifo_depth; + /* Clear existing TXFIFO for all IN eps except ep0 */ +- for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); +- num += 2) { ++ for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); num += 2) { + dep = dwc->eps[num]; ++ if (!dep) ++ continue; ++ + /* Don't change TXFRAMNUM on usb31 version */ + size = DWC3_IP_IS(DWC3) ? 0 : + dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & +@@ -3670,6 +3678,8 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep, + + for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { + dep = dwc->eps[i]; ++ if (!dep) ++ continue; + + if (!(dep->flags & DWC3_EP_ENABLED)) + continue; +@@ -3858,6 +3868,10 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, + u8 epnum = event->endpoint_number; + + dep = dwc->eps[epnum]; ++ if (!dep) { ++ dev_warn(dwc->dev, "spurious event, endpoint %u is not allocated\n", epnum); ++ return; ++ } + + if (!(dep->flags & DWC3_EP_ENABLED)) { + if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED)) +@@ -4570,6 +4584,12 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) + if (!count) + return IRQ_NONE; + ++ if (count > evt->length) { ++ dev_err_ratelimited(dwc->dev, "invalid count(%u) > evt->length(%u)\n", ++ count, evt->length); ++ return IRQ_NONE; ++ } ++ + evt->count = count; + evt->flags |= DWC3_EVENT_PENDING; + +diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c +index 573109ca5b7990..a09f72772e6e95 100644 +--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c ++++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c +@@ -548,6 +548,9 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) + d->vhub = vhub; + d->index = idx; + d->name = devm_kasprintf(parent, GFP_KERNEL, "port%d", idx+1); ++ if (!d->name) ++ return -ENOMEM; ++ + d->regs = vhub->regs + 0x100 + 0x10 * idx; + + ast_vhub_init_ep0(vhub, &d->ep0, d); +diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c +index a219260ad3e6c2..cc1f579f02de1c 100644 +--- a/drivers/usb/host/max3421-hcd.c ++++ b/drivers/usb/host/max3421-hcd.c +@@ -1946,6 +1946,12 @@ max3421_remove(struct spi_device *spi) + usb_put_hcd(hcd); + } + ++static const struct spi_device_id max3421_spi_ids[] = { ++ { "max3421" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(spi, max3421_spi_ids); ++ + static const struct of_device_id max3421_of_match_table[] = { + { .compatible = "maxim,max3421", }, + {}, +@@ -1955,6 +1961,7 @@ MODULE_DEVICE_TABLE(of, max3421_of_match_table); + static struct spi_driver max3421_driver = { + .probe = max3421_probe, + .remove = max3421_remove, ++ .id_table = max3421_spi_ids, + .driver = { + .name = "max3421-hcd", + .of_match_table = max3421_of_match_table, +diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c +index 900ea0d368e034..9f0a6b27e47cb6 100644 +--- a/drivers/usb/host/ohci-pci.c ++++ b/drivers/usb/host/ohci-pci.c +@@ -165,6 +165,25 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) + return 0; + } + ++static int ohci_quirk_loongson(struct usb_hcd *hcd) ++{ ++ struct pci_dev *pdev = to_pci_dev(hcd->self.controller); ++ ++ /* ++ * Loongson's LS7A OHCI controller (rev 0x02) has a ++ * flaw. MMIO register with offset 0x60/64 is treated ++ * as legacy PS2-compatible keyboard/mouse interface. ++ * Since OHCI only use 4KB BAR resource, LS7A OHCI's ++ * 32KB BAR is wrapped around (the 2nd 4KB BAR space ++ * is the same as the 1st 4KB internally). So add 4KB ++ * offset (0x1000) to the OHCI registers as a quirk. ++ */ ++ if (pdev->revision == 0x2) ++ hcd->regs += SZ_4K; /* SZ_4K = 0x1000 */ ++ ++ return 0; ++} ++ + static int ohci_quirk_qemu(struct usb_hcd *hcd) + { + struct ohci_hcd *ohci = hcd_to_ohci(hcd); +@@ -224,6 +243,10 @@ static const struct pci_device_id ohci_pci_quirks[] = { + PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), + .driver_data = (unsigned long)ohci_quirk_amd700, + }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a24), ++ .driver_data = (unsigned long)ohci_quirk_loongson, ++ }, + { + .vendor = PCI_VENDOR_ID_APPLE, + .device = 0x003f, +diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c +index 87f1597a0e5ab7..257e4d79971fda 100644 +--- a/drivers/usb/host/xhci-mvebu.c ++++ b/drivers/usb/host/xhci-mvebu.c +@@ -73,13 +73,3 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) + + return 0; + } +- +-int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +-{ +- struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- +- /* Without reset on resume, the HC won't work at all */ +- xhci->quirks |= XHCI_RESET_ON_RESUME; +- +- return 0; +-} +diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h +index 3be021793cc8b0..9d26e22c48422f 100644 +--- a/drivers/usb/host/xhci-mvebu.h ++++ b/drivers/usb/host/xhci-mvebu.h +@@ -12,16 +12,10 @@ struct usb_hcd; + + #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) + int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); +-int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd); + #else + static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) + { + return 0; + } +- +-static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +-{ +- return 0; +-} + #endif + #endif /* __LINUX_XHCI_MVEBU_H */ +diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c +index d68e9abcdc69a6..8832e0cedadaff 100644 +--- a/drivers/usb/host/xhci-plat.c ++++ b/drivers/usb/host/xhci-plat.c +@@ -106,7 +106,7 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = { + }; + + static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { +- .init_quirk = xhci_mvebu_a3700_init_quirk, ++ .quirks = XHCI_RESET_ON_RESUME, + }; + + static const struct xhci_plat_priv xhci_plat_brcm = { +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 4a081685a1953e..cb944396294516 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1214,16 +1214,19 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, + * Stopped state, but it will soon change to Running. + * + * Assume this bug on unexpected Stop Endpoint failures. +- * Keep retrying until the EP starts and stops again, on +- * chips where this is known to help. Wait for 100ms. ++ * Keep retrying until the EP starts and stops again. + */ +- if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) +- break; + fallthrough; + case EP_STATE_RUNNING: + /* Race, HW handled stop ep cmd before ep was running */ + xhci_dbg(xhci, "Stop ep completion ctx error, ctx_state %d\n", + GET_EP_CTX_STATE(ep_ctx)); ++ /* ++ * Don't retry forever if we guessed wrong or a defective HC never starts ++ * the EP or says 'Running' but fails the command. We must give back TDs. ++ */ ++ if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) ++ break; + + command = xhci_alloc_command(xhci, false, GFP_ATOMIC); + if (!command) { +@@ -3876,7 +3879,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + * enqueue a No Op TRB, this can prevent the Setup and Data Stage + * TRB to be breaked by the Link TRB. + */ +- if (trb_is_link(ep_ring->enqueue + 1)) { ++ if (last_trb_on_seg(ep_ring->enq_seg, ep_ring->enqueue + 1)) { + field = TRB_TYPE(TRB_TR_NOOP) | ep_ring->cycle_state; + queue_trb(xhci, ep_ring, false, 0, 0, + TRB_INTR_TARGET(0), field); +diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c +index b8e2bfd4282809..b583b31ea5e72e 100644 +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -1093,6 +1093,8 @@ static const struct usb_device_id id_table_combined[] = { + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) }, ++ /* Abacus Electrics */ ++ { USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) }, + { } /* Terminating entry */ + }; + +diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h +index 52be47d684ea66..9acb6f83732763 100644 +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -442,6 +442,11 @@ + #define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ + #define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ + ++/* ++ * Abacus Electrics ++ */ ++#define ABACUS_OPTICAL_PROBE_PID 0xf458 /* ABACUS ELECTRICS Optical Probe */ ++ + /* + * Oceanic product ids + */ +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index a9f95bb35bb0f5..5d669511609892 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -611,6 +611,7 @@ static void option_instat_callback(struct urb *urb); + /* Sierra Wireless products */ + #define SIERRA_VENDOR_ID 0x1199 + #define SIERRA_PRODUCT_EM9191 0x90d3 ++#define SIERRA_PRODUCT_EM9291 0x90e3 + + /* UNISOC (Spreadtrum) products */ + #define UNISOC_VENDOR_ID 0x1782 +@@ -2432,6 +2433,8 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x30) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, + { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0530, 0xff), /* TCL IK512 MBIM */ +diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c +index 24b8772a345e2f..bac5ab6377ae4b 100644 +--- a/drivers/usb/serial/usb-serial-simple.c ++++ b/drivers/usb/serial/usb-serial-simple.c +@@ -101,6 +101,11 @@ DEVICE(nokia, NOKIA_IDS); + { USB_DEVICE(0x09d7, 0x0100) } /* NovAtel FlexPack GPS */ + DEVICE_N(novatel_gps, NOVATEL_IDS, 3); + ++/* OWON electronic test and measurement equipment driver */ ++#define OWON_IDS() \ ++ { USB_DEVICE(0x5345, 0x1234) } /* HDS200 oscilloscopes and others */ ++DEVICE(owon, OWON_IDS); ++ + /* Siemens USB/MPI adapter */ + #define SIEMENS_IDS() \ + { USB_DEVICE(0x908, 0x0004) } +@@ -135,6 +140,7 @@ static struct usb_serial_driver * const serial_drivers[] = { + &motorola_tetra_device, + &nokia_device, + &novatel_gps_device, ++ &owon_device, + &siemens_mpi_device, + &suunto_device, + &vivopay_device, +@@ -154,6 +160,7 @@ static const struct usb_device_id id_table[] = { + MOTOROLA_TETRA_IDS(), + NOKIA_IDS(), + NOVATEL_IDS(), ++ OWON_IDS(), + SIEMENS_IDS(), + SUUNTO_IDS(), + VIVOPAY_IDS(), +diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h +index 1f8c9b16a0fb85..d460d71b425783 100644 +--- a/drivers/usb/storage/unusual_uas.h ++++ b/drivers/usb/storage/unusual_uas.h +@@ -83,6 +83,13 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_REPORT_LUNS), + ++/* Reported-by: Oliver Neukum */ ++UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, ++ "ADATA", ++ "Portable HDD CH94", ++ USB_SC_DEVICE, USB_PR_DEVICE, NULL, ++ US_FL_NO_ATA_1X), ++ + /* Reported-by: Benjamin Tissoires */ + UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, + "Initio Corporation", +diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig +index d43153fec18ea8..af5c214b220699 100644 +--- a/drivers/xen/Kconfig ++++ b/drivers/xen/Kconfig +@@ -278,7 +278,7 @@ config XEN_PRIVCMD_IRQFD + + config XEN_ACPI_PROCESSOR + tristate "Xen ACPI processor" +- depends on XEN && XEN_PV_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ ++ depends on XEN && XEN_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ + default m + help + This ACPI processor uploads Power Management information to the Xen +diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c +index 68092b64e29eac..e794606e7c780b 100644 +--- a/fs/btrfs/file.c ++++ b/fs/btrfs/file.c +@@ -2225,15 +2225,20 @@ static void btrfs_punch_hole_lock_range(struct inode *inode, + * will always return true. + * So here we need to do extra page alignment for + * filemap_range_has_page(). ++ * ++ * And do not decrease page_lockend right now, as it can be 0. + */ + const u64 page_lockstart = round_up(lockstart, PAGE_SIZE); +- const u64 page_lockend = round_down(lockend + 1, PAGE_SIZE) - 1; ++ const u64 page_lockend = round_down(lockend + 1, PAGE_SIZE); + + while (1) { + truncate_pagecache_range(inode, lockstart, lockend); + + lock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend, + cached_state); ++ /* The same page or adjacent pages. */ ++ if (page_lockend <= page_lockstart) ++ break; + /* + * We can't have ordered extents in the range, nor dirty/writeback + * pages, because we have locked the inode's VFS lock in exclusive +@@ -2245,7 +2250,7 @@ static void btrfs_punch_hole_lock_range(struct inode *inode, + * we do, unlock the range and retry. + */ + if (!filemap_range_has_page(inode->i_mapping, page_lockstart, +- page_lockend)) ++ page_lockend - 1)) + break; + + unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend, +diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c +index db6977c15c2828..f0befbeb6cb833 100644 +--- a/fs/ceph/inode.c ++++ b/fs/ceph/inode.c +@@ -2319,7 +2319,7 @@ static int fill_fscrypt_truncate(struct inode *inode, + + /* Try to writeback the dirty pagecaches */ + if (issued & (CEPH_CAP_FILE_BUFFER)) { +- loff_t lend = orig_pos + CEPH_FSCRYPT_BLOCK_SHIFT - 1; ++ loff_t lend = orig_pos + CEPH_FSCRYPT_BLOCK_SIZE - 1; + + ret = filemap_write_and_wait_range(inode->i_mapping, + orig_pos, lend); +diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c +index 6fe3c941b56514..4d6ba140276b5f 100644 +--- a/fs/ext4/block_validity.c ++++ b/fs/ext4/block_validity.c +@@ -351,10 +351,9 @@ int ext4_check_blockref(const char *function, unsigned int line, + { + __le32 *bref = p; + unsigned int blk; ++ journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; + +- if (ext4_has_feature_journal(inode->i_sb) && +- (inode->i_ino == +- le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) ++ if (journal && inode == journal->j_inode) + return 0; + + while (bref < p+max) { +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index ddfeaf19bff1ba..d3d28e65872027 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -378,10 +378,11 @@ static int __check_block_validity(struct inode *inode, const char *func, + unsigned int line, + struct ext4_map_blocks *map) + { +- if (ext4_has_feature_journal(inode->i_sb) && +- (inode->i_ino == +- le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) ++ journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; ++ ++ if (journal && inode == journal->j_inode) + return 0; ++ + if (!ext4_inode_block_valid(inode, map->m_pblk, map->m_len)) { + ext4_error_inode(inode, func, line, map->m_pblk, + "lblock %lu mapped to illegal pblock %llu " +@@ -5478,7 +5479,7 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + oldsize & (inode->i_sb->s_blocksize - 1)) { + error = ext4_inode_attach_jinode(inode); + if (error) +- goto err_out; ++ goto out_mmap_sem; + } + + handle = ext4_journal_start(inode, EXT4_HT_INODE, 3); +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index e7e6701806ad26..7ffdf0d037fae0 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -224,7 +224,7 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio, + } + + /* truncate len if we find any trailing uptodate block(s) */ +- for ( ; i <= last; i++) { ++ while (++i <= last) { + if (ifs_block_is_uptodate(ifs, i)) { + plen -= (last - i + 1) * block_size; + last = i - 1; +diff --git a/fs/namespace.c b/fs/namespace.c +index 671e266b8fc5d2..5a885d35efe937 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -2439,56 +2439,62 @@ static struct mountpoint *do_lock_mount(struct path *path, bool beneath) + struct vfsmount *mnt = path->mnt; + struct dentry *dentry; + struct mountpoint *mp = ERR_PTR(-ENOENT); ++ struct path under = {}; + + for (;;) { +- struct mount *m; ++ struct mount *m = real_mount(mnt); + + if (beneath) { +- m = real_mount(mnt); ++ path_put(&under); + read_seqlock_excl(&mount_lock); +- dentry = dget(m->mnt_mountpoint); ++ under.mnt = mntget(&m->mnt_parent->mnt); ++ under.dentry = dget(m->mnt_mountpoint); + read_sequnlock_excl(&mount_lock); ++ dentry = under.dentry; + } else { + dentry = path->dentry; + } + + inode_lock(dentry->d_inode); +- if (unlikely(cant_mount(dentry))) { +- inode_unlock(dentry->d_inode); +- goto out; +- } +- + namespace_lock(); + +- if (beneath && (!is_mounted(mnt) || m->mnt_mountpoint != dentry)) { ++ if (unlikely(cant_mount(dentry) || !is_mounted(mnt))) ++ break; // not to be mounted on ++ ++ if (beneath && unlikely(m->mnt_mountpoint != dentry || ++ &m->mnt_parent->mnt != under.mnt)) { + namespace_unlock(); + inode_unlock(dentry->d_inode); +- goto out; ++ continue; // got moved + } + + mnt = lookup_mnt(path); +- if (likely(!mnt)) ++ if (unlikely(mnt)) { ++ namespace_unlock(); ++ inode_unlock(dentry->d_inode); ++ path_put(path); ++ path->mnt = mnt; ++ path->dentry = dget(mnt->mnt_root); ++ continue; // got overmounted ++ } ++ mp = get_mountpoint(dentry); ++ if (IS_ERR(mp)) + break; +- +- namespace_unlock(); +- inode_unlock(dentry->d_inode); +- if (beneath) +- dput(dentry); +- path_put(path); +- path->mnt = mnt; +- path->dentry = dget(mnt->mnt_root); +- } +- +- mp = get_mountpoint(dentry); +- if (IS_ERR(mp)) { +- namespace_unlock(); +- inode_unlock(dentry->d_inode); ++ if (beneath) { ++ /* ++ * @under duplicates the references that will stay ++ * at least until namespace_unlock(), so the path_put() ++ * below is safe (and OK to do under namespace_lock - ++ * we are not dropping the final references here). ++ */ ++ path_put(&under); ++ } ++ return mp; + } +- +-out: ++ namespace_unlock(); ++ inode_unlock(dentry->d_inode); + if (beneath) +- dput(dentry); +- ++ path_put(&under); + return mp; + } + +@@ -2499,14 +2505,11 @@ static inline struct mountpoint *lock_mount(struct path *path) + + static void unlock_mount(struct mountpoint *where) + { +- struct dentry *dentry = where->m_dentry; +- ++ inode_unlock(where->m_dentry->d_inode); + read_seqlock_excl(&mount_lock); + put_mountpoint(where); + read_sequnlock_excl(&mount_lock); +- + namespace_unlock(); +- inode_unlock(dentry->d_inode); + } + + static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp) +diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c +index 2ecd0303f9421b..4aea458216117f 100644 +--- a/fs/ntfs3/file.c ++++ b/fs/ntfs3/file.c +@@ -335,6 +335,7 @@ static int ntfs_extend(struct inode *inode, loff_t pos, size_t count, + } + + if (extend_init && !is_compressed(ni)) { ++ WARN_ON(ni->i_valid >= pos); + err = ntfs_extend_initialized_size(file, ni, ni->i_valid, pos); + if (err) + goto out; +diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c +index c2a98b2736645d..f04922eb45d4c9 100644 +--- a/fs/smb/client/sess.c ++++ b/fs/smb/client/sess.c +@@ -732,6 +732,22 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) + *pbcc_area = bcc_ptr; + } + ++static void ++ascii_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) ++{ ++ char *bcc_ptr = *pbcc_area; ++ ++ strcpy(bcc_ptr, "Linux version "); ++ bcc_ptr += strlen("Linux version "); ++ strcpy(bcc_ptr, init_utsname()->release); ++ bcc_ptr += strlen(init_utsname()->release) + 1; ++ ++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); ++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ ++ *pbcc_area = bcc_ptr; ++} ++ + static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, + const struct nls_table *nls_cp) + { +@@ -756,6 +772,25 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, + *pbcc_area = bcc_ptr; + } + ++static void ascii_domain_string(char **pbcc_area, struct cifs_ses *ses, ++ const struct nls_table *nls_cp) ++{ ++ char *bcc_ptr = *pbcc_area; ++ int len; ++ ++ /* copy domain */ ++ if (ses->domainName != NULL) { ++ len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN); ++ if (WARN_ON_ONCE(len < 0)) ++ len = CIFS_MAX_DOMAINNAME_LEN - 1; ++ bcc_ptr += len; ++ } /* else we send a null domain name so server will default to its own domain */ ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ ++ *pbcc_area = bcc_ptr; ++} ++ + static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, + const struct nls_table *nls_cp) + { +@@ -801,25 +836,10 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, + *bcc_ptr = 0; + bcc_ptr++; /* account for null termination */ + +- /* copy domain */ +- if (ses->domainName != NULL) { +- len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN); +- if (WARN_ON_ONCE(len < 0)) +- len = CIFS_MAX_DOMAINNAME_LEN - 1; +- bcc_ptr += len; +- } /* else we send a null domain name so server will default to its own domain */ +- *bcc_ptr = 0; +- bcc_ptr++; +- + /* BB check for overflow here */ + +- strcpy(bcc_ptr, "Linux version "); +- bcc_ptr += strlen("Linux version "); +- strcpy(bcc_ptr, init_utsname()->release); +- bcc_ptr += strlen(init_utsname()->release) + 1; +- +- strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); +- bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ ascii_domain_string(&bcc_ptr, ses, nls_cp); ++ ascii_oslm_strings(&bcc_ptr, nls_cp); + + *pbcc_area = bcc_ptr; + } +@@ -1622,7 +1642,7 @@ sess_auth_kerberos(struct sess_data *sess_data) + sess_data->iov[1].iov_len = msg->secblob_len; + pSMB->req.SecurityBlobLength = cpu_to_le16(sess_data->iov[1].iov_len); + +- if (ses->capabilities & CAP_UNICODE) { ++ if (pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) { + /* unicode strings must be word aligned */ + if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) { + *bcc_ptr = 0; +@@ -1631,8 +1651,8 @@ sess_auth_kerberos(struct sess_data *sess_data) + unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); + unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + } else { +- /* BB: is this right? */ +- ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); ++ ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp); ++ ascii_domain_string(&bcc_ptr, ses, sess_data->nls_cp); + } + + sess_data->iov[2].iov_len = (long) bcc_ptr - +diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c +index bc1bac36c1b291..caa1d852ece49c 100644 +--- a/fs/smb/client/smb1ops.c ++++ b/fs/smb/client/smb1ops.c +@@ -597,6 +597,42 @@ static int cifs_query_path_info(const unsigned int xid, + CIFSSMBClose(xid, tcon, fid.netfid); + } + ++#ifdef CONFIG_CIFS_XATTR ++ /* ++ * For WSL CHR and BLK reparse points it is required to fetch ++ * EA $LXDEV which contains major and minor device numbers. ++ */ ++ if (!rc && data->reparse_point) { ++ struct smb2_file_full_ea_info *ea; ++ ++ ea = (struct smb2_file_full_ea_info *)data->wsl.eas; ++ rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_DEV, ++ &ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1], ++ SMB2_WSL_XATTR_DEV_SIZE, cifs_sb); ++ if (rc == SMB2_WSL_XATTR_DEV_SIZE) { ++ ea->next_entry_offset = cpu_to_le32(0); ++ ea->flags = 0; ++ ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN; ++ ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE); ++ memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1); ++ data->wsl.eas_len = sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 + ++ SMB2_WSL_XATTR_DEV_SIZE; ++ rc = 0; ++ } else if (rc >= 0) { ++ /* It is an error if EA $LXDEV has wrong size. */ ++ rc = -EINVAL; ++ } else { ++ /* ++ * In all other cases ignore error if fetching ++ * of EA $LXDEV failed. It is needed only for ++ * WSL CHR and BLK reparse points and wsl_to_fattr() ++ * handle the case when EA is missing. ++ */ ++ rc = 0; ++ } ++ } ++#endif ++ + return rc; + } + +diff --git a/fs/splice.c b/fs/splice.c +index d983d375ff1130..6f9b06bbb860ac 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -45,7 +45,7 @@ + * here if set to avoid blocking other users of this pipe if splice is + * being done on it. + */ +-static noinline void noinline pipe_clear_nowait(struct file *file) ++static noinline void pipe_clear_nowait(struct file *file) + { + fmode_t fmode = READ_ONCE(file->f_mode); + +diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h +index b9caa01dfac485..adec808b371a11 100644 +--- a/include/linux/energy_model.h ++++ b/include/linux/energy_model.h +@@ -243,7 +243,6 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd, + scale_cpu = arch_scale_cpu_capacity(cpu); + ps = &pd->table[pd->nr_perf_states - 1]; + +- max_util = map_util_perf(max_util); + max_util = min(max_util, allowed_cpu_cap); + freq = map_util_freq(max_util, ps->frequency, scale_cpu); + +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index ab2a7ef61d420f..b4fcd0164048ed 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -1038,10 +1038,11 @@ struct v4l2_subdev_platform_data { + * @active_state: Active state for the subdev (NULL for subdevs tracking the + * state internally). Initialized by calling + * v4l2_subdev_init_finalize(). +- * @enabled_streams: Bitmask of enabled streams used by +- * v4l2_subdev_enable_streams() and +- * v4l2_subdev_disable_streams() helper functions for fallback +- * cases. ++ * @enabled_pads: Bitmask of enabled pads used by v4l2_subdev_enable_streams() ++ * and v4l2_subdev_disable_streams() helper functions for ++ * fallback cases. ++ * @s_stream_enabled: Tracks whether streaming has been enabled with s_stream. ++ * This is only for call_s_stream() internal use. + * + * Each instance of a subdev driver should create this struct, either + * stand-alone or embedded in a larger struct. +@@ -1089,7 +1090,8 @@ struct v4l2_subdev { + * doesn't support it. + */ + struct v4l2_subdev_state *active_state; +- u64 enabled_streams; ++ u64 enabled_pads; ++ bool s_stream_enabled; + }; + + +@@ -1916,4 +1918,17 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers; + void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + const struct v4l2_event *ev); + ++/** ++ * v4l2_subdev_is_streaming() - Returns if the subdevice is streaming ++ * @sd: The subdevice ++ * ++ * v4l2_subdev_is_streaming() tells if the subdevice is currently streaming. ++ * "Streaming" here means whether .s_stream() or .enable_streams() has been ++ * successfully called, and the streaming has not yet been disabled. ++ * ++ * If the subdevice implements .enable_streams() this function must be called ++ * while holding the active state lock. ++ */ ++bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd); ++ + #endif /* _V4L2_SUBDEV_H */ +diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h +index 5870a94599a258..d5f6a228df6594 100644 +--- a/include/soc/qcom/ice.h ++++ b/include/soc/qcom/ice.h +@@ -34,4 +34,6 @@ int qcom_ice_program_key(struct qcom_ice *ice, + int slot); + int qcom_ice_evict_key(struct qcom_ice *ice, int slot); + struct qcom_ice *of_qcom_ice_get(struct device *dev); ++struct qcom_ice *devm_of_qcom_ice_get(struct device *dev); ++ + #endif /* __QCOM_ICE_H__ */ +diff --git a/include/trace/stages/stage3_trace_output.h b/include/trace/stages/stage3_trace_output.h +index c1fb1355d3094b..1e7b0bef95f525 100644 +--- a/include/trace/stages/stage3_trace_output.h ++++ b/include/trace/stages/stage3_trace_output.h +@@ -119,6 +119,14 @@ + trace_print_array_seq(p, array, count, el_size); \ + }) + ++#undef __print_dynamic_array ++#define __print_dynamic_array(array, el_size) \ ++ ({ \ ++ __print_array(__get_dynamic_array(array), \ ++ __get_dynamic_array_len(array) / (el_size), \ ++ (el_size)); \ ++ }) ++ + #undef __print_hex_dump + #define __print_hex_dump(prefix_str, prefix_type, \ + rowsize, groupsize, buf, len, ascii) \ +diff --git a/include/trace/stages/stage7_class_define.h b/include/trace/stages/stage7_class_define.h +index bcb960d16fc0ed..fcd564a590f434 100644 +--- a/include/trace/stages/stage7_class_define.h ++++ b/include/trace/stages/stage7_class_define.h +@@ -22,6 +22,7 @@ + #undef __get_rel_cpumask + #undef __get_rel_sockaddr + #undef __print_array ++#undef __print_dynamic_array + #undef __print_hex_dump + #undef __get_buf + +diff --git a/init/Kconfig b/init/Kconfig +index 1105cb53f391ab..8b630143c720f6 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -689,7 +689,7 @@ endmenu # "CPU/Task time and stats accounting" + + config CPU_ISOLATION + bool "CPU isolation" +- depends on SMP || COMPILE_TEST ++ depends on SMP + default y + help + Make sure that CPUs running critical tasks are not disturbed by +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index efa7849b82c184..3ce93418e0151d 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -1247,21 +1247,22 @@ static __cold void io_fallback_tw(struct io_uring_task *tctx, bool sync) + while (node) { + req = container_of(node, struct io_kiocb, io_task_work.node); + node = node->next; +- if (sync && last_ctx != req->ctx) { ++ if (last_ctx != req->ctx) { + if (last_ctx) { +- flush_delayed_work(&last_ctx->fallback_work); ++ if (sync) ++ flush_delayed_work(&last_ctx->fallback_work); + percpu_ref_put(&last_ctx->refs); + } + last_ctx = req->ctx; + percpu_ref_get(&last_ctx->refs); + } +- if (llist_add(&req->io_task_work.node, +- &req->ctx->fallback_llist)) +- schedule_delayed_work(&req->ctx->fallback_work, 1); ++ if (llist_add(&req->io_task_work.node, &last_ctx->fallback_llist)) ++ schedule_delayed_work(&last_ctx->fallback_work, 1); + } + + if (last_ctx) { +- flush_delayed_work(&last_ctx->fallback_work); ++ if (sync) ++ flush_delayed_work(&last_ctx->fallback_work); + percpu_ref_put(&last_ctx->refs); + } + } +@@ -1916,7 +1917,7 @@ struct io_wq_work *io_wq_free_work(struct io_wq_work *work) + struct io_kiocb *req = container_of(work, struct io_kiocb, work); + struct io_kiocb *nxt = NULL; + +- if (req_ref_put_and_test(req)) { ++ if (req_ref_put_and_test_atomic(req)) { + if (req->flags & IO_REQ_LINK_FLAGS) + nxt = io_req_find_next(req); + io_free_req(req); +diff --git a/io_uring/refs.h b/io_uring/refs.h +index 1336de3f2a30aa..21a379b0f22d61 100644 +--- a/io_uring/refs.h ++++ b/io_uring/refs.h +@@ -17,6 +17,13 @@ static inline bool req_ref_inc_not_zero(struct io_kiocb *req) + return atomic_inc_not_zero(&req->refs); + } + ++static inline bool req_ref_put_and_test_atomic(struct io_kiocb *req) ++{ ++ WARN_ON_ONCE(!(data_race(req->flags) & REQ_F_REFCOUNT)); ++ WARN_ON_ONCE(req_ref_zero_or_close_to_overflow(req)); ++ return atomic_dec_and_test(&req->refs); ++} ++ + static inline bool req_ref_put_and_test(struct io_kiocb *req) + { + if (likely(!(req->flags & REQ_F_REFCOUNT))) +diff --git a/kernel/bpf/bpf_cgrp_storage.c b/kernel/bpf/bpf_cgrp_storage.c +index ee1c7b77096e7b..fbbf3b6b9f8353 100644 +--- a/kernel/bpf/bpf_cgrp_storage.c ++++ b/kernel/bpf/bpf_cgrp_storage.c +@@ -162,6 +162,7 @@ BPF_CALL_5(bpf_cgrp_storage_get, struct bpf_map *, map, struct cgroup *, cgroup, + void *, value, u64, flags, gfp_t, gfp_flags) + { + struct bpf_local_storage_data *sdata; ++ bool nobusy; + + WARN_ON_ONCE(!bpf_rcu_lock_held()); + if (flags & ~(BPF_LOCAL_STORAGE_GET_F_CREATE)) +@@ -170,21 +171,21 @@ BPF_CALL_5(bpf_cgrp_storage_get, struct bpf_map *, map, struct cgroup *, cgroup, + if (!cgroup) + return (unsigned long)NULL; + +- if (!bpf_cgrp_storage_trylock()) +- return (unsigned long)NULL; ++ nobusy = bpf_cgrp_storage_trylock(); + +- sdata = cgroup_storage_lookup(cgroup, map, true); ++ sdata = cgroup_storage_lookup(cgroup, map, nobusy); + if (sdata) + goto unlock; + + /* only allocate new storage, when the cgroup is refcounted */ + if (!percpu_ref_is_dying(&cgroup->self.refcnt) && +- (flags & BPF_LOCAL_STORAGE_GET_F_CREATE)) ++ (flags & BPF_LOCAL_STORAGE_GET_F_CREATE) && nobusy) + sdata = bpf_local_storage_update(cgroup, (struct bpf_local_storage_map *)map, + value, BPF_NOEXIST, gfp_flags); + + unlock: +- bpf_cgrp_storage_unlock(); ++ if (nobusy) ++ bpf_cgrp_storage_unlock(); + return IS_ERR_OR_NULL(sdata) ? (unsigned long)NULL : (unsigned long)sdata->data; + } + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index d6a4102312fadd..e443506b0a65a1 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -20106,6 +20106,33 @@ BTF_ID(func, __rcu_read_unlock) + #endif + BTF_SET_END(btf_id_deny) + ++/* fexit and fmod_ret can't be used to attach to __noreturn functions. ++ * Currently, we must manually list all __noreturn functions here. Once a more ++ * robust solution is implemented, this workaround can be removed. ++ */ ++BTF_SET_START(noreturn_deny) ++#ifdef CONFIG_IA32_EMULATION ++BTF_ID(func, __ia32_sys_exit) ++BTF_ID(func, __ia32_sys_exit_group) ++#endif ++#ifdef CONFIG_KUNIT ++BTF_ID(func, __kunit_abort) ++BTF_ID(func, kunit_try_catch_throw) ++#endif ++#ifdef CONFIG_MODULES ++BTF_ID(func, __module_put_and_kthread_exit) ++#endif ++#ifdef CONFIG_X86_64 ++BTF_ID(func, __x64_sys_exit) ++BTF_ID(func, __x64_sys_exit_group) ++#endif ++BTF_ID(func, do_exit) ++BTF_ID(func, do_group_exit) ++BTF_ID(func, kthread_complete_and_exit) ++BTF_ID(func, kthread_exit) ++BTF_ID(func, make_task_dead) ++BTF_SET_END(noreturn_deny) ++ + static bool can_be_sleepable(struct bpf_prog *prog) + { + if (prog->type == BPF_PROG_TYPE_TRACING) { +@@ -20194,6 +20221,11 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) + } else if (prog->type == BPF_PROG_TYPE_TRACING && + btf_id_set_contains(&btf_id_deny, btf_id)) { + return -EINVAL; ++ } else if ((prog->expected_attach_type == BPF_TRACE_FEXIT || ++ prog->expected_attach_type == BPF_MODIFY_RETURN) && ++ btf_id_set_contains(&noreturn_deny, btf_id)) { ++ verbose(env, "Attaching fexit/fmod_ret to __noreturn functions is rejected.\n"); ++ return -EINVAL; + } + + key = bpf_trampoline_compute_key(tgt_prog, prog->aux->attach_btf, btf_id); +diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c +index f005c66f378c32..a600819799637b 100644 +--- a/kernel/dma/contiguous.c ++++ b/kernel/dma/contiguous.c +@@ -70,8 +70,7 @@ struct cma *dma_contiguous_default_area; + * Users, who want to set the size of global CMA area for their system + * should use cma= kernel parameter. + */ +-static const phys_addr_t size_bytes __initconst = +- (phys_addr_t)CMA_SIZE_MBYTES * SZ_1M; ++#define size_bytes ((phys_addr_t)CMA_SIZE_MBYTES * SZ_1M) + static phys_addr_t size_cmdline __initdata = -1; + static phys_addr_t base_cmdline __initdata; + static phys_addr_t limit_cmdline __initdata; +diff --git a/kernel/events/core.c b/kernel/events/core.c +index b710976fb01b17..987807b1040ae0 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -13419,6 +13419,9 @@ inherit_event(struct perf_event *parent_event, + if (IS_ERR(child_event)) + return child_event; + ++ get_ctx(child_ctx); ++ child_event->ctx = child_ctx; ++ + pmu_ctx = find_get_pmu_context(child_event->pmu, child_ctx, child_event); + if (IS_ERR(pmu_ctx)) { + free_event(child_event); +@@ -13441,8 +13444,6 @@ inherit_event(struct perf_event *parent_event, + return NULL; + } + +- get_ctx(child_ctx); +- + /* + * Make the child state follow the state of the parent event, + * not its attr.disabled bit. We hold the parent's mutex, +@@ -13463,7 +13464,6 @@ inherit_event(struct perf_event *parent_event, + local64_set(&hwc->period_left, sample_period); + } + +- child_event->ctx = child_ctx; + child_event->overflow_handler = parent_event->overflow_handler; + child_event->overflow_handler_context + = parent_event->overflow_handler_context; +diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig +index 33a2e991f60814..b411315ecd3c4b 100644 +--- a/kernel/module/Kconfig ++++ b/kernel/module/Kconfig +@@ -229,6 +229,7 @@ comment "Do not forget to sign required modules with scripts/sign-file" + choice + prompt "Which hash algorithm should modules be signed with?" + depends on MODULE_SIG || IMA_APPRAISE_MODSIG ++ default MODULE_SIG_SHA512 + help + This determines which sort of hashing algorithm will be used during + signature generation. This algorithm _must_ be built into the kernel +diff --git a/kernel/panic.c b/kernel/panic.c +index ef9f9a4e928de6..d7973e97547482 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -763,9 +763,15 @@ device_initcall(register_warn_debugfs); + */ + __visible noinstr void __stack_chk_fail(void) + { ++ unsigned long flags; ++ + instrumentation_begin(); ++ flags = user_access_save(); ++ + panic("stack-protector: Kernel stack is corrupted in: %pB", + __builtin_return_address(0)); ++ ++ user_access_restore(flags); + instrumentation_end(); + } + EXPORT_SYMBOL(__stack_chk_fail); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 8c5f75af07db0e..760a6c3781cbfc 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -7406,18 +7406,13 @@ int sched_core_idle_cpu(int cpu) + * required to meet deadlines. + */ + unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, +- enum cpu_util_type type, +- struct task_struct *p) ++ unsigned long *min, ++ unsigned long *max) + { +- unsigned long dl_util, util, irq, max; ++ unsigned long util, irq, scale; + struct rq *rq = cpu_rq(cpu); + +- max = arch_scale_cpu_capacity(cpu); +- +- if (!uclamp_is_used() && +- type == FREQUENCY_UTIL && rt_rq_is_runnable(&rq->rt)) { +- return max; +- } ++ scale = arch_scale_cpu_capacity(cpu); + + /* + * Early check to see if IRQ/steal time saturates the CPU, can be +@@ -7425,45 +7420,49 @@ unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, + * update_irq_load_avg(). + */ + irq = cpu_util_irq(rq); +- if (unlikely(irq >= max)) +- return max; ++ if (unlikely(irq >= scale)) { ++ if (min) ++ *min = scale; ++ if (max) ++ *max = scale; ++ return scale; ++ } ++ ++ if (min) { ++ /* ++ * The minimum utilization returns the highest level between: ++ * - the computed DL bandwidth needed with the IRQ pressure which ++ * steals time to the deadline task. ++ * - The minimum performance requirement for CFS and/or RT. ++ */ ++ *min = max(irq + cpu_bw_dl(rq), uclamp_rq_get(rq, UCLAMP_MIN)); ++ ++ /* ++ * When an RT task is runnable and uclamp is not used, we must ++ * ensure that the task will run at maximum compute capacity. ++ */ ++ if (!uclamp_is_used() && rt_rq_is_runnable(&rq->rt)) ++ *min = max(*min, scale); ++ } + + /* + * Because the time spend on RT/DL tasks is visible as 'lost' time to + * CFS tasks and we use the same metric to track the effective + * utilization (PELT windows are synchronized) we can directly add them + * to obtain the CPU's actual utilization. +- * +- * CFS and RT utilization can be boosted or capped, depending on +- * utilization clamp constraints requested by currently RUNNABLE +- * tasks. +- * When there are no CFS RUNNABLE tasks, clamps are released and +- * frequency will be gracefully reduced with the utilization decay. + */ + util = util_cfs + cpu_util_rt(rq); +- if (type == FREQUENCY_UTIL) +- util = uclamp_rq_util_with(rq, util, p); +- +- dl_util = cpu_util_dl(rq); ++ util += cpu_util_dl(rq); + + /* +- * For frequency selection we do not make cpu_util_dl() a permanent part +- * of this sum because we want to use cpu_bw_dl() later on, but we need +- * to check if the CFS+RT+DL sum is saturated (ie. no idle time) such +- * that we select f_max when there is no idle time. +- * +- * NOTE: numerical errors or stop class might cause us to not quite hit +- * saturation when we should -- something for later. ++ * The maximum hint is a soft bandwidth requirement, which can be lower ++ * than the actual utilization because of uclamp_max requirements. + */ +- if (util + dl_util >= max) +- return max; ++ if (max) ++ *max = min(scale, uclamp_rq_get(rq, UCLAMP_MAX)); + +- /* +- * OTOH, for energy computation we need the estimated running time, so +- * include util_dl and ignore dl_bw. +- */ +- if (type == ENERGY_UTIL) +- util += dl_util; ++ if (util >= scale) ++ return scale; + + /* + * There is still idle time; further improve the number by using the +@@ -7474,28 +7473,15 @@ unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, + * U' = irq + --------- * U + * max + */ +- util = scale_irq_capacity(util, irq, max); ++ util = scale_irq_capacity(util, irq, scale); + util += irq; + +- /* +- * Bandwidth required by DEADLINE must always be granted while, for +- * FAIR and RT, we use blocked utilization of IDLE CPUs as a mechanism +- * to gracefully reduce the frequency when no tasks show up for longer +- * periods of time. +- * +- * Ideally we would like to set bw_dl as min/guaranteed freq and util + +- * bw_dl as requested freq. However, cpufreq is not yet ready for such +- * an interface. So, we only do the latter for now. +- */ +- if (type == FREQUENCY_UTIL) +- util += cpu_bw_dl(rq); +- +- return min(max, util); ++ return min(scale, util); + } + + unsigned long sched_cpu_util(int cpu) + { +- return effective_cpu_util(cpu, cpu_util_cfs(cpu), ENERGY_UTIL, NULL); ++ return effective_cpu_util(cpu, cpu_util_cfs(cpu), NULL, NULL); + } + #endif /* CONFIG_SMP */ + +@@ -10048,7 +10034,7 @@ void __init sched_init(void) + #ifdef CONFIG_SMP + rq->sd = NULL; + rq->rd = NULL; +- rq->cpu_capacity = rq->cpu_capacity_orig = SCHED_CAPACITY_SCALE; ++ rq->cpu_capacity = SCHED_CAPACITY_SCALE; + rq->balance_callback = &balance_push_callback; + rq->active_balance = 0; + rq->next_balance = jiffies; +diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c +index 57c92d751bcd73..95baa12a10293e 100644 +--- a/kernel/sched/cpudeadline.c ++++ b/kernel/sched/cpudeadline.c +@@ -131,7 +131,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p, + if (!dl_task_fits_capacity(p, cpu)) { + cpumask_clear_cpu(cpu, later_mask); + +- cap = capacity_orig_of(cpu); ++ cap = arch_scale_cpu_capacity(cpu); + + if (cap > max_cap || + (cpu == task_cpu(p) && cap == max_cap)) { +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index 259521b179aa11..776be0549162c9 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -47,7 +47,7 @@ struct sugov_cpu { + u64 last_update; + + unsigned long util; +- unsigned long bw_dl; ++ unsigned long bw_min; + + /* The field below is for single-CPU policies only: */ + #ifdef CONFIG_NO_HZ_COMMON +@@ -81,9 +81,20 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) + if (!cpufreq_this_cpu_can_update(sg_policy->policy)) + return false; + +- if (unlikely(sg_policy->limits_changed)) { +- sg_policy->limits_changed = false; ++ if (unlikely(READ_ONCE(sg_policy->limits_changed))) { ++ WRITE_ONCE(sg_policy->limits_changed, false); + sg_policy->need_freq_update = true; ++ ++ /* ++ * The above limits_changed update must occur before the reads ++ * of policy limits in cpufreq_driver_resolve_freq() or a policy ++ * limits update might be missed, so use a memory barrier to ++ * ensure it. ++ * ++ * This pairs with the write memory barrier in sugov_limits(). ++ */ ++ smp_mb(); ++ + return true; + } + +@@ -155,7 +166,6 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, + unsigned int freq = arch_scale_freq_invariant() ? + policy->cpuinfo.max_freq : policy->cur; + +- util = map_util_perf(util); + freq = map_util_freq(util, freq, max); + + if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update) +@@ -165,14 +175,30 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, + return cpufreq_driver_resolve_freq(policy, freq); + } + ++unsigned long sugov_effective_cpu_perf(int cpu, unsigned long actual, ++ unsigned long min, ++ unsigned long max) ++{ ++ /* Add dvfs headroom to actual utilization */ ++ actual = map_util_perf(actual); ++ /* Actually we don't need to target the max performance */ ++ if (actual < max) ++ max = actual; ++ ++ /* ++ * Ensure at least minimum performance while providing more compute ++ * capacity when possible. ++ */ ++ return max(min, max); ++} ++ + static void sugov_get_util(struct sugov_cpu *sg_cpu) + { +- unsigned long util = cpu_util_cfs_boost(sg_cpu->cpu); +- struct rq *rq = cpu_rq(sg_cpu->cpu); ++ unsigned long min, max, util = cpu_util_cfs_boost(sg_cpu->cpu); + +- sg_cpu->bw_dl = cpu_bw_dl(rq); +- sg_cpu->util = effective_cpu_util(sg_cpu->cpu, util, +- FREQUENCY_UTIL, NULL); ++ util = effective_cpu_util(sg_cpu->cpu, util, &min, &max); ++ sg_cpu->bw_min = min; ++ sg_cpu->util = sugov_effective_cpu_perf(sg_cpu->cpu, util, min, max); + } + + /** +@@ -318,8 +344,8 @@ static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; } + */ + static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu) + { +- if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl) +- sg_cpu->sg_policy->limits_changed = true; ++ if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_min) ++ WRITE_ONCE(sg_cpu->sg_policy->limits_changed, true); + } + + static inline bool sugov_update_single_common(struct sugov_cpu *sg_cpu, +@@ -419,8 +445,8 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, + sugov_cpu_is_busy(sg_cpu) && sg_cpu->util < prev_util) + sg_cpu->util = prev_util; + +- cpufreq_driver_adjust_perf(sg_cpu->cpu, map_util_perf(sg_cpu->bw_dl), +- map_util_perf(sg_cpu->util), max_cap); ++ cpufreq_driver_adjust_perf(sg_cpu->cpu, sg_cpu->bw_min, ++ sg_cpu->util, max_cap); + + sg_cpu->sg_policy->last_freq_update_time = time; + } +@@ -829,7 +855,16 @@ static void sugov_limits(struct cpufreq_policy *policy) + mutex_unlock(&sg_policy->work_lock); + } + +- sg_policy->limits_changed = true; ++ /* ++ * The limits_changed update below must take place before the updates ++ * of policy limits in cpufreq_set_policy() or a policy limits update ++ * might be missed, so use a memory barrier to ensure it. ++ * ++ * This pairs with the memory barrier in sugov_should_update_freq(). ++ */ ++ smp_wmb(); ++ ++ WRITE_ONCE(sg_policy->limits_changed, true); + } + + struct cpufreq_governor schedutil_gov = { +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 6c639e48e49a97..a15cf7969953a5 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -132,7 +132,7 @@ static inline unsigned long __dl_bw_capacity(const struct cpumask *mask) + int i; + + for_each_cpu_and(i, mask, cpu_active_mask) +- cap += capacity_orig_of(i); ++ cap += arch_scale_cpu_capacity(i); + + return cap; + } +@@ -144,7 +144,7 @@ static inline unsigned long __dl_bw_capacity(const struct cpumask *mask) + static inline unsigned long dl_bw_capacity(int i) + { + if (!sched_asym_cpucap_active() && +- capacity_orig_of(i) == SCHED_CAPACITY_SCALE) { ++ arch_scale_cpu_capacity(i) == SCHED_CAPACITY_SCALE) { + return dl_bw_cpus(i) << SCHED_CAPACITY_SHIFT; + } else { + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 2808dbdd03847e..268e2a49b964e0 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -4951,7 +4951,7 @@ static inline void util_est_update(struct cfs_rq *cfs_rq, + * To avoid overestimation of actual task utilization, skip updates if + * we cannot grant there is idle time in this CPU. + */ +- if (task_util(p) > capacity_orig_of(cpu_of(rq_of(cfs_rq)))) ++ if (task_util(p) > arch_scale_cpu_capacity(cpu_of(rq_of(cfs_rq)))) + return; + + /* +@@ -4999,14 +4999,14 @@ static inline int util_fits_cpu(unsigned long util, + return fits; + + /* +- * We must use capacity_orig_of() for comparing against uclamp_min and ++ * We must use arch_scale_cpu_capacity() for comparing against uclamp_min and + * uclamp_max. We only care about capacity pressure (by using + * capacity_of()) for comparing against the real util. + * + * If a task is boosted to 1024 for example, we don't want a tiny + * pressure to skew the check whether it fits a CPU or not. + * +- * Similarly if a task is capped to capacity_orig_of(little_cpu), it ++ * Similarly if a task is capped to arch_scale_cpu_capacity(little_cpu), it + * should fit a little cpu even if there's some pressure. + * + * Only exception is for thermal pressure since it has a direct impact +@@ -5018,7 +5018,7 @@ static inline int util_fits_cpu(unsigned long util, + * For uclamp_max, we can tolerate a drop in performance level as the + * goal is to cap the task. So it's okay if it's getting less. + */ +- capacity_orig = capacity_orig_of(cpu); ++ capacity_orig = arch_scale_cpu_capacity(cpu); + capacity_orig_thermal = capacity_orig - arch_scale_thermal_pressure(cpu); + + /* +@@ -7515,7 +7515,7 @@ select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target) + * Look for the CPU with best capacity. + */ + else if (fits < 0) +- cpu_cap = capacity_orig_of(cpu) - thermal_load_avg(cpu_rq(cpu)); ++ cpu_cap = arch_scale_cpu_capacity(cpu) - thermal_load_avg(cpu_rq(cpu)); + + /* + * First, select CPU which fits better (-1 being better than 0). +@@ -7757,7 +7757,7 @@ cpu_util(int cpu, struct task_struct *p, int dst_cpu, int boost) + util = max(util, util_est); + } + +- return min(util, capacity_orig_of(cpu)); ++ return min(util, arch_scale_cpu_capacity(cpu)); + } + + unsigned long cpu_util_cfs(int cpu) +@@ -7859,7 +7859,7 @@ static inline void eenv_pd_busy_time(struct energy_env *eenv, + for_each_cpu(cpu, pd_cpus) { + unsigned long util = cpu_util(cpu, p, -1, 0); + +- busy_time += effective_cpu_util(cpu, util, ENERGY_UTIL, NULL); ++ busy_time += effective_cpu_util(cpu, util, NULL, NULL); + } + + eenv->pd_busy_time = min(eenv->pd_cap, busy_time); +@@ -7882,7 +7882,7 @@ eenv_pd_max_util(struct energy_env *eenv, struct cpumask *pd_cpus, + for_each_cpu(cpu, pd_cpus) { + struct task_struct *tsk = (cpu == dst_cpu) ? p : NULL; + unsigned long util = cpu_util(cpu, p, dst_cpu, 1); +- unsigned long eff_util; ++ unsigned long eff_util, min, max; + + /* + * Performance domain frequency: utilization clamping +@@ -7891,7 +7891,23 @@ eenv_pd_max_util(struct energy_env *eenv, struct cpumask *pd_cpus, + * NOTE: in case RT tasks are running, by default the + * FREQUENCY_UTIL's utilization can be max OPP. + */ +- eff_util = effective_cpu_util(cpu, util, FREQUENCY_UTIL, tsk); ++ eff_util = effective_cpu_util(cpu, util, &min, &max); ++ ++ /* Task's uclamp can modify min and max value */ ++ if (tsk && uclamp_is_used()) { ++ min = max(min, uclamp_eff_value(p, UCLAMP_MIN)); ++ ++ /* ++ * If there is no active max uclamp constraint, ++ * directly use task's one, otherwise keep max. ++ */ ++ if (uclamp_rq_is_idle(cpu_rq(cpu))) ++ max = uclamp_eff_value(p, UCLAMP_MAX); ++ else ++ max = max(max, uclamp_eff_value(p, UCLAMP_MAX)); ++ } ++ ++ eff_util = sugov_effective_cpu_perf(cpu, eff_util, min, max); + max_util = max(max_util, eff_util); + } + +@@ -9544,8 +9560,6 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) + unsigned long capacity = scale_rt_capacity(cpu); + struct sched_group *sdg = sd->groups; + +- cpu_rq(cpu)->cpu_capacity_orig = arch_scale_cpu_capacity(cpu); +- + if (!capacity) + capacity = 1; + +@@ -9621,7 +9635,7 @@ static inline int + check_cpu_capacity(struct rq *rq, struct sched_domain *sd) + { + return ((rq->cpu_capacity * sd->imbalance_pct) < +- (rq->cpu_capacity_orig * 100)); ++ (arch_scale_cpu_capacity(cpu_of(rq)) * 100)); + } + + /* +@@ -9632,7 +9646,7 @@ check_cpu_capacity(struct rq *rq, struct sched_domain *sd) + static inline int check_misfit_status(struct rq *rq, struct sched_domain *sd) + { + return rq->misfit_task_load && +- (rq->cpu_capacity_orig < rq->rd->max_cpu_capacity || ++ (arch_scale_cpu_capacity(rq->cpu) < rq->rd->max_cpu_capacity || + check_cpu_capacity(rq, sd)); + } + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index b89223a973168f..91b1ee0d81fce4 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -519,7 +519,7 @@ static inline bool rt_task_fits_capacity(struct task_struct *p, int cpu) + min_cap = uclamp_eff_value(p, UCLAMP_MIN); + max_cap = uclamp_eff_value(p, UCLAMP_MAX); + +- cpu_cap = capacity_orig_of(cpu); ++ cpu_cap = arch_scale_cpu_capacity(cpu); + + return cpu_cap >= min(min_cap, max_cap); + } +diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h +index d48c6a292a83db..60dc51f43dd91f 100644 +--- a/kernel/sched/sched.h ++++ b/kernel/sched/sched.h +@@ -1048,7 +1048,6 @@ struct rq { + struct sched_domain __rcu *sd; + + unsigned long cpu_capacity; +- unsigned long cpu_capacity_orig; + + struct balance_callback *balance_callback; + +@@ -2985,29 +2984,14 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} + #endif + + #ifdef CONFIG_SMP +-static inline unsigned long capacity_orig_of(int cpu) +-{ +- return cpu_rq(cpu)->cpu_capacity_orig; +-} ++unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, ++ unsigned long *min, ++ unsigned long *max); + +-/** +- * enum cpu_util_type - CPU utilization type +- * @FREQUENCY_UTIL: Utilization used to select frequency +- * @ENERGY_UTIL: Utilization used during energy calculation +- * +- * The utilization signals of all scheduling classes (CFS/RT/DL) and IRQ time +- * need to be aggregated differently depending on the usage made of them. This +- * enum is used within effective_cpu_util() to differentiate the types of +- * utilization expected by the callers, and adjust the aggregation accordingly. +- */ +-enum cpu_util_type { +- FREQUENCY_UTIL, +- ENERGY_UTIL, +-}; ++unsigned long sugov_effective_cpu_perf(int cpu, unsigned long actual, ++ unsigned long min, ++ unsigned long max); + +-unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, +- enum cpu_util_type type, +- struct task_struct *p); + + /* + * Verify the fitness of task @p to run on @cpu taking into account the +diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c +index 2ed884bb362137..c61698cff0f3a8 100644 +--- a/kernel/sched/topology.c ++++ b/kernel/sched/topology.c +@@ -2486,12 +2486,15 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att + /* Attach the domains */ + rcu_read_lock(); + for_each_cpu(i, cpu_map) { ++ unsigned long capacity; ++ + rq = cpu_rq(i); + sd = *per_cpu_ptr(d.sd, i); + ++ capacity = arch_scale_cpu_capacity(i); + /* Use READ_ONCE()/WRITE_ONCE() to avoid load/store tearing: */ +- if (rq->cpu_capacity_orig > READ_ONCE(d.rd->max_cpu_capacity)) +- WRITE_ONCE(d.rd->max_cpu_capacity, rq->cpu_capacity_orig); ++ if (capacity > READ_ONCE(d.rd->max_cpu_capacity)) ++ WRITE_ONCE(d.rd->max_cpu_capacity, capacity); + + cpu_attach_domain(sd, d.rd, i); + } +diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c +index 7f2b17fc8ce403..ecdb8c2b2cab21 100644 +--- a/kernel/time/tick-common.c ++++ b/kernel/time/tick-common.c +@@ -495,6 +495,7 @@ void tick_resume(void) + + #ifdef CONFIG_SUSPEND + static DEFINE_RAW_SPINLOCK(tick_freeze_lock); ++static DEFINE_WAIT_OVERRIDE_MAP(tick_freeze_map, LD_WAIT_SLEEP); + static unsigned int tick_freeze_depth; + + /** +@@ -514,9 +515,22 @@ void tick_freeze(void) + if (tick_freeze_depth == num_online_cpus()) { + trace_suspend_resume(TPS("timekeeping_freeze"), + smp_processor_id(), true); ++ /* ++ * All other CPUs have their interrupts disabled and are ++ * suspended to idle. Other tasks have been frozen so there ++ * is no scheduling happening. This means that there is no ++ * concurrency in the system at this point. Therefore it is ++ * okay to acquire a sleeping lock on PREEMPT_RT, such as a ++ * spinlock, because the lock cannot be held by other CPUs ++ * or threads and acquiring it cannot block. ++ * ++ * Inform lockdep about the situation. ++ */ ++ lock_map_acquire_try(&tick_freeze_map); + system_state = SYSTEM_SUSPEND; + sched_clock_suspend(); + timekeeping_suspend(); ++ lock_map_release(&tick_freeze_map); + } else { + tick_suspend_local(); + } +@@ -538,8 +552,16 @@ void tick_unfreeze(void) + raw_spin_lock(&tick_freeze_lock); + + if (tick_freeze_depth == num_online_cpus()) { ++ /* ++ * Similar to tick_freeze(). On resumption the first CPU may ++ * acquire uncontended sleeping locks while other CPUs block on ++ * tick_freeze_lock. ++ */ ++ lock_map_acquire_try(&tick_freeze_map); + timekeeping_resume(); + sched_clock_resume(); ++ lock_map_release(&tick_freeze_map); ++ + system_state = SYSTEM_RUNNING; + trace_suspend_resume(TPS("timekeeping_freeze"), + smp_processor_id(), false); +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 545393601be8ce..97f660a8ddc73d 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -400,7 +400,7 @@ static const struct bpf_func_proto bpf_trace_printk_proto = { + .arg2_type = ARG_CONST_SIZE, + }; + +-static void __set_printk_clr_event(void) ++static void __set_printk_clr_event(struct work_struct *work) + { + /* + * This program might be calling bpf_trace_printk, +@@ -413,10 +413,11 @@ static void __set_printk_clr_event(void) + if (trace_set_clr_event("bpf_trace", "bpf_trace_printk", 1)) + pr_warn_ratelimited("could not enable bpf_trace_printk events"); + } ++static DECLARE_WORK(set_printk_work, __set_printk_clr_event); + + const struct bpf_func_proto *bpf_get_trace_printk_proto(void) + { +- __set_printk_clr_event(); ++ schedule_work(&set_printk_work); + return &bpf_trace_printk_proto; + } + +@@ -459,7 +460,7 @@ static const struct bpf_func_proto bpf_trace_vprintk_proto = { + + const struct bpf_func_proto *bpf_get_trace_vprintk_proto(void) + { +- __set_printk_clr_event(); ++ schedule_work(&set_printk_work); + return &bpf_trace_vprintk_proto; + } + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 1a936978c2b1a6..5f74e9f9c8a734 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -470,6 +470,7 @@ static void test_event_printk(struct trace_event_call *call) + case '%': + continue; + case 'p': ++ do_pointer: + /* Find dereferencing fields */ + switch (fmt[i + 1]) { + case 'B': case 'R': case 'r': +@@ -498,6 +499,12 @@ static void test_event_printk(struct trace_event_call *call) + continue; + if (fmt[i + j] == '*') { + star = true; ++ /* Handle %*pbl case */ ++ if (!j && fmt[i + 1] == 'p') { ++ arg++; ++ i++; ++ goto do_pointer; ++ } + continue; + } + if ((fmt[i + j] == 's')) { +diff --git a/lib/test_ubsan.c b/lib/test_ubsan.c +index 2062be1f2e80f6..f90f2b9842ec4f 100644 +--- a/lib/test_ubsan.c ++++ b/lib/test_ubsan.c +@@ -35,18 +35,22 @@ static void test_ubsan_shift_out_of_bounds(void) + + static void test_ubsan_out_of_bounds(void) + { +- volatile int i = 4, j = 5, k = -1; +- volatile char above[4] = { }; /* Protect surrounding memory. */ +- volatile int arr[4]; +- volatile char below[4] = { }; /* Protect surrounding memory. */ ++ int i = 4, j = 4, k = -1; ++ volatile struct { ++ char above[4]; /* Protect surrounding memory. */ ++ int arr[4]; ++ char below[4]; /* Protect surrounding memory. */ ++ } data; + +- above[0] = below[0]; ++ OPTIMIZER_HIDE_VAR(i); ++ OPTIMIZER_HIDE_VAR(j); ++ OPTIMIZER_HIDE_VAR(k); + + UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above"); +- arr[j] = i; ++ data.arr[j] = i; + + UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below"); +- arr[k] = i; ++ data.arr[k] = i; + } + + enum ubsan_test_enum { +diff --git a/net/9p/client.c b/net/9p/client.c +index d841d82e908fe3..cf73fe306219a9 100644 +--- a/net/9p/client.c ++++ b/net/9p/client.c +@@ -1547,7 +1547,8 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + struct p9_client *clnt = fid->clnt; + struct p9_req_t *req; + int count = iov_iter_count(to); +- int rsize, received, non_zc = 0; ++ u32 rsize, received; ++ bool non_zc = false; + char *dataptr; + + *err = 0; +@@ -1570,7 +1571,7 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + 0, 11, "dqd", fid->fid, + offset, rsize); + } else { +- non_zc = 1; ++ non_zc = true; + req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, + rsize); + } +@@ -1591,11 +1592,11 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, + return 0; + } + if (rsize < received) { +- pr_err("bogus RREAD count (%d > %d)\n", received, rsize); ++ pr_err("bogus RREAD count (%u > %u)\n", received, rsize); + received = rsize; + } + +- p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", received); ++ p9_debug(P9_DEBUG_9P, "<<< RREAD count %u\n", received); + + if (non_zc) { + int n = copy_to_iter(dataptr, received, to); +@@ -1622,9 +1623,9 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) + *err = 0; + + while (iov_iter_count(from)) { +- int count = iov_iter_count(from); +- int rsize = fid->iounit; +- int written; ++ size_t count = iov_iter_count(from); ++ u32 rsize = fid->iounit; ++ u32 written; + + if (!rsize || rsize > clnt->msize - P9_IOHDRSZ) + rsize = clnt->msize - P9_IOHDRSZ; +@@ -1632,7 +1633,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) + if (count < rsize) + rsize = count; + +- p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d (/%d)\n", ++ p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %u (/%zu)\n", + fid->fid, offset, rsize, count); + + /* Don't bother zerocopy for small IO (< 1024) */ +@@ -1658,11 +1659,11 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) + break; + } + if (rsize < written) { +- pr_err("bogus RWRITE count (%d > %d)\n", written, rsize); ++ pr_err("bogus RWRITE count (%u > %u)\n", written, rsize); + written = rsize; + } + +- p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", written); ++ p9_debug(P9_DEBUG_9P, "<<< RWRITE count %u\n", written); + + p9_req_put(clnt, req); + iov_iter_revert(from, count - written - iov_iter_count(from)); +@@ -2049,7 +2050,8 @@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate); + + int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) + { +- int err, rsize, non_zc = 0; ++ int err, non_zc = 0; ++ u32 rsize; + struct p9_client *clnt; + struct p9_req_t *req; + char *dataptr; +@@ -2058,7 +2060,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) + + iov_iter_kvec(&to, ITER_DEST, &kv, 1, count); + +- p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", ++ p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %u\n", + fid->fid, offset, count); + + clnt = fid->clnt; +@@ -2093,11 +2095,11 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) + goto free_and_error; + } + if (rsize < count) { +- pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize); ++ pr_err("bogus RREADDIR count (%u > %u)\n", count, rsize); + count = rsize; + } + +- p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); ++ p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %u\n", count); + + if (non_zc) + memmove(data, dataptr, count); +diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c +index 4417a18b3e951a..f63586c9ce0216 100644 +--- a/net/core/lwtunnel.c ++++ b/net/core/lwtunnel.c +@@ -332,6 +332,8 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) + struct dst_entry *dst; + int ret; + ++ local_bh_disable(); ++ + if (dev_xmit_recursion()) { + net_crit_ratelimited("%s(): recursion limit reached on datapath\n", + __func__); +@@ -347,8 +349,10 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) + lwtstate = dst->lwtstate; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || +- lwtstate->type > LWTUNNEL_ENCAP_MAX) +- return 0; ++ lwtstate->type > LWTUNNEL_ENCAP_MAX) { ++ ret = 0; ++ goto out; ++ } + + ret = -EOPNOTSUPP; + rcu_read_lock(); +@@ -363,11 +367,13 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) + if (ret == -EOPNOTSUPP) + goto drop; + +- return ret; ++ goto out; + + drop: + kfree_skb(skb); + ++out: ++ local_bh_enable(); + return ret; + } + EXPORT_SYMBOL_GPL(lwtunnel_output); +@@ -379,6 +385,8 @@ int lwtunnel_xmit(struct sk_buff *skb) + struct dst_entry *dst; + int ret; + ++ local_bh_disable(); ++ + if (dev_xmit_recursion()) { + net_crit_ratelimited("%s(): recursion limit reached on datapath\n", + __func__); +@@ -395,8 +403,10 @@ int lwtunnel_xmit(struct sk_buff *skb) + lwtstate = dst->lwtstate; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || +- lwtstate->type > LWTUNNEL_ENCAP_MAX) +- return 0; ++ lwtstate->type > LWTUNNEL_ENCAP_MAX) { ++ ret = 0; ++ goto out; ++ } + + ret = -EOPNOTSUPP; + rcu_read_lock(); +@@ -411,11 +421,13 @@ int lwtunnel_xmit(struct sk_buff *skb) + if (ret == -EOPNOTSUPP) + goto drop; + +- return ret; ++ goto out; + + drop: + kfree_skb(skb); + ++out: ++ local_bh_enable(); + return ret; + } + EXPORT_SYMBOL_GPL(lwtunnel_xmit); +@@ -427,6 +439,8 @@ int lwtunnel_input(struct sk_buff *skb) + struct dst_entry *dst; + int ret; + ++ DEBUG_NET_WARN_ON_ONCE(!in_softirq()); ++ + if (dev_xmit_recursion()) { + net_crit_ratelimited("%s(): recursion limit reached on datapath\n", + __func__); +diff --git a/net/core/selftests.c b/net/core/selftests.c +index acb1ee97bbd324..7af99d07762ea0 100644 +--- a/net/core/selftests.c ++++ b/net/core/selftests.c +@@ -100,10 +100,10 @@ static struct sk_buff *net_test_get_skb(struct net_device *ndev, + ehdr->h_proto = htons(ETH_P_IP); + + if (attr->tcp) { ++ memset(thdr, 0, sizeof(*thdr)); + thdr->source = htons(attr->sport); + thdr->dest = htons(attr->dport); + thdr->doff = sizeof(struct tcphdr) / 4; +- thdr->check = 0; + } else { + uhdr->source = htons(attr->sport); + uhdr->dest = htons(attr->dport); +@@ -144,10 +144,18 @@ static struct sk_buff *net_test_get_skb(struct net_device *ndev, + attr->id = net_test_next_id; + shdr->id = net_test_next_id++; + +- if (attr->size) +- skb_put(skb, attr->size); +- if (attr->max_size && attr->max_size > skb->len) +- skb_put(skb, attr->max_size - skb->len); ++ if (attr->size) { ++ void *payload = skb_put(skb, attr->size); ++ ++ memset(payload, 0, attr->size); ++ } ++ ++ if (attr->max_size && attr->max_size > skb->len) { ++ size_t pad_len = attr->max_size - skb->len; ++ void *pad = skb_put(skb, pad_len); ++ ++ memset(pad, 0, pad_len); ++ } + + skb->csum = 0; + skb->ip_summed = CHECKSUM_PARTIAL; +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index 880c5f16b29ccf..371255e624332f 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -958,6 +958,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + + if (cl != NULL) { + int old_flags; ++ int len = 0; + + if (parentid) { + if (cl->cl_parent && +@@ -988,9 +989,13 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (usc != NULL) + hfsc_change_usc(cl, usc, cur_time); + ++ if (cl->qdisc->q.qlen != 0) ++ len = qdisc_peek_len(cl->qdisc); ++ /* Check queue length again since some qdisc implementations ++ * (e.g., netem/codel) might empty the queue during the peek ++ * operation. ++ */ + if (cl->qdisc->q.qlen != 0) { +- int len = qdisc_peek_len(cl->qdisc); +- + if (cl->cl_flags & HFSC_RSC) { + if (old_flags & HFSC_RSC) + update_ed(cl, len); +@@ -1633,10 +1638,16 @@ hfsc_dequeue(struct Qdisc *sch) + if (cl->qdisc->q.qlen != 0) { + /* update ed */ + next_len = qdisc_peek_len(cl->qdisc); +- if (realtime) +- update_ed(cl, next_len); +- else +- update_d(cl, next_len); ++ /* Check queue length again since some qdisc implementations ++ * (e.g., netem/codel) might empty the queue during the peek ++ * operation. ++ */ ++ if (cl->qdisc->q.qlen != 0) { ++ if (realtime) ++ update_ed(cl, next_len); ++ else ++ update_d(cl, next_len); ++ } + } else { + /* the class becomes passive */ + eltree_remove(cl); +diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c +index 77a3d016cadec1..ddc3e4e5e18d78 100644 +--- a/net/tipc/monitor.c ++++ b/net/tipc/monitor.c +@@ -716,7 +716,8 @@ void tipc_mon_reinit_self(struct net *net) + if (!mon) + continue; + write_lock_bh(&mon->lock); +- mon->self->addr = tipc_own_addr(net); ++ if (mon->self) ++ mon->self->addr = tipc_own_addr(net); + write_unlock_bh(&mon->lock); + } + } +diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h +index 1c6b843b8c4eeb..06be777b3b14b7 100644 +--- a/samples/trace_events/trace-events-sample.h ++++ b/samples/trace_events/trace-events-sample.h +@@ -302,6 +302,7 @@ TRACE_EVENT(foo_bar, + __bitmask( cpus, num_possible_cpus() ) + __cpumask( cpum ) + __vstring( vstr, fmt, va ) ++ __string_len( lstr, foo, bar / 2 < strlen(foo) ? bar / 2 : strlen(foo) ) + ), + + TP_fast_assign( +@@ -310,12 +311,14 @@ TRACE_EVENT(foo_bar, + memcpy(__get_dynamic_array(list), lst, + __length_of(lst) * sizeof(int)); + __assign_str(str, string); ++ __assign_str(lstr, foo); + __assign_vstr(vstr, fmt, va); + __assign_bitmask(cpus, cpumask_bits(mask), num_possible_cpus()); + __assign_cpumask(cpum, cpumask_bits(mask)); + ), + +- TP_printk("foo %s %d %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, ++ TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s [%d] %*pbl", ++ __entry->foo, __entry->bar, + + /* + * Notice here the use of some helper functions. This includes: +@@ -359,8 +362,17 @@ TRACE_EVENT(foo_bar, + __print_array(__get_dynamic_array(list), + __get_dynamic_array_len(list) / sizeof(int), + sizeof(int)), +- __get_str(str), __get_bitmask(cpus), __get_cpumask(cpum), +- __get_str(vstr)) ++ ++/* A shortcut is to use __print_dynamic_array for dynamic arrays */ ++ ++ __print_dynamic_array(list, sizeof(int)), ++ ++ __get_str(str), __get_str(lstr), ++ __get_bitmask(cpus), __get_cpumask(cpum), ++ __get_str(vstr), ++ __get_dynamic_array_len(cpus), ++ __get_dynamic_array_len(cpus), ++ __get_dynamic_array(cpus)) + ); + + /* +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index 44f20b1b853a50..4aecfb0a0ef6ae 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -268,7 +268,7 @@ objtool-args-$(CONFIG_SLS) += --sls + objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval + objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call + objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess +-objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable ++objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV)) += --no-unreachable + objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES) + + objtool-args = $(objtool-args-y) \ +diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c +index 1b6e376f3833cb..fe222c4b74c006 100644 +--- a/sound/soc/codecs/wcd934x.c ++++ b/sound/soc/codecs/wcd934x.c +@@ -2281,7 +2281,7 @@ static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data) + { + struct wcd934x_codec *wcd = data; + unsigned long status = 0; +- int i, j, port_id; ++ unsigned int i, j, port_id; + unsigned int val, int_val = 0; + irqreturn_t ret = IRQ_NONE; + bool tx; +diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c +index ff9f6a1c95df19..40b6a837f66bbc 100644 +--- a/sound/soc/qcom/apq8016_sbc.c ++++ b/sound/soc/qcom/apq8016_sbc.c +@@ -343,4 +343,4 @@ module_platform_driver(apq8016_sbc_platform_driver); + + MODULE_AUTHOR("Srinivas Kandagatla variant->exit) + drvdata->variant->exit(pdev); +- +- +- return 0; + } + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); + +@@ -1307,4 +1304,4 @@ void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev) + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown); + + MODULE_DESCRIPTION("QTi LPASS CPU Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c +index 24b1a7523adb90..ce753ebc08945a 100644 +--- a/sound/soc/qcom/lpass-hdmi.c ++++ b/sound/soc/qcom/lpass-hdmi.c +@@ -251,4 +251,4 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = { + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops); + + MODULE_DESCRIPTION("QTi LPASS HDMI Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c +index 2c97f295e39400..2a82684c04de45 100644 +--- a/sound/soc/qcom/lpass-ipq806x.c ++++ b/sound/soc/qcom/lpass-ipq806x.c +@@ -172,9 +172,9 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = { + .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id), + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + }; + module_platform_driver(ipq806x_lpass_cpu_platform_driver); + + MODULE_DESCRIPTION("QTi LPASS CPU Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c +index 73e3d39bd24c30..f918d9e16dc041 100644 +--- a/sound/soc/qcom/lpass-platform.c ++++ b/sound/soc/qcom/lpass-platform.c +@@ -1383,4 +1383,4 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register); + + MODULE_DESCRIPTION("QTi LPASS Platform Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c +index d16c0d83aaad92..98faf82c22568e 100644 +--- a/sound/soc/qcom/lpass-sc7180.c ++++ b/sound/soc/qcom/lpass-sc7180.c +@@ -315,11 +315,11 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = { + .pm = &sc7180_lpass_pm_ops, + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, + }; + + module_platform_driver(sc7180_lpass_cpu_platform_driver); + + MODULE_DESCRIPTION("SC7180 LPASS CPU DRIVER"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c +index 6b2eb25ed9390c..97b9053ed3b027 100644 +--- a/sound/soc/qcom/lpass-sc7280.c ++++ b/sound/soc/qcom/lpass-sc7280.c +@@ -445,7 +445,7 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = { + .pm = &sc7280_lpass_pm_ops, + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, + }; + +diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h +index ea12f02eca55f6..5caec24555ea2e 100644 +--- a/sound/soc/qcom/lpass.h ++++ b/sound/soc/qcom/lpass.h +@@ -399,8 +399,8 @@ struct lpass_pcm_data { + }; + + /* register the platform driver from the CPU DAI driver */ +-int asoc_qcom_lpass_platform_register(struct platform_device *); +-int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); ++int asoc_qcom_lpass_platform_register(struct platform_device *pdev); ++void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); + void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); + int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); + extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; +diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c +index 919e326b9462b3..fcef53b97ff98a 100644 +--- a/sound/soc/qcom/qdsp6/q6afe.c ++++ b/sound/soc/qcom/qdsp6/q6afe.c +@@ -552,13 +552,13 @@ struct q6afe_port { + }; + + struct afe_cmd_remote_lpass_core_hw_vote_request { +- uint32_t hw_block_id; +- char client_name[8]; ++ uint32_t hw_block_id; ++ char client_name[8]; + } __packed; + + struct afe_cmd_remote_lpass_core_hw_devote_request { +- uint32_t hw_block_id; +- uint32_t client_handle; ++ uint32_t hw_block_id; ++ uint32_t client_handle; + } __packed; + + +diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c +index def05ce58d176e..179f4f7386dd00 100644 +--- a/sound/soc/qcom/qdsp6/q6apm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6apm-dai.c +@@ -64,20 +64,16 @@ struct q6apm_dai_rtd { + phys_addr_t phys; + unsigned int pcm_size; + unsigned int pcm_count; +- unsigned int pos; /* Buffer position */ + unsigned int periods; + unsigned int bytes_sent; + unsigned int bytes_received; + unsigned int copied_total; + uint16_t bits_per_sample; +- uint16_t source; /* Encoding source bit mask */ +- uint16_t session_id; ++ snd_pcm_uframes_t queue_ptr; + bool next_track; + enum stream_state state; + struct q6apm_graph *graph; + spinlock_t lock; +- uint32_t initial_samples_drop; +- uint32_t trailing_samples_drop; + bool notify_on_drain; + }; + +@@ -127,25 +123,16 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo + { + struct q6apm_dai_rtd *prtd = priv; + struct snd_pcm_substream *substream = prtd->substream; +- unsigned long flags; + + switch (opcode) { + case APM_CLIENT_EVENT_CMD_EOS_DONE: + prtd->state = Q6APM_STREAM_STOPPED; + break; + case APM_CLIENT_EVENT_DATA_WRITE_DONE: +- spin_lock_irqsave(&prtd->lock, flags); +- prtd->pos += prtd->pcm_count; +- spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); +- if (prtd->state == Q6APM_STREAM_RUNNING) +- q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); + + break; + case APM_CLIENT_EVENT_DATA_READ_DONE: +- spin_lock_irqsave(&prtd->lock, flags); +- prtd->pos += prtd->pcm_count; +- spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); + if (prtd->state == Q6APM_STREAM_RUNNING) + q6apm_read(prtd->graph); +@@ -251,7 +238,6 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, + } + + prtd->pcm_count = snd_pcm_lib_period_bytes(substream); +- prtd->pos = 0; + /* rate and channels are sent to audio driver */ + ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); + if (ret < 0) { +@@ -297,6 +283,27 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, + return 0; + } + ++static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct q6apm_dai_rtd *prtd = runtime->private_data; ++ int i, ret = 0, avail_periods; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size; ++ for (i = 0; i < avail_periods; i++) { ++ ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP); ++ if (ret < 0) { ++ dev_err(component->dev, "Error queuing playback buffer %d\n", ret); ++ return ret; ++ } ++ prtd->queue_ptr += runtime->period_size; ++ } ++ } ++ ++ return ret; ++} ++ + static int q6apm_dai_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) + { +@@ -308,9 +315,6 @@ static int q6apm_dai_trigger(struct snd_soc_component *component, + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +- /* start writing buffers for playback only as we already queued capture buffers */ +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +- ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); + break; + case SNDRV_PCM_TRIGGER_STOP: + /* TODO support be handled via SoftPause Module */ +@@ -432,16 +436,12 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component, + struct snd_pcm_runtime *runtime = substream->runtime; + struct q6apm_dai_rtd *prtd = runtime->private_data; + snd_pcm_uframes_t ptr; +- unsigned long flags; + +- spin_lock_irqsave(&prtd->lock, flags); +- if (prtd->pos == prtd->pcm_size) +- prtd->pos = 0; +- +- ptr = bytes_to_frames(runtime, prtd->pos); +- spin_unlock_irqrestore(&prtd->lock, flags); ++ ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size; ++ if (ptr) ++ return ptr - 1; + +- return ptr; ++ return 0; + } + + static int q6apm_dai_hw_params(struct snd_soc_component *component, +@@ -656,8 +656,6 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component, + prtd->pcm_size = runtime->fragments * runtime->fragment_size; + prtd->bits_per_sample = 16; + +- prtd->pos = 0; +- + if (prtd->next_track != true) { + memcpy(&prtd->codec, codec, sizeof(*codec)); + +@@ -721,14 +719,12 @@ static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component, + + switch (metadata->key) { + case SNDRV_COMPRESS_ENCODER_PADDING: +- prtd->trailing_samples_drop = metadata->value[0]; + q6apm_remove_trailing_silence(component->dev, prtd->graph, +- prtd->trailing_samples_drop); ++ metadata->value[0]); + break; + case SNDRV_COMPRESS_ENCODER_DELAY: +- prtd->initial_samples_drop = metadata->value[0]; + q6apm_remove_initial_silence(component->dev, prtd->graph, +- prtd->initial_samples_drop); ++ metadata->value[0]); + break; + default: + ret = -EINVAL; +@@ -840,6 +836,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = { + .hw_params = q6apm_dai_hw_params, + .pointer = q6apm_dai_pointer, + .trigger = q6apm_dai_trigger, ++ .ack = q6apm_dai_ack, + .compress_ops = &q6apm_dai_compress_ops, + .use_dai_pcm_id = true, + }; +diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h +index 394604c349432f..a33d92c7bd6bff 100644 +--- a/sound/soc/qcom/qdsp6/q6asm.h ++++ b/sound/soc/qcom/qdsp6/q6asm.h +@@ -36,16 +36,16 @@ enum { + #define ASM_LAST_BUFFER_FLAG BIT(30) + + struct q6asm_flac_cfg { +- u32 sample_rate; +- u32 ext_sample_rate; +- u32 min_frame_size; +- u32 max_frame_size; +- u16 stream_info_present; +- u16 min_blk_size; +- u16 max_blk_size; +- u16 ch_cfg; +- u16 sample_size; +- u16 md5_sum; ++ u32 sample_rate; ++ u32 ext_sample_rate; ++ u32 min_frame_size; ++ u32 max_frame_size; ++ u16 stream_info_present; ++ u16 min_blk_size; ++ u16 max_blk_size; ++ u16 ch_cfg; ++ u16 sample_size; ++ u16 md5_sum; + }; + + struct q6asm_wma_cfg { +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index 130b22a34fb3b5..70572c83e1017d 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -545,6 +545,7 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap + + if (mod) { + int pn, id = 0; ++ + mod->module_id = module_id; + mod->max_ip_port = max_ip_port; + mod->max_op_port = max_op_port; +@@ -1271,7 +1272,7 @@ int audioreach_tplg_init(struct snd_soc_component *component) + + ret = request_firmware(&fw, tplg_fw_name, dev); + if (ret < 0) { +- dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); ++ dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret); + goto err; + } + +diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c +index d1fd40e3f7a9d8..1367752f2b63a6 100644 +--- a/sound/soc/qcom/sc7180.c ++++ b/sound/soc/qcom/sc7180.c +@@ -428,4 +428,4 @@ static struct platform_driver sc7180_snd_driver = { + module_platform_driver(sc7180_snd_driver); + + MODULE_DESCRIPTION("sc7180 ASoC Machine Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c +index 6e5f194bc34b06..d5cc967992d161 100644 +--- a/sound/soc/qcom/sc8280xp.c ++++ b/sound/soc/qcom/sc8280xp.c +@@ -174,4 +174,4 @@ static struct platform_driver snd_sc8280xp_driver = { + module_platform_driver(snd_sc8280xp_driver); + MODULE_AUTHOR("Srinivas Kandagatla substreams) + return -ENOMEM; + ++ /* ++ * Initialize critical substream fields early in case we hit an ++ * error path and end up trying to clean up uninitialized structures ++ * elsewhere. ++ */ ++ for (i = 0; i < snd->nsubstreams; ++i) { ++ struct virtio_pcm_substream *vss = &snd->substreams[i]; ++ ++ vss->snd = snd; ++ vss->sid = i; ++ INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); ++ init_waitqueue_head(&vss->msg_empty); ++ spin_lock_init(&vss->lock); ++ } ++ + info = kcalloc(snd->nsubstreams, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; +@@ -350,12 +365,6 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd) + struct virtio_pcm_substream *vss = &snd->substreams[i]; + struct virtio_pcm *vpcm; + +- vss->snd = snd; +- vss->sid = i; +- INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); +- init_waitqueue_head(&vss->msg_empty); +- spin_lock_init(&vss->lock); +- + rc = virtsnd_pcm_build_hw(vss, &info[i]); + if (rc) + goto on_exit; +diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c +index 90ae2ea61324cc..174e076e56af2a 100644 +--- a/tools/bpf/bpftool/prog.c ++++ b/tools/bpf/bpftool/prog.c +@@ -1924,6 +1924,7 @@ static int do_loader(int argc, char **argv) + + obj = bpf_object__open_file(file, &open_opts); + if (!obj) { ++ err = -1; + p_err("failed to open object file"); + goto err_close_obj; + } +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 8ba5bcfd5cd572..a1b14378bab045 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1225,12 +1225,15 @@ static const char *uaccess_safe_builtin[] = { + "__ubsan_handle_load_invalid_value", + /* STACKLEAK */ + "stackleak_track_stack", ++ /* TRACE_BRANCH_PROFILING */ ++ "ftrace_likely_update", ++ /* STACKPROTECTOR */ ++ "__stack_chk_fail", + /* misc */ + "csum_partial_copy_generic", + "copy_mc_fragile", + "copy_mc_fragile_handle_tail", + "copy_mc_enhanced_fast_string", +- "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */ + "rep_stos_alternative", + "rep_movs_alternative", + "__copy_user_nocache", +@@ -1549,6 +1552,8 @@ static int add_jump_destinations(struct objtool_file *file) + unsigned long dest_off; + + for_each_insn(file, insn) { ++ struct symbol *func = insn_func(insn); ++ + if (insn->jump_dest) { + /* + * handle_group_alt() may have previously set +@@ -1572,7 +1577,7 @@ static int add_jump_destinations(struct objtool_file *file) + } else if (reloc->sym->return_thunk) { + add_return_call(file, insn, true); + continue; +- } else if (insn_func(insn)) { ++ } else if (func) { + /* + * External sibling call or internal sibling call with + * STT_FUNC reloc. +@@ -1605,6 +1610,15 @@ static int add_jump_destinations(struct objtool_file *file) + continue; + } + ++ /* ++ * GCOV/KCOV dead code can jump to the end of the ++ * function/section. ++ */ ++ if (file->ignore_unreachables && func && ++ dest_sec == insn->sec && ++ dest_off == func->offset + func->len) ++ continue; ++ + WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", + dest_sec->name, dest_off); + return -1; +@@ -1613,8 +1627,7 @@ static int add_jump_destinations(struct objtool_file *file) + /* + * Cross-function jump. + */ +- if (insn_func(insn) && insn_func(jump_dest) && +- insn_func(insn) != insn_func(jump_dest)) { ++ if (func && insn_func(jump_dest) && func != insn_func(jump_dest)) { + + /* + * For GCC 8+, create parent/child links for any cold +@@ -1631,10 +1644,10 @@ static int add_jump_destinations(struct objtool_file *file) + * case where the parent function's only reference to a + * subfunction is through a jump table. + */ +- if (!strstr(insn_func(insn)->name, ".cold") && ++ if (!strstr(func->name, ".cold") && + strstr(insn_func(jump_dest)->name, ".cold")) { +- insn_func(insn)->cfunc = insn_func(jump_dest); +- insn_func(jump_dest)->pfunc = insn_func(insn); ++ func->cfunc = insn_func(jump_dest); ++ insn_func(jump_dest)->pfunc = func; + } + } + +@@ -3569,6 +3582,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + !strncmp(func->name, "__pfx_", 6)) + return 0; + ++ if (file->ignore_unreachables) ++ return 0; ++ + WARN("%s() falls through to next function %s()", + func->name, insn_func(insn)->name); + return 1; +@@ -3788,6 +3804,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + if (!next_insn) { + if (state.cfi.cfa.base == CFI_UNDEFINED) + return 0; ++ if (file->ignore_unreachables) ++ return 0; ++ + WARN("%s: unexpected end of section", sec->name); + return 1; + } +@@ -3940,6 +3959,9 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) + break; + } + ++ if (insn->dead_end) ++ return 0; ++ + if (!next) { + WARN_INSN(insn, "teh end!"); + return -1; +diff --git a/tools/testing/selftests/mincore/mincore_selftest.c b/tools/testing/selftests/mincore/mincore_selftest.c +index e949a43a614508..efabfcbe0b498c 100644 +--- a/tools/testing/selftests/mincore/mincore_selftest.c ++++ b/tools/testing/selftests/mincore/mincore_selftest.c +@@ -261,9 +261,6 @@ TEST(check_file_mmap) + TH_LOG("No read-ahead pages found in memory"); + } + +- EXPECT_LT(i, vec_size) { +- TH_LOG("Read-ahead pages reached the end of the file"); +- } + /* + * End of the readahead window. The rest of the pages shouldn't + * be in memory. +diff --git a/tools/testing/selftests/ublk/test_stripe_04.sh b/tools/testing/selftests/ublk/test_stripe_04.sh +new file mode 100755 +index 00000000000000..1f2b642381d179 +--- /dev/null ++++ b/tools/testing/selftests/ublk/test_stripe_04.sh +@@ -0,0 +1,24 @@ ++#!/bin/bash ++# SPDX-License-Identifier: GPL-2.0 ++ ++. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh ++ ++TID="stripe_04" ++ERR_CODE=0 ++ ++_prep_test "stripe" "mkfs & mount & umount on zero copy" ++ ++backfile_0=$(_create_backfile 256M) ++backfile_1=$(_create_backfile 256M) ++dev_id=$(_add_ublk_dev -t stripe -z -q 2 "$backfile_0" "$backfile_1") ++_check_add_dev $TID $? "$backfile_0" "$backfile_1" ++ ++_mkfs_mount_test /dev/ublkb"${dev_id}" ++ERR_CODE=$? ++ ++_cleanup_test "stripe" ++ ++_remove_backfile "$backfile_0" ++_remove_backfile "$backfile_1" ++ ++_show_result $TID $ERR_CODE diff --git a/patch/kernel/archive/spacemit-6.6/patch-6.6.89-90.patch b/patch/kernel/archive/spacemit-6.6/patch-6.6.89-90.patch new file mode 100644 index 000000000000..ef784cc2c4ca --- /dev/null +++ b/patch/kernel/archive/spacemit-6.6/patch-6.6.89-90.patch @@ -0,0 +1,5797 @@ +diff --git a/Makefile b/Makefile +index 23e90df5785c84..587a1586e76db8 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 89 ++SUBLEVEL = 90 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi +index f2386dcb9ff2c0..dda4fa91b2f2cc 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi +@@ -40,6 +40,9 @@ ethphy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&gpio4>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; ++ micrel,led-mode = <1>; ++ clocks = <&clks IMX6UL_CLK_ENET_REF>; ++ clock-names = "rmii-ref"; + status = "okay"; + }; + }; +diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi +index 5268a43218415f..ce5409acae1ce0 100644 +--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi ++++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi +@@ -73,14 +73,13 @@ scmi_reset: protocol@16 { + }; + + intc: interrupt-controller@4ac00000 { +- compatible = "arm,cortex-a7-gic"; ++ compatible = "arm,gic-400"; + #interrupt-cells = <3>; +- #address-cells = <1>; + interrupt-controller; + reg = <0x0 0x4ac10000 0x0 0x1000>, +- <0x0 0x4ac20000 0x0 0x2000>, +- <0x0 0x4ac40000 0x0 0x2000>, +- <0x0 0x4ac60000 0x0 0x2000>; ++ <0x0 0x4ac20000 0x0 0x20000>, ++ <0x0 0x4ac40000 0x0 0x20000>, ++ <0x0 0x4ac60000 0x0 0x20000>; + }; + + psci { +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index ecfbff6991bb5d..edc4c727783d82 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -879,10 +879,12 @@ static u8 spectre_bhb_loop_affected(void) + static const struct midr_range spectre_bhb_k132_list[] = { + MIDR_ALL_VERSIONS(MIDR_CORTEX_X3), + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2), ++ {}, + }; + static const struct midr_range spectre_bhb_k38_list[] = { + MIDR_ALL_VERSIONS(MIDR_CORTEX_A715), + MIDR_ALL_VERSIONS(MIDR_CORTEX_A720), ++ {}, + }; + static const struct midr_range spectre_bhb_k32_list[] = { + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78), +diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c +index 6ce427b58836c5..ecd27b48d61f9d 100644 +--- a/arch/parisc/math-emu/driver.c ++++ b/arch/parisc/math-emu/driver.c +@@ -103,9 +103,19 @@ handle_fpe(struct pt_regs *regs) + + memcpy(regs->fr, frcopy, sizeof regs->fr); + if (signalcode != 0) { +- force_sig_fault(signalcode >> 24, signalcode & 0xffffff, +- (void __user *) regs->iaoq[0]); +- return -1; ++ int sig = signalcode >> 24; ++ ++ if (sig == SIGFPE) { ++ /* ++ * Clear floating point trap bit to avoid trapping ++ * again on the first floating-point instruction in ++ * the userspace signal handler. ++ */ ++ regs->fr[0] &= ~(1ULL << 38); ++ } ++ force_sig_fault(sig, signalcode & 0xffffff, ++ (void __user *) regs->iaoq[0]); ++ return -1; + } + + return signalcode ? -1 : 0; +diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper +index 352d7de24018fb..ddb02cf0caaf59 100755 +--- a/arch/powerpc/boot/wrapper ++++ b/arch/powerpc/boot/wrapper +@@ -234,10 +234,8 @@ fi + + # suppress some warnings in recent ld versions + nowarn="-z noexecstack" +-if ! ld_is_lld; then +- if [ "$LD_VERSION" -ge "$(echo 2.39 | ld_version)" ]; then +- nowarn="$nowarn --no-warn-rwx-segments" +- fi ++if "${CROSS}ld" -v --no-warn-rwx-segments >/dev/null 2>&1; then ++ nowarn="$nowarn --no-warn-rwx-segments" + fi + + platformo=$object/"$platform".o +diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c +index c6a4ac766b2bf9..28460e33408084 100644 +--- a/arch/powerpc/mm/book3s64/radix_pgtable.c ++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c +@@ -1056,6 +1056,19 @@ int __meminit radix__vmemmap_populate(unsigned long start, unsigned long end, in + pmd_t *pmd; + pte_t *pte; + ++ /* ++ * Make sure we align the start vmemmap addr so that we calculate ++ * the correct start_pfn in altmap boundary check to decided whether ++ * we should use altmap or RAM based backing memory allocation. Also ++ * the address need to be aligned for set_pte operation. ++ ++ * If the start addr is already PMD_SIZE aligned we will try to use ++ * a pmd mapping. We don't want to be too aggressive here beacause ++ * that will cause more allocations in RAM. So only if the namespace ++ * vmemmap start addr is PMD_SIZE aligned we will use PMD mapping. ++ */ ++ ++ start = ALIGN_DOWN(start, PAGE_SIZE); + for (addr = start; addr < end; addr = next) { + next = pmd_addr_end(addr, end); + +@@ -1081,8 +1094,8 @@ int __meminit radix__vmemmap_populate(unsigned long start, unsigned long end, in + * in altmap block allocation failures, in which case + * we fallback to RAM for vmemmap allocation. + */ +- if (altmap && (!IS_ALIGNED(addr, PMD_SIZE) || +- altmap_cross_boundary(altmap, addr, PMD_SIZE))) { ++ if (!IS_ALIGNED(addr, PMD_SIZE) || (altmap && ++ altmap_cross_boundary(altmap, addr, PMD_SIZE))) { + /* + * make sure we don't create altmap mappings + * covering things outside the device. +diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h +index 9f5d6e14c40553..7228e266b9a1ae 100644 +--- a/arch/riscv/include/asm/patch.h ++++ b/arch/riscv/include/asm/patch.h +@@ -9,7 +9,7 @@ + int patch_insn_write(void *addr, const void *insn, size_t len); + int patch_text_nosync(void *addr, const void *insns, size_t len); + int patch_text_set_nosync(void *addr, u8 c, size_t len); +-int patch_text(void *addr, u32 *insns, int ninsns); ++int patch_text(void *addr, u32 *insns, size_t len); + + extern int riscv_patch_in_stop_machine; + +diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c +index 78387d843aa56b..aeda87240dbc1e 100644 +--- a/arch/riscv/kernel/patch.c ++++ b/arch/riscv/kernel/patch.c +@@ -19,7 +19,7 @@ + struct patch_insn { + void *addr; + u32 *insns; +- int ninsns; ++ size_t len; + atomic_t cpu_count; + }; + +@@ -234,14 +234,10 @@ NOKPROBE_SYMBOL(patch_text_nosync); + static int patch_text_cb(void *data) + { + struct patch_insn *patch = data; +- unsigned long len; +- int i, ret = 0; ++ int ret = 0; + + if (atomic_inc_return(&patch->cpu_count) == num_online_cpus()) { +- for (i = 0; ret == 0 && i < patch->ninsns; i++) { +- len = GET_INSN_LENGTH(patch->insns[i]); +- ret = patch_insn_write(patch->addr + i * len, &patch->insns[i], len); +- } ++ ret = patch_insn_write(patch->addr, patch->insns, patch->len); + /* + * Make sure the patching store is effective *before* we + * increment the counter which releases all waiting CPUs +@@ -262,13 +258,13 @@ static int patch_text_cb(void *data) + } + NOKPROBE_SYMBOL(patch_text_cb); + +-int patch_text(void *addr, u32 *insns, int ninsns) ++int patch_text(void *addr, u32 *insns, size_t len) + { + int ret; + struct patch_insn patch = { + .addr = addr, + .insns = insns, +- .ninsns = ninsns, ++ .len = len, + .cpu_count = ATOMIC_INIT(0), + }; + +diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c +index 4fbc70e823f0fa..297427ffc4e043 100644 +--- a/arch/riscv/kernel/probes/kprobes.c ++++ b/arch/riscv/kernel/probes/kprobes.c +@@ -23,13 +23,13 @@ post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *); + + static void __kprobes arch_prepare_ss_slot(struct kprobe *p) + { ++ size_t len = GET_INSN_LENGTH(p->opcode); + u32 insn = __BUG_INSN_32; +- unsigned long offset = GET_INSN_LENGTH(p->opcode); + +- p->ainsn.api.restore = (unsigned long)p->addr + offset; ++ p->ainsn.api.restore = (unsigned long)p->addr + len; + +- patch_text_nosync(p->ainsn.api.insn, &p->opcode, 1); +- patch_text_nosync((void *)p->ainsn.api.insn + offset, &insn, 1); ++ patch_text_nosync(p->ainsn.api.insn, &p->opcode, len); ++ patch_text_nosync((void *)p->ainsn.api.insn + len, &insn, GET_INSN_LENGTH(insn)); + } + + static void __kprobes arch_prepare_simulate(struct kprobe *p) +@@ -116,16 +116,18 @@ void *alloc_insn_page(void) + /* install breakpoint in text */ + void __kprobes arch_arm_kprobe(struct kprobe *p) + { +- u32 insn = (p->opcode & __INSN_LENGTH_MASK) == __INSN_LENGTH_32 ? +- __BUG_INSN_32 : __BUG_INSN_16; ++ size_t len = GET_INSN_LENGTH(p->opcode); ++ u32 insn = len == 4 ? __BUG_INSN_32 : __BUG_INSN_16; + +- patch_text(p->addr, &insn, 1); ++ patch_text(p->addr, &insn, len); + } + + /* remove breakpoint from text */ + void __kprobes arch_disarm_kprobe(struct kprobe *p) + { +- patch_text(p->addr, &p->opcode, 1); ++ size_t len = GET_INSN_LENGTH(p->opcode); ++ ++ patch_text(p->addr, &p->opcode, len); + } + + void __kprobes arch_remove_kprobe(struct kprobe *p) +diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c +index 26eeb397363193..16eb4cd11cbd67 100644 +--- a/arch/riscv/net/bpf_jit_comp64.c ++++ b/arch/riscv/net/bpf_jit_comp64.c +@@ -14,6 +14,7 @@ + #include "bpf_jit.h" + + #define RV_FENTRY_NINSNS 2 ++#define RV_FENTRY_NBYTES (RV_FENTRY_NINSNS * 4) + + #define RV_REG_TCC RV_REG_A6 + #define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */ +@@ -681,7 +682,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + if (ret) + return ret; + +- if (memcmp(ip, old_insns, RV_FENTRY_NINSNS * 4)) ++ if (memcmp(ip, old_insns, RV_FENTRY_NBYTES)) + return -EFAULT; + + ret = gen_jump_or_nops(new_addr, ip, new_insns, is_call); +@@ -690,8 +691,8 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + + cpus_read_lock(); + mutex_lock(&text_mutex); +- if (memcmp(ip, new_insns, RV_FENTRY_NINSNS * 4)) +- ret = patch_text(ip, new_insns, RV_FENTRY_NINSNS); ++ if (memcmp(ip, new_insns, RV_FENTRY_NBYTES)) ++ ret = patch_text(ip, new_insns, RV_FENTRY_NBYTES); + mutex_unlock(&text_mutex); + cpus_read_unlock(); + +diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c +index 66d5782df18f8c..835c9febb6a854 100644 +--- a/arch/x86/events/intel/core.c ++++ b/arch/x86/events/intel/core.c +@@ -4206,7 +4206,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) + arr[pebs_enable] = (struct perf_guest_switch_msr){ + .msr = MSR_IA32_PEBS_ENABLE, + .host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask, +- .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask, ++ .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask & kvm_pmu->pebs_enable, + }; + + if (arr[pebs_enable].host) { +diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h +index 9b419f0de713cc..e59ded9761663e 100644 +--- a/arch/x86/include/asm/kvm-x86-ops.h ++++ b/arch/x86/include/asm/kvm-x86-ops.h +@@ -48,6 +48,7 @@ KVM_X86_OP(set_idt) + KVM_X86_OP(get_gdt) + KVM_X86_OP(set_gdt) + KVM_X86_OP(sync_dirty_debug_regs) ++KVM_X86_OP(set_dr6) + KVM_X86_OP(set_dr7) + KVM_X86_OP(cache_reg) + KVM_X86_OP(get_rflags) +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index 39672561c6be87..5dfb8cc9616e55 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -1595,6 +1595,7 @@ struct kvm_x86_ops { + void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); + void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); + void (*sync_dirty_debug_regs)(struct kvm_vcpu *vcpu); ++ void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value); + void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value); + void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); + unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index 1d06b8fc15a85c..29c1be65cb71a0 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -2014,11 +2014,11 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd) + svm->asid = sd->next_asid++; + } + +-static void svm_set_dr6(struct vcpu_svm *svm, unsigned long value) ++static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value) + { +- struct vmcb *vmcb = svm->vmcb; ++ struct vmcb *vmcb = to_svm(vcpu)->vmcb; + +- if (svm->vcpu.arch.guest_state_protected) ++ if (vcpu->arch.guest_state_protected) + return; + + if (unlikely(value != vmcb->save.dr6)) { +@@ -4220,10 +4220,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) + * Run with all-zero DR6 unless needed, so that we can get the exact cause + * of a #DB. + */ +- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) +- svm_set_dr6(svm, vcpu->arch.dr6); +- else +- svm_set_dr6(svm, DR6_ACTIVE_LOW); ++ if (likely(!(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))) ++ svm_set_dr6(vcpu, DR6_ACTIVE_LOW); + + clgi(); + kvm_load_guest_xsave_state(vcpu); +@@ -5002,6 +5000,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { + .set_idt = svm_set_idt, + .get_gdt = svm_get_gdt, + .set_gdt = svm_set_gdt, ++ .set_dr6 = svm_set_dr6, + .set_dr7 = svm_set_dr7, + .sync_dirty_debug_regs = svm_sync_dirty_debug_regs, + .cache_reg = svm_cache_reg, +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index 52098844290ad4..e5a2c230110ea4 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -5617,6 +5617,12 @@ static void vmx_sync_dirty_debug_regs(struct kvm_vcpu *vcpu) + set_debugreg(DR6_RESERVED, 6); + } + ++static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val) ++{ ++ lockdep_assert_irqs_disabled(); ++ set_debugreg(vcpu->arch.dr6, 6); ++} ++ + static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val) + { + vmcs_writel(GUEST_DR7, val); +@@ -7356,10 +7362,6 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu) + vmx->loaded_vmcs->host_state.cr4 = cr4; + } + +- /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */ +- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) +- set_debugreg(vcpu->arch.dr6, 6); +- + /* When single-stepping over STI and MOV SS, we must clear the + * corresponding interruptibility bits in the guest state. Otherwise + * vmentry fails as it then expects bit 14 (BS) in pending debug +@@ -8292,6 +8294,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { + .set_idt = vmx_set_idt, + .get_gdt = vmx_get_gdt, + .set_gdt = vmx_set_gdt, ++ .set_dr6 = vmx_set_dr6, + .set_dr7 = vmx_set_dr7, + .sync_dirty_debug_regs = vmx_sync_dirty_debug_regs, + .cache_reg = vmx_cache_reg, +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index f67fe8a65820c8..1eeb01afa40ba9 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -10772,6 +10772,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) + set_debugreg(vcpu->arch.eff_db[1], 1); + set_debugreg(vcpu->arch.eff_db[2], 2); + set_debugreg(vcpu->arch.eff_db[3], 3); ++ /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */ ++ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) ++ static_call(kvm_x86_set_dr6)(vcpu, vcpu->arch.dr6); + } else if (unlikely(hw_breakpoint_active())) { + set_debugreg(0, 7); + } +diff --git a/drivers/base/module.c b/drivers/base/module.c +index a33663d92256d8..955582b34e54af 100644 +--- a/drivers/base/module.c ++++ b/drivers/base/module.c +@@ -42,16 +42,13 @@ int module_add_driver(struct module *mod, struct device_driver *drv) + if (mod) + mk = &mod->mkobj; + else if (drv->mod_name) { +- struct kobject *mkobj; +- +- /* Lookup built-in module entry in /sys/modules */ +- mkobj = kset_find_obj(module_kset, drv->mod_name); +- if (mkobj) { +- mk = container_of(mkobj, struct module_kobject, kobj); ++ /* Lookup or create built-in module entry in /sys/modules */ ++ mk = lookup_or_create_module_kobject(drv->mod_name); ++ if (mk) { + /* remember our module structure */ + drv->p->mkobj = mk; +- /* kset_find_obj took a reference */ +- kobject_put(mkobj); ++ /* lookup_or_create_module_kobject took a reference */ ++ kobject_put(&mk->kobj); + } + } + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index bc3f63f1ccd863..d6195565ef7aeb 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -3521,22 +3521,16 @@ static void btusb_coredump_qca(struct hci_dev *hdev) + bt_dev_err(hdev, "%s: triggle crash failed (%d)", __func__, err); + } + +-/* +- * ==0: not a dump pkt. +- * < 0: fails to handle a dump pkt +- * > 0: otherwise. +- */ ++/* Return: 0 on success, negative errno on failure. */ + static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- int ret = 1; ++ int ret = 0; + u8 pkt_type; + u8 *sk_ptr; + unsigned int sk_len; + u16 seqno; + u32 dump_size; + +- struct hci_event_hdr *event_hdr; +- struct hci_acl_hdr *acl_hdr; + struct qca_dump_hdr *dump_hdr; + struct btusb_data *btdata = hci_get_drvdata(hdev); + struct usb_device *udev = btdata->udev; +@@ -3546,30 +3540,14 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + sk_len = skb->len; + + if (pkt_type == HCI_ACLDATA_PKT) { +- acl_hdr = hci_acl_hdr(skb); +- if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE) +- return 0; + sk_ptr += HCI_ACL_HDR_SIZE; + sk_len -= HCI_ACL_HDR_SIZE; +- event_hdr = (struct hci_event_hdr *)sk_ptr; +- } else { +- event_hdr = hci_event_hdr(skb); + } + +- if ((event_hdr->evt != HCI_VENDOR_PKT) +- || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) +- return 0; +- + sk_ptr += HCI_EVENT_HDR_SIZE; + sk_len -= HCI_EVENT_HDR_SIZE; + + dump_hdr = (struct qca_dump_hdr *)sk_ptr; +- if ((sk_len < offsetof(struct qca_dump_hdr, data)) +- || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) +- || (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) +- return 0; +- +- /*it is dump pkt now*/ + seqno = le16_to_cpu(dump_hdr->seqno); + if (seqno == 0) { + set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags); +@@ -3643,17 +3621,84 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + return ret; + } + ++/* Return: true if the ACL packet is a dump packet, false otherwise. */ ++static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ u8 *sk_ptr; ++ unsigned int sk_len; ++ ++ struct hci_event_hdr *event_hdr; ++ struct hci_acl_hdr *acl_hdr; ++ struct qca_dump_hdr *dump_hdr; ++ ++ sk_ptr = skb->data; ++ sk_len = skb->len; ++ ++ acl_hdr = hci_acl_hdr(skb); ++ if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE) ++ return false; ++ ++ sk_ptr += HCI_ACL_HDR_SIZE; ++ sk_len -= HCI_ACL_HDR_SIZE; ++ event_hdr = (struct hci_event_hdr *)sk_ptr; ++ ++ if ((event_hdr->evt != HCI_VENDOR_PKT) || ++ (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) ++ return false; ++ ++ sk_ptr += HCI_EVENT_HDR_SIZE; ++ sk_len -= HCI_EVENT_HDR_SIZE; ++ ++ dump_hdr = (struct qca_dump_hdr *)sk_ptr; ++ if ((sk_len < offsetof(struct qca_dump_hdr, data)) || ++ (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ return false; ++ ++ return true; ++} ++ ++/* Return: true if the event packet is a dump packet, false otherwise. */ ++static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ u8 *sk_ptr; ++ unsigned int sk_len; ++ ++ struct hci_event_hdr *event_hdr; ++ struct qca_dump_hdr *dump_hdr; ++ ++ sk_ptr = skb->data; ++ sk_len = skb->len; ++ ++ event_hdr = hci_event_hdr(skb); ++ ++ if ((event_hdr->evt != HCI_VENDOR_PKT) ++ || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) ++ return false; ++ ++ sk_ptr += HCI_EVENT_HDR_SIZE; ++ sk_len -= HCI_EVENT_HDR_SIZE; ++ ++ dump_hdr = (struct qca_dump_hdr *)sk_ptr; ++ if ((sk_len < offsetof(struct qca_dump_hdr, data)) || ++ (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ return false; ++ ++ return true; ++} ++ + static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- if (handle_dump_pkt_qca(hdev, skb)) +- return 0; ++ if (acl_pkt_is_dump_qca(hdev, skb)) ++ return handle_dump_pkt_qca(hdev, skb); + return hci_recv_frame(hdev, skb); + } + + static int btusb_recv_evt_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- if (handle_dump_pkt_qca(hdev, skb)) +- return 0; ++ if (evt_pkt_is_dump_qca(hdev, skb)) ++ return handle_dump_pkt_qca(hdev, skb); + return hci_recv_frame(hdev, skb); + } + +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 0ac0998152ce81..6682f422cadd90 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -534,16 +534,18 @@ void cpufreq_disable_fast_switch(struct cpufreq_policy *policy) + EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch); + + static unsigned int __resolve_freq(struct cpufreq_policy *policy, +- unsigned int target_freq, unsigned int relation) ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ unsigned int relation) + { + unsigned int idx; + +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (!policy->freq_table) + return target_freq; + +- idx = cpufreq_frequency_table_target(policy, target_freq, relation); ++ idx = cpufreq_frequency_table_target(policy, target_freq, min, max, relation); + policy->cached_resolved_idx = idx; + policy->cached_target_freq = target_freq; + return policy->freq_table[idx].frequency; +@@ -563,7 +565,21 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy, + unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy, + unsigned int target_freq) + { +- return __resolve_freq(policy, target_freq, CPUFREQ_RELATION_LE); ++ unsigned int min = READ_ONCE(policy->min); ++ unsigned int max = READ_ONCE(policy->max); ++ ++ /* ++ * If this function runs in parallel with cpufreq_set_policy(), it may ++ * read policy->min before the update and policy->max after the update ++ * or the other way around, so there is no ordering guarantee. ++ * ++ * Resolve this by always honoring the max (in case it comes from ++ * thermal throttling or similar). ++ */ ++ if (unlikely(min > max)) ++ min = max; ++ ++ return __resolve_freq(policy, target_freq, min, max, CPUFREQ_RELATION_LE); + } + EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq); + +@@ -2335,7 +2351,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, + if (cpufreq_disabled()) + return -ENODEV; + +- target_freq = __resolve_freq(policy, target_freq, relation); ++ target_freq = __resolve_freq(policy, target_freq, policy->min, ++ policy->max, relation); + + pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", + policy->cpu, target_freq, relation, old_target_freq); +@@ -2625,11 +2642,18 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, + * Resolve policy min/max to available frequencies. It ensures + * no frequency resolution will neither overshoot the requested maximum + * nor undershoot the requested minimum. ++ * ++ * Avoid storing intermediate values in policy->max or policy->min and ++ * compiler optimizations around them because they may be accessed ++ * concurrently by cpufreq_driver_resolve_freq() during the update. + */ +- policy->min = new_data.min; +- policy->max = new_data.max; +- policy->min = __resolve_freq(policy, policy->min, CPUFREQ_RELATION_L); +- policy->max = __resolve_freq(policy, policy->max, CPUFREQ_RELATION_H); ++ WRITE_ONCE(policy->max, __resolve_freq(policy, new_data.max, ++ new_data.min, new_data.max, ++ CPUFREQ_RELATION_H)); ++ new_data.min = __resolve_freq(policy, new_data.min, new_data.min, ++ new_data.max, CPUFREQ_RELATION_L); ++ WRITE_ONCE(policy->min, new_data.min > policy->max ? policy->max : new_data.min); ++ + trace_cpu_frequency_limits(policy); + + policy->cached_target_freq = UINT_MAX; +diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c +index c52d19d67557f5..65cbd5ecbaf83d 100644 +--- a/drivers/cpufreq/cpufreq_ondemand.c ++++ b/drivers/cpufreq/cpufreq_ondemand.c +@@ -77,7 +77,8 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy, + return freq_next; + } + +- index = cpufreq_frequency_table_target(policy, freq_next, relation); ++ index = cpufreq_frequency_table_target(policy, freq_next, policy->min, ++ policy->max, relation); + freq_req = freq_table[index].frequency; + freq_reduc = freq_req * od_tuners->powersave_bias / 1000; + freq_avg = freq_req - freq_reduc; +diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c +index c17dc51a5a022d..94de089b145394 100644 +--- a/drivers/cpufreq/freq_table.c ++++ b/drivers/cpufreq/freq_table.c +@@ -116,8 +116,8 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy) + EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); + + int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, +- unsigned int target_freq, +- unsigned int relation) ++ unsigned int target_freq, unsigned int min, ++ unsigned int max, unsigned int relation) + { + struct cpufreq_frequency_table optimal = { + .driver_data = ~0, +@@ -148,7 +148,7 @@ int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, + cpufreq_for_each_valid_entry_idx(pos, table, i) { + freq = pos->frequency; + +- if ((freq < policy->min) || (freq > policy->max)) ++ if (freq < min || freq > max) + continue; + if (freq == target_freq) { + optimal.driver_data = i; +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index 8b31cd54bdb6de..e04fd1a7e9aaea 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -98,7 +98,7 @@ static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id) + if (status & priv->ecc_stat_ce_mask) { + regmap_read(drvdata->mc_vbase, priv->ecc_saddr_offset, + &err_addr); +- if (priv->ecc_uecnt_offset) ++ if (priv->ecc_cecnt_offset) + regmap_read(drvdata->mc_vbase, priv->ecc_cecnt_offset, + &err_count); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count, +@@ -1015,9 +1015,6 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, + } + } + +- /* Interrupt mode set to every SBERR */ +- regmap_write(ecc_mgr_map, ALTR_A10_ECC_INTMODE_OFST, +- ALTR_A10_ECC_INTMODE); + /* Enable ECC */ + ecc_set_bits(ecc_ctrl_en_mask, (ecc_block_base + + ALTR_A10_ECC_CTRL_OFST)); +@@ -2138,6 +2135,10 @@ static int altr_edac_a10_probe(struct platform_device *pdev) + return PTR_ERR(edac->ecc_mgr_map); + } + ++ /* Set irq mask for DDR SBE to avoid any pending irq before registration */ ++ regmap_write(edac->ecc_mgr_map, A10_SYSMGR_ECC_INTMASK_SET_OFST, ++ (A10_SYSMGR_ECC_INTMASK_SDMMCB | A10_SYSMGR_ECC_INTMASK_DDR0)); ++ + edac->irq_chip.name = pdev->dev.of_node->name; + edac->irq_chip.irq_mask = a10_eccmgr_irq_mask; + edac->irq_chip.irq_unmask = a10_eccmgr_irq_unmask; +diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h +index 3727e72c8c2e70..7248d24c4908d7 100644 +--- a/drivers/edac/altera_edac.h ++++ b/drivers/edac/altera_edac.h +@@ -249,6 +249,8 @@ struct altr_sdram_mc_data { + #define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94 + #define A10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98 + #define A10_SYSMGR_ECC_INTMASK_OCRAM BIT(1) ++#define A10_SYSMGR_ECC_INTMASK_SDMMCB BIT(16) ++#define A10_SYSMGR_ECC_INTMASK_DDR0 BIT(17) + + #define A10_SYSMGR_ECC_INTSTAT_SERR_OFST 0x9C + #define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0 +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 7cd6b1564e8018..7c2db3f017651b 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -225,7 +225,8 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, + memcpy(buffer + idx, drv_info->rx_buffer + idx * sz, + buf_sz); + +- ffa_rx_release(); ++ if (!(flags & PARTITION_INFO_GET_RETURN_COUNT_ONLY)) ++ ffa_rx_release(); + + mutex_unlock(&drv_info->rx_lock); + +diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c +index dcf774d3edfe4c..51eeaf14367dac 100644 +--- a/drivers/firmware/arm_scmi/bus.c ++++ b/drivers/firmware/arm_scmi/bus.c +@@ -240,6 +240,9 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent, + if (!dev) + return NULL; + ++ /* Drop the refcnt bumped implicitly by device_find_child */ ++ put_device(dev); ++ + return to_scmi_dev(dev); + } + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +index 2ad9f900a85749..a048022d9865a7 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +@@ -172,7 +172,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, + struct mod_hdcp_display_adjustment display_adjust; + unsigned int conn_index = aconnector->base.index; + +- mutex_lock(&hdcp_w->mutex); ++ guard(mutex)(&hdcp_w->mutex); ++ drm_connector_get(&aconnector->base); ++ if (hdcp_w->aconnector[conn_index]) ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); + hdcp_w->aconnector[conn_index] = aconnector; + + memset(&link_adjust, 0, sizeof(link_adjust)); +@@ -209,7 +212,6 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, + mod_hdcp_update_display(&hdcp_w->hdcp, conn_index, &link_adjust, &display_adjust, &hdcp_w->output); + + process_output(hdcp_w); +- mutex_unlock(&hdcp_w->mutex); + } + + static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, +@@ -220,8 +222,7 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, + struct drm_connector_state *conn_state = aconnector->base.state; + unsigned int conn_index = aconnector->base.index; + +- mutex_lock(&hdcp_w->mutex); +- hdcp_w->aconnector[conn_index] = aconnector; ++ guard(mutex)(&hdcp_w->mutex); + + /* the removal of display will invoke auth reset -> hdcp destroy and + * we'd expect the Content Protection (CP) property changed back to +@@ -237,9 +238,11 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, + } + + mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output); +- ++ if (hdcp_w->aconnector[conn_index]) { ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); ++ hdcp_w->aconnector[conn_index] = NULL; ++ } + process_output(hdcp_w); +- mutex_unlock(&hdcp_w->mutex); + } + + void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index) +@@ -247,7 +250,7 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde + struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; + unsigned int conn_index; + +- mutex_lock(&hdcp_w->mutex); ++ guard(mutex)(&hdcp_w->mutex); + + mod_hdcp_reset_connection(&hdcp_w->hdcp, &hdcp_w->output); + +@@ -256,11 +259,13 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde + for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) { + hdcp_w->encryption_status[conn_index] = + MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; ++ if (hdcp_w->aconnector[conn_index]) { ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); ++ hdcp_w->aconnector[conn_index] = NULL; ++ } + } + + process_output(hdcp_w); +- +- mutex_unlock(&hdcp_w->mutex); + } + + void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, unsigned int link_index) +@@ -277,7 +282,7 @@ static void event_callback(struct work_struct *work) + hdcp_work = container_of(to_delayed_work(work), struct hdcp_workqueue, + callback_dwork); + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + cancel_delayed_work(&hdcp_work->callback_dwork); + +@@ -285,8 +290,6 @@ static void event_callback(struct work_struct *work) + &hdcp_work->output); + + process_output(hdcp_work); +- +- mutex_unlock(&hdcp_work->mutex); + } + + static void event_property_update(struct work_struct *work) +@@ -323,7 +326,7 @@ static void event_property_update(struct work_struct *work) + continue; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + if (conn_state->commit) { + ret = wait_for_completion_interruptible_timeout(&conn_state->commit->hw_done, +@@ -355,7 +358,6 @@ static void event_property_update(struct work_struct *work) + drm_hdcp_update_content_protection(connector, + DRM_MODE_CONTENT_PROTECTION_DESIRED); + } +- mutex_unlock(&hdcp_work->mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); + } + } +@@ -368,7 +370,7 @@ static void event_property_validate(struct work_struct *work) + struct amdgpu_dm_connector *aconnector; + unsigned int conn_index; + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; + conn_index++) { +@@ -408,8 +410,6 @@ static void event_property_validate(struct work_struct *work) + schedule_work(&hdcp_work->property_update_work); + } + } +- +- mutex_unlock(&hdcp_work->mutex); + } + + static void event_watchdog_timer(struct work_struct *work) +@@ -420,7 +420,7 @@ static void event_watchdog_timer(struct work_struct *work) + struct hdcp_workqueue, + watchdog_timer_dwork); + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + cancel_delayed_work(&hdcp_work->watchdog_timer_dwork); + +@@ -429,8 +429,6 @@ static void event_watchdog_timer(struct work_struct *work) + &hdcp_work->output); + + process_output(hdcp_work); +- +- mutex_unlock(&hdcp_work->mutex); + } + + static void event_cpirq(struct work_struct *work) +@@ -439,13 +437,11 @@ static void event_cpirq(struct work_struct *work) + + hdcp_work = container_of(work, struct hdcp_workqueue, cpirq_work); + +- mutex_lock(&hdcp_work->mutex); ++ guard(mutex)(&hdcp_work->mutex); + + mod_hdcp_process_event(&hdcp_work->hdcp, MOD_HDCP_EVENT_CPIRQ, &hdcp_work->output); + + process_output(hdcp_work); +- +- mutex_unlock(&hdcp_work->mutex); + } + + void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work) +@@ -479,7 +475,7 @@ static bool enable_assr(void *handle, struct dc_link *link) + + dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.context.mem_context.shared_buf; + +- mutex_lock(&psp->dtm_context.mutex); ++ guard(mutex)(&psp->dtm_context.mutex); + memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory)); + + dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE; +@@ -494,8 +490,6 @@ static bool enable_assr(void *handle, struct dc_link *link) + res = false; + } + +- mutex_unlock(&psp->dtm_context.mutex); +- + return res; + } + +@@ -504,6 +498,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) + struct hdcp_workqueue *hdcp_work = handle; + struct amdgpu_dm_connector *aconnector = config->dm_stream_ctx; + int link_index = aconnector->dc_link->link_index; ++ unsigned int conn_index = aconnector->base.index; + struct mod_hdcp_display *display = &hdcp_work[link_index].display; + struct mod_hdcp_link *link = &hdcp_work[link_index].link; + struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; +@@ -557,13 +552,14 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) + (!!aconnector->base.state) ? + aconnector->base.state->hdcp_content_type : -1); + +- mutex_lock(&hdcp_w->mutex); ++ guard(mutex)(&hdcp_w->mutex); + + mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output); +- ++ drm_connector_get(&aconnector->base); ++ if (hdcp_w->aconnector[conn_index]) ++ drm_connector_put(&hdcp_w->aconnector[conn_index]->base); ++ hdcp_w->aconnector[conn_index] = aconnector; + process_output(hdcp_w); +- mutex_unlock(&hdcp_w->mutex); +- + } + + /** +diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c +index 1d22dba69b2753..b943221b238f87 100644 +--- a/drivers/gpu/drm/drm_file.c ++++ b/drivers/gpu/drm/drm_file.c +@@ -1015,6 +1015,10 @@ void drm_show_fdinfo(struct seq_file *m, struct file *f) + struct drm_file *file = f->private_data; + struct drm_device *dev = file->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); ++ int idx; ++ ++ if (!drm_dev_enter(dev, &idx)) ++ return; + + drm_printf(&p, "drm-driver:\t%s\n", dev->driver->name); + drm_printf(&p, "drm-client-id:\t%llu\n", file->client_id); +@@ -1029,6 +1033,8 @@ void drm_show_fdinfo(struct seq_file *m, struct file *f) + + if (dev->driver->show_fdinfo) + dev->driver->show_fdinfo(&p, file); ++ ++ drm_dev_exit(idx); + } + EXPORT_SYMBOL(drm_show_fdinfo); + +diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h +index 298ad38e6c7df6..c36d956b9b824f 100644 +--- a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h ++++ b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h +@@ -25,6 +25,7 @@ int intel_pxp_gsccs_init(struct intel_pxp *pxp); + + int intel_pxp_gsccs_create_session(struct intel_pxp *pxp, int arb_session_id); + void intel_pxp_gsccs_end_arb_fw_session(struct intel_pxp *pxp, u32 arb_session_id); ++bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp); + + #else + static inline void intel_pxp_gsccs_fini(struct intel_pxp *pxp) +@@ -36,8 +37,11 @@ static inline int intel_pxp_gsccs_init(struct intel_pxp *pxp) + return 0; + } + +-#endif ++static inline bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp) ++{ ++ return false; ++} + +-bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp); ++#endif + + #endif /*__INTEL_PXP_GSCCS_H__ */ +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index 2a942dc6a6dc23..2a82119eb58ed8 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -790,13 +790,13 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, + FREQ_1000_1001(params[i].pixel_freq)); + DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", + i, params[i].phy_freq, +- FREQ_1000_1001(params[i].phy_freq/1000)*1000); ++ FREQ_1000_1001(params[i].phy_freq/10)*10); + /* Match strict frequency */ + if (phy_freq == params[i].phy_freq && + vclk_freq == params[i].vclk_freq) + return MODE_OK; + /* Match 1000/1001 variant */ +- if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/1000)*1000) && ++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && + vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) + return MODE_OK; + } +@@ -1070,7 +1070,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + + for (freq = 0 ; params[freq].pixel_freq ; ++freq) { + if ((phy_freq == params[freq].phy_freq || +- phy_freq == FREQ_1000_1001(params[freq].phy_freq/1000)*1000) && ++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && + (vclk_freq == params[freq].vclk_freq || + vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { + if (vclk_freq != params[freq].vclk_freq) +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c +index 03eacb22648ef7..1bfa312d6fb857 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.c ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.c +@@ -90,7 +90,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) + while (!list_empty(&fctx->pending)) { + fence = list_entry(fctx->pending.next, typeof(*fence), head); + +- if (error) ++ if (error && !dma_fence_is_signaled_locked(&fence->base)) + dma_fence_set_error(&fence->base, error); + + if (nouveau_fence_signal(fence)) +diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c +index 5d4f04a3c6d322..b44b36bd565ea4 100644 +--- a/drivers/i2c/busses/i2c-imx-lpi2c.c ++++ b/drivers/i2c/busses/i2c-imx-lpi2c.c +@@ -616,9 +616,9 @@ static int lpi2c_imx_probe(struct platform_device *pdev) + return 0; + + rpm_disable: +- pm_runtime_put(&pdev->dev); +- pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); + + return ret; + } +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index ef3fae113dd643..2e7a12f306510c 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -3682,6 +3682,14 @@ static int __init parse_ivrs_acpihid(char *str) + while (*uid == '0' && *(uid + 1)) + uid++; + ++ if (strlen(hid) >= ACPIHID_HID_LEN) { ++ pr_err("Invalid command line: hid is too long\n"); ++ return 1; ++ } else if (strlen(uid) >= ACPIHID_UID_LEN) { ++ pr_err("Invalid command line: uid is too long\n"); ++ return 1; ++ } ++ + i = early_acpihid_map_size++; + memcpy(early_acpihid_map[i].hid, hid, strlen(hid)); + memcpy(early_acpihid_map[i].uid, uid, strlen(uid)); +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +index 6cecbac0e6babf..f2260f45728e79 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +@@ -1443,26 +1443,37 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid) + return 0; + } + ++static int arm_smmu_streams_cmp_key(const void *lhs, const struct rb_node *rhs) ++{ ++ struct arm_smmu_stream *stream_rhs = ++ rb_entry(rhs, struct arm_smmu_stream, node); ++ const u32 *sid_lhs = lhs; ++ ++ if (*sid_lhs < stream_rhs->id) ++ return -1; ++ if (*sid_lhs > stream_rhs->id) ++ return 1; ++ return 0; ++} ++ ++static int arm_smmu_streams_cmp_node(struct rb_node *lhs, ++ const struct rb_node *rhs) ++{ ++ return arm_smmu_streams_cmp_key( ++ &rb_entry(lhs, struct arm_smmu_stream, node)->id, rhs); ++} ++ + static struct arm_smmu_master * + arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid) + { + struct rb_node *node; +- struct arm_smmu_stream *stream; + + lockdep_assert_held(&smmu->streams_mutex); + +- node = smmu->streams.rb_node; +- while (node) { +- stream = rb_entry(node, struct arm_smmu_stream, node); +- if (stream->id < sid) +- node = node->rb_right; +- else if (stream->id > sid) +- node = node->rb_left; +- else +- return stream->master; +- } +- +- return NULL; ++ node = rb_find(&sid, &smmu->streams, arm_smmu_streams_cmp_key); ++ if (!node) ++ return NULL; ++ return rb_entry(node, struct arm_smmu_stream, node)->master; + } + + /* IRQ and event handlers */ +@@ -2575,8 +2586,6 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + { + int i; + int ret = 0; +- struct arm_smmu_stream *new_stream, *cur_stream; +- struct rb_node **new_node, *parent_node = NULL; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev); + + master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams), +@@ -2587,9 +2596,10 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + + mutex_lock(&smmu->streams_mutex); + for (i = 0; i < fwspec->num_ids; i++) { ++ struct arm_smmu_stream *new_stream = &master->streams[i]; ++ struct rb_node *existing; + u32 sid = fwspec->ids[i]; + +- new_stream = &master->streams[i]; + new_stream->id = sid; + new_stream->master = master; + +@@ -2598,28 +2608,23 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + break; + + /* Insert into SID tree */ +- new_node = &(smmu->streams.rb_node); +- while (*new_node) { +- cur_stream = rb_entry(*new_node, struct arm_smmu_stream, +- node); +- parent_node = *new_node; +- if (cur_stream->id > new_stream->id) { +- new_node = &((*new_node)->rb_left); +- } else if (cur_stream->id < new_stream->id) { +- new_node = &((*new_node)->rb_right); +- } else { +- dev_warn(master->dev, +- "stream %u already in tree\n", +- cur_stream->id); +- ret = -EINVAL; +- break; +- } +- } +- if (ret) +- break; ++ existing = rb_find_add(&new_stream->node, &smmu->streams, ++ arm_smmu_streams_cmp_node); ++ if (existing) { ++ struct arm_smmu_master *existing_master = ++ rb_entry(existing, struct arm_smmu_stream, node) ++ ->master; ++ ++ /* Bridged PCI devices may end up with duplicated IDs */ ++ if (existing_master == master) ++ continue; + +- rb_link_node(&new_stream->node, parent_node, new_node); +- rb_insert_color(&new_stream->node, &smmu->streams); ++ dev_warn(master->dev, ++ "stream %u already in tree from dev %s\n", sid, ++ dev_name(existing_master->dev)); ++ ret = -EINVAL; ++ break; ++ } + } + + if (ret) { +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index d6381c00bb8ddc..6a745616d85a4b 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -4855,6 +4855,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_igfx); + ++/* QM57/QS57 integrated gfx malfunctions with dmar */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_iommu_igfx); ++ + /* Broadwell igfx malfunctions with dmar */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1606, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160B, quirk_iommu_igfx); +@@ -4932,7 +4935,6 @@ static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev) + } + } + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt); +-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt); + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 3f1029c0825e95..f2b3a4e2e54fc8 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -566,6 +566,18 @@ int iommu_probe_device(struct device *dev) + mutex_lock(&iommu_probe_device_lock); + ret = __iommu_probe_device(dev, NULL); + mutex_unlock(&iommu_probe_device_lock); ++ ++ /* ++ * The dma_configure replay paths need bus_iommu_probe() to ++ * finish before they can call arch_setup_dma_ops() ++ */ ++ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !ret && dev->iommu_group) { ++ mutex_lock(&dev->iommu_group->mutex); ++ if (!dev->iommu_group->default_domain && ++ !dev_iommu_ops(dev)->set_platform_dma_ops) ++ ret = -EPROBE_DEFER; ++ mutex_unlock(&dev->iommu_group->mutex); ++ } + if (ret) + return ret; + +@@ -3149,6 +3161,12 @@ int iommu_device_use_default_domain(struct device *dev) + return 0; + + mutex_lock(&group->mutex); ++ /* We may race against bus_iommu_probe() finalising groups here */ ++ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !group->default_domain && ++ !dev_iommu_ops(dev)->set_platform_dma_ops) { ++ ret = -EPROBE_DEFER; ++ goto unlock_out; ++ } + if (group->owner_cnt) { + if (group->owner || !iommu_is_default_domain(group) || + !xa_empty(&group->pasid_array)) { +diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c +index 7124565234a586..0807e4aca933fb 100644 +--- a/drivers/irqchip/irq-qcom-mpm.c ++++ b/drivers/irqchip/irq-qcom-mpm.c +@@ -226,6 +226,9 @@ static int qcom_mpm_alloc(struct irq_domain *domain, unsigned int virq, + if (ret) + return ret; + ++ if (pin == GPIO_NO_WAKE_IRQ) ++ return irq_domain_disconnect_hierarchy(domain, virq); ++ + ret = irq_domain_set_hwirq_and_chip(domain, virq, pin, + &qcom_mpm_chip, priv); + if (ret) +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 30ddfb21f65818..2d3afeaf886877 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -68,6 +68,8 @@ + #define LIST_DIRTY 1 + #define LIST_SIZE 2 + ++#define SCAN_RESCHED_CYCLE 16 ++ + /*--------------------------------------------------------------*/ + + /* +@@ -2387,7 +2389,12 @@ static void __scan(struct dm_bufio_client *c) + + atomic_long_dec(&c->need_shrink); + freed++; +- cond_resched(); ++ ++ if (unlikely(freed % SCAN_RESCHED_CYCLE == 0)) { ++ dm_bufio_unlock(c); ++ cond_resched(); ++ dm_bufio_lock(c); ++ } + } + } + } +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index eb2b44f4a61f08..1e27a5bce2d942 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -4687,7 +4687,7 @@ static void dm_integrity_dtr(struct dm_target *ti) + BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress)); + BUG_ON(!list_empty(&ic->wait_list)); + +- if (ic->mode == 'B') ++ if (ic->mode == 'B' && ic->bitmap_flush_work.work.func) + cancel_delayed_work_sync(&ic->bitmap_flush_work); + if (ic->metadata_wq) + destroy_workqueue(ic->metadata_wq); +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index fd84e06670e8d7..319bd10548e9ad 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -500,8 +500,9 @@ static char **realloc_argv(unsigned int *size, char **old_argv) + gfp = GFP_NOIO; + } + argv = kmalloc_array(new_size, sizeof(*argv), gfp); +- if (argv && old_argv) { +- memcpy(argv, old_argv, *size * sizeof(*argv)); ++ if (argv) { ++ if (old_argv) ++ memcpy(argv, old_argv, *size * sizeof(*argv)); + *size = new_size; + } + +diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c +index c675dec587efb2..597b00e8c9539d 100644 +--- a/drivers/mmc/host/renesas_sdhi_core.c ++++ b/drivers/mmc/host/renesas_sdhi_core.c +@@ -1107,26 +1107,26 @@ int renesas_sdhi_probe(struct platform_device *pdev, + num_irqs = platform_irq_count(pdev); + if (num_irqs < 0) { + ret = num_irqs; +- goto eirq; ++ goto edisclk; + } + + /* There must be at least one IRQ source */ + if (!num_irqs) { + ret = -ENXIO; +- goto eirq; ++ goto edisclk; + } + + for (i = 0; i < num_irqs; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) { + ret = irq; +- goto eirq; ++ goto edisclk; + } + + ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, + dev_name(&pdev->dev), host); + if (ret) +- goto eirq; ++ goto edisclk; + } + + ret = tmio_mmc_host_probe(host); +@@ -1138,8 +1138,6 @@ int renesas_sdhi_probe(struct platform_device *pdev, + + return ret; + +-eirq: +- tmio_mmc_host_remove(host); + edisclk: + renesas_sdhi_clk_disable(host); + efree: +diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c +index 8d27933c3733b1..f91f25578f075b 100644 +--- a/drivers/net/dsa/ocelot/felix_vsc9959.c ++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c +@@ -1543,7 +1543,7 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) + struct tc_taprio_qopt_offload *taprio; + struct ocelot_port *ocelot_port; + struct timespec64 base_ts; +- int port; ++ int i, port; + u32 val; + + mutex_lock(&ocelot->fwd_domain_lock); +@@ -1575,6 +1575,9 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) + QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M, + QSYS_PARAM_CFG_REG_3); + ++ for (i = 0; i < taprio->num_entries; i++) ++ vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]); ++ + ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, + QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, + QSYS_TAS_PARAM_CFG_CTRL); +diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c +index fb7a5403e630db..889a18962270aa 100644 +--- a/drivers/net/ethernet/amd/pds_core/auxbus.c ++++ b/drivers/net/ethernet/amd/pds_core/auxbus.c +@@ -172,48 +172,57 @@ static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf, + return padev; + } + +-int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf) ++void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf, ++ struct pds_auxiliary_dev **pd_ptr) + { + struct pds_auxiliary_dev *padev; +- int err = 0; ++ ++ if (!*pd_ptr) ++ return; + + mutex_lock(&pf->config_lock); + +- padev = pf->vfs[cf->vf_id].padev; +- if (padev) { +- pds_client_unregister(pf, padev->client_id); +- auxiliary_device_delete(&padev->aux_dev); +- auxiliary_device_uninit(&padev->aux_dev); +- padev->client_id = 0; +- } +- pf->vfs[cf->vf_id].padev = NULL; ++ padev = *pd_ptr; ++ pds_client_unregister(pf, padev->client_id); ++ auxiliary_device_delete(&padev->aux_dev); ++ auxiliary_device_uninit(&padev->aux_dev); ++ *pd_ptr = NULL; + + mutex_unlock(&pf->config_lock); +- return err; + } + +-int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf) ++int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf, ++ enum pds_core_vif_types vt, ++ struct pds_auxiliary_dev **pd_ptr) + { + struct pds_auxiliary_dev *padev; +- enum pds_core_vif_types vt; + char devname[PDS_DEVNAME_LEN]; ++ unsigned long mask; + u16 vt_support; + int client_id; + int err = 0; + ++ if (!cf) ++ return -ENODEV; ++ ++ if (vt >= PDS_DEV_TYPE_MAX) ++ return -EINVAL; ++ + mutex_lock(&pf->config_lock); + +- /* We only support vDPA so far, so it is the only one to +- * be verified that it is available in the Core device and +- * enabled in the devlink param. In the future this might +- * become a loop for several VIF types. +- */ ++ mask = BIT_ULL(PDSC_S_FW_DEAD) | ++ BIT_ULL(PDSC_S_STOPPING_DRIVER); ++ if (cf->state & mask) { ++ dev_err(pf->dev, "%s: can't add dev, VF client in bad state %#lx\n", ++ __func__, cf->state); ++ err = -ENXIO; ++ goto out_unlock; ++ } + + /* Verify that the type is supported and enabled. It is not + * an error if there is no auxbus device support for this + * VF, it just means something else needs to happen with it. + */ +- vt = PDS_DEV_TYPE_VDPA; + vt_support = !!le16_to_cpu(pf->dev_ident.vif_types[vt]); + if (!(vt_support && + pf->viftype_status[vt].supported && +@@ -239,7 +248,7 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf) + err = PTR_ERR(padev); + goto out_unlock; + } +- pf->vfs[cf->vf_id].padev = padev; ++ *pd_ptr = padev; + + out_unlock: + mutex_unlock(&pf->config_lock); +diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h +index 858bebf7977624..61ee607ee48ace 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.h ++++ b/drivers/net/ethernet/amd/pds_core/core.h +@@ -300,8 +300,11 @@ void pdsc_health_thread(struct work_struct *work); + int pdsc_register_notify(struct notifier_block *nb); + void pdsc_unregister_notify(struct notifier_block *nb); + void pdsc_notify(unsigned long event, void *data); +-int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf); +-int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf); ++int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf, ++ enum pds_core_vif_types vt, ++ struct pds_auxiliary_dev **pd_ptr); ++void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf, ++ struct pds_auxiliary_dev **pd_ptr); + + void pdsc_process_adminq(struct pdsc_qcq *qcq); + void pdsc_work_thread(struct work_struct *work); +diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c +index f0e39ab4004503..e65a1632df505d 100644 +--- a/drivers/net/ethernet/amd/pds_core/dev.c ++++ b/drivers/net/ethernet/amd/pds_core/dev.c +@@ -42,6 +42,8 @@ int pdsc_err_to_errno(enum pds_core_status_code code) + return -ERANGE; + case PDS_RC_BAD_ADDR: + return -EFAULT; ++ case PDS_RC_BAD_PCI: ++ return -ENXIO; + case PDS_RC_EOPCODE: + case PDS_RC_EINTR: + case PDS_RC_DEV_CMD: +@@ -65,7 +67,7 @@ bool pdsc_is_fw_running(struct pdsc *pdsc) + /* Firmware is useful only if the running bit is set and + * fw_status != 0xff (bad PCI read) + */ +- return (pdsc->fw_status != 0xff) && ++ return (pdsc->fw_status != PDS_RC_BAD_PCI) && + (pdsc->fw_status & PDS_CORE_FW_STS_F_RUNNING); + } + +@@ -131,6 +133,7 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds) + unsigned long max_wait; + unsigned long duration; + int timeout = 0; ++ bool running; + int done = 0; + int err = 0; + int status; +@@ -139,6 +142,10 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds) + max_wait = start_time + (max_seconds * HZ); + + while (!done && !timeout) { ++ running = pdsc_is_fw_running(pdsc); ++ if (!running) ++ break; ++ + done = pdsc_devcmd_done(pdsc); + if (done) + break; +@@ -155,7 +162,7 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds) + dev_dbg(dev, "DEVCMD %d %s after %ld secs\n", + opcode, pdsc_devcmd_str(opcode), duration / HZ); + +- if (!done || timeout) { ++ if ((!done || timeout) && running) { + dev_err(dev, "DEVCMD %d %s timeout, done %d timeout %d max_seconds=%d\n", + opcode, pdsc_devcmd_str(opcode), done, timeout, + max_seconds); +diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c +index 0032e8e3518117..bee70e46e34c68 100644 +--- a/drivers/net/ethernet/amd/pds_core/devlink.c ++++ b/drivers/net/ethernet/amd/pds_core/devlink.c +@@ -55,8 +55,11 @@ int pdsc_dl_enable_set(struct devlink *dl, u32 id, + for (vf_id = 0; vf_id < pdsc->num_vfs; vf_id++) { + struct pdsc *vf = pdsc->vfs[vf_id].vf; + +- err = ctx->val.vbool ? pdsc_auxbus_dev_add(vf, pdsc) : +- pdsc_auxbus_dev_del(vf, pdsc); ++ if (ctx->val.vbool) ++ err = pdsc_auxbus_dev_add(vf, pdsc, vt_entry->vif_id, ++ &pdsc->vfs[vf_id].padev); ++ else ++ pdsc_auxbus_dev_del(vf, pdsc, &pdsc->vfs[vf_id].padev); + } + + return err; +diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c +index eddbf0acdde77f..76652e0e5b6d9c 100644 +--- a/drivers/net/ethernet/amd/pds_core/main.c ++++ b/drivers/net/ethernet/amd/pds_core/main.c +@@ -189,7 +189,8 @@ static int pdsc_init_vf(struct pdsc *vf) + devl_unlock(dl); + + pf->vfs[vf->vf_id].vf = vf; +- err = pdsc_auxbus_dev_add(vf, pf); ++ err = pdsc_auxbus_dev_add(vf, pf, PDS_DEV_TYPE_VDPA, ++ &pf->vfs[vf->vf_id].padev); + if (err) { + devl_lock(dl); + devl_unregister(dl); +@@ -415,7 +416,7 @@ static void pdsc_remove(struct pci_dev *pdev) + + pf = pdsc_get_pf_struct(pdsc->pdev); + if (!IS_ERR(pf)) { +- pdsc_auxbus_dev_del(pdsc, pf); ++ pdsc_auxbus_dev_del(pdsc, pf, &pf->vfs[pdsc->vf_id].padev); + pf->vfs[pdsc->vf_id].vf = NULL; + } + } else { +@@ -475,6 +476,15 @@ static void pdsc_reset_prepare(struct pci_dev *pdev) + pdsc_stop_health_thread(pdsc); + pdsc_fw_down(pdsc); + ++ if (pdev->is_virtfn) { ++ struct pdsc *pf; ++ ++ pf = pdsc_get_pf_struct(pdsc->pdev); ++ if (!IS_ERR(pf)) ++ pdsc_auxbus_dev_del(pdsc, pf, ++ &pf->vfs[pdsc->vf_id].padev); ++ } ++ + pdsc_unmap_bars(pdsc); + pci_release_regions(pdev); + pci_disable_device(pdev); +@@ -510,6 +520,15 @@ static void pdsc_reset_done(struct pci_dev *pdev) + + pdsc_fw_up(pdsc); + pdsc_restart_health_thread(pdsc); ++ ++ if (pdev->is_virtfn) { ++ struct pdsc *pf; ++ ++ pf = pdsc_get_pf_struct(pdsc->pdev); ++ if (!IS_ERR(pf)) ++ pdsc_auxbus_dev_add(pdsc, pf, PDS_DEV_TYPE_VDPA, ++ &pf->vfs[pdsc->vf_id].padev); ++ } + } + + static const struct pci_error_handlers pdsc_err_handler = { +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +index 230726d7b74f63..d41b58fad37bbf 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +@@ -373,8 +373,13 @@ static int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata, + } + + /* Set up the header page info */ +- xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa, +- XGBE_SKB_ALLOC_SIZE); ++ if (pdata->netdev->features & NETIF_F_RXCSUM) { ++ xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa, ++ XGBE_SKB_ALLOC_SIZE); ++ } else { ++ xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa, ++ pdata->rx_buf_size); ++ } + + /* Set up the buffer page info */ + xgbe_set_buffer_data(&rdata->rx.buf, &ring->rx_buf_pa, +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +index f393228d41c7be..f1b0fb02b3cd14 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +@@ -320,6 +320,18 @@ static void xgbe_config_sph_mode(struct xgbe_prv_data *pdata) + XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE); + } + ++static void xgbe_disable_sph_mode(struct xgbe_prv_data *pdata) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < pdata->channel_count; i++) { ++ if (!pdata->channel[i]->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 0); ++ } ++} ++ + static int xgbe_write_rss_reg(struct xgbe_prv_data *pdata, unsigned int type, + unsigned int index, unsigned int val) + { +@@ -3545,8 +3557,12 @@ static int xgbe_init(struct xgbe_prv_data *pdata) + xgbe_config_tx_coalesce(pdata); + xgbe_config_rx_buffer_size(pdata); + xgbe_config_tso_mode(pdata); +- xgbe_config_sph_mode(pdata); +- xgbe_config_rss(pdata); ++ ++ if (pdata->netdev->features & NETIF_F_RXCSUM) { ++ xgbe_config_sph_mode(pdata); ++ xgbe_config_rss(pdata); ++ } ++ + desc_if->wrapper_tx_desc_init(pdata); + desc_if->wrapper_rx_desc_init(pdata); + xgbe_enable_dma_interrupts(pdata); +@@ -3702,5 +3718,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) + hw_if->disable_vxlan = xgbe_disable_vxlan; + hw_if->set_vxlan_id = xgbe_set_vxlan_id; + ++ /* For Split Header*/ ++ hw_if->enable_sph = xgbe_config_sph_mode; ++ hw_if->disable_sph = xgbe_disable_sph_mode; ++ + DBGPR("<--xgbe_init_function_ptrs\n"); + } +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +index 6b73648b377936..34d45cebefb5d3 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +@@ -2257,10 +2257,17 @@ static int xgbe_set_features(struct net_device *netdev, + if (ret) + return ret; + +- if ((features & NETIF_F_RXCSUM) && !rxcsum) ++ if ((features & NETIF_F_RXCSUM) && !rxcsum) { ++ hw_if->enable_sph(pdata); ++ hw_if->enable_vxlan(pdata); + hw_if->enable_rx_csum(pdata); +- else if (!(features & NETIF_F_RXCSUM) && rxcsum) ++ schedule_work(&pdata->restart_work); ++ } else if (!(features & NETIF_F_RXCSUM) && rxcsum) { ++ hw_if->disable_sph(pdata); ++ hw_if->disable_vxlan(pdata); + hw_if->disable_rx_csum(pdata); ++ schedule_work(&pdata->restart_work); ++ } + + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan) + hw_if->enable_rx_vlan_stripping(pdata); +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h +index ad136ed493ed1f..173f4dad470f55 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h +@@ -865,6 +865,10 @@ struct xgbe_hw_if { + void (*enable_vxlan)(struct xgbe_prv_data *); + void (*disable_vxlan)(struct xgbe_prv_data *); + void (*set_vxlan_id)(struct xgbe_prv_data *); ++ ++ /* For Split Header */ ++ void (*enable_sph)(struct xgbe_prv_data *pdata); ++ void (*disable_sph)(struct xgbe_prv_data *pdata); + }; + + /* This structure represents implementation specific routines for an +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c +index c067898820360e..32813cdd5aa5cb 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c +@@ -66,20 +66,30 @@ static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, + } + } + ++ if (cmn_req->req_type == ++ cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) ++ info->dest_buf_size += len; ++ + if (info->dest_buf) { + if ((info->seg_start + off + len) <= + BNXT_COREDUMP_BUF_LEN(info->buf_len)) { +- memcpy(info->dest_buf + off, dma_buf, len); ++ u16 copylen = min_t(u16, len, ++ info->dest_buf_size - off); ++ ++ memcpy(info->dest_buf + off, dma_buf, copylen); ++ if (copylen < len) ++ break; + } else { + rc = -ENOBUFS; ++ if (cmn_req->req_type == ++ cpu_to_le16(HWRM_DBG_COREDUMP_LIST)) { ++ kfree(info->dest_buf); ++ info->dest_buf = NULL; ++ } + break; + } + } + +- if (cmn_req->req_type == +- cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) +- info->dest_buf_size += len; +- + if (!(cmn_resp->flags & HWRM_DBG_CMN_FLAGS_MORE)) + break; + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index 2e7ddbca9d53b1..dcedafa4d2e14f 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -1393,6 +1393,17 @@ static int bnxt_get_regs_len(struct net_device *dev) + return reg_len; + } + ++#define BNXT_PCIE_32B_ENTRY(start, end) \ ++ { offsetof(struct pcie_ctx_hw_stats, start), \ ++ offsetof(struct pcie_ctx_hw_stats, end) } ++ ++static const struct { ++ u16 start; ++ u16 end; ++} bnxt_pcie_32b_entries[] = { ++ BNXT_PCIE_32B_ENTRY(pcie_ltssm_histogram[0], pcie_ltssm_histogram[3]), ++}; ++ + static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *_p) + { +@@ -1424,12 +1435,27 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, + req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); + rc = hwrm_req_send(bp, req); + if (!rc) { +- __le64 *src = (__le64 *)hw_pcie_stats; +- u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); +- int i; +- +- for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) +- dst[i] = le64_to_cpu(src[i]); ++ u8 *dst = (u8 *)(_p + BNXT_PXP_REG_LEN); ++ u8 *src = (u8 *)hw_pcie_stats; ++ int i, j; ++ ++ for (i = 0, j = 0; i < sizeof(*hw_pcie_stats); ) { ++ if (i >= bnxt_pcie_32b_entries[j].start && ++ i <= bnxt_pcie_32b_entries[j].end) { ++ u32 *dst32 = (u32 *)(dst + i); ++ ++ *dst32 = le32_to_cpu(*(__le32 *)(src + i)); ++ i += 4; ++ if (i > bnxt_pcie_32b_entries[j].end && ++ j < ARRAY_SIZE(bnxt_pcie_32b_entries) - 1) ++ j++; ++ } else { ++ u64 *dst64 = (u64 *)(dst + i); ++ ++ *dst64 = le64_to_cpu(*(__le64 *)(src + i)); ++ i += 8; ++ } ++ } + } + hwrm_req_drop(bp, req); + } +diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c +index db6615aa921b19..ce46f3ac3b5a18 100644 +--- a/drivers/net/ethernet/dlink/dl2k.c ++++ b/drivers/net/ethernet/dlink/dl2k.c +@@ -352,7 +352,7 @@ parse_eeprom (struct net_device *dev) + eth_hw_addr_set(dev, psrom->mac_addr); + + if (np->chip_id == CHIP_IP1000A) { +- np->led_mode = psrom->led_mode; ++ np->led_mode = le16_to_cpu(psrom->led_mode); + return 0; + } + +diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h +index 195dc6cfd8955c..0e33e2eaae9606 100644 +--- a/drivers/net/ethernet/dlink/dl2k.h ++++ b/drivers/net/ethernet/dlink/dl2k.h +@@ -335,7 +335,7 @@ typedef struct t_SROM { + u16 sub_system_id; /* 0x06 */ + u16 pci_base_1; /* 0x08 (IP1000A only) */ + u16 pci_base_2; /* 0x0a (IP1000A only) */ +- u16 led_mode; /* 0x0c (IP1000A only) */ ++ __le16 led_mode; /* 0x0c (IP1000A only) */ + u16 reserved1[9]; /* 0x0e-0x1f */ + u8 mac_addr[6]; /* 0x20-0x25 */ + u8 reserved2[10]; /* 0x26-0x2f */ +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 2d6b50903c923d..7261838a09db63 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -695,7 +695,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; + } +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +index 4f385a18d288e4..36206273453f3a 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +@@ -60,7 +60,7 @@ static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = { + .name = "tm_qset", + .cmd = HNAE3_DBG_CMD_TM_QSET, + .dentry = HNS3_DBG_DENTRY_TM, +- .buf_len = HNS3_DBG_READ_LEN, ++ .buf_len = HNS3_DBG_READ_LEN_1MB, + .init = hns3_dbg_common_file_init, + }, + { +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +index 801801e8803e9f..0ed01f4d680618 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +@@ -473,20 +473,14 @@ static void hns3_mask_vector_irq(struct hns3_enet_tqp_vector *tqp_vector, + writel(mask_en, tqp_vector->mask_addr); + } + +-static void hns3_vector_enable(struct hns3_enet_tqp_vector *tqp_vector) ++static void hns3_irq_enable(struct hns3_enet_tqp_vector *tqp_vector) + { + napi_enable(&tqp_vector->napi); + enable_irq(tqp_vector->vector_irq); +- +- /* enable vector */ +- hns3_mask_vector_irq(tqp_vector, 1); + } + +-static void hns3_vector_disable(struct hns3_enet_tqp_vector *tqp_vector) ++static void hns3_irq_disable(struct hns3_enet_tqp_vector *tqp_vector) + { +- /* disable vector */ +- hns3_mask_vector_irq(tqp_vector, 0); +- + disable_irq(tqp_vector->vector_irq); + napi_disable(&tqp_vector->napi); + cancel_work_sync(&tqp_vector->rx_group.dim.work); +@@ -707,11 +701,42 @@ static int hns3_set_rx_cpu_rmap(struct net_device *netdev) + return 0; + } + ++static void hns3_enable_irqs_and_tqps(struct net_device *netdev) ++{ ++ struct hns3_nic_priv *priv = netdev_priv(netdev); ++ struct hnae3_handle *h = priv->ae_handle; ++ u16 i; ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_irq_enable(&priv->tqp_vector[i]); ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_mask_vector_irq(&priv->tqp_vector[i], 1); ++ ++ for (i = 0; i < h->kinfo.num_tqps; i++) ++ hns3_tqp_enable(h->kinfo.tqp[i]); ++} ++ ++static void hns3_disable_irqs_and_tqps(struct net_device *netdev) ++{ ++ struct hns3_nic_priv *priv = netdev_priv(netdev); ++ struct hnae3_handle *h = priv->ae_handle; ++ u16 i; ++ ++ for (i = 0; i < h->kinfo.num_tqps; i++) ++ hns3_tqp_disable(h->kinfo.tqp[i]); ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_mask_vector_irq(&priv->tqp_vector[i], 0); ++ ++ for (i = 0; i < priv->vector_num; i++) ++ hns3_irq_disable(&priv->tqp_vector[i]); ++} ++ + static int hns3_nic_net_up(struct net_device *netdev) + { + struct hns3_nic_priv *priv = netdev_priv(netdev); + struct hnae3_handle *h = priv->ae_handle; +- int i, j; + int ret; + + ret = hns3_nic_reset_all_ring(h); +@@ -720,23 +745,13 @@ static int hns3_nic_net_up(struct net_device *netdev) + + clear_bit(HNS3_NIC_STATE_DOWN, &priv->state); + +- /* enable the vectors */ +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_enable(&priv->tqp_vector[i]); +- +- /* enable rcb */ +- for (j = 0; j < h->kinfo.num_tqps; j++) +- hns3_tqp_enable(h->kinfo.tqp[j]); ++ hns3_enable_irqs_and_tqps(netdev); + + /* start the ae_dev */ + ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0; + if (ret) { + set_bit(HNS3_NIC_STATE_DOWN, &priv->state); +- while (j--) +- hns3_tqp_disable(h->kinfo.tqp[j]); +- +- for (j = i - 1; j >= 0; j--) +- hns3_vector_disable(&priv->tqp_vector[j]); ++ hns3_disable_irqs_and_tqps(netdev); + } + + return ret; +@@ -823,17 +838,9 @@ static void hns3_reset_tx_queue(struct hnae3_handle *h) + static void hns3_nic_net_down(struct net_device *netdev) + { + struct hns3_nic_priv *priv = netdev_priv(netdev); +- struct hnae3_handle *h = hns3_get_handle(netdev); + const struct hnae3_ae_ops *ops; +- int i; + +- /* disable vectors */ +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_disable(&priv->tqp_vector[i]); +- +- /* disable rcb */ +- for (i = 0; i < h->kinfo.num_tqps; i++) +- hns3_tqp_disable(h->kinfo.tqp[i]); ++ hns3_disable_irqs_and_tqps(netdev); + + /* stop ae_dev */ + ops = priv->ae_handle->ae_algo->ops; +@@ -5870,8 +5877,6 @@ int hns3_set_channels(struct net_device *netdev, + void hns3_external_lb_prepare(struct net_device *ndev, bool if_running) + { + struct hns3_nic_priv *priv = netdev_priv(ndev); +- struct hnae3_handle *h = priv->ae_handle; +- int i; + + if (!if_running) + return; +@@ -5882,11 +5887,7 @@ void hns3_external_lb_prepare(struct net_device *ndev, bool if_running) + netif_carrier_off(ndev); + netif_tx_disable(ndev); + +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_disable(&priv->tqp_vector[i]); +- +- for (i = 0; i < h->kinfo.num_tqps; i++) +- hns3_tqp_disable(h->kinfo.tqp[i]); ++ hns3_disable_irqs_and_tqps(ndev); + + /* delay ring buffer clearing to hns3_reset_notify_uninit_enet + * during reset process, because driver may not be able +@@ -5902,7 +5903,6 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running) + { + struct hns3_nic_priv *priv = netdev_priv(ndev); + struct hnae3_handle *h = priv->ae_handle; +- int i; + + if (!if_running) + return; +@@ -5918,11 +5918,7 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running) + + clear_bit(HNS3_NIC_STATE_DOWN, &priv->state); + +- for (i = 0; i < priv->vector_num; i++) +- hns3_vector_enable(&priv->tqp_vector[i]); +- +- for (i = 0; i < h->kinfo.num_tqps; i++) +- hns3_tqp_enable(h->kinfo.tqp[i]); ++ hns3_enable_irqs_and_tqps(ndev); + + netif_tx_wake_all_queues(ndev); + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c +index ddc691424c8163..9a806ac727cf5b 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c +@@ -440,6 +440,13 @@ static int hclge_ptp_create_clock(struct hclge_dev *hdev) + ptp->info.settime64 = hclge_ptp_settime; + + ptp->info.n_alarm = 0; ++ ++ spin_lock_init(&ptp->lock); ++ ptp->io_base = hdev->hw.hw.io_base + HCLGE_PTP_REG_OFFSET; ++ ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE; ++ ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF; ++ hdev->ptp = ptp; ++ + ptp->clock = ptp_clock_register(&ptp->info, &hdev->pdev->dev); + if (IS_ERR(ptp->clock)) { + dev_err(&hdev->pdev->dev, +@@ -451,12 +458,6 @@ static int hclge_ptp_create_clock(struct hclge_dev *hdev) + return -ENODEV; + } + +- spin_lock_init(&ptp->lock); +- ptp->io_base = hdev->hw.hw.io_base + HCLGE_PTP_REG_OFFSET; +- ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE; +- ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF; +- hdev->ptp = ptp; +- + return 0; + } + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +index 69bfcfb148def4..1ba0b57c7a72d7 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +@@ -1257,9 +1257,8 @@ static void hclgevf_sync_vlan_filter(struct hclgevf_dev *hdev) + rtnl_unlock(); + } + +-static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) ++static int hclgevf_en_hw_strip_rxvtag_cmd(struct hclgevf_dev *hdev, bool enable) + { +- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hclge_vf_to_pf_msg send_msg; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN, +@@ -1268,6 +1267,19 @@ static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) + return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + } + ++static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) ++{ ++ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); ++ int ret; ++ ++ ret = hclgevf_en_hw_strip_rxvtag_cmd(hdev, enable); ++ if (ret) ++ return ret; ++ ++ hdev->rxvtag_strip_en = enable; ++ return 0; ++} ++ + static int hclgevf_reset_tqp(struct hnae3_handle *handle) + { + #define HCLGEVF_RESET_ALL_QUEUE_DONE 1U +@@ -2143,12 +2155,13 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) + tc_valid, tc_size); + } + +-static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev) ++static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev, ++ bool rxvtag_strip_en) + { + struct hnae3_handle *nic = &hdev->nic; + int ret; + +- ret = hclgevf_en_hw_strip_rxvtag(nic, true); ++ ret = hclgevf_en_hw_strip_rxvtag(nic, rxvtag_strip_en); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to enable rx vlan offload, ret = %d\n", ret); +@@ -2815,7 +2828,7 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) + if (ret) + return ret; + +- ret = hclgevf_init_vlan_config(hdev); ++ ret = hclgevf_init_vlan_config(hdev, hdev->rxvtag_strip_en); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed(%d) to initialize VLAN config\n", ret); +@@ -2928,7 +2941,7 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) + goto err_config; + } + +- ret = hclgevf_init_vlan_config(hdev); ++ ret = hclgevf_init_vlan_config(hdev, true); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed(%d) to initialize VLAN config\n", ret); +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +index cccef32284616b..0208425ab594f5 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +@@ -253,6 +253,7 @@ struct hclgevf_dev { + int *vector_irq; + + bool gro_en; ++ bool rxvtag_strip_en; + + unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)]; + +diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +index 3ca5f44dea26eb..88c1acd5e8f05d 100644 +--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c ++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +@@ -1824,6 +1824,11 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg) + pf = vf->pf; + dev = ice_pf_to_dev(pf); + vf_vsi = ice_get_vf_vsi(vf); ++ if (!vf_vsi) { ++ dev_err(dev, "Can not get FDIR vf_vsi for VF %u\n", vf->vf_id); ++ v_ret = VIRTCHNL_STATUS_ERR_PARAM; ++ goto err_exit; ++ } + + #define ICE_VF_MAX_FDIR_FILTERS 128 + if (!ice_fdir_num_avail_fltr(&pf->hw, vf_vsi) || +diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c +index b6bb01a486d9d8..a82af96e6bd12f 100644 +--- a/drivers/net/ethernet/intel/igc/igc_ptp.c ++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c +@@ -1237,6 +1237,8 @@ void igc_ptp_reset(struct igc_adapter *adapter) + /* reset the tstamp_config */ + igc_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); + ++ mutex_lock(&adapter->ptm_lock); ++ + spin_lock_irqsave(&adapter->tmreg_lock, flags); + + switch (adapter->hw.mac.type) { +@@ -1255,7 +1257,6 @@ void igc_ptp_reset(struct igc_adapter *adapter) + if (!igc_is_crosststamp_supported(adapter)) + break; + +- mutex_lock(&adapter->ptm_lock); + wr32(IGC_PCIE_DIG_DELAY, IGC_PCIE_DIG_DELAY_DEFAULT); + wr32(IGC_PCIE_PHY_DELAY, IGC_PCIE_PHY_DELAY_DEFAULT); + +@@ -1279,7 +1280,6 @@ void igc_ptp_reset(struct igc_adapter *adapter) + netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n"); + + igc_ptm_reset(hw); +- mutex_unlock(&adapter->ptm_lock); + break; + default: + /* No work to do. */ +@@ -1296,5 +1296,7 @@ void igc_ptp_reset(struct igc_adapter *adapter) + out: + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + ++ mutex_unlock(&adapter->ptm_lock); ++ + wrfl(); + } +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +index 6f1fe7e283d4eb..7a30095b3486f3 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +@@ -917,7 +917,7 @@ static void octep_hb_timeout_task(struct work_struct *work) + miss_cnt); + rtnl_lock(); + if (netif_running(oct->netdev)) +- octep_stop(oct->netdev); ++ dev_close(oct->netdev); + rtnl_unlock(); + } + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index dc89dbc13b251f..d2ec8f642c2fa0 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2180,14 +2180,18 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, + ring->data[idx] = new_data; + rxd->rxd1 = (unsigned int)dma_addr; + release_desc: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) { ++ if (unlikely(dma_addr == DMA_MAPPING_ERROR)) ++ addr64 = FIELD_GET(RX_DMA_ADDR64_MASK, ++ rxd->rxd2); ++ else ++ addr64 = RX_DMA_PREP_ADDR64(dma_addr); ++ } ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; + else +- rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); +- +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA) && +- likely(dma_addr != DMA_MAPPING_ERROR)) +- rxd->rxd2 |= RX_DMA_PREP_ADDR64(dma_addr); ++ rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size) | addr64; + + ring->calc_idx = idx; + done++; +diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c +index 25989c79c92e61..c2ab87828d8589 100644 +--- a/drivers/net/ethernet/mediatek/mtk_star_emac.c ++++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c +@@ -1163,6 +1163,7 @@ static int mtk_star_tx_poll(struct napi_struct *napi, int budget) + struct net_device *ndev = priv->ndev; + unsigned int head = ring->head; + unsigned int entry = ring->tail; ++ unsigned long flags; + + while (entry != head && count < (MTK_STAR_RING_NUM_DESCS - 1)) { + ret = mtk_star_tx_complete_one(priv); +@@ -1182,9 +1183,9 @@ static int mtk_star_tx_poll(struct napi_struct *napi, int budget) + netif_wake_queue(ndev); + + if (napi_complete(napi)) { +- spin_lock(&priv->lock); ++ spin_lock_irqsave(&priv->lock, flags); + mtk_star_enable_dma_irq(priv, false, true); +- spin_unlock(&priv->lock); ++ spin_unlock_irqrestore(&priv->lock, flags); + } + + return 0; +@@ -1341,16 +1342,16 @@ static int mtk_star_rx(struct mtk_star_priv *priv, int budget) + static int mtk_star_rx_poll(struct napi_struct *napi, int budget) + { + struct mtk_star_priv *priv; ++ unsigned long flags; + int work_done = 0; + + priv = container_of(napi, struct mtk_star_priv, rx_napi); + + work_done = mtk_star_rx(priv, budget); +- if (work_done < budget) { +- napi_complete_done(napi, work_done); +- spin_lock(&priv->lock); ++ if (work_done < budget && napi_complete_done(napi, work_done)) { ++ spin_lock_irqsave(&priv->lock, flags); + mtk_star_enable_dma_irq(priv, true, false); +- spin_unlock(&priv->lock); ++ spin_unlock_irqrestore(&priv->lock, flags); + } + + return work_done; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +index 7eba3a5bb97cae..326c72b3df8671 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +@@ -3499,7 +3499,9 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) + int err; + + mutex_init(&esw->offloads.termtbl_mutex); +- mlx5_rdma_enable_roce(esw->dev); ++ err = mlx5_rdma_enable_roce(esw->dev); ++ if (err) ++ goto err_roce; + + err = mlx5_esw_host_number_init(esw); + if (err) +@@ -3560,6 +3562,7 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) + esw_offloads_metadata_uninit(esw); + err_metadata: + mlx5_rdma_disable_roce(esw->dev); ++err_roce: + mutex_destroy(&esw->offloads.termtbl_mutex); + return err; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c +index a42f6cd99b7448..5c552b71e371c5 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c +@@ -118,8 +118,8 @@ static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid * + + static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev) + { ++ u8 mac[ETH_ALEN] = {}; + union ib_gid gid; +- u8 mac[ETH_ALEN]; + + mlx5_rdma_make_default_gid(dev, &gid); + return mlx5_core_roce_gid_set(dev, 0, +@@ -140,17 +140,17 @@ void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev) + mlx5_nic_vport_disable_roce(dev); + } + +-void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) ++int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) + { + int err; + + if (!MLX5_CAP_GEN(dev, roce)) +- return; ++ return 0; + + err = mlx5_nic_vport_enable_roce(dev); + if (err) { + mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err); +- return; ++ return err; + } + + err = mlx5_rdma_add_roce_addr(dev); +@@ -165,10 +165,11 @@ void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) + goto del_roce_addr; + } + +- return; ++ return err; + + del_roce_addr: + mlx5_rdma_del_roce_addr(dev); + disable_roce: + mlx5_nic_vport_disable_roce(dev); ++ return err; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.h b/drivers/net/ethernet/mellanox/mlx5/core/rdma.h +index 750cff2a71a4bb..3d9e76c3d42fb1 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.h +@@ -8,12 +8,12 @@ + + #ifdef CONFIG_MLX5_ESWITCH + +-void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev); ++int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev); + void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev); + + #else /* CONFIG_MLX5_ESWITCH */ + +-static inline void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) {} ++static inline int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) { return 0; } + static inline void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev) {} + + #endif /* CONFIG_MLX5_ESWITCH */ +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 92010bfe5e4133..5d2ceff72784f2 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1949,6 +1949,7 @@ static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx, + if (nr_frags <= 0) { + tx->frame_data0 |= TX_DESC_DATA0_LS_; + tx->frame_data0 |= TX_DESC_DATA0_IOC_; ++ tx->frame_last = tx->frame_first; + } + tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; + tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); +@@ -2018,6 +2019,7 @@ static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx, + tx->frame_first = 0; + tx->frame_data0 = 0; + tx->frame_tail = 0; ++ tx->frame_last = 0; + return -ENOMEM; + } + +@@ -2058,16 +2060,18 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx, + TX_DESC_DATA0_DTYPE_DATA_) { + tx->frame_data0 |= TX_DESC_DATA0_LS_; + tx->frame_data0 |= TX_DESC_DATA0_IOC_; ++ tx->frame_last = tx->frame_tail; + } + +- tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; +- buffer_info = &tx->buffer_info[tx->frame_tail]; ++ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_last]; ++ buffer_info = &tx->buffer_info[tx->frame_last]; + buffer_info->skb = skb; + if (time_stamp) + buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED; + if (ignore_sync) + buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC; + ++ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; + tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); + tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); + tx->last_tail = tx->frame_tail; +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 3b2c6046eb3ad5..b6c83c68241e63 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -974,6 +974,7 @@ struct lan743x_tx { + u32 frame_first; + u32 frame_data0; + u32 frame_tail; ++ u32 frame_last; + + struct lan743x_tx_buffer_info *buffer_info; + +diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c +index f6aa5d6b6597e0..252d8e6f18c3cc 100644 +--- a/drivers/net/ethernet/mscc/ocelot.c ++++ b/drivers/net/ethernet/mscc/ocelot.c +@@ -453,9 +453,158 @@ static u16 ocelot_vlan_unaware_pvid(struct ocelot *ocelot, + return VLAN_N_VID - bridge_num - 1; + } + ++/** ++ * ocelot_update_vlan_reclassify_rule() - Make switch aware only to bridge VLAN TPID ++ * ++ * @ocelot: Switch private data structure ++ * @port: Index of ingress port ++ * ++ * IEEE 802.1Q-2018 clauses "5.5 C-VLAN component conformance" and "5.6 S-VLAN ++ * component conformance" suggest that a C-VLAN component should only recognize ++ * and filter on C-Tags, and an S-VLAN component should only recognize and ++ * process based on C-Tags. ++ * ++ * In Linux, as per commit 1a0b20b25732 ("Merge branch 'bridge-next'"), C-VLAN ++ * components are largely represented by a bridge with vlan_protocol 802.1Q, ++ * and S-VLAN components by a bridge with vlan_protocol 802.1ad. ++ * ++ * Currently the driver only offloads vlan_protocol 802.1Q, but the hardware ++ * design is non-conformant, because the switch assigns each frame to a VLAN ++ * based on an entirely different question, as detailed in figure "Basic VLAN ++ * Classification Flow" from its manual and reproduced below. ++ * ++ * Set TAG_TYPE, PCP, DEI, VID to port-default values in VLAN_CFG register ++ * if VLAN_AWARE_ENA[port] and frame has outer tag then: ++ * if VLAN_INNER_TAG_ENA[port] and frame has inner tag then: ++ * TAG_TYPE = (Frame.InnerTPID <> 0x8100) ++ * Set PCP, DEI, VID to values from inner VLAN header ++ * else: ++ * TAG_TYPE = (Frame.OuterTPID <> 0x8100) ++ * Set PCP, DEI, VID to values from outer VLAN header ++ * if VID == 0 then: ++ * VID = VLAN_CFG.VLAN_VID ++ * ++ * Summarized, the switch will recognize both 802.1Q and 802.1ad TPIDs as VLAN ++ * "with equal rights", and just set the TAG_TYPE bit to 0 (if 802.1Q) or to 1 ++ * (if 802.1ad). It will classify based on whichever of the tags is "outer", no ++ * matter what TPID that may have (or "inner", if VLAN_INNER_TAG_ENA[port]). ++ * ++ * In the VLAN Table, the TAG_TYPE information is not accessible - just the ++ * classified VID is - so it is as if each VLAN Table entry is for 2 VLANs: ++ * C-VLAN X, and S-VLAN X. ++ * ++ * Whereas the Linux bridge behavior is to only filter on frames with a TPID ++ * equal to the vlan_protocol, and treat everything else as VLAN-untagged. ++ * ++ * Consider an ingress packet tagged with 802.1ad VID=3 and 802.1Q VID=5, ++ * received on a bridge vlan_filtering=1 vlan_protocol=802.1Q port. This frame ++ * should be treated as 802.1Q-untagged, and classified to the PVID of that ++ * bridge port. Not to VID=3, and not to VID=5. ++ * ++ * The VCAP IS1 TCAM has everything we need to overwrite the choices made in ++ * the basic VLAN classification pipeline: it can match on TAG_TYPE in the key, ++ * and it can modify the classified VID in the action. Thus, for each port ++ * under a vlan_filtering bridge, we can insert a rule in VCAP IS1 lookup 0 to ++ * match on 802.1ad tagged frames and modify their classified VID to the 802.1Q ++ * PVID of the port. This effectively makes it appear to the outside world as ++ * if those packets were processed as VLAN-untagged. ++ * ++ * The rule needs to be updated each time the bridge PVID changes, and needs ++ * to be deleted if the bridge PVID is deleted, or if the port becomes ++ * VLAN-unaware. ++ */ ++static int ocelot_update_vlan_reclassify_rule(struct ocelot *ocelot, int port) ++{ ++ unsigned long cookie = OCELOT_VCAP_IS1_VLAN_RECLASSIFY(ocelot, port); ++ struct ocelot_vcap_block *block_vcap_is1 = &ocelot->block[VCAP_IS1]; ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ const struct ocelot_bridge_vlan *pvid_vlan; ++ struct ocelot_vcap_filter *filter; ++ int err, val, pcp, dei; ++ bool vid_replace_ena; ++ u16 vid; ++ ++ pvid_vlan = ocelot_port->pvid_vlan; ++ vid_replace_ena = ocelot_port->vlan_aware && pvid_vlan; ++ ++ filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, cookie, ++ false); ++ if (!vid_replace_ena) { ++ /* If the reclassification filter doesn't need to exist, delete ++ * it if it was previously installed, and exit doing nothing ++ * otherwise. ++ */ ++ if (filter) ++ return ocelot_vcap_filter_del(ocelot, filter); ++ ++ return 0; ++ } ++ ++ /* The reclassification rule must apply. See if it already exists ++ * or if it must be created. ++ */ ++ ++ /* Treating as VLAN-untagged means using as classified VID equal to ++ * the bridge PVID, and PCP/DEI set to the port default QoS values. ++ */ ++ vid = pvid_vlan->vid; ++ val = ocelot_read_gix(ocelot, ANA_PORT_QOS_CFG, port); ++ pcp = ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_X(val); ++ dei = !!(val & ANA_PORT_QOS_CFG_DP_DEFAULT_VAL); ++ ++ if (filter) { ++ bool changed = false; ++ ++ /* Filter exists, just update it */ ++ if (filter->action.vid != vid) { ++ filter->action.vid = vid; ++ changed = true; ++ } ++ if (filter->action.pcp != pcp) { ++ filter->action.pcp = pcp; ++ changed = true; ++ } ++ if (filter->action.dei != dei) { ++ filter->action.dei = dei; ++ changed = true; ++ } ++ ++ if (!changed) ++ return 0; ++ ++ return ocelot_vcap_filter_replace(ocelot, filter); ++ } ++ ++ /* Filter doesn't exist, create it */ ++ filter = kzalloc(sizeof(*filter), GFP_KERNEL); ++ if (!filter) ++ return -ENOMEM; ++ ++ filter->key_type = OCELOT_VCAP_KEY_ANY; ++ filter->ingress_port_mask = BIT(port); ++ filter->vlan.tpid = OCELOT_VCAP_BIT_1; ++ filter->prio = 1; ++ filter->id.cookie = cookie; ++ filter->id.tc_offload = false; ++ filter->block_id = VCAP_IS1; ++ filter->type = OCELOT_VCAP_FILTER_OFFLOAD; ++ filter->lookup = 0; ++ filter->action.vid_replace_ena = true; ++ filter->action.pcp_dei_ena = true; ++ filter->action.vid = vid; ++ filter->action.pcp = pcp; ++ filter->action.dei = dei; ++ ++ err = ocelot_vcap_filter_add(ocelot, filter, NULL); ++ if (err) ++ kfree(filter); ++ ++ return err; ++} ++ + /* Default vlan to clasify for untagged frames (may be zero) */ +-static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, +- const struct ocelot_bridge_vlan *pvid_vlan) ++static int ocelot_port_set_pvid(struct ocelot *ocelot, int port, ++ const struct ocelot_bridge_vlan *pvid_vlan) + { + struct ocelot_port *ocelot_port = ocelot->ports[port]; + u16 pvid = ocelot_vlan_unaware_pvid(ocelot, ocelot_port->bridge); +@@ -475,15 +624,23 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, + * happens automatically), but also 802.1p traffic which gets + * classified to VLAN 0, but that is always in our RX filter, so it + * would get accepted were it not for this setting. ++ * ++ * Also, we only support the bridge 802.1Q VLAN protocol, so ++ * 802.1ad-tagged frames (carrying S-Tags) should be considered ++ * 802.1Q-untagged, and also dropped. + */ + if (!pvid_vlan && ocelot_port->vlan_aware) + val = ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | +- ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA; ++ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA | ++ ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA; + + ocelot_rmw_gix(ocelot, val, + ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | +- ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, ++ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA | ++ ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA, + ANA_PORT_DROP_CFG, port); ++ ++ return ocelot_update_vlan_reclassify_rule(ocelot, port); + } + + static struct ocelot_bridge_vlan *ocelot_bridge_vlan_find(struct ocelot *ocelot, +@@ -631,7 +788,10 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, + ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M, + ANA_PORT_VLAN_CFG, port); + +- ocelot_port_set_pvid(ocelot, port, ocelot_port->pvid_vlan); ++ err = ocelot_port_set_pvid(ocelot, port, ocelot_port->pvid_vlan); ++ if (err) ++ return err; ++ + ocelot_port_manage_port_tag(ocelot, port); + + return 0; +@@ -670,6 +830,7 @@ EXPORT_SYMBOL(ocelot_vlan_prepare); + int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, + bool untagged) + { ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; + int err; + + /* Ignore VID 0 added to our RX filter by the 8021q module, since +@@ -684,9 +845,17 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, + return err; + + /* Default ingress vlan classification */ +- if (pvid) +- ocelot_port_set_pvid(ocelot, port, +- ocelot_bridge_vlan_find(ocelot, vid)); ++ if (pvid) { ++ err = ocelot_port_set_pvid(ocelot, port, ++ ocelot_bridge_vlan_find(ocelot, vid)); ++ if (err) ++ return err; ++ } else if (ocelot_port->pvid_vlan && ++ ocelot_bridge_vlan_find(ocelot, vid) == ocelot_port->pvid_vlan) { ++ err = ocelot_port_set_pvid(ocelot, port, NULL); ++ if (err) ++ return err; ++ } + + /* Untagged egress vlan clasification */ + ocelot_port_manage_port_tag(ocelot, port); +@@ -712,8 +881,11 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) + return err; + + /* Ingress */ +- if (del_pvid) +- ocelot_port_set_pvid(ocelot, port, NULL); ++ if (del_pvid) { ++ err = ocelot_port_set_pvid(ocelot, port, NULL); ++ if (err) ++ return err; ++ } + + /* Egress */ + ocelot_port_manage_port_tag(ocelot, port); +@@ -2607,7 +2779,7 @@ int ocelot_port_set_default_prio(struct ocelot *ocelot, int port, u8 prio) + ANA_PORT_QOS_CFG, + port); + +- return 0; ++ return ocelot_update_vlan_reclassify_rule(ocelot, port); + } + EXPORT_SYMBOL_GPL(ocelot_port_set_default_prio); + +diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c +index 73cdec5ca6a34d..5734b86aed5b53 100644 +--- a/drivers/net/ethernet/mscc/ocelot_vcap.c ++++ b/drivers/net/ethernet/mscc/ocelot_vcap.c +@@ -695,6 +695,7 @@ static void is1_entry_set(struct ocelot *ocelot, int ix, + vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_MC, filter->dmac_mc); + vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_BC, filter->dmac_bc); + vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_TAGGED, tag->tagged); ++ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TPID, tag->tpid); + vcap_key_set(vcap, &data, VCAP_IS1_HK_VID, + tag->vid.value, tag->vid.mask); + vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP, +diff --git a/drivers/net/ethernet/vertexcom/mse102x.c b/drivers/net/ethernet/vertexcom/mse102x.c +index 8f67c39f479eef..060a566bc6aae1 100644 +--- a/drivers/net/ethernet/vertexcom/mse102x.c ++++ b/drivers/net/ethernet/vertexcom/mse102x.c +@@ -6,6 +6,7 @@ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + ++#include + #include + #include + #include +@@ -33,7 +34,7 @@ + #define CMD_CTR (0x2 << CMD_SHIFT) + + #define CMD_MASK GENMASK(15, CMD_SHIFT) +-#define LEN_MASK GENMASK(CMD_SHIFT - 1, 0) ++#define LEN_MASK GENMASK(CMD_SHIFT - 2, 0) + + #define DET_CMD_LEN 4 + #define DET_SOF_LEN 2 +@@ -262,7 +263,7 @@ static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp, + } + + static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff, +- unsigned int frame_len) ++ unsigned int frame_len, bool drop) + { + struct mse102x_net_spi *mses = to_mse102x_spi(mse); + struct spi_transfer *xfer = &mses->spi_xfer; +@@ -280,6 +281,9 @@ static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff, + netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n", + __func__, ret); + mse->stats.xfer_err++; ++ } else if (drop) { ++ netdev_dbg(mse->ndev, "%s: Drop frame\n", __func__); ++ ret = -EINVAL; + } else if (*sof != cpu_to_be16(DET_SOF)) { + netdev_dbg(mse->ndev, "%s: SPI start of frame is invalid (0x%04x)\n", + __func__, *sof); +@@ -307,6 +311,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + struct sk_buff *skb; + unsigned int rxalign; + unsigned int rxlen; ++ bool drop = false; + __be16 rx = 0; + u16 cmd_resp; + u8 *rxpkt; +@@ -329,7 +334,8 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n", + __func__, cmd_resp); + mse->stats.invalid_rts++; +- return; ++ drop = true; ++ goto drop; + } + + net_dbg_ratelimited("%s: Unexpected response to first CMD\n", +@@ -337,12 +343,20 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + } + + rxlen = cmd_resp & LEN_MASK; +- if (!rxlen) { +- net_dbg_ratelimited("%s: No frame length defined\n", __func__); ++ if (rxlen < ETH_ZLEN || rxlen > VLAN_ETH_FRAME_LEN) { ++ net_dbg_ratelimited("%s: Invalid frame length: %d\n", __func__, ++ rxlen); + mse->stats.invalid_len++; +- return; ++ drop = true; + } + ++ /* In case of a invalid CMD_RTS, the frame must be consumed anyway. ++ * So assume the maximum possible frame length. ++ */ ++drop: ++ if (drop) ++ rxlen = VLAN_ETH_FRAME_LEN; ++ + rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4); + skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign); + if (!skb) +@@ -353,7 +367,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + * They are copied, but ignored. + */ + rxpkt = skb_put(skb, rxlen) - DET_SOF_LEN; +- if (mse102x_rx_frame_spi(mse, rxpkt, rxlen)) { ++ if (mse102x_rx_frame_spi(mse, rxpkt, rxlen, drop)) { + mse->ndev->stats.rx_errors++; + dev_kfree_skb(skb); + return; +@@ -509,6 +523,7 @@ static irqreturn_t mse102x_irq(int irq, void *_mse) + static int mse102x_net_open(struct net_device *ndev) + { + struct mse102x_net *mse = netdev_priv(ndev); ++ struct mse102x_net_spi *mses = to_mse102x_spi(mse); + int ret; + + ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT, +@@ -524,6 +539,13 @@ static int mse102x_net_open(struct net_device *ndev) + + netif_carrier_on(ndev); + ++ /* The SPI interrupt can stuck in case of pending packet(s). ++ * So poll for possible packet(s) to re-arm the interrupt. ++ */ ++ mutex_lock(&mses->lock); ++ mse102x_rx_pkt_spi(mse); ++ mutex_unlock(&mses->lock); ++ + netif_dbg(mse, ifup, ndev, "network device up\n"); + + return 0; +diff --git a/drivers/net/mdio/mdio-mux-meson-gxl.c b/drivers/net/mdio/mdio-mux-meson-gxl.c +index 76188575ca1fcf..19153d44800a94 100644 +--- a/drivers/net/mdio/mdio-mux-meson-gxl.c ++++ b/drivers/net/mdio/mdio-mux-meson-gxl.c +@@ -17,6 +17,7 @@ + #define REG2_LEDACT GENMASK(23, 22) + #define REG2_LEDLINK GENMASK(25, 24) + #define REG2_DIV4SEL BIT(27) ++#define REG2_REVERSED BIT(28) + #define REG2_ADCBYPASS BIT(30) + #define REG2_CLKINSEL BIT(31) + #define ETH_REG3 0x4 +@@ -65,7 +66,7 @@ static void gxl_enable_internal_mdio(struct gxl_mdio_mux *priv) + * The only constraint is that it must match the one in + * drivers/net/phy/meson-gxl.c to properly match the PHY. + */ +- writel(FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), ++ writel(REG2_REVERSED | FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), + priv->regs + ETH_REG2); + + /* Enable the internal phy */ +diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c +index bb0bf141587274..7b3739b29c8f72 100644 +--- a/drivers/net/usb/rndis_host.c ++++ b/drivers/net/usb/rndis_host.c +@@ -630,16 +630,6 @@ static const struct driver_info zte_rndis_info = { + .tx_fixup = rndis_tx_fixup, + }; + +-static const struct driver_info wwan_rndis_info = { +- .description = "Mobile Broadband RNDIS device", +- .flags = FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, +- .bind = rndis_bind, +- .unbind = rndis_unbind, +- .status = rndis_status, +- .rx_fixup = rndis_rx_fixup, +- .tx_fixup = rndis_tx_fixup, +-}; +- + /*-------------------------------------------------------------------------*/ + + static const struct usb_device_id products [] = { +@@ -676,11 +666,9 @@ static const struct usb_device_id products [] = { + USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &rndis_info, + }, { +- /* Mobile Broadband Modem, seen in Novatel Verizon USB730L and +- * Telit FN990A (RNDIS) +- */ ++ /* Novatel Verizon USB730L */ + USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1), +- .driver_info = (unsigned long)&wwan_rndis_info, ++ .driver_info = (unsigned long) &rndis_info, + }, + { }, // END + }; +diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c +index 6e6e9f05509ab0..06d19e90eadb59 100644 +--- a/drivers/net/vxlan/vxlan_vnifilter.c ++++ b/drivers/net/vxlan/vxlan_vnifilter.c +@@ -627,7 +627,11 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan, + * default dst remote_ip previously added for this vni + */ + if (!vxlan_addr_any(&vninode->remote_ip) || +- !vxlan_addr_any(&dst->remote_ip)) ++ !vxlan_addr_any(&dst->remote_ip)) { ++ u32 hash_index = fdb_head_index(vxlan, all_zeros_mac, ++ vninode->vni); ++ ++ spin_lock_bh(&vxlan->hash_lock[hash_index]); + __vxlan_fdb_delete(vxlan, all_zeros_mac, + (vxlan_addr_any(&vninode->remote_ip) ? + dst->remote_ip : vninode->remote_ip), +@@ -635,6 +639,8 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan, + vninode->vni, vninode->vni, + dst->remote_ifindex, + true); ++ spin_unlock_bh(&vxlan->hash_lock[hash_index]); ++ } + + if (vxlan->dev->flags & IFF_UP) { + if (vxlan_addr_multicast(&vninode->remote_ip) && +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +index 2178675ae1a44d..6f64a05debd2cb 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -903,14 +903,16 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) + } + + /* 1) Prepare USB boot loader for runtime image */ +- brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state)); ++ err = brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state)); ++ if (err) ++ goto fail; + + rdlstate = le32_to_cpu(state.state); + rdlbytes = le32_to_cpu(state.bytes); + + /* 2) Check we are in the Waiting state */ + if (rdlstate != DL_WAITING) { +- brcmf_err("Failed to DL_START\n"); ++ brcmf_err("Invalid DL state: %u\n", rdlstate); + err = -EINVAL; + goto fail; + } +diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c +index 506d2f31efb5af..7ebc0df0944cb5 100644 +--- a/drivers/net/wireless/purelifi/plfxlc/mac.c ++++ b/drivers/net/wireless/purelifi/plfxlc/mac.c +@@ -103,7 +103,6 @@ int plfxlc_mac_init_hw(struct ieee80211_hw *hw) + void plfxlc_mac_release(struct plfxlc_mac *mac) + { + plfxlc_chip_release(&mac->chip); +- lockdep_assert_held(&mac->lock); + } + + int plfxlc_op_start(struct ieee80211_hw *hw) +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index a763df0200ab46..fdde38903ebcd5 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3377,7 +3377,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev) + + dev_info(dev->ctrl.device, "restart after slot reset\n"); + pci_restore_state(pdev); +- if (!nvme_try_sched_reset(&dev->ctrl)) ++ if (nvme_try_sched_reset(&dev->ctrl)) + nvme_unquiesce_io_queues(&dev->ctrl); + return PCI_ERS_RESULT_RECOVERED; + } +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 84db7f4f861cb1..5b76670f34be29 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1710,7 +1710,7 @@ static void __nvme_tcp_stop_queue(struct nvme_tcp_queue *queue) + cancel_work_sync(&queue->io_work); + } + +-static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid) ++static void nvme_tcp_stop_queue_nowait(struct nvme_ctrl *nctrl, int qid) + { + struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); + struct nvme_tcp_queue *queue = &ctrl->queues[qid]; +@@ -1724,6 +1724,31 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid) + mutex_unlock(&queue->queue_lock); + } + ++static void nvme_tcp_wait_queue(struct nvme_ctrl *nctrl, int qid) ++{ ++ struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); ++ struct nvme_tcp_queue *queue = &ctrl->queues[qid]; ++ int timeout = 100; ++ ++ while (timeout > 0) { ++ if (!test_bit(NVME_TCP_Q_ALLOCATED, &queue->flags) || ++ !sk_wmem_alloc_get(queue->sock->sk)) ++ return; ++ msleep(2); ++ timeout -= 2; ++ } ++ dev_warn(nctrl->device, ++ "qid %d: timeout draining sock wmem allocation expired\n", ++ qid); ++} ++ ++static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid) ++{ ++ nvme_tcp_stop_queue_nowait(nctrl, qid); ++ nvme_tcp_wait_queue(nctrl, qid); ++} ++ ++ + static void nvme_tcp_setup_sock_ops(struct nvme_tcp_queue *queue) + { + write_lock_bh(&queue->sock->sk->sk_callback_lock); +@@ -1790,7 +1815,9 @@ static void nvme_tcp_stop_io_queues(struct nvme_ctrl *ctrl) + int i; + + for (i = 1; i < ctrl->queue_count; i++) +- nvme_tcp_stop_queue(ctrl, i); ++ nvme_tcp_stop_queue_nowait(ctrl, i); ++ for (i = 1; i < ctrl->queue_count; i++) ++ nvme_tcp_wait_queue(ctrl, i); + } + + static int nvme_tcp_start_io_queues(struct nvme_ctrl *ctrl, +diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c +index 822a750b064b27..cedfbd4258631d 100644 +--- a/drivers/pci/controller/dwc/pci-imx6.c ++++ b/drivers/pci/controller/dwc/pci-imx6.c +@@ -1283,7 +1283,8 @@ static int imx6_pcie_probe(struct platform_device *pdev) + case IMX8MQ_EP: + if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR) + imx6_pcie->controller_id = 1; +- ++ fallthrough; ++ case IMX7D: + imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev, + "pciephy"); + if (IS_ERR(imx6_pcie->pciephy_reset)) { +diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c +index 70907e8f3ea96d..946a546cd9dd01 100644 +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -823,10 +823,9 @@ static void amd_pmc_s2idle_check(void) + struct smu_metrics table; + int rc; + +- /* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */ +- if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) && +- table.s0i3_last_entry_status) +- usleep_range(10000, 20000); ++ /* Avoid triggering OVP */ ++ if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status) ++ msleep(2500); + + /* Dump the IdleMask before we add to the STB */ + amd_pmc_idlemask_read(pdev, pdev->dev, NULL); +diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +index a3b25253b6fdeb..2c9c5cc7d854ed 100644 +--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c ++++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +@@ -121,15 +121,13 @@ static int uncore_event_cpu_online(unsigned int cpu) + { + struct uncore_data *data; + int target; ++ int ret; + + /* Check if there is an online cpu in the package for uncore MSR */ + target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu)); + if (target < nr_cpu_ids) + return 0; + +- /* Use this CPU on this die as a control CPU */ +- cpumask_set_cpu(cpu, &uncore_cpu_mask); +- + data = uncore_get_instance(cpu); + if (!data) + return 0; +@@ -138,7 +136,14 @@ static int uncore_event_cpu_online(unsigned int cpu) + data->die_id = topology_die_id(cpu); + data->domain_id = UNCORE_DOMAIN_ID_INVALID; + +- return uncore_freq_add_entry(data, cpu); ++ ret = uncore_freq_add_entry(data, cpu); ++ if (ret) ++ return ret; ++ ++ /* Use this CPU on this die as a control CPU */ ++ cpumask_set_cpu(cpu, &uncore_cpu_mask); ++ ++ return 0; + } + + static int uncore_event_cpu_offline(unsigned int cpu) +diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c +index 460f232dad508b..147d7052794f77 100644 +--- a/drivers/spi/spi-tegra114.c ++++ b/drivers/spi/spi-tegra114.c +@@ -728,9 +728,9 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi) + u32 inactive_cycles; + u8 cs_state; + +- if (setup->unit != SPI_DELAY_UNIT_SCK || +- hold->unit != SPI_DELAY_UNIT_SCK || +- inactive->unit != SPI_DELAY_UNIT_SCK) { ++ if ((setup->unit && setup->unit != SPI_DELAY_UNIT_SCK) || ++ (hold->unit && hold->unit != SPI_DELAY_UNIT_SCK) || ++ (inactive->unit && inactive->unit != SPI_DELAY_UNIT_SCK)) { + dev_err(&spi->dev, + "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n", + SPI_DELAY_UNIT_SCK); +diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c +index 99baa60ef50fe9..15a8402ee8a17a 100644 +--- a/drivers/usb/host/xhci-debugfs.c ++++ b/drivers/usb/host/xhci-debugfs.c +@@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci) + "command-ring", + xhci->debugfs_root); + +- xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring, ++ xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring, + "event-ring", + xhci->debugfs_root); + +diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c +index 0df5d807a77e8f..a2b6a922077ee3 100644 +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -1880,9 +1880,10 @@ int xhci_bus_resume(struct usb_hcd *hcd) + int slot_id; + int sret; + u32 next_state; +- u32 temp, portsc; ++ u32 portsc; + struct xhci_hub *rhub; + struct xhci_port **ports; ++ bool disabled_irq = false; + + rhub = xhci_get_rhub(hcd); + ports = rhub->ports; +@@ -1898,17 +1899,20 @@ int xhci_bus_resume(struct usb_hcd *hcd) + return -ESHUTDOWN; + } + +- /* delay the irqs */ +- temp = readl(&xhci->op_regs->command); +- temp &= ~CMD_EIE; +- writel(temp, &xhci->op_regs->command); +- + /* bus specific resume for ports we suspended at bus_suspend */ +- if (hcd->speed >= HCD_USB3) ++ if (hcd->speed >= HCD_USB3) { + next_state = XDEV_U0; +- else ++ } else { + next_state = XDEV_RESUME; +- ++ if (bus_state->bus_suspended) { ++ /* ++ * prevent port event interrupts from interfering ++ * with usb2 port resume process ++ */ ++ xhci_disable_interrupter(xhci->interrupters[0]); ++ disabled_irq = true; ++ } ++ } + port_index = max_ports; + while (port_index--) { + portsc = readl(ports[port_index]->addr); +@@ -1977,11 +1981,9 @@ int xhci_bus_resume(struct usb_hcd *hcd) + (void) readl(&xhci->op_regs->command); + + bus_state->next_statechange = jiffies + msecs_to_jiffies(5); +- /* re-enable irqs */ +- temp = readl(&xhci->op_regs->command); +- temp |= CMD_EIE; +- writel(temp, &xhci->op_regs->command); +- temp = readl(&xhci->op_regs->command); ++ /* re-enable interrupter */ ++ if (disabled_irq) ++ xhci_enable_interrupter(xhci->interrupters[0]); + + spin_unlock_irqrestore(&xhci->lock, flags); + return 0; +diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c +index fbc486546b8533..22cca89efbfd72 100644 +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -29,6 +29,7 @@ + static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, + unsigned int cycle_state, + unsigned int max_packet, ++ unsigned int num, + gfp_t flags) + { + struct xhci_segment *seg; +@@ -60,6 +61,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, + for (i = 0; i < TRBS_PER_SEGMENT; i++) + seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE); + } ++ seg->num = num; + seg->dma = dma; + seg->next = NULL; + +@@ -316,6 +318,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, + */ + ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; + } ++EXPORT_SYMBOL_GPL(xhci_initialize_ring_info); + + /* Allocate segments and link them for a ring */ + static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, +@@ -324,6 +327,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) + { + struct xhci_segment *prev; ++ unsigned int num = 0; + bool chain_links; + + /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */ +@@ -331,16 +335,17 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, + (type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST))); + +- prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); ++ prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags); + if (!prev) + return -ENOMEM; +- num_segs--; ++ num++; + + *first = prev; +- while (num_segs > 0) { ++ while (num < num_segs) { + struct xhci_segment *next; + +- next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); ++ next = xhci_segment_alloc(xhci, cycle_state, max_packet, num, ++ flags); + if (!next) { + prev = *first; + while (prev) { +@@ -353,7 +358,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, + xhci_link_segments(prev, next, type, chain_links); + + prev = next; +- num_segs--; ++ num++; + } + xhci_link_segments(prev, *first, type, chain_links); + *last = prev; +@@ -1799,23 +1804,13 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, + } + + static void +-xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) ++xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + { +- struct device *dev = xhci_to_hcd(xhci)->self.sysdev; +- size_t erst_size; +- u64 tmp64; + u32 tmp; + + if (!ir) + return; + +- erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; +- if (ir->erst.entries) +- dma_free_coherent(dev, erst_size, +- ir->erst.entries, +- ir->erst.erst_dma_addr); +- ir->erst.entries = NULL; +- + /* + * Clean out interrupter registers except ERSTBA. Clearing either the + * low or high 32 bits of ERSTBA immediately causes the controller to +@@ -1826,19 +1821,60 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + tmp &= ERST_SIZE_MASK; + writel(tmp, &ir->ir_set->erst_size); + +- tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); +- tmp64 &= (u64) ERST_PTR_MASK; +- xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue); ++ xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue); + } ++} + +- /* free interrrupter event ring */ ++static void ++xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) ++{ ++ struct device *dev = xhci_to_hcd(xhci)->self.sysdev; ++ size_t erst_size; ++ ++ if (!ir) ++ return; ++ ++ erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; ++ if (ir->erst.entries) ++ dma_free_coherent(dev, erst_size, ++ ir->erst.entries, ++ ir->erst.erst_dma_addr); ++ ir->erst.entries = NULL; ++ ++ /* free interrupter event ring */ + if (ir->event_ring) + xhci_ring_free(xhci, ir->event_ring); ++ + ir->event_ring = NULL; + + kfree(ir); + } + ++void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir) ++{ ++ struct xhci_hcd *xhci = hcd_to_xhci(hcd); ++ unsigned int intr_num; ++ ++ spin_lock_irq(&xhci->lock); ++ ++ /* interrupter 0 is primary interrupter, don't touch it */ ++ if (!ir || !ir->intr_num || ir->intr_num >= xhci->max_interrupters) { ++ xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n"); ++ spin_unlock_irq(&xhci->lock); ++ return; ++ } ++ ++ intr_num = ir->intr_num; ++ ++ xhci_remove_interrupter(xhci, ir); ++ xhci->interrupters[intr_num] = NULL; ++ ++ spin_unlock_irq(&xhci->lock); ++ ++ xhci_free_interrupter(xhci, ir); ++} ++EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter); ++ + void xhci_mem_cleanup(struct xhci_hcd *xhci) + { + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; +@@ -1846,9 +1882,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + + cancel_delayed_work_sync(&xhci->cmd_timer); + +- xhci_free_interrupter(xhci, xhci->interrupter); +- xhci->interrupter = NULL; +- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring"); ++ for (i = 0; xhci->interrupters && i < xhci->max_interrupters; i++) { ++ if (xhci->interrupters[i]) { ++ xhci_remove_interrupter(xhci, xhci->interrupters[i]); ++ xhci_free_interrupter(xhci, xhci->interrupters[i]); ++ xhci->interrupters[i] = NULL; ++ } ++ } ++ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters"); + + if (xhci->cmd_ring) + xhci_ring_free(xhci, xhci->cmd_ring); +@@ -1918,6 +1959,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + for (i = 0; i < xhci->num_port_caps; i++) + kfree(xhci->port_caps[i].psi); + kfree(xhci->port_caps); ++ kfree(xhci->interrupters); + xhci->num_port_caps = 0; + + xhci->usb2_rhub.ports = NULL; +@@ -1926,6 +1968,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + xhci->rh_bw = NULL; + xhci->ext_caps = NULL; + xhci->port_caps = NULL; ++ xhci->interrupters = NULL; + + xhci->page_size = 0; + xhci->page_shift = 0; +@@ -1935,7 +1978,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) + + static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + { +- u64 temp; + dma_addr_t deq; + + deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, +@@ -1943,15 +1985,12 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter + if (!deq) + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n"); + /* Update HC event ring dequeue pointer */ +- temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); +- temp &= ERST_PTR_MASK; + /* Don't clear the EHB bit (which is RW1C) because + * there might be more events to service. + */ +- temp &= ~ERST_EHB; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Write event ring dequeue pointer, preserving EHB bit"); +- xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, ++ xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK), + &ir->ir_set->erst_dequeue); + } + +@@ -2236,18 +2275,24 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) + } + + static struct xhci_interrupter * +-xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags) ++xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags) + { + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + struct xhci_interrupter *ir; ++ unsigned int max_segs; + int ret; + ++ if (!segs) ++ segs = ERST_DEFAULT_SEGS; ++ ++ max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2)); ++ segs = min(segs, max_segs); ++ + ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); + if (!ir) + return NULL; + +- ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, +- 0, flags); ++ ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags); + if (!ir->event_ring) { + xhci_warn(xhci, "Failed to allocate interrupter event ring\n"); + kfree(ir); +@@ -2278,12 +2323,19 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, + return -EINVAL; + } + ++ if (xhci->interrupters[intr_num]) { ++ xhci_warn(xhci, "Interrupter %d\n already set up", intr_num); ++ return -EINVAL; ++ } ++ ++ xhci->interrupters[intr_num] = ir; ++ ir->intr_num = intr_num; + ir->ir_set = &xhci->run_regs->ir_set[intr_num]; + + /* set ERST count with the number of entries in the segment table */ + erst_size = readl(&ir->ir_set->erst_size); + erst_size &= ERST_SIZE_MASK; +- erst_size |= ERST_NUM_SEGS; ++ erst_size |= ir->event_ring->num_segs; + writel(erst_size, &ir->ir_set->erst_size); + + erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); +@@ -2300,10 +2352,58 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, + return 0; + } + ++struct xhci_interrupter * ++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, ++ u32 imod_interval) ++{ ++ struct xhci_hcd *xhci = hcd_to_xhci(hcd); ++ struct xhci_interrupter *ir; ++ unsigned int i; ++ int err = -ENOSPC; ++ ++ if (!xhci->interrupters || xhci->max_interrupters <= 1) ++ return NULL; ++ ++ ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL); ++ if (!ir) ++ return NULL; ++ ++ spin_lock_irq(&xhci->lock); ++ ++ /* Find available secondary interrupter, interrupter 0 is reserved for primary */ ++ for (i = 1; i < xhci->max_interrupters; i++) { ++ if (xhci->interrupters[i] == NULL) { ++ err = xhci_add_interrupter(xhci, ir, i); ++ break; ++ } ++ } ++ ++ spin_unlock_irq(&xhci->lock); ++ ++ if (err) { ++ xhci_warn(xhci, "Failed to add secondary interrupter, max interrupters %d\n", ++ xhci->max_interrupters); ++ xhci_free_interrupter(xhci, ir); ++ return NULL; ++ } ++ ++ err = xhci_set_interrupter_moderation(ir, imod_interval); ++ if (err) ++ xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n", ++ i, imod_interval); ++ ++ xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n", ++ i, xhci->max_interrupters); ++ ++ return ir; ++} ++EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter); ++ + int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) + { +- dma_addr_t dma; ++ struct xhci_interrupter *ir; + struct device *dev = xhci_to_hcd(xhci)->self.sysdev; ++ dma_addr_t dma; + unsigned int val, val2; + u64 val_64; + u32 page_size, temp; +@@ -2428,11 +2528,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) + /* Allocate and set up primary interrupter 0 with an event ring. */ + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Allocating primary event ring"); +- xhci->interrupter = xhci_alloc_interrupter(xhci, flags); +- if (!xhci->interrupter) ++ xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters), ++ flags, dev_to_node(dev)); ++ ++ ir = xhci_alloc_interrupter(xhci, 0, flags); ++ if (!ir) + goto fail; + +- if (xhci_add_interrupter(xhci, xhci->interrupter, 0)) ++ if (xhci_add_interrupter(xhci, ir, 0)) + goto fail; + + xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index cb944396294516..5a53280fa2edfd 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -3167,7 +3167,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + return; + + /* Update HC event ring dequeue pointer */ +- temp_64 &= ERST_DESI_MASK; ++ temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK; + temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK); + } + +@@ -3225,7 +3225,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) + writel(status, &xhci->op_regs->status); + + /* This is the handler of the primary interrupter */ +- ir = xhci->interrupter; ++ ir = xhci->interrupters[0]; + if (!hcd->msi_enabled) { + u32 irq_pending; + irq_pending = readl(&ir->ir_set->irq_pending); +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 70e6c240a5409f..ce38cd2435c8c3 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -297,7 +297,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) + xhci_info(xhci, "Fault detected\n"); + } + +-static int xhci_enable_interrupter(struct xhci_interrupter *ir) ++int xhci_enable_interrupter(struct xhci_interrupter *ir) + { + u32 iman; + +@@ -310,7 +310,7 @@ static int xhci_enable_interrupter(struct xhci_interrupter *ir) + return 0; + } + +-static int xhci_disable_interrupter(struct xhci_interrupter *ir) ++int xhci_disable_interrupter(struct xhci_interrupter *ir) + { + u32 iman; + +@@ -323,6 +323,23 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) + return 0; + } + ++/* interrupt moderation interval imod_interval in nanoseconds */ ++int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, ++ u32 imod_interval) ++{ ++ u32 imod; ++ ++ if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250) ++ return -EINVAL; ++ ++ imod = readl(&ir->ir_set->irq_control); ++ imod &= ~ER_IRQ_INTERVAL_MASK; ++ imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK; ++ writel(imod, &ir->ir_set->irq_control); ++ ++ return 0; ++} ++ + static void compliance_mode_recovery(struct timer_list *t) + { + struct xhci_hcd *xhci; +@@ -457,7 +474,7 @@ static int xhci_init(struct usb_hcd *hcd) + + static int xhci_run_finished(struct xhci_hcd *xhci) + { +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir = xhci->interrupters[0]; + unsigned long flags; + u32 temp; + +@@ -505,11 +522,10 @@ static int xhci_run_finished(struct xhci_hcd *xhci) + */ + int xhci_run(struct usb_hcd *hcd) + { +- u32 temp; + u64 temp_64; + int ret; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir = xhci->interrupters[0]; + /* Start the xHCI host controller running only after the USB 2.0 roothub + * is setup. + */ +@@ -525,12 +541,7 @@ int xhci_run(struct usb_hcd *hcd) + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "ERST deq = 64'h%0lx", (long unsigned int) temp_64); + +- xhci_dbg_trace(xhci, trace_xhci_dbg_init, +- "// Set the interrupt modulation register"); +- temp = readl(&ir->ir_set->irq_control); +- temp &= ~ER_IRQ_INTERVAL_MASK; +- temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK; +- writel(temp, &ir->ir_set->irq_control); ++ xhci_set_interrupter_moderation(ir, xhci->imod_interval); + + if (xhci->quirks & XHCI_NEC_HOST) { + struct xhci_command *command; +@@ -573,7 +584,7 @@ void xhci_stop(struct usb_hcd *hcd) + { + u32 temp; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir = xhci->interrupters[0]; + + mutex_lock(&xhci->mutex); + +@@ -669,36 +680,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown); + #ifdef CONFIG_PM + static void xhci_save_registers(struct xhci_hcd *xhci) + { +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir; ++ unsigned int i; + + xhci->s3.command = readl(&xhci->op_regs->command); + xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification); + xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); + xhci->s3.config_reg = readl(&xhci->op_regs->config_reg); + +- if (!ir) +- return; ++ /* save both primary and all secondary interrupters */ ++ /* fixme, shold we lock to prevent race with remove secondary interrupter? */ ++ for (i = 0; i < xhci->max_interrupters; i++) { ++ ir = xhci->interrupters[i]; ++ if (!ir) ++ continue; + +- ir->s3_erst_size = readl(&ir->ir_set->erst_size); +- ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); +- ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); +- ir->s3_irq_pending = readl(&ir->ir_set->irq_pending); +- ir->s3_irq_control = readl(&ir->ir_set->irq_control); ++ ir->s3_erst_size = readl(&ir->ir_set->erst_size); ++ ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); ++ ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); ++ ir->s3_irq_pending = readl(&ir->ir_set->irq_pending); ++ ir->s3_irq_control = readl(&ir->ir_set->irq_control); ++ } + } + + static void xhci_restore_registers(struct xhci_hcd *xhci) + { +- struct xhci_interrupter *ir = xhci->interrupter; ++ struct xhci_interrupter *ir; ++ unsigned int i; + + writel(xhci->s3.command, &xhci->op_regs->command); + writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification); + xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); + writel(xhci->s3.config_reg, &xhci->op_regs->config_reg); +- writel(ir->s3_erst_size, &ir->ir_set->erst_size); +- xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base); +- xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue); +- writel(ir->s3_irq_pending, &ir->ir_set->irq_pending); +- writel(ir->s3_irq_control, &ir->ir_set->irq_control); ++ ++ /* FIXME should we lock to protect against freeing of interrupters */ ++ for (i = 0; i < xhci->max_interrupters; i++) { ++ ir = xhci->interrupters[i]; ++ if (!ir) ++ continue; ++ ++ writel(ir->s3_erst_size, &ir->ir_set->erst_size); ++ xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base); ++ xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue); ++ writel(ir->s3_irq_pending, &ir->ir_set->irq_pending); ++ writel(ir->s3_irq_control, &ir->ir_set->irq_control); ++ } + } + + static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) +@@ -1061,7 +1087,7 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg) + xhci_dbg(xhci, "// Disabling event ring interrupts\n"); + temp = readl(&xhci->op_regs->status); + writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status); +- xhci_disable_interrupter(xhci->interrupter); ++ xhci_disable_interrupter(xhci->interrupters[0]); + + xhci_dbg(xhci, "cleaning up memory\n"); + xhci_mem_cleanup(xhci); +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index df87e8bcb7d246..74bdd035d756a4 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1293,6 +1293,7 @@ struct xhci_segment { + union xhci_trb *trbs; + /* private to HCD */ + struct xhci_segment *next; ++ unsigned int num; + dma_addr_t dma; + /* Max packet sized bounce buffer for td-fragmant alignment */ + dma_addr_t bounce_dma; +@@ -1422,12 +1423,8 @@ struct urb_priv { + struct xhci_td td[]; + }; + +-/* +- * Each segment table entry is 4*32bits long. 1K seems like an ok size: +- * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, +- * meaning 64 ring segments. +- * Initial allocated size of the ERST, in number of entries */ +-#define ERST_NUM_SEGS 1 ++/* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */ ++#define ERST_DEFAULT_SEGS 2 + /* Poll every 60 seconds */ + #define POLL_TIMEOUT 60 + /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ +@@ -1552,7 +1549,7 @@ struct xhci_hcd { + struct reset_control *reset; + /* data structures */ + struct xhci_device_context_array *dcbaa; +- struct xhci_interrupter *interrupter; ++ struct xhci_interrupter **interrupters; + struct xhci_ring *cmd_ring; + unsigned int cmd_ring_state; + #define CMD_RING_STATE_RUNNING (1 << 0) +@@ -1869,6 +1866,11 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, + int type, gfp_t flags); + void xhci_free_container_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx); ++struct xhci_interrupter * ++xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, ++ u32 imod_interval); ++void xhci_remove_secondary_interrupter(struct usb_hcd ++ *hcd, struct xhci_interrupter *ir); + + /* xHCI host controller glue */ + typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); +@@ -1904,6 +1906,10 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + struct usb_device *hdev, + struct usb_tt *tt, gfp_t mem_flags); ++int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, ++ u32 imod_interval); ++int xhci_enable_interrupter(struct xhci_interrupter *ir); ++int xhci_disable_interrupter(struct xhci_interrupter *ir); + + /* xHCI ring, segment, TRB, and TD functions */ + dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 11c4d69177f0ca..48d2579236729d 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -2058,12 +2058,13 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, + + /* + * If the found extent starts after requested offset, then +- * adjust extent_end to be right before this extent begins ++ * adjust cur_offset to be right before this extent begins. + */ + if (found_key.offset > cur_offset) { +- extent_end = found_key.offset; +- extent_type = 0; +- goto must_cow; ++ if (cow_start == (u64)-1) ++ cow_start = cur_offset; ++ cur_offset = found_key.offset; ++ goto next_slot; + } + + /* +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index 0af3535e08f308..4536b6fcfa0256 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -2932,6 +2932,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, + req->CreateContextsOffset = cpu_to_le32( + sizeof(struct smb2_create_req) + + iov[1].iov_len); ++ le32_add_cpu(&req->CreateContextsLength, iov[n_iov-1].iov_len); + pc_buf = iov[n_iov-1].iov_base; + } + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index 5345d2417c7fc9..f4b20b80af0620 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -546,7 +546,19 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, + retval = -ENOMEM; + goto out; + } +- sess->user = user; ++ ++ if (!sess->user) { ++ /* First successful authentication */ ++ sess->user = user; ++ } else { ++ if (!ksmbd_compare_user(sess->user, user)) { ++ ksmbd_debug(AUTH, "different user tried to reuse session\n"); ++ retval = -EPERM; ++ ksmbd_free_user(user); ++ goto out; ++ } ++ ksmbd_free_user(user); ++ } + + memcpy(sess->sess_key, resp->payload, resp->session_key_len); + memcpy(out_blob, resp->payload + resp->session_key_len, +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index d41d67ec5ee51a..13750a5e5ba02e 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -1599,11 +1599,6 @@ static int krb5_authenticate(struct ksmbd_work *work, + if (prev_sess_id && prev_sess_id != sess->id) + destroy_previous_session(conn, sess->user, prev_sess_id); + +- if (sess->state == SMB2_SESSION_VALID) { +- ksmbd_free_user(sess->user); +- sess->user = NULL; +- } +- + retval = ksmbd_krb5_authenticate(sess, in_blob, in_len, + out_blob, &out_len); + if (retval) { +diff --git a/include/linux/bpf.h b/include/linux/bpf.h +index 035e627f94f62d..17de12a98f858a 100644 +--- a/include/linux/bpf.h ++++ b/include/linux/bpf.h +@@ -1430,6 +1430,7 @@ struct bpf_prog_aux { + bool sleepable; + bool tail_call_reachable; + bool xdp_has_frags; ++ bool changes_pkt_data; + /* BTF_KIND_FUNC_PROTO for valid attach_btf_id */ + const struct btf_type *attach_func_proto; + /* function name for valid attach_btf_id */ +diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h +index 92919d52f7e1b2..32e89758176be8 100644 +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -573,6 +573,7 @@ struct bpf_subprog_info { + bool tail_call_reachable; + bool has_ld_abs; + bool is_async_cb; ++ bool changes_pkt_data; + }; + + struct bpf_verifier_env; +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index 9ca4211c063f39..184a84dd467ec7 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -787,8 +787,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy, + int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy); + + int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, +- unsigned int target_freq, +- unsigned int relation); ++ unsigned int target_freq, unsigned int min, ++ unsigned int max, unsigned int relation); + int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, + unsigned int freq); + +@@ -853,12 +853,12 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy, + return best; + } + +-/* Works only on sorted freq-tables */ +-static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy, +- unsigned int target_freq, +- bool efficiencies) ++static inline int find_index_l(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ bool efficiencies) + { +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_al(policy, target_freq, +@@ -868,6 +868,14 @@ static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy, + efficiencies); + } + ++/* Works only on sorted freq-tables */ ++static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ bool efficiencies) ++{ ++ return find_index_l(policy, target_freq, policy->min, policy->max, efficiencies); ++} ++ + /* Find highest freq at or below target in a table in ascending order */ + static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy, + unsigned int target_freq, +@@ -921,12 +929,12 @@ static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy, + return best; + } + +-/* Works only on sorted freq-tables */ +-static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy, +- unsigned int target_freq, +- bool efficiencies) ++static inline int find_index_h(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ bool efficiencies) + { +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_ah(policy, target_freq, +@@ -936,6 +944,14 @@ static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy, + efficiencies); + } + ++/* Works only on sorted freq-tables */ ++static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ bool efficiencies) ++{ ++ return find_index_h(policy, target_freq, policy->min, policy->max, efficiencies); ++} ++ + /* Find closest freq to target in a table in ascending order */ + static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, + unsigned int target_freq, +@@ -1006,12 +1022,12 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, + return best; + } + +-/* Works only on sorted freq-tables */ +-static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, +- unsigned int target_freq, +- bool efficiencies) ++static inline int find_index_c(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int min, unsigned int max, ++ bool efficiencies) + { +- target_freq = clamp_val(target_freq, policy->min, policy->max); ++ target_freq = clamp_val(target_freq, min, max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_ac(policy, target_freq, +@@ -1021,7 +1037,17 @@ static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, + efficiencies); + } + +-static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, int idx) ++/* Works only on sorted freq-tables */ ++static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ bool efficiencies) ++{ ++ return find_index_c(policy, target_freq, policy->min, policy->max, efficiencies); ++} ++ ++static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, ++ unsigned int min, unsigned int max, ++ int idx) + { + unsigned int freq; + +@@ -1030,11 +1056,13 @@ static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, int idx) + + freq = policy->freq_table[idx].frequency; + +- return freq == clamp_val(freq, policy->min, policy->max); ++ return freq == clamp_val(freq, min, max); + } + + static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + unsigned int target_freq, ++ unsigned int min, ++ unsigned int max, + unsigned int relation) + { + bool efficiencies = policy->efficiencies_available && +@@ -1045,29 +1073,26 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + relation &= ~CPUFREQ_RELATION_E; + + if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED)) +- return cpufreq_table_index_unsorted(policy, target_freq, +- relation); ++ return cpufreq_table_index_unsorted(policy, target_freq, min, ++ max, relation); + retry: + switch (relation) { + case CPUFREQ_RELATION_L: +- idx = cpufreq_table_find_index_l(policy, target_freq, +- efficiencies); ++ idx = find_index_l(policy, target_freq, min, max, efficiencies); + break; + case CPUFREQ_RELATION_H: +- idx = cpufreq_table_find_index_h(policy, target_freq, +- efficiencies); ++ idx = find_index_h(policy, target_freq, min, max, efficiencies); + break; + case CPUFREQ_RELATION_C: +- idx = cpufreq_table_find_index_c(policy, target_freq, +- efficiencies); ++ idx = find_index_c(policy, target_freq, min, max, efficiencies); + break; + default: + WARN_ON_ONCE(1); + return 0; + } + +- /* Limit frequency index to honor policy->min/max */ +- if (!cpufreq_is_in_limits(policy, idx) && efficiencies) { ++ /* Limit frequency index to honor min and max */ ++ if (!cpufreq_is_in_limits(policy, min, max, idx) && efficiencies) { + efficiencies = false; + goto retry; + } +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 5090e940ba3e46..adf65eacade062 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -915,7 +915,7 @@ bool bpf_jit_needs_zext(void); + bool bpf_jit_supports_subprog_tailcalls(void); + bool bpf_jit_supports_kfunc_call(void); + bool bpf_jit_supports_far_kfunc_call(void); +-bool bpf_helper_changes_pkt_data(void *func); ++bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id); + + static inline bool bpf_dump_raw_ok(const struct cred *cred) + { +diff --git a/include/linux/module.h b/include/linux/module.h +index a98e188cf37b81..f2a8624eef1eca 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -162,6 +162,8 @@ extern void cleanup_module(void); + #define __INITRODATA_OR_MODULE __INITRODATA + #endif /*CONFIG_MODULES*/ + ++struct module_kobject *lookup_or_create_module_kobject(const char *name); ++ + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) + +diff --git a/include/linux/pds/pds_core_if.h b/include/linux/pds/pds_core_if.h +index e838a2b90440ca..17a87c1a55d7c7 100644 +--- a/include/linux/pds/pds_core_if.h ++++ b/include/linux/pds/pds_core_if.h +@@ -79,6 +79,7 @@ enum pds_core_status_code { + PDS_RC_EVFID = 31, /* VF ID does not exist */ + PDS_RC_BAD_FW = 32, /* FW file is invalid or corrupted */ + PDS_RC_ECLIENT = 33, /* No such client id */ ++ PDS_RC_BAD_PCI = 255, /* Broken PCI when reading status */ + }; + + /** +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 5f11f987334190..f7d392d849be56 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -685,6 +685,11 @@ typedef unsigned int sk_buff_data_t; + typedef unsigned char *sk_buff_data_t; + #endif + ++enum skb_tstamp_type { ++ SKB_CLOCK_REALTIME, ++ SKB_CLOCK_MONOTONIC, ++}; ++ + /** + * DOC: Basic sk_buff geometry + * +@@ -804,10 +809,8 @@ typedef unsigned char *sk_buff_data_t; + * @dst_pending_confirm: need to confirm neighbour + * @decrypted: Decrypted SKB + * @slow_gro: state present at GRO time, slower prepare step required +- * @mono_delivery_time: When set, skb->tstamp has the +- * delivery_time in mono clock base (i.e. EDT). Otherwise, the +- * skb->tstamp has the (rcv) timestamp at ingress and +- * delivery_time at egress. ++ * @tstamp_type: When set, skb->tstamp has the ++ * delivery_time clock base of skb->tstamp. + * @napi_id: id of the NAPI struct this skb came from + * @sender_cpu: (aka @napi_id) source CPU in XPS + * @alloc_cpu: CPU which did the skb allocation. +@@ -935,7 +938,7 @@ struct sk_buff { + /* private: */ + __u8 __mono_tc_offset[0]; + /* public: */ +- __u8 mono_delivery_time:1; /* See SKB_MONO_DELIVERY_TIME_MASK */ ++ __u8 tstamp_type:1; /* See skb_tstamp_type */ + #ifdef CONFIG_NET_XGRESS + __u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */ + __u8 tc_skip_classify:1; +@@ -4189,7 +4192,7 @@ static inline void skb_get_new_timestampns(const struct sk_buff *skb, + static inline void __net_timestamp(struct sk_buff *skb) + { + skb->tstamp = ktime_get_real(); +- skb->mono_delivery_time = 0; ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + } + + static inline ktime_t net_timedelta(ktime_t t) +@@ -4198,10 +4201,33 @@ static inline ktime_t net_timedelta(ktime_t t) + } + + static inline void skb_set_delivery_time(struct sk_buff *skb, ktime_t kt, +- bool mono) ++ u8 tstamp_type) + { + skb->tstamp = kt; +- skb->mono_delivery_time = kt && mono; ++ ++ if (kt) ++ skb->tstamp_type = tstamp_type; ++ else ++ skb->tstamp_type = SKB_CLOCK_REALTIME; ++} ++ ++static inline void skb_set_delivery_type_by_clockid(struct sk_buff *skb, ++ ktime_t kt, clockid_t clockid) ++{ ++ u8 tstamp_type = SKB_CLOCK_REALTIME; ++ ++ switch (clockid) { ++ case CLOCK_REALTIME: ++ break; ++ case CLOCK_MONOTONIC: ++ tstamp_type = SKB_CLOCK_MONOTONIC; ++ break; ++ default: ++ WARN_ON_ONCE(1); ++ kt = 0; ++ } ++ ++ skb_set_delivery_time(skb, kt, tstamp_type); + } + + DECLARE_STATIC_KEY_FALSE(netstamp_needed_key); +@@ -4211,8 +4237,8 @@ DECLARE_STATIC_KEY_FALSE(netstamp_needed_key); + */ + static inline void skb_clear_delivery_time(struct sk_buff *skb) + { +- if (skb->mono_delivery_time) { +- skb->mono_delivery_time = 0; ++ if (skb->tstamp_type) { ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + if (static_branch_unlikely(&netstamp_needed_key)) + skb->tstamp = ktime_get_real(); + else +@@ -4222,7 +4248,7 @@ static inline void skb_clear_delivery_time(struct sk_buff *skb) + + static inline void skb_clear_tstamp(struct sk_buff *skb) + { +- if (skb->mono_delivery_time) ++ if (skb->tstamp_type) + return; + + skb->tstamp = 0; +@@ -4230,7 +4256,7 @@ static inline void skb_clear_tstamp(struct sk_buff *skb) + + static inline ktime_t skb_tstamp(const struct sk_buff *skb) + { +- if (skb->mono_delivery_time) ++ if (skb->tstamp_type) + return 0; + + return skb->tstamp; +@@ -4238,7 +4264,7 @@ static inline ktime_t skb_tstamp(const struct sk_buff *skb) + + static inline ktime_t skb_tstamp_cond(const struct sk_buff *skb, bool cond) + { +- if (!skb->mono_delivery_time && skb->tstamp) ++ if (skb->tstamp_type != SKB_CLOCK_MONOTONIC && skb->tstamp) + return skb->tstamp; + + if (static_branch_unlikely(&netstamp_needed_key) || cond) +diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h +index 153960663ce4c2..5af6eb14c5db15 100644 +--- a/include/net/inet_frag.h ++++ b/include/net/inet_frag.h +@@ -76,7 +76,7 @@ struct frag_v6_compare_key { + * @stamp: timestamp of the last received fragment + * @len: total length of the original datagram + * @meat: length of received fragments so far +- * @mono_delivery_time: stamp has a mono delivery time (EDT) ++ * @tstamp_type: stamp has a mono delivery time (EDT) + * @flags: fragment queue flags + * @max_size: maximum received fragment size + * @fqdir: pointer to struct fqdir +@@ -97,7 +97,7 @@ struct inet_frag_queue { + ktime_t stamp; + int len; + int meat; +- u8 mono_delivery_time; ++ u8 tstamp_type; + __u8 flags; + u16 max_size; + struct fqdir *fqdir; +diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h +index c601a4598b0da8..eb19668a06db17 100644 +--- a/include/soc/mscc/ocelot_vcap.h ++++ b/include/soc/mscc/ocelot_vcap.h +@@ -13,6 +13,7 @@ + */ + #define OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream) ((upstream) << 16 | (port)) + #define OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port) (port) ++#define OCELOT_VCAP_IS1_VLAN_RECLASSIFY(ocelot, port) ((ocelot)->num_phys_ports + (port)) + #define OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port) (port) + #define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) ((ocelot)->num_phys_ports + (port)) + #define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2) +@@ -499,6 +500,7 @@ struct ocelot_vcap_key_vlan { + struct ocelot_vcap_u8 pcp; /* PCP (3 bit) */ + enum ocelot_vcap_bit dei; /* DEI */ + enum ocelot_vcap_bit tagged; /* Tagged/untagged frame */ ++ enum ocelot_vcap_bit tpid; + }; + + struct ocelot_vcap_key_etype { +diff --git a/include/sound/ump_convert.h b/include/sound/ump_convert.h +index d099ae27f8491a..682499b871eac4 100644 +--- a/include/sound/ump_convert.h ++++ b/include/sound/ump_convert.h +@@ -19,7 +19,7 @@ struct ump_cvt_to_ump_bank { + /* context for converting from MIDI1 byte stream to UMP packet */ + struct ump_cvt_to_ump { + /* MIDI1 intermediate buffer */ +- unsigned char buf[4]; ++ unsigned char buf[6]; /* up to 6 bytes for SysEx */ + int len; + int cmd_bytes; + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 02f327f05fd619..81fd1bb9941644 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -2893,7 +2893,7 @@ void __weak bpf_jit_compile(struct bpf_prog *prog) + { + } + +-bool __weak bpf_helper_changes_pkt_data(void *func) ++bool __weak bpf_helper_changes_pkt_data(enum bpf_func_id func_id) + { + return false; + } +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index e443506b0a65a1..756e179a1efe3e 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -2636,16 +2636,36 @@ static int cmp_subprogs(const void *a, const void *b) + ((struct bpf_subprog_info *)b)->start; + } + ++/* Find subprogram that contains instruction at 'off' */ ++static struct bpf_subprog_info *find_containing_subprog(struct bpf_verifier_env *env, int off) ++{ ++ struct bpf_subprog_info *vals = env->subprog_info; ++ int l, r, m; ++ ++ if (off >= env->prog->len || off < 0 || env->subprog_cnt == 0) ++ return NULL; ++ ++ l = 0; ++ r = env->subprog_cnt - 1; ++ while (l < r) { ++ m = l + (r - l + 1) / 2; ++ if (vals[m].start <= off) ++ l = m; ++ else ++ r = m - 1; ++ } ++ return &vals[l]; ++} ++ ++/* Find subprogram that starts exactly at 'off' */ + static int find_subprog(struct bpf_verifier_env *env, int off) + { + struct bpf_subprog_info *p; + +- p = bsearch(&off, env->subprog_info, env->subprog_cnt, +- sizeof(env->subprog_info[0]), cmp_subprogs); +- if (!p) ++ p = find_containing_subprog(env, off); ++ if (!p || p->start != off) + return -ENOENT; + return p - env->subprog_info; +- + } + + static int add_subprog(struct bpf_verifier_env *env, int off) +@@ -9344,6 +9364,8 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, + + if (env->log.level & BPF_LOG_LEVEL) + verbose(env, "Func#%d is global and valid. Skipping.\n", subprog); ++ if (env->subprog_info[subprog].changes_pkt_data) ++ clear_all_pkt_pointers(env); + clear_caller_saved_regs(env, caller->regs); + + /* All global functions return a 64-bit SCALAR_VALUE */ +@@ -9987,7 +10009,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn + } + + /* With LD_ABS/IND some JITs save/restore skb from r1. */ +- changes_data = bpf_helper_changes_pkt_data(fn->func); ++ changes_data = bpf_helper_changes_pkt_data(func_id); + if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) { + verbose(env, "kernel subsystem misconfigured func %s#%d: r1 != ctx\n", + func_id_name(func_id), func_id); +@@ -15094,6 +15116,29 @@ static int check_return_code(struct bpf_verifier_env *env) + return 0; + } + ++static void mark_subprog_changes_pkt_data(struct bpf_verifier_env *env, int off) ++{ ++ struct bpf_subprog_info *subprog; ++ ++ subprog = find_containing_subprog(env, off); ++ subprog->changes_pkt_data = true; ++} ++ ++/* 't' is an index of a call-site. ++ * 'w' is a callee entry point. ++ * Eventually this function would be called when env->cfg.insn_state[w] == EXPLORED. ++ * Rely on DFS traversal order and absence of recursive calls to guarantee that ++ * callee's change_pkt_data marks would be correct at that moment. ++ */ ++static void merge_callee_effects(struct bpf_verifier_env *env, int t, int w) ++{ ++ struct bpf_subprog_info *caller, *callee; ++ ++ caller = find_containing_subprog(env, t); ++ callee = find_containing_subprog(env, w); ++ caller->changes_pkt_data |= callee->changes_pkt_data; ++} ++ + /* non-recursive DFS pseudo code + * 1 procedure DFS-iterative(G,v): + * 2 label v as discovered +@@ -15227,6 +15272,7 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns, + bool visit_callee) + { + int ret, insn_sz; ++ int w; + + insn_sz = bpf_is_ldimm64(&insns[t]) ? 2 : 1; + ret = push_insn(t, t + insn_sz, FALLTHROUGH, env); +@@ -15238,8 +15284,10 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns, + mark_jmp_point(env, t + insn_sz); + + if (visit_callee) { ++ w = t + insns[t].imm + 1; + mark_prune_point(env, t); +- ret = push_insn(t, t + insns[t].imm + 1, BRANCH, env); ++ merge_callee_effects(env, t, w); ++ ret = push_insn(t, w, BRANCH, env); + } + return ret; + } +@@ -15291,6 +15339,8 @@ static int visit_insn(int t, struct bpf_verifier_env *env) + mark_prune_point(env, t); + mark_jmp_point(env, t); + } ++ if (bpf_helper_call(insn) && bpf_helper_changes_pkt_data(insn->imm)) ++ mark_subprog_changes_pkt_data(env, t); + if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { + struct bpf_kfunc_call_arg_meta meta; + +@@ -15412,6 +15462,7 @@ static int check_cfg(struct bpf_verifier_env *env) + } + } + ret = 0; /* cfg looks good */ ++ env->prog->aux->changes_pkt_data = env->subprog_info[0].changes_pkt_data; + + err_free: + kvfree(insn_state); +@@ -18572,6 +18623,7 @@ static int jit_subprogs(struct bpf_verifier_env *env) + } + func[i]->aux->num_exentries = num_exentries; + func[i]->aux->tail_call_reachable = env->subprog_info[i].tail_call_reachable; ++ func[i]->aux->changes_pkt_data = env->subprog_info[i].changes_pkt_data; + func[i] = bpf_int_jit_compile(func[i]); + if (!func[i]->jited) { + err = -ENOTSUPP; +@@ -19856,6 +19908,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, + } + if (tgt_prog) { + struct bpf_prog_aux *aux = tgt_prog->aux; ++ bool tgt_changes_pkt_data; + + if (bpf_prog_is_dev_bound(prog->aux) && + !bpf_prog_dev_bound_match(prog, tgt_prog)) { +@@ -19884,6 +19937,14 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, + "Extension programs should be JITed\n"); + return -EINVAL; + } ++ tgt_changes_pkt_data = aux->func ++ ? aux->func[subprog]->aux->changes_pkt_data ++ : aux->changes_pkt_data; ++ if (prog->aux->changes_pkt_data && !tgt_changes_pkt_data) { ++ bpf_log(log, ++ "Extension program changes packet data, while original does not\n"); ++ return -EINVAL; ++ } + } + if (!tgt_prog->jited) { + bpf_log(log, "Can attach to only JITed progs\n"); +@@ -20343,10 +20404,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 + if (ret < 0) + goto skip_full_check; + +- ret = check_attach_btf_id(env); +- if (ret) +- goto skip_full_check; +- + ret = resolve_pseudo_ldimm64(env); + if (ret < 0) + goto skip_full_check; +@@ -20361,6 +20418,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 + if (ret < 0) + goto skip_full_check; + ++ ret = check_attach_btf_id(env); ++ if (ret) ++ goto skip_full_check; ++ + ret = do_check_subprogs(env); + ret = ret ?: do_check_main(env); + +diff --git a/kernel/params.c b/kernel/params.c +index 2d4a0564697e83..c7aed3c51cd538 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -759,7 +759,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-static struct module_kobject * __init locate_module_kobject(const char *name) ++struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +@@ -801,7 +801,7 @@ static void __init kernel_add_sysfs_param(const char *name, + struct module_kobject *mk; + int err; + +- mk = locate_module_kobject(name); ++ mk = lookup_or_create_module_kobject(name); + if (!mk) + return; + +@@ -872,7 +872,7 @@ static void __init version_sysfs_builtin(void) + int err; + + for (vattr = __start___modver; vattr < __stop___modver; vattr++) { +- mk = locate_module_kobject(vattr->module_name); ++ mk = lookup_or_create_module_kobject(vattr->module_name); + if (mk) { + err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); + WARN_ON_ONCE(err); +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index a41c99350a5bf7..95868c31573007 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -7027,13 +7027,14 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, + /* Copy the data into the page, so we can start over. */ + ret = trace_seq_to_buffer(&iter->seq, + page_address(spd.pages[i]), +- trace_seq_used(&iter->seq)); ++ min((size_t)trace_seq_used(&iter->seq), ++ PAGE_SIZE)); + if (ret < 0) { + __free_page(spd.pages[i]); + break; + } + spd.partial[i].offset = 0; +- spd.partial[i].len = trace_seq_used(&iter->seq); ++ spd.partial[i].len = ret; + + trace_seq_init(&iter->seq); + } +diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c +index 2b948d35fb59ea..448ee37ae2450a 100644 +--- a/kernel/trace/trace_output.c ++++ b/kernel/trace/trace_output.c +@@ -950,11 +950,12 @@ enum print_line_t print_event_fields(struct trace_iterator *iter, + struct trace_event_call *call; + struct list_head *head; + ++ lockdep_assert_held_read(&trace_event_sem); ++ + /* ftrace defined events have separate call structures */ + if (event->type <= __TRACE_LAST_TYPE) { + bool found = false; + +- down_read(&trace_event_sem); + list_for_each_entry(call, &ftrace_events, list) { + if (call->event.type == event->type) { + found = true; +@@ -964,7 +965,6 @@ enum print_line_t print_event_fields(struct trace_iterator *iter, + if (call->event.type > __TRACE_LAST_TYPE) + break; + } +- up_read(&trace_event_sem); + if (!found) { + trace_seq_printf(&iter->seq, "UNKNOWN TYPE %d\n", event->type); + goto out; +diff --git a/mm/memblock.c b/mm/memblock.c +index e8a2a1537d6a85..047dce35cf6e0e 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -2122,11 +2122,14 @@ static void __init memmap_init_reserved_pages(void) + struct memblock_region *region; + phys_addr_t start, end; + int nid; ++ unsigned long max_reserved; + + /* + * set nid on all reserved pages and also treat struct + * pages for the NOMAP regions as PageReserved + */ ++repeat: ++ max_reserved = memblock.reserved.max; + for_each_mem_region(region) { + nid = memblock_get_region_node(region); + start = region->base; +@@ -2135,8 +2138,15 @@ static void __init memmap_init_reserved_pages(void) + if (memblock_is_nomap(region)) + reserve_bootmem_region(start, end, nid); + +- memblock_set_node(start, end, &memblock.reserved, nid); ++ memblock_set_node(start, region->size, &memblock.reserved, nid); + } ++ /* ++ * 'max' is changed means memblock.reserved has been doubled its ++ * array, which may result a new reserved region before current ++ * 'start'. Now we should repeat the procedure to set its node id. ++ */ ++ if (max_reserved != memblock.reserved.max) ++ goto repeat; + + /* initialize struct pages for the reserved regions */ + for_each_reserved_mem_region(region) { +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index d4dcdb2370cc98..72ee41b894a520 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7386,6 +7386,9 @@ static int l2cap_recv_frag(struct l2cap_conn *conn, struct sk_buff *skb, + return -ENOMEM; + /* Init rx_len */ + conn->rx_len = len; ++ ++ skb_set_delivery_time(conn->rx_skb, skb->tstamp, ++ skb->tstamp_type); + } + + /* Copy as much as the rx_skb can hold */ +diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c +index 6ef04f9fe481be..4fbfbafdfa0274 100644 +--- a/net/bridge/netfilter/nf_conntrack_bridge.c ++++ b/net/bridge/netfilter/nf_conntrack_bridge.c +@@ -32,7 +32,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, + struct sk_buff *)) + { + int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + unsigned int hlen, ll_rs, mtu; + ktime_t tstamp = skb->tstamp; + struct ip_frag_state state; +@@ -82,7 +82,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, + if (iter.frag) + ip_fraglist_prepare(skb, &iter); + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, data, skb); + if (err || !iter.frag) + break; +@@ -113,7 +113,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, + goto blackhole; + } + +- skb_set_delivery_time(skb2, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb2, tstamp, tstamp_type); + err = output(net, sk, data, skb2); + if (err) + goto blackhole; +diff --git a/net/core/dev.c b/net/core/dev.c +index c31a7f7bedf3db..4006fd164b7bc7 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2189,7 +2189,7 @@ EXPORT_SYMBOL(net_disable_timestamp); + static inline void net_timestamp_set(struct sk_buff *skb) + { + skb->tstamp = 0; +- skb->mono_delivery_time = 0; ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + if (static_branch_unlikely(&netstamp_needed_key)) + skb->tstamp = ktime_get_real(); + } +diff --git a/net/core/filter.c b/net/core/filter.c +index 39eef3370d800e..066277b91a1be8 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -7734,13 +7734,13 @@ BPF_CALL_3(bpf_skb_set_tstamp, struct sk_buff *, skb, + if (!tstamp) + return -EINVAL; + skb->tstamp = tstamp; +- skb->mono_delivery_time = 1; ++ skb->tstamp_type = SKB_CLOCK_MONOTONIC; + break; + case BPF_SKB_TSTAMP_UNSPEC: + if (tstamp) + return -EINVAL; + skb->tstamp = 0; +- skb->mono_delivery_time = 0; ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + break; + default: + return -EINVAL; +@@ -7868,42 +7868,37 @@ static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = { + + #endif /* CONFIG_INET */ + +-bool bpf_helper_changes_pkt_data(void *func) +-{ +- if (func == bpf_skb_vlan_push || +- func == bpf_skb_vlan_pop || +- func == bpf_skb_store_bytes || +- func == bpf_skb_change_proto || +- func == bpf_skb_change_head || +- func == sk_skb_change_head || +- func == bpf_skb_change_tail || +- func == sk_skb_change_tail || +- func == bpf_skb_adjust_room || +- func == sk_skb_adjust_room || +- func == bpf_skb_pull_data || +- func == sk_skb_pull_data || +- func == bpf_clone_redirect || +- func == bpf_l3_csum_replace || +- func == bpf_l4_csum_replace || +- func == bpf_xdp_adjust_head || +- func == bpf_xdp_adjust_meta || +- func == bpf_msg_pull_data || +- func == bpf_msg_push_data || +- func == bpf_msg_pop_data || +- func == bpf_xdp_adjust_tail || +-#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF) +- func == bpf_lwt_seg6_store_bytes || +- func == bpf_lwt_seg6_adjust_srh || +- func == bpf_lwt_seg6_action || +-#endif +-#ifdef CONFIG_INET +- func == bpf_sock_ops_store_hdr_opt || +-#endif +- func == bpf_lwt_in_push_encap || +- func == bpf_lwt_xmit_push_encap) ++bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id) ++{ ++ switch (func_id) { ++ case BPF_FUNC_clone_redirect: ++ case BPF_FUNC_l3_csum_replace: ++ case BPF_FUNC_l4_csum_replace: ++ case BPF_FUNC_lwt_push_encap: ++ case BPF_FUNC_lwt_seg6_action: ++ case BPF_FUNC_lwt_seg6_adjust_srh: ++ case BPF_FUNC_lwt_seg6_store_bytes: ++ case BPF_FUNC_msg_pop_data: ++ case BPF_FUNC_msg_pull_data: ++ case BPF_FUNC_msg_push_data: ++ case BPF_FUNC_skb_adjust_room: ++ case BPF_FUNC_skb_change_head: ++ case BPF_FUNC_skb_change_proto: ++ case BPF_FUNC_skb_change_tail: ++ case BPF_FUNC_skb_pull_data: ++ case BPF_FUNC_skb_store_bytes: ++ case BPF_FUNC_skb_vlan_pop: ++ case BPF_FUNC_skb_vlan_push: ++ case BPF_FUNC_store_hdr_opt: ++ case BPF_FUNC_xdp_adjust_head: ++ case BPF_FUNC_xdp_adjust_meta: ++ case BPF_FUNC_xdp_adjust_tail: ++ /* tail-called program could call any of the above */ ++ case BPF_FUNC_tail_call: + return true; +- +- return false; ++ default: ++ return false; ++ } + } + + const struct bpf_func_proto bpf_event_output_data_proto __weak; +@@ -9443,7 +9438,7 @@ static struct bpf_insn *bpf_convert_tstamp_read(const struct bpf_prog *prog, + TC_AT_INGRESS_MASK | SKB_MONO_DELIVERY_TIME_MASK); + *insn++ = BPF_JMP32_IMM(BPF_JNE, tmp_reg, + TC_AT_INGRESS_MASK | SKB_MONO_DELIVERY_TIME_MASK, 2); +- /* skb->tc_at_ingress && skb->mono_delivery_time, ++ /* skb->tc_at_ingress && skb->tstamp_type, + * read 0 as the (rcv) timestamp. + */ + *insn++ = BPF_MOV64_IMM(value_reg, 0); +@@ -9468,7 +9463,7 @@ static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog, + * the bpf prog is aware the tstamp could have delivery time. + * Thus, write skb->tstamp as is if tstamp_type_access is true. + * Otherwise, writing at ingress will have to clear the +- * mono_delivery_time bit also. ++ * skb->tstamp_type bit also. + */ + if (!prog->tstamp_type_access) { + __u8 tmp_reg = BPF_REG_AX; +@@ -9478,7 +9473,7 @@ static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog, + *insn++ = BPF_JMP32_IMM(BPF_JSET, tmp_reg, TC_AT_INGRESS_MASK, 1); + /* goto */ + *insn++ = BPF_JMP_A(2); +- /* : mono_delivery_time */ ++ /* : skb->tstamp_type */ + *insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, ~SKB_MONO_DELIVERY_TIME_MASK); + *insn++ = BPF_STX_MEM(BPF_B, skb_reg, tmp_reg, SKB_BF_MONO_TC_OFFSET); + } +diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c +index 6dd960ec558cf6..ba0455ad770193 100644 +--- a/net/ieee802154/6lowpan/reassembly.c ++++ b/net/ieee802154/6lowpan/reassembly.c +@@ -130,7 +130,7 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, + goto err; + + fq->q.stamp = skb->tstamp; +- fq->q.mono_delivery_time = skb->mono_delivery_time; ++ fq->q.tstamp_type = skb->tstamp_type; + if (frag_type == LOWPAN_DISPATCH_FRAG1) + fq->q.flags |= INET_FRAG_FIRST_IN; + +diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c +index c88c9034d63004..496308c0238485 100644 +--- a/net/ipv4/inet_fragment.c ++++ b/net/ipv4/inet_fragment.c +@@ -619,7 +619,7 @@ void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head, + skb_mark_not_on_list(head); + head->prev = NULL; + head->tstamp = q->stamp; +- head->mono_delivery_time = q->mono_delivery_time; ++ head->tstamp_type = q->tstamp_type; + + if (sk) + refcount_add(sum_truesize - head_truesize, &sk->sk_wmem_alloc); +diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c +index 877d1e03150c77..484edc8513e4b7 100644 +--- a/net/ipv4/ip_fragment.c ++++ b/net/ipv4/ip_fragment.c +@@ -360,7 +360,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) + qp->iif = dev->ifindex; + + qp->q.stamp = skb->tstamp; +- qp->q.mono_delivery_time = skb->mono_delivery_time; ++ qp->q.tstamp_type = skb->tstamp_type; + qp->q.meat += skb->len; + qp->ecn |= ecn; + add_frag_mem_limit(qp->q.fqdir, skb->truesize); +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 765bd3f2a84089..b8cfe6afc84b88 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -764,7 +764,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + { + struct iphdr *iph; + struct sk_buff *skb2; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + struct rtable *rt = skb_rtable(skb); + unsigned int mtu, hlen, ll_rs; + struct ip_fraglist_iter iter; +@@ -856,7 +856,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + } + } + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, skb); + + if (!err) +@@ -912,7 +912,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + /* + * Put this fragment into the sending queue. + */ +- skb_set_delivery_time(skb2, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb2, tstamp, tstamp_type); + err = output(net, sk, skb2); + if (err) + goto fail; +@@ -1648,7 +1648,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, + arg->csumoffset) = csum_fold(csum_add(nskb->csum, + arg->csum)); + nskb->ip_summed = CHECKSUM_NONE; +- nskb->mono_delivery_time = !!transmit_time; ++ if (transmit_time) ++ nskb->tstamp_type = SKB_CLOCK_MONOTONIC; + if (txhash) + skb_set_hash(nskb, txhash, PKT_HASH_TYPE_L4); + ip_push_pending_frames(sk, &fl4); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 3771ed22c2f56f..560273e7f77365 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1266,7 +1266,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + tp = tcp_sk(sk); + prior_wstamp = tp->tcp_wstamp_ns; + tp->tcp_wstamp_ns = max(tp->tcp_wstamp_ns, tp->tcp_clock_cache); +- skb_set_delivery_time(skb, tp->tcp_wstamp_ns, true); ++ skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); + if (clone_it) { + oskb = skb; + +@@ -1607,7 +1607,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, + + skb_split(skb, buff, len); + +- skb_set_delivery_time(buff, skb->tstamp, true); ++ skb_set_delivery_time(buff, skb->tstamp, SKB_CLOCK_MONOTONIC); + tcp_fragment_tstamp(skb, buff); + + old_factor = tcp_skb_pcount(skb); +@@ -2703,7 +2703,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, + if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { + /* "skb_mstamp_ns" is used as a start point for the retransmit timer */ + tp->tcp_wstamp_ns = tp->tcp_clock_cache; +- skb_set_delivery_time(skb, tp->tcp_wstamp_ns, true); ++ skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); + list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); + tcp_init_tso_segs(skb, mss_now); + goto repair; /* Skip network transmission */ +@@ -3688,11 +3688,11 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, + #ifdef CONFIG_SYN_COOKIES + if (unlikely(synack_type == TCP_SYNACK_COOKIE && ireq->tstamp_ok)) + skb_set_delivery_time(skb, cookie_init_timestamp(req, now), +- true); ++ SKB_CLOCK_MONOTONIC); + else + #endif + { +- skb_set_delivery_time(skb, now, true); ++ skb_set_delivery_time(skb, now, SKB_CLOCK_MONOTONIC); + if (!tcp_rsk(req)->snt_synack) /* Timestamp first SYNACK */ + tcp_rsk(req)->snt_synack = tcp_skb_timestamp_us(skb); + } +@@ -3741,7 +3741,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, + bpf_skops_write_hdr_opt((struct sock *)sk, skb, req, syn_skb, + synack_type, &opts); + +- skb_set_delivery_time(skb, now, true); ++ skb_set_delivery_time(skb, now, SKB_CLOCK_MONOTONIC); + tcp_add_tx_delay(skb, tp); + + return skb; +@@ -3923,7 +3923,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) + + err = tcp_transmit_skb(sk, syn_data, 1, sk->sk_allocation); + +- skb_set_delivery_time(syn, syn_data->skb_mstamp_ns, true); ++ skb_set_delivery_time(syn, syn_data->skb_mstamp_ns, SKB_CLOCK_MONOTONIC); + + /* Now full SYN+DATA was cloned and sent (or not), + * remove the SYN from the original skb (syn_data) +diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c +index 2ab16139c197b3..132cfc3b2c847b 100644 +--- a/net/ipv4/udp_offload.c ++++ b/net/ipv4/udp_offload.c +@@ -247,6 +247,62 @@ static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs) + return segs; + } + ++static void __udpv6_gso_segment_csum(struct sk_buff *seg, ++ struct in6_addr *oldip, ++ const struct in6_addr *newip, ++ __be16 *oldport, __be16 newport) ++{ ++ struct udphdr *uh = udp_hdr(seg); ++ ++ if (ipv6_addr_equal(oldip, newip) && *oldport == newport) ++ return; ++ ++ if (uh->check) { ++ inet_proto_csum_replace16(&uh->check, seg, oldip->s6_addr32, ++ newip->s6_addr32, true); ++ ++ inet_proto_csum_replace2(&uh->check, seg, *oldport, newport, ++ false); ++ if (!uh->check) ++ uh->check = CSUM_MANGLED_0; ++ } ++ ++ *oldip = *newip; ++ *oldport = newport; ++} ++ ++static struct sk_buff *__udpv6_gso_segment_list_csum(struct sk_buff *segs) ++{ ++ const struct ipv6hdr *iph; ++ const struct udphdr *uh; ++ struct ipv6hdr *iph2; ++ struct sk_buff *seg; ++ struct udphdr *uh2; ++ ++ seg = segs; ++ uh = udp_hdr(seg); ++ iph = ipv6_hdr(seg); ++ uh2 = udp_hdr(seg->next); ++ iph2 = ipv6_hdr(seg->next); ++ ++ if (!(*(const u32 *)&uh->source ^ *(const u32 *)&uh2->source) && ++ ipv6_addr_equal(&iph->saddr, &iph2->saddr) && ++ ipv6_addr_equal(&iph->daddr, &iph2->daddr)) ++ return segs; ++ ++ while ((seg = seg->next)) { ++ uh2 = udp_hdr(seg); ++ iph2 = ipv6_hdr(seg); ++ ++ __udpv6_gso_segment_csum(seg, &iph2->saddr, &iph->saddr, ++ &uh2->source, uh->source); ++ __udpv6_gso_segment_csum(seg, &iph2->daddr, &iph->daddr, ++ &uh2->dest, uh->dest); ++ } ++ ++ return segs; ++} ++ + static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb, + netdev_features_t features, + bool is_ipv6) +@@ -259,7 +315,10 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb, + + udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss); + +- return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb); ++ if (is_ipv6) ++ return __udpv6_gso_segment_list_csum(skb); ++ else ++ return __udpv4_gso_segment_list_csum(skb); + } + + struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index cd89a2b35dfb56..c86d5dca29df01 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -864,7 +864,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + struct rt6_info *rt = dst_rt6_info(skb_dst(skb)); + struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? + inet6_sk(skb->sk) : NULL; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + struct ip6_frag_state state; + unsigned int mtu, hlen, nexthdr_offset; + ktime_t tstamp = skb->tstamp; +@@ -958,7 +958,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + if (iter.frag) + ip6_fraglist_prepare(skb, &iter); + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, skb); + if (!err) + IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), +@@ -1019,7 +1019,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + /* + * Put this fragment into the sending queue. + */ +- skb_set_delivery_time(frag, tstamp, mono_delivery_time); ++ skb_set_delivery_time(frag, tstamp, tstamp_type); + err = output(net, sk, frag); + if (err) + goto fail; +diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c +index 857713d7a38a54..7c4af48d529e1e 100644 +--- a/net/ipv6/netfilter.c ++++ b/net/ipv6/netfilter.c +@@ -126,7 +126,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + struct sk_buff *)) + { + int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; +- bool mono_delivery_time = skb->mono_delivery_time; ++ u8 tstamp_type = skb->tstamp_type; + ktime_t tstamp = skb->tstamp; + struct ip6_frag_state state; + u8 *prevhdr, nexthdr = 0; +@@ -192,7 +192,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + if (iter.frag) + ip6_fraglist_prepare(skb, &iter); + +- skb_set_delivery_time(skb, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb, tstamp, tstamp_type); + err = output(net, sk, data, skb); + if (err || !iter.frag) + break; +@@ -225,7 +225,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + goto blackhole; + } + +- skb_set_delivery_time(skb2, tstamp, mono_delivery_time); ++ skb_set_delivery_time(skb2, tstamp, tstamp_type); + err = output(net, sk, data, skb2); + if (err) + goto blackhole; +diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c +index c78b13ea5b196a..82e51b2ec4f512 100644 +--- a/net/ipv6/netfilter/nf_conntrack_reasm.c ++++ b/net/ipv6/netfilter/nf_conntrack_reasm.c +@@ -268,7 +268,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, + fq->iif = dev->ifindex; + + fq->q.stamp = skb->tstamp; +- fq->q.mono_delivery_time = skb->mono_delivery_time; ++ fq->q.tstamp_type = skb->tstamp_type; + fq->q.meat += skb->len; + fq->ecn |= ecn; + if (payload_len > fq->q.max_size) +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 2af98edef87ee0..cb219d4bdf25ed 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -198,7 +198,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, + fq->iif = dev->ifindex; + + fq->q.stamp = skb->tstamp; +- fq->q.mono_delivery_time = skb->mono_delivery_time; ++ fq->q.tstamp_type = skb->tstamp_type; + fq->q.meat += skb->len; + fq->ecn |= ecn; + add_frag_mem_limit(fq->q.fqdir, skb->truesize); +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index f285e52b8b8579..624ab1424eba7d 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -934,7 +934,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 + mark = inet_twsk(sk)->tw_mark; + else + mark = READ_ONCE(sk->sk_mark); +- skb_set_delivery_time(buff, tcp_transmit_time(sk), true); ++ skb_set_delivery_time(buff, tcp_transmit_time(sk), SKB_CLOCK_MONOTONIC); + } + if (txhash) { + /* autoflowlabel/skb_get_hash_flowi6 rely on buff->hash */ +diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c +index b0455fda7d0baf..ac87fcff4795e8 100644 +--- a/net/sched/act_bpf.c ++++ b/net/sched/act_bpf.c +@@ -54,8 +54,8 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb, + bpf_compute_data_pointers(skb); + filter_res = bpf_prog_run(filter, skb); + } +- if (unlikely(!skb->tstamp && skb->mono_delivery_time)) +- skb->mono_delivery_time = 0; ++ if (unlikely(!skb->tstamp && skb->tstamp_type)) ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + if (skb_sk_is_prefetched(skb) && filter_res != TC_ACT_OK) + skb_orphan(skb); + +diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c +index 382c7a71f81f2d..db7151c6b70b79 100644 +--- a/net/sched/cls_bpf.c ++++ b/net/sched/cls_bpf.c +@@ -104,8 +104,8 @@ TC_INDIRECT_SCOPE int cls_bpf_classify(struct sk_buff *skb, + bpf_compute_data_pointers(skb); + filter_res = bpf_prog_run(prog->filter, skb); + } +- if (unlikely(!skb->tstamp && skb->mono_delivery_time)) +- skb->mono_delivery_time = 0; ++ if (unlikely(!skb->tstamp && skb->tstamp_type)) ++ skb->tstamp_type = SKB_CLOCK_REALTIME; + + if (prog->exts_integrated) { + res->class = 0; +diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c +index 19901e77cd3b7f..9b36955e32b142 100644 +--- a/net/sched/sch_drr.c ++++ b/net/sched/sch_drr.c +@@ -35,6 +35,11 @@ struct drr_sched { + struct Qdisc_class_hash clhash; + }; + ++static bool cl_is_active(struct drr_class *cl) ++{ ++ return !list_empty(&cl->alist); ++} ++ + static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid) + { + struct drr_sched *q = qdisc_priv(sch); +@@ -105,6 +110,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + return -ENOBUFS; + + gnet_stats_basic_sync_init(&cl->bstats); ++ INIT_LIST_HEAD(&cl->alist); + cl->common.classid = classid; + cl->quantum = quantum; + cl->qdisc = qdisc_create_dflt(sch->dev_queue, +@@ -229,7 +235,7 @@ static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg) + { + struct drr_class *cl = (struct drr_class *)arg; + +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + } + + static int drr_dump_class(struct Qdisc *sch, unsigned long arg, +@@ -336,7 +342,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + int err = 0; +- bool first; + + cl = drr_classify(skb, sch, &err); + if (cl == NULL) { +@@ -346,7 +351,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- first = !cl->qdisc->q.qlen; + err = qdisc_enqueue(skb, cl->qdisc, to_free); + if (unlikely(err != NET_XMIT_SUCCESS)) { + if (net_xmit_drop_count(err)) { +@@ -356,7 +360,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- if (first) { ++ if (!cl_is_active(cl)) { + list_add_tail(&cl->alist, &q->active); + cl->deficit = cl->quantum; + } +@@ -390,7 +394,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch) + if (unlikely(skb == NULL)) + goto out; + if (cl->qdisc->q.qlen == 0) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + + bstats_update(&cl->bstats, skb); + qdisc_bstats_update(sch, skb); +@@ -431,7 +435,7 @@ static void drr_reset_qdisc(struct Qdisc *sch) + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) { + if (cl->qdisc->q.qlen) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + qdisc_reset(cl->qdisc); + } + } +diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c +index 9fd70462b41d5a..9da86db4d2c2fe 100644 +--- a/net/sched/sch_ets.c ++++ b/net/sched/sch_ets.c +@@ -74,6 +74,11 @@ static const struct nla_policy ets_class_policy[TCA_ETS_MAX + 1] = { + [TCA_ETS_QUANTA_BAND] = { .type = NLA_U32 }, + }; + ++static bool cl_is_active(struct ets_class *cl) ++{ ++ return !list_empty(&cl->alist); ++} ++ + static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr, + unsigned int *quantum, + struct netlink_ext_ack *extack) +@@ -293,7 +298,7 @@ static void ets_class_qlen_notify(struct Qdisc *sch, unsigned long arg) + * to remove them. + */ + if (!ets_class_is_strict(q, cl) && sch->q.qlen) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + } + + static int ets_class_dump(struct Qdisc *sch, unsigned long arg, +@@ -416,7 +421,6 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct ets_sched *q = qdisc_priv(sch); + struct ets_class *cl; + int err = 0; +- bool first; + + cl = ets_classify(skb, sch, &err); + if (!cl) { +@@ -426,7 +430,6 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- first = !cl->qdisc->q.qlen; + err = qdisc_enqueue(skb, cl->qdisc, to_free); + if (unlikely(err != NET_XMIT_SUCCESS)) { + if (net_xmit_drop_count(err)) { +@@ -436,7 +439,7 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return err; + } + +- if (first && !ets_class_is_strict(q, cl)) { ++ if (!cl_is_active(cl) && !ets_class_is_strict(q, cl)) { + list_add_tail(&cl->alist, &q->active); + cl->deficit = cl->quantum; + } +@@ -488,7 +491,7 @@ static struct sk_buff *ets_qdisc_dequeue(struct Qdisc *sch) + if (unlikely(!skb)) + goto out; + if (cl->qdisc->q.qlen == 0) +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + return ets_qdisc_dequeue_skb(sch, skb); + } + +@@ -657,7 +660,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, + } + for (i = q->nbands; i < oldbands; i++) { + if (i >= q->nstrict && q->classes[i].qdisc->q.qlen) +- list_del(&q->classes[i].alist); ++ list_del_init(&q->classes[i].alist); + qdisc_tree_flush_backlog(q->classes[i].qdisc); + } + q->nstrict = nstrict; +@@ -713,7 +716,7 @@ static void ets_qdisc_reset(struct Qdisc *sch) + + for (band = q->nstrict; band < q->nbands; band++) { + if (q->classes[band].qdisc->q.qlen) +- list_del(&q->classes[band].alist); ++ list_del_init(&q->classes[band].alist); + } + for (band = 0; band < q->nbands; band++) + qdisc_reset(q->classes[band].qdisc); +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index 371255e624332f..5d9cccfac4a155 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -203,7 +203,10 @@ eltree_insert(struct hfsc_class *cl) + static inline void + eltree_remove(struct hfsc_class *cl) + { +- rb_erase(&cl->el_node, &cl->sched->eligible); ++ if (!RB_EMPTY_NODE(&cl->el_node)) { ++ rb_erase(&cl->el_node, &cl->sched->eligible); ++ RB_CLEAR_NODE(&cl->el_node); ++ } + } + + static inline void +@@ -1224,7 +1227,8 @@ hfsc_qlen_notify(struct Qdisc *sch, unsigned long arg) + /* vttree is now handled in update_vf() so that update_vf(cl, 0, 0) + * needs to be called explicitly to remove a class from vttree. + */ +- update_vf(cl, 0, 0); ++ if (cl->cl_nactive) ++ update_vf(cl, 0, 0); + if (cl->cl_flags & HFSC_RSC) + eltree_remove(cl); + } +@@ -1566,7 +1570,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) + return err; + } + +- if (first) { ++ if (first && !cl->cl_nactive) { + if (cl->cl_flags & HFSC_RSC) + init_ed(cl, len); + if (cl->cl_flags & HFSC_FSC) +diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c +index 19035ef8387fed..9a3f7ea80b34b9 100644 +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -1485,6 +1485,8 @@ static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) + { + struct htb_class *cl = (struct htb_class *)arg; + ++ if (!cl->prio_activity) ++ return; + htb_deactivate(qdisc_priv(sch), cl); + } + +diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c +index 546c10adcacdea..5e557b960bde33 100644 +--- a/net/sched/sch_qfq.c ++++ b/net/sched/sch_qfq.c +@@ -202,6 +202,11 @@ struct qfq_sched { + */ + enum update_reason {enqueue, requeue}; + ++static bool cl_is_active(struct qfq_class *cl) ++{ ++ return !list_empty(&cl->alist); ++} ++ + static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid) + { + struct qfq_sched *q = qdisc_priv(sch); +@@ -347,7 +352,7 @@ static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) + struct qfq_aggregate *agg = cl->agg; + + +- list_del(&cl->alist); /* remove from RR queue of the aggregate */ ++ list_del_init(&cl->alist); /* remove from RR queue of the aggregate */ + if (list_empty(&agg->active)) /* agg is now inactive */ + qfq_deactivate_agg(q, agg); + } +@@ -477,6 +482,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + gnet_stats_basic_sync_init(&cl->bstats); + cl->common.classid = classid; + cl->deficit = lmax; ++ INIT_LIST_HEAD(&cl->alist); + + cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + classid, NULL); +@@ -985,7 +991,7 @@ static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg, + cl->deficit -= (int) len; + + if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */ +- list_del(&cl->alist); ++ list_del_init(&cl->alist); + else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) { + cl->deficit += agg->lmax; + list_move_tail(&cl->alist, &agg->active); +@@ -1217,7 +1223,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct qfq_class *cl; + struct qfq_aggregate *agg; + int err = 0; +- bool first; + + cl = qfq_classify(skb, sch, &err); + if (cl == NULL) { +@@ -1239,7 +1244,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + + gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; +- first = !cl->qdisc->q.qlen; + err = qdisc_enqueue(skb, cl->qdisc, to_free); + if (unlikely(err != NET_XMIT_SUCCESS)) { + pr_debug("qfq_enqueue: enqueue failed %d\n", err); +@@ -1255,8 +1259,8 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, + ++sch->q.qlen; + + agg = cl->agg; +- /* if the queue was not empty, then done here */ +- if (!first) { ++ /* if the class is active, then done here */ ++ if (cl_is_active(cl)) { + if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && + list_first_entry(&agg->active, struct qfq_class, alist) + == cl && cl->deficit < len) +@@ -1418,6 +1422,8 @@ static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl = (struct qfq_class *)arg; + ++ if (list_empty(&cl->alist)) ++ return; + qfq_deactivate_class(q, cl); + } + +diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c +index 619a817ee91cb8..4c1318ce8ae58f 100644 +--- a/sound/soc/codecs/ak4613.c ++++ b/sound/soc/codecs/ak4613.c +@@ -840,14 +840,14 @@ static void ak4613_parse_of(struct ak4613_priv *priv, + /* Input 1 - 2 */ + for (i = 0; i < 2; i++) { + snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1); +- if (!of_get_property(np, prop, NULL)) ++ if (!of_property_read_bool(np, prop)) + priv->ic |= 1 << i; + } + + /* Output 1 - 6 */ + for (i = 0; i < 6; i++) { + snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1); +- if (!of_get_property(np, prop, NULL)) ++ if (!of_property_read_bool(np, prop)) + priv->oc |= 1 << i; + } + +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index e65fe3a7c3e42c..7eea70eea68b47 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -2935,7 +2935,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop) + unsigned int i, nb_controls; + int ret; + +- if (!of_property_read_bool(dev->of_node, prop)) ++ if (!of_property_present(dev->of_node, prop)) + return 0; + + strings = devm_kcalloc(dev, nb_controls_max, +@@ -3009,23 +3009,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, + if (rx_mask) + snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask); + +- if (of_property_read_bool(np, "dai-tdm-slot-num")) { +- ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); +- if (ret) +- return ret; +- +- if (slots) +- *slots = val; +- } +- +- if (of_property_read_bool(np, "dai-tdm-slot-width")) { +- ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); +- if (ret) +- return ret; ++ ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); ++ if (ret && ret != -EINVAL) ++ return ret; ++ if (!ret && slots) ++ *slots = val; + +- if (slot_width) +- *slot_width = val; +- } ++ ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); ++ if (ret && ret != -EINVAL) ++ return ret; ++ if (!ret && slot_width) ++ *slot_width = val; + + return 0; + } +@@ -3249,10 +3243,10 @@ unsigned int snd_soc_daifmt_parse_format(struct device_node *np, + * SND_SOC_DAIFMT_INV_MASK area + */ + snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix); +- bit = !!of_get_property(np, prop, NULL); ++ bit = of_property_read_bool(np, prop); + + snprintf(prop, sizeof(prop), "%sframe-inversion", prefix); +- frame = !!of_get_property(np, prop, NULL); ++ frame = of_property_read_bool(np, prop); + + switch ((bit << 4) + frame) { + case 0x11: +@@ -3289,12 +3283,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, + * check "[prefix]frame-master" + */ + snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); +- bit = !!of_get_property(np, prop, NULL); ++ bit = of_property_present(np, prop); + if (bit && bitclkmaster) + *bitclkmaster = of_parse_phandle(np, prop, 0); + + snprintf(prop, sizeof(prop), "%sframe-master", prefix); +- frame = !!of_get_property(np, prop, NULL); ++ frame = of_property_present(np, prop); + if (frame && framemaster) + *framemaster = of_parse_phandle(np, prop, 0); + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 60248a6820aacc..30e93f9aad7624 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1534,10 +1534,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, + /* + * Filter for systems with 'component_chaining' enabled. + * This helps to avoid unnecessary re-configuration of an +- * already active BE on such systems. ++ * already active BE on such systems and ensures the BE DAI ++ * widget is powered ON after hw_params() BE DAI callback. + */ + if (fe->card->component_chaining && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && ++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && ++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) + continue; + +diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c +index 68aa174be12d71..f71f6ff3e2b0f7 100644 +--- a/sound/usb/endpoint.c ++++ b/sound/usb/endpoint.c +@@ -926,14 +926,21 @@ static int endpoint_set_interface(struct snd_usb_audio *chip, + { + int altset = set ? ep->altsetting : 0; + int err; ++ int retries = 0; ++ const int max_retries = 5; + + if (ep->iface_ref->altset == altset) + return 0; + + usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n", + ep->iface, altset, ep->ep_num); ++retry: + err = usb_set_interface(chip->dev, ep->iface, altset); + if (err < 0) { ++ if (err == -EPROTO && ++retries <= max_retries) { ++ msleep(5 * (1 << (retries - 1))); ++ goto retry; ++ } + usb_audio_err_ratelimited( + chip, "%d:%d: usb_set_interface failed (%d)\n", + ep->iface, altset, err); +diff --git a/sound/usb/format.c b/sound/usb/format.c +index 3b3a5ea6fcbfc0..f33d25a4e4cc7c 100644 +--- a/sound/usb/format.c ++++ b/sound/usb/format.c +@@ -263,7 +263,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof + } + + /* Jabra Evolve 65 headset */ +- if (chip->usb_id == USB_ID(0x0b0e, 0x030b)) { ++ if (chip->usb_id == USB_ID(0x0b0e, 0x030b) || ++ chip->usb_id == USB_ID(0x0b0e, 0x030c)) { + /* only 48kHz for playback while keeping 16kHz for capture */ + if (fp->nr_rates != 1) + return set_fixed_rate(fp, 48000, SNDRV_PCM_RATE_48000); +diff --git a/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c +new file mode 100644 +index 00000000000000..7526de3790814c +--- /dev/null ++++ b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c +@@ -0,0 +1,107 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "bpf/libbpf.h" ++#include "changes_pkt_data_freplace.skel.h" ++#include "changes_pkt_data.skel.h" ++#include ++ ++static void print_verifier_log(const char *log) ++{ ++ if (env.verbosity >= VERBOSE_VERY) ++ fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log); ++} ++ ++static void test_aux(const char *main_prog_name, ++ const char *to_be_replaced, ++ const char *replacement, ++ bool expect_load) ++{ ++ struct changes_pkt_data_freplace *freplace = NULL; ++ struct bpf_program *freplace_prog = NULL; ++ struct bpf_program *main_prog = NULL; ++ LIBBPF_OPTS(bpf_object_open_opts, opts); ++ struct changes_pkt_data *main = NULL; ++ char log[16*1024]; ++ int err; ++ ++ opts.kernel_log_buf = log; ++ opts.kernel_log_size = sizeof(log); ++ if (env.verbosity >= VERBOSE_SUPER) ++ opts.kernel_log_level = 1 | 2 | 4; ++ main = changes_pkt_data__open_opts(&opts); ++ if (!ASSERT_OK_PTR(main, "changes_pkt_data__open")) ++ goto out; ++ main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name); ++ if (!ASSERT_OK_PTR(main_prog, "main_prog")) ++ goto out; ++ bpf_program__set_autoload(main_prog, true); ++ err = changes_pkt_data__load(main); ++ print_verifier_log(log); ++ if (!ASSERT_OK(err, "changes_pkt_data__load")) ++ goto out; ++ freplace = changes_pkt_data_freplace__open_opts(&opts); ++ if (!ASSERT_OK_PTR(freplace, "changes_pkt_data_freplace__open")) ++ goto out; ++ freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement); ++ if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog")) ++ goto out; ++ bpf_program__set_autoload(freplace_prog, true); ++ bpf_program__set_autoattach(freplace_prog, true); ++ bpf_program__set_attach_target(freplace_prog, ++ bpf_program__fd(main_prog), ++ to_be_replaced); ++ err = changes_pkt_data_freplace__load(freplace); ++ print_verifier_log(log); ++ if (expect_load) { ++ ASSERT_OK(err, "changes_pkt_data_freplace__load"); ++ } else { ++ ASSERT_ERR(err, "changes_pkt_data_freplace__load"); ++ ASSERT_HAS_SUBSTR(log, "Extension program changes packet data", "error log"); ++ } ++ ++out: ++ changes_pkt_data_freplace__destroy(freplace); ++ changes_pkt_data__destroy(main); ++} ++ ++/* There are two global subprograms in both changes_pkt_data.skel.h: ++ * - one changes packet data; ++ * - another does not. ++ * It is ok to freplace subprograms that change packet data with those ++ * that either do or do not. It is only ok to freplace subprograms ++ * that do not change packet data with those that do not as well. ++ * The below tests check outcomes for each combination of such freplace. ++ * Also test a case when main subprogram itself is replaced and is a single ++ * subprogram in a program. ++ */ ++void test_changes_pkt_data_freplace(void) ++{ ++ struct { ++ const char *main; ++ const char *to_be_replaced; ++ bool changes; ++ } mains[] = { ++ { "main_with_subprogs", "changes_pkt_data", true }, ++ { "main_with_subprogs", "does_not_change_pkt_data", false }, ++ { "main_changes", "main_changes", true }, ++ { "main_does_not_change", "main_does_not_change", false }, ++ }; ++ struct { ++ const char *func; ++ bool changes; ++ } replacements[] = { ++ { "changes_pkt_data", true }, ++ { "does_not_change_pkt_data", false } ++ }; ++ char buf[64]; ++ ++ for (int i = 0; i < ARRAY_SIZE(mains); ++i) { ++ for (int j = 0; j < ARRAY_SIZE(replacements); ++j) { ++ snprintf(buf, sizeof(buf), "%s_with_%s", ++ mains[i].to_be_replaced, replacements[j].func); ++ if (!test__start_subtest(buf)) ++ continue; ++ test_aux(mains[i].main, mains[i].to_be_replaced, replacements[j].func, ++ mains[i].changes || !replacements[j].changes); ++ } ++ } ++} +diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data.c b/tools/testing/selftests/bpf/progs/changes_pkt_data.c +new file mode 100644 +index 00000000000000..43cada48b28ad4 +--- /dev/null ++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data.c +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++ ++__noinline ++long changes_pkt_data(struct __sk_buff *sk) ++{ ++ return bpf_skb_pull_data(sk, 0); ++} ++ ++__noinline __weak ++long does_not_change_pkt_data(struct __sk_buff *sk) ++{ ++ return 0; ++} ++ ++SEC("?tc") ++int main_with_subprogs(struct __sk_buff *sk) ++{ ++ changes_pkt_data(sk); ++ does_not_change_pkt_data(sk); ++ return 0; ++} ++ ++SEC("?tc") ++int main_changes(struct __sk_buff *sk) ++{ ++ bpf_skb_pull_data(sk, 0); ++ return 0; ++} ++ ++SEC("?tc") ++int main_does_not_change(struct __sk_buff *sk) ++{ ++ return 0; ++} ++ ++char _license[] SEC("license") = "GPL"; +diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c +new file mode 100644 +index 00000000000000..f9a622705f1b3b +--- /dev/null ++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++ ++SEC("?freplace") ++long changes_pkt_data(struct __sk_buff *sk) ++{ ++ return bpf_skb_pull_data(sk, 0); ++} ++ ++SEC("?freplace") ++long does_not_change_pkt_data(struct __sk_buff *sk) ++{ ++ return 0; ++} ++ ++char _license[] SEC("license") = "GPL"; +diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c +index ee76b51005abe7..3c8f6646e33dae 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_sock.c ++++ b/tools/testing/selftests/bpf/progs/verifier_sock.c +@@ -50,6 +50,13 @@ struct { + __uint(map_flags, BPF_F_NO_PREALLOC); + } sk_storage_map SEC(".maps"); + ++struct { ++ __uint(type, BPF_MAP_TYPE_PROG_ARRAY); ++ __uint(max_entries, 1); ++ __uint(key_size, sizeof(__u32)); ++ __uint(value_size, sizeof(__u32)); ++} jmp_table SEC(".maps"); ++ + SEC("cgroup/skb") + __description("skb->sk: no NULL check") + __failure __msg("invalid mem access 'sock_common_or_null'") +@@ -977,4 +984,53 @@ l1_%=: r0 = *(u8*)(r7 + 0); \ + : __clobber_all); + } + ++__noinline ++long skb_pull_data2(struct __sk_buff *sk, __u32 len) ++{ ++ return bpf_skb_pull_data(sk, len); ++} ++ ++__noinline ++long skb_pull_data1(struct __sk_buff *sk, __u32 len) ++{ ++ return skb_pull_data2(sk, len); ++} ++ ++/* global function calls bpf_skb_pull_data(), which invalidates packet ++ * pointers established before global function call. ++ */ ++SEC("tc") ++__failure __msg("invalid mem access") ++int invalidate_pkt_pointers_from_global_func(struct __sk_buff *sk) ++{ ++ int *p = (void *)(long)sk->data; ++ ++ if ((void *)(p + 1) > (void *)(long)sk->data_end) ++ return TCX_DROP; ++ skb_pull_data1(sk, 0); ++ *p = 42; /* this is unsafe */ ++ return TCX_PASS; ++} ++ ++__noinline ++int tail_call(struct __sk_buff *sk) ++{ ++ bpf_tail_call_static(sk, &jmp_table, 0); ++ return 0; ++} ++ ++/* Tail calls invalidate packet pointers. */ ++SEC("tc") ++__failure __msg("invalid mem access") ++int invalidate_pkt_pointers_by_tail_call(struct __sk_buff *sk) ++{ ++ int *p = (void *)(long)sk->data; ++ ++ if ((void *)(p + 1) > (void *)(long)sk->data_end) ++ return TCX_DROP; ++ tail_call(sk); ++ *p = 42; /* this is unsafe */ ++ return TCX_PASS; ++} ++ + char _license[] SEC("license") = "GPL"; diff --git a/patch/kernel/archive/spacemit-6.6/patch-6.6.90-91.patch b/patch/kernel/archive/spacemit-6.6/patch-6.6.90-91.patch new file mode 100644 index 000000000000..8cffc8d8b248 --- /dev/null +++ b/patch/kernel/archive/spacemit-6.6/patch-6.6.90-91.patch @@ -0,0 +1,4952 @@ +diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu +index 657bdee28d845a..0426ec112155ec 100644 +--- a/Documentation/ABI/testing/sysfs-devices-system-cpu ++++ b/Documentation/ABI/testing/sysfs-devices-system-cpu +@@ -514,6 +514,7 @@ Description: information about CPUs heterogeneity. + + What: /sys/devices/system/cpu/vulnerabilities + /sys/devices/system/cpu/vulnerabilities/gather_data_sampling ++ /sys/devices/system/cpu/vulnerabilities/indirect_target_selection + /sys/devices/system/cpu/vulnerabilities/itlb_multihit + /sys/devices/system/cpu/vulnerabilities/l1tf + /sys/devices/system/cpu/vulnerabilities/mds +diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst +index ff0b440ef2dc90..d2caa390395e5b 100644 +--- a/Documentation/admin-guide/hw-vuln/index.rst ++++ b/Documentation/admin-guide/hw-vuln/index.rst +@@ -22,3 +22,4 @@ are configurable at compile, boot or run time. + srso + gather_data_sampling + reg-file-data-sampling ++ indirect-target-selection +diff --git a/Documentation/admin-guide/hw-vuln/indirect-target-selection.rst b/Documentation/admin-guide/hw-vuln/indirect-target-selection.rst +new file mode 100644 +index 00000000000000..d9ca64108d2332 +--- /dev/null ++++ b/Documentation/admin-guide/hw-vuln/indirect-target-selection.rst +@@ -0,0 +1,168 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Indirect Target Selection (ITS) ++=============================== ++ ++ITS is a vulnerability in some Intel CPUs that support Enhanced IBRS and were ++released before Alder Lake. ITS may allow an attacker to control the prediction ++of indirect branches and RETs located in the lower half of a cacheline. ++ ++ITS is assigned CVE-2024-28956 with a CVSS score of 4.7 (Medium). ++ ++Scope of Impact ++--------------- ++- **eIBRS Guest/Host Isolation**: Indirect branches in KVM/kernel may still be ++ predicted with unintended target corresponding to a branch in the guest. ++ ++- **Intra-Mode BTI**: In-kernel training such as through cBPF or other native ++ gadgets. ++ ++- **Indirect Branch Prediction Barrier (IBPB)**: After an IBPB, indirect ++ branches may still be predicted with targets corresponding to direct branches ++ executed prior to the IBPB. This is fixed by the IPU 2025.1 microcode, which ++ should be available via distro updates. Alternatively microcode can be ++ obtained from Intel's github repository [#f1]_. ++ ++Affected CPUs ++------------- ++Below is the list of ITS affected CPUs [#f2]_ [#f3]_: ++ ++ ======================== ============ ==================== =============== ++ Common name Family_Model eIBRS Intra-mode BTI ++ Guest/Host Isolation ++ ======================== ============ ==================== =============== ++ SKYLAKE_X (step >= 6) 06_55H Affected Affected ++ ICELAKE_X 06_6AH Not affected Affected ++ ICELAKE_D 06_6CH Not affected Affected ++ ICELAKE_L 06_7EH Not affected Affected ++ TIGERLAKE_L 06_8CH Not affected Affected ++ TIGERLAKE 06_8DH Not affected Affected ++ KABYLAKE_L (step >= 12) 06_8EH Affected Affected ++ KABYLAKE (step >= 13) 06_9EH Affected Affected ++ COMETLAKE 06_A5H Affected Affected ++ COMETLAKE_L 06_A6H Affected Affected ++ ROCKETLAKE 06_A7H Not affected Affected ++ ======================== ============ ==================== =============== ++ ++- All affected CPUs enumerate Enhanced IBRS feature. ++- IBPB isolation is affected on all ITS affected CPUs, and need a microcode ++ update for mitigation. ++- None of the affected CPUs enumerate BHI_CTRL which was introduced in Golden ++ Cove (Alder Lake and Sapphire Rapids). This can help guests to determine the ++ host's affected status. ++- Intel Atom CPUs are not affected by ITS. ++ ++Mitigation ++---------- ++As only the indirect branches and RETs that have their last byte of instruction ++in the lower half of the cacheline are vulnerable to ITS, the basic idea behind ++the mitigation is to not allow indirect branches in the lower half. ++ ++This is achieved by relying on existing retpoline support in the kernel, and in ++compilers. ITS-vulnerable retpoline sites are runtime patched to point to newly ++added ITS-safe thunks. These safe thunks consists of indirect branch in the ++second half of the cacheline. Not all retpoline sites are patched to thunks, if ++a retpoline site is evaluated to be ITS-safe, it is replaced with an inline ++indirect branch. ++ ++Dynamic thunks ++~~~~~~~~~~~~~~ ++From a dynamically allocated pool of safe-thunks, each vulnerable site is ++replaced with a new thunk, such that they get a unique address. This could ++improve the branch prediction accuracy. Also, it is a defense-in-depth measure ++against aliasing. ++ ++Note, for simplicity, indirect branches in eBPF programs are always replaced ++with a jump to a static thunk in __x86_indirect_its_thunk_array. If required, ++in future this can be changed to use dynamic thunks. ++ ++All vulnerable RETs are replaced with a static thunk, they do not use dynamic ++thunks. This is because RETs get their prediction from RSB mostly that does not ++depend on source address. RETs that underflow RSB may benefit from dynamic ++thunks. But, RETs significantly outnumber indirect branches, and any benefit ++from a unique source address could be outweighed by the increased icache ++footprint and iTLB pressure. ++ ++Retpoline ++~~~~~~~~~ ++Retpoline sequence also mitigates ITS-unsafe indirect branches. For this ++reason, when retpoline is enabled, ITS mitigation only relocates the RETs to ++safe thunks. Unless user requested the RSB-stuffing mitigation. ++ ++RSB Stuffing ++~~~~~~~~~~~~ ++RSB-stuffing via Call Depth Tracking is a mitigation for Retbleed RSB-underflow ++attacks. And it also mitigates RETs that are vulnerable to ITS. ++ ++Mitigation in guests ++^^^^^^^^^^^^^^^^^^^^ ++All guests deploy ITS mitigation by default, irrespective of eIBRS enumeration ++and Family/Model of the guest. This is because eIBRS feature could be hidden ++from a guest. One exception to this is when a guest enumerates BHI_DIS_S, which ++indicates that the guest is running on an unaffected host. ++ ++To prevent guests from unnecessarily deploying the mitigation on unaffected ++platforms, Intel has defined ITS_NO bit(62) in MSR IA32_ARCH_CAPABILITIES. When ++a guest sees this bit set, it should not enumerate the ITS bug. Note, this bit ++is not set by any hardware, but is **intended for VMMs to synthesize** it for ++guests as per the host's affected status. ++ ++Mitigation options ++^^^^^^^^^^^^^^^^^^ ++The ITS mitigation can be controlled using the "indirect_target_selection" ++kernel parameter. The available options are: ++ ++ ======== =================================================================== ++ on (default) Deploy the "Aligned branch/return thunks" mitigation. ++ If spectre_v2 mitigation enables retpoline, aligned-thunks are only ++ deployed for the affected RET instructions. Retpoline mitigates ++ indirect branches. ++ ++ off Disable ITS mitigation. ++ ++ vmexit Equivalent to "=on" if the CPU is affected by guest/host isolation ++ part of ITS. Otherwise, mitigation is not deployed. This option is ++ useful when host userspace is not in the threat model, and only ++ attacks from guest to host are considered. ++ ++ stuff Deploy RSB-fill mitigation when retpoline is also deployed. ++ Otherwise, deploy the default mitigation. When retpoline mitigation ++ is enabled, RSB-stuffing via Call-Depth-Tracking also mitigates ++ ITS. ++ ++ force Force the ITS bug and deploy the default mitigation. ++ ======== =================================================================== ++ ++Sysfs reporting ++--------------- ++ ++The sysfs file showing ITS mitigation status is: ++ ++ /sys/devices/system/cpu/vulnerabilities/indirect_target_selection ++ ++Note, microcode mitigation status is not reported in this file. ++ ++The possible values in this file are: ++ ++.. list-table:: ++ ++ * - Not affected ++ - The processor is not vulnerable. ++ * - Vulnerable ++ - System is vulnerable and no mitigation has been applied. ++ * - Vulnerable, KVM: Not affected ++ - System is vulnerable to intra-mode BTI, but not affected by eIBRS ++ guest/host isolation. ++ * - Mitigation: Aligned branch/return thunks ++ - The mitigation is enabled, affected indirect branches and RETs are ++ relocated to safe thunks. ++ * - Mitigation: Retpolines, Stuffing RSB ++ - The mitigation is enabled using retpoline and RSB stuffing. ++ ++References ++---------- ++.. [#f1] Microcode repository - https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files ++ ++.. [#f2] Affected Processors list - https://www.intel.com/content/www/us/en/developer/topic-technology/software-security-guidance/processors-affected-consolidated-product-cpu-model.html ++ ++.. [#f3] Affected Processors list (machine readable) - https://github.com/intel/Intel-affected-processor-list +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 184f2f96f6a547..f95734ceb82b86 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -2060,6 +2060,23 @@ + different crypto accelerators. This option can be used + to achieve best performance for particular HW. + ++ indirect_target_selection= [X86,Intel] Mitigation control for Indirect ++ Target Selection(ITS) bug in Intel CPUs. Updated ++ microcode is also required for a fix in IBPB. ++ ++ on: Enable mitigation (default). ++ off: Disable mitigation. ++ force: Force the ITS bug and deploy default ++ mitigation. ++ vmexit: Only deploy mitigation if CPU is affected by ++ guest/host isolation part of ITS. ++ stuff: Deploy RSB-fill mitigation when retpoline is ++ also deployed. Otherwise, deploy the default ++ mitigation. ++ ++ For details see: ++ Documentation/admin-guide/hw-vuln/indirect-target-selection.rst ++ + init= [KNL] + Format: + Run specified binary instead of /sbin/init as init +@@ -3331,6 +3348,7 @@ + expose users to several CPU vulnerabilities. + Equivalent to: if nokaslr then kpti=0 [ARM64] + gather_data_sampling=off [X86] ++ indirect_target_selection=off [X86] + kvm.nx_huge_pages=off [X86] + l1tf=off [X86] + mds=off [X86] +diff --git a/Makefile b/Makefile +index 587a1586e76db8..a6a1942e2d00a9 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 90 ++SUBLEVEL = 91 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi +index 6c48fa4b0d0c4f..6457d2c377017a 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi +@@ -148,6 +148,19 @@ reg_usdhc2_vmmc: regulator-usdhc2 { + startup-delay-us = <20000>; + }; + ++ reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc { ++ compatible = "regulator-gpio"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2_vsel>; ++ gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; ++ regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <1800000>; ++ states = <1800000 0x1>, ++ <3300000 0x0>; ++ regulator-name = "PMIC_USDHC_VSELECT"; ++ vin-supply = <®_nvcc_sd>; ++ }; ++ + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; +@@ -266,7 +279,7 @@ &gpio1 { + "SODIMM_19", + "", + "", +- "", ++ "PMIC_USDHC_VSELECT", + "", + "", + "", +@@ -787,6 +800,7 @@ &usdhc2 { + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_cd>; + pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_cd_sleep>; + vmmc-supply = <®_usdhc2_vmmc>; ++ vqmmc-supply = <®_usdhc2_vqmmc>; + }; + + &wdog1 { +@@ -1209,13 +1223,17 @@ pinctrl_usdhc2_pwr_en: usdhc2pwrengrp { + ; /* SODIMM 76 */ + }; + ++ pinctrl_usdhc2_vsel: usdhc2vselgrp { ++ fsl,pins = ++ ; /* PMIC_USDHC_VSELECT */ ++ }; ++ + /* + * Note: Due to ERR050080 we use discrete external on-module resistors pulling-up to the + * on-module +V3.3_1.8_SD (LDO5) rail and explicitly disable the internal pull-ups here. + */ + pinctrl_usdhc2: usdhc2grp { + fsl,pins = +- , + , /* SODIMM 78 */ + , /* SODIMM 74 */ + , /* SODIMM 80 */ +@@ -1226,7 +1244,6 @@ pinctrl_usdhc2: usdhc2grp { + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = +- , + , + , + , +@@ -1237,7 +1254,6 @@ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = +- , + , + , + , +@@ -1249,7 +1265,6 @@ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + /* Avoid backfeeding with removed card power */ + pinctrl_usdhc2_sleep: usdhc2slpgrp { + fsl,pins = +- , + , + , + , +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index 2a4e686e633c62..8a6b7feca3e428 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -81,6 +81,7 @@ + #define ARM_CPU_PART_CORTEX_A78AE 0xD42 + #define ARM_CPU_PART_CORTEX_X1 0xD44 + #define ARM_CPU_PART_CORTEX_A510 0xD46 ++#define ARM_CPU_PART_CORTEX_X1C 0xD4C + #define ARM_CPU_PART_CORTEX_A520 0xD80 + #define ARM_CPU_PART_CORTEX_A710 0xD47 + #define ARM_CPU_PART_CORTEX_A715 0xD4D +@@ -166,6 +167,7 @@ + #define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE) + #define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1) + #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510) ++#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C) + #define MIDR_CORTEX_A520 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A520) + #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710) + #define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715) +diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h +index 0ccf51afde31a6..12c0278294e3f6 100644 +--- a/arch/arm64/include/asm/insn.h ++++ b/arch/arm64/include/asm/insn.h +@@ -687,6 +687,7 @@ u32 aarch64_insn_gen_cas(enum aarch64_insn_register result, + } + #endif + u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type); ++u32 aarch64_insn_gen_dsb(enum aarch64_insn_mb_type type); + + s32 aarch64_get_branch_offset(u32 insn); + u32 aarch64_set_branch_offset(u32 insn, s32 offset); +diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spectre.h +index 0c2b47673922e3..32475d19c15f44 100644 +--- a/arch/arm64/include/asm/spectre.h ++++ b/arch/arm64/include/asm/spectre.h +@@ -97,6 +97,9 @@ enum mitigation_state arm64_get_meltdown_state(void); + + enum mitigation_state arm64_get_spectre_bhb_state(void); + bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope); ++extern bool __nospectre_bhb; ++u8 get_spectre_bhb_loop_value(void); ++bool is_spectre_bhb_fw_mitigated(void); + void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused); + bool try_emulate_el1_ssbs(struct pt_regs *regs, u32 instr); + +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index edc4c727783d82..28c48bc9c09538 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -891,6 +891,7 @@ static u8 spectre_bhb_loop_affected(void) + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78AE), + MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C), + MIDR_ALL_VERSIONS(MIDR_CORTEX_X1), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X1C), + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), + MIDR_ALL_VERSIONS(MIDR_CORTEX_X2), + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), +@@ -998,6 +999,11 @@ bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, + return true; + } + ++u8 get_spectre_bhb_loop_value(void) ++{ ++ return max_bhb_k; ++} ++ + static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot) + { + const char *v = arm64_get_bp_hardening_vector(slot); +@@ -1015,7 +1021,7 @@ static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot) + isb(); + } + +-static bool __read_mostly __nospectre_bhb; ++bool __read_mostly __nospectre_bhb; + static int __init parse_spectre_bhb_param(char *str) + { + __nospectre_bhb = true; +@@ -1093,6 +1099,11 @@ void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry) + update_mitigation_state(&spectre_bhb_state, state); + } + ++bool is_spectre_bhb_fw_mitigated(void) ++{ ++ return test_bit(BHB_FW, &system_bhb_mitigations); ++} ++ + /* Patched to NOP when enabled */ + void noinstr spectre_bhb_patch_loop_mitigation_enable(struct alt_instr *alt, + __le32 *origptr, +diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c +index a635ab83fee359..7232b1e70a125f 100644 +--- a/arch/arm64/lib/insn.c ++++ b/arch/arm64/lib/insn.c +@@ -5,6 +5,7 @@ + * + * Copyright (C) 2014-2016 Zi Shen Lim + */ ++#include + #include + #include + #include +@@ -1471,43 +1472,41 @@ u32 aarch64_insn_gen_extr(enum aarch64_insn_variant variant, + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, Rm); + } + +-u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type) ++static u32 __get_barrier_crm_val(enum aarch64_insn_mb_type type) + { +- u32 opt; +- u32 insn; +- + switch (type) { + case AARCH64_INSN_MB_SY: +- opt = 0xf; +- break; ++ return 0xf; + case AARCH64_INSN_MB_ST: +- opt = 0xe; +- break; ++ return 0xe; + case AARCH64_INSN_MB_LD: +- opt = 0xd; +- break; ++ return 0xd; + case AARCH64_INSN_MB_ISH: +- opt = 0xb; +- break; ++ return 0xb; + case AARCH64_INSN_MB_ISHST: +- opt = 0xa; +- break; ++ return 0xa; + case AARCH64_INSN_MB_ISHLD: +- opt = 0x9; +- break; ++ return 0x9; + case AARCH64_INSN_MB_NSH: +- opt = 0x7; +- break; ++ return 0x7; + case AARCH64_INSN_MB_NSHST: +- opt = 0x6; +- break; ++ return 0x6; + case AARCH64_INSN_MB_NSHLD: +- opt = 0x5; +- break; ++ return 0x5; + default: +- pr_err("%s: unknown dmb type %d\n", __func__, type); ++ pr_err("%s: unknown barrier type %d\n", __func__, type); + return AARCH64_BREAK_FAULT; + } ++} ++ ++u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type) ++{ ++ u32 opt; ++ u32 insn; ++ ++ opt = __get_barrier_crm_val(type); ++ if (opt == AARCH64_BREAK_FAULT) ++ return AARCH64_BREAK_FAULT; + + insn = aarch64_insn_get_dmb_value(); + insn &= ~GENMASK(11, 8); +@@ -1515,3 +1514,18 @@ u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type) + + return insn; + } ++ ++u32 aarch64_insn_gen_dsb(enum aarch64_insn_mb_type type) ++{ ++ u32 opt, insn; ++ ++ opt = __get_barrier_crm_val(type); ++ if (opt == AARCH64_BREAK_FAULT) ++ return AARCH64_BREAK_FAULT; ++ ++ insn = aarch64_insn_get_dsb_base_value(); ++ insn &= ~GENMASK(11, 8); ++ insn |= (opt << 8); ++ ++ return insn; ++} +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 5074bd1d37b5f6..75523c1be07350 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -7,6 +7,7 @@ + + #define pr_fmt(fmt) "bpf_jit: " fmt + ++#include + #include + #include + #include +@@ -17,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -653,7 +655,51 @@ static void build_plt(struct jit_ctx *ctx) + plt->target = (u64)&dummy_tramp; + } + +-static void build_epilogue(struct jit_ctx *ctx) ++/* Clobbers BPF registers 1-4, aka x0-x3 */ ++static void __maybe_unused build_bhb_mitigation(struct jit_ctx *ctx) ++{ ++ const u8 r1 = bpf2a64[BPF_REG_1]; /* aka x0 */ ++ u8 k = get_spectre_bhb_loop_value(); ++ ++ if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY) || ++ cpu_mitigations_off() || __nospectre_bhb || ++ arm64_get_spectre_v2_state() == SPECTRE_VULNERABLE) ++ return; ++ ++ if (capable(CAP_SYS_ADMIN)) ++ return; ++ ++ if (supports_clearbhb(SCOPE_SYSTEM)) { ++ emit(aarch64_insn_gen_hint(AARCH64_INSN_HINT_CLEARBHB), ctx); ++ return; ++ } ++ ++ if (k) { ++ emit_a64_mov_i64(r1, k, ctx); ++ emit(A64_B(1), ctx); ++ emit(A64_SUBS_I(true, r1, r1, 1), ctx); ++ emit(A64_B_(A64_COND_NE, -2), ctx); ++ emit(aarch64_insn_gen_dsb(AARCH64_INSN_MB_ISH), ctx); ++ emit(aarch64_insn_get_isb_value(), ctx); ++ } ++ ++ if (is_spectre_bhb_fw_mitigated()) { ++ emit(A64_ORR_I(false, r1, AARCH64_INSN_REG_ZR, ++ ARM_SMCCC_ARCH_WORKAROUND_3), ctx); ++ switch (arm_smccc_1_1_get_conduit()) { ++ case SMCCC_CONDUIT_HVC: ++ emit(aarch64_insn_get_hvc_value(), ctx); ++ break; ++ case SMCCC_CONDUIT_SMC: ++ emit(aarch64_insn_get_smc_value(), ctx); ++ break; ++ default: ++ pr_err_once("Firmware mitigation enabled with unknown conduit\n"); ++ } ++ } ++} ++ ++static void build_epilogue(struct jit_ctx *ctx, bool was_classic) + { + const u8 r0 = bpf2a64[BPF_REG_0]; + const u8 r6 = bpf2a64[BPF_REG_6]; +@@ -675,10 +721,13 @@ static void build_epilogue(struct jit_ctx *ctx) + emit(A64_POP(r8, r9, A64_SP), ctx); + emit(A64_POP(r6, r7, A64_SP), ctx); + ++ if (was_classic) ++ build_bhb_mitigation(ctx); ++ + /* Restore FP/LR registers */ + emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); + +- /* Set return value */ ++ /* Move the return value from bpf:r0 (aka x7) to x0 */ + emit(A64_MOV(1, A64_R(0), r0), ctx); + + /* Authenticate lr */ +@@ -1586,7 +1635,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + } + + ctx.epilogue_offset = ctx.idx; +- build_epilogue(&ctx); ++ build_epilogue(&ctx, was_classic); + build_plt(&ctx); + + extable_align = __alignof__(struct exception_table_entry); +@@ -1622,7 +1671,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + goto out_off; + } + +- build_epilogue(&ctx); ++ build_epilogue(&ctx, was_classic); + build_plt(&ctx); + + /* 3. Extra pass to validate JITed code. */ +diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h +index 4a2b40ce39e091..841612913f0d1b 100644 +--- a/arch/mips/include/asm/ptrace.h ++++ b/arch/mips/include/asm/ptrace.h +@@ -65,7 +65,8 @@ static inline void instruction_pointer_set(struct pt_regs *regs, + + /* Query offset/name of register from its name/offset */ + extern int regs_query_register_offset(const char *name); +-#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) ++#define MAX_REG_OFFSET \ ++ (offsetof(struct pt_regs, __last) - sizeof(unsigned long)) + + /** + * regs_get_register() - get register value from its offset +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index d874ea22512b5c..4372657ab0d6fa 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -2610,6 +2610,17 @@ config MITIGATION_SPECTRE_BHI + indirect branches. + See + ++config MITIGATION_ITS ++ bool "Enable Indirect Target Selection mitigation" ++ depends on CPU_SUP_INTEL && X86_64 ++ depends on RETPOLINE && RETHUNK ++ default y ++ help ++ Enable Indirect Target Selection (ITS) mitigation. ITS is a bug in ++ BPU on some Intel CPUs that may allow Spectre V2 style attacks. If ++ disabled, mitigation cannot be enabled via cmdline. ++ See ++ + endif + + config ARCH_HAS_ADD_PAGES +diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S +index 2192b6c33ea009..1f9e508ac075c3 100644 +--- a/arch/x86/entry/entry_64.S ++++ b/arch/x86/entry/entry_64.S +@@ -1569,7 +1569,9 @@ SYM_CODE_END(rewind_stack_and_make_dead) + * ORC to unwind properly. + * + * The alignment is for performance and not for safety, and may be safely +- * refactored in the future if needed. ++ * refactored in the future if needed. The .skips are for safety, to ensure ++ * that all RETs are in the second half of a cacheline to mitigate Indirect ++ * Target Selection, rather than taking the slowpath via its_return_thunk. + */ + SYM_FUNC_START(clear_bhb_loop) + push %rbp +@@ -1579,10 +1581,22 @@ SYM_FUNC_START(clear_bhb_loop) + call 1f + jmp 5f + .align 64, 0xcc ++ /* ++ * Shift instructions so that the RET is in the upper half of the ++ * cacheline and don't take the slowpath to its_return_thunk. ++ */ ++ .skip 32 - (.Lret1 - 1f), 0xcc + ANNOTATE_INTRA_FUNCTION_CALL + 1: call 2f +- RET ++.Lret1: RET + .align 64, 0xcc ++ /* ++ * As above shift instructions for RET at .Lret2 as well. ++ * ++ * This should be ideally be: .skip 32 - (.Lret2 - 2f), 0xcc ++ * but some Clang versions (e.g. 18) don't like this. ++ */ ++ .skip 32 - 18, 0xcc + 2: movl $5, %eax + 3: jmp 4f + nop +@@ -1590,7 +1604,7 @@ SYM_FUNC_START(clear_bhb_loop) + jnz 3b + sub $1, %ecx + jnz 1b +- RET ++.Lret2: RET + 5: lfence + pop %rbp + RET +diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h +index cb9ce0f9e78e05..6740b839153a04 100644 +--- a/arch/x86/include/asm/alternative.h ++++ b/arch/x86/include/asm/alternative.h +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #define ALT_FLAGS_SHIFT 16 + +@@ -130,6 +131,37 @@ static __always_inline int x86_call_depth_emit_accounting(u8 **pprog, + } + #endif + ++#ifdef CONFIG_MITIGATION_ITS ++extern void its_init_mod(struct module *mod); ++extern void its_fini_mod(struct module *mod); ++extern void its_free_mod(struct module *mod); ++extern u8 *its_static_thunk(int reg); ++#else /* CONFIG_MITIGATION_ITS */ ++static inline void its_init_mod(struct module *mod) { } ++static inline void its_fini_mod(struct module *mod) { } ++static inline void its_free_mod(struct module *mod) { } ++static inline u8 *its_static_thunk(int reg) ++{ ++ WARN_ONCE(1, "ITS not compiled in"); ++ ++ return NULL; ++} ++#endif ++ ++#if defined(CONFIG_RETHUNK) && defined(CONFIG_OBJTOOL) ++extern bool cpu_wants_rethunk(void); ++extern bool cpu_wants_rethunk_at(void *addr); ++#else ++static __always_inline bool cpu_wants_rethunk(void) ++{ ++ return false; ++} ++static __always_inline bool cpu_wants_rethunk_at(void *addr) ++{ ++ return false; ++} ++#endif ++ + #ifdef CONFIG_SMP + extern void alternatives_smp_module_add(struct module *mod, char *name, + void *locks, void *locks_end, +diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h +index 55d18eef6775a6..8a2482651a6f1e 100644 +--- a/arch/x86/include/asm/cpufeatures.h ++++ b/arch/x86/include/asm/cpufeatures.h +@@ -468,6 +468,7 @@ + #define X86_FEATURE_BHI_CTRL (21*32+ 2) /* "" BHI_DIS_S HW control available */ + #define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* "" BHI_DIS_S HW control enabled */ + #define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* "" Clear branch history at vmexit using SW loop */ ++#define X86_FEATURE_INDIRECT_THUNK_ITS (21*32 + 5) /* "" Use thunk for indirect branches in lower half of cacheline */ + + /* + * BUG word(s) +@@ -518,4 +519,6 @@ + #define X86_BUG_RFDS X86_BUG(1*32 + 2) /* CPU is vulnerable to Register File Data Sampling */ + #define X86_BUG_BHI X86_BUG(1*32 + 3) /* CPU is affected by Branch History Injection */ + #define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */ ++#define X86_BUG_ITS X86_BUG(1*32 + 5) /* CPU is affected by Indirect Target Selection */ ++#define X86_BUG_ITS_NATIVE_ONLY X86_BUG(1*32 + 6) /* CPU is affected by ITS, VMX is not affected */ + #endif /* _ASM_X86_CPUFEATURES_H */ +diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h +index 0ee6ed0ff2bf20..79c35947e20cb7 100644 +--- a/arch/x86/include/asm/microcode.h ++++ b/arch/x86/include/asm/microcode.h +@@ -17,10 +17,12 @@ struct ucode_cpu_info { + void load_ucode_bsp(void); + void load_ucode_ap(void); + void microcode_bsp_resume(void); ++bool __init microcode_loader_disabled(void); + #else + static inline void load_ucode_bsp(void) { } + static inline void load_ucode_ap(void) { } + static inline void microcode_bsp_resume(void) { } ++static inline bool __init microcode_loader_disabled(void) { return false; } + #endif + + extern unsigned long initrd_start_early; +diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h +index 623bb48774d44c..9fbad4cb971bff 100644 +--- a/arch/x86/include/asm/msr-index.h ++++ b/arch/x86/include/asm/msr-index.h +@@ -180,6 +180,14 @@ + * VERW clears CPU Register + * File. + */ ++#define ARCH_CAP_ITS_NO BIT_ULL(62) /* ++ * Not susceptible to ++ * Indirect Target Selection. ++ * This bit is not set by ++ * HW, but is synthesized by ++ * VMMs for guests to know ++ * their affected status. ++ */ + + #define ARCH_CAP_XAPIC_DISABLE BIT(21) /* + * IA32_XAPIC_DISABLE_STATUS MSR +diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h +index ee642d26e30457..bc4fa6d09d29d9 100644 +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -219,9 +219,8 @@ + .endm + + /* +- * Equivalent to -mindirect-branch-cs-prefix; emit the 5 byte jmp/call +- * to the retpoline thunk with a CS prefix when the register requires +- * a RAX prefix byte to encode. Also see apply_retpolines(). ++ * Emits a conditional CS prefix that is compatible with ++ * -mindirect-branch-cs-prefix. + */ + .macro __CS_PREFIX reg:req + .irp rs,r8,r9,r10,r11,r12,r13,r14,r15 +@@ -365,10 +364,14 @@ + ".long 999b\n\t" \ + ".popsection\n\t" + ++#define ITS_THUNK_SIZE 64 ++ + typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE]; ++typedef u8 its_thunk_t[ITS_THUNK_SIZE]; + extern retpoline_thunk_t __x86_indirect_thunk_array[]; + extern retpoline_thunk_t __x86_indirect_call_thunk_array[]; + extern retpoline_thunk_t __x86_indirect_jump_thunk_array[]; ++extern its_thunk_t __x86_indirect_its_thunk_array[]; + + #ifdef CONFIG_RETHUNK + extern void __x86_return_thunk(void); +@@ -392,6 +395,12 @@ static inline void srso_return_thunk(void) {} + static inline void srso_alias_return_thunk(void) {} + #endif + ++#ifdef CONFIG_MITIGATION_ITS ++extern void its_return_thunk(void); ++#else ++static inline void its_return_thunk(void) {} ++#endif ++ + extern void retbleed_return_thunk(void); + extern void srso_return_thunk(void); + extern void srso_alias_return_thunk(void); +@@ -412,11 +421,6 @@ extern void (*x86_return_thunk)(void); + #ifdef CONFIG_CALL_DEPTH_TRACKING + extern void __x86_return_skl(void); + +-static inline void x86_set_skl_return_thunk(void) +-{ +- x86_return_thunk = &__x86_return_skl; +-} +- + #define CALL_DEPTH_ACCOUNT \ + ALTERNATIVE("", \ + __stringify(INCREMENT_CALL_DEPTH), \ +@@ -429,7 +433,6 @@ DECLARE_PER_CPU(u64, __x86_stuffs_count); + DECLARE_PER_CPU(u64, __x86_ctxsw_count); + #endif + #else +-static inline void x86_set_skl_return_thunk(void) {} + + #define CALL_DEPTH_ACCOUNT "" + +@@ -454,20 +457,23 @@ static inline void x86_set_skl_return_thunk(void) {} + + #ifdef CONFIG_X86_64 + ++/* ++ * Emits a conditional CS prefix that is compatible with ++ * -mindirect-branch-cs-prefix. ++ */ ++#define __CS_PREFIX(reg) \ ++ ".irp rs,r8,r9,r10,r11,r12,r13,r14,r15\n" \ ++ ".ifc \\rs," reg "\n" \ ++ ".byte 0x2e\n" \ ++ ".endif\n" \ ++ ".endr\n" ++ + /* + * Inline asm uses the %V modifier which is only in newer GCC + * which is ensured when CONFIG_RETPOLINE is defined. + */ +-# define CALL_NOSPEC \ +- ALTERNATIVE_2( \ +- ANNOTATE_RETPOLINE_SAFE \ +- "call *%[thunk_target]\n", \ +- "call __x86_indirect_thunk_%V[thunk_target]\n", \ +- X86_FEATURE_RETPOLINE, \ +- "lfence;\n" \ +- ANNOTATE_RETPOLINE_SAFE \ +- "call *%[thunk_target]\n", \ +- X86_FEATURE_RETPOLINE_LFENCE) ++#define CALL_NOSPEC __CS_PREFIX("%V[thunk_target]") \ ++ "call __x86_indirect_thunk_%V[thunk_target]\n" + + # define THUNK_TARGET(addr) [thunk_target] "r" (addr) + +diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c +index aae7456ece0700..4817e424d69658 100644 +--- a/arch/x86/kernel/alternative.c ++++ b/arch/x86/kernel/alternative.c +@@ -18,6 +18,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -30,6 +32,8 @@ + #include + #include + #include ++#include ++#include + + int __read_mostly alternatives_patched; + +@@ -123,6 +127,135 @@ const unsigned char * const x86_nops[ASM_NOP_MAX+1] = + #endif + }; + ++#ifdef CONFIG_MITIGATION_ITS ++ ++#ifdef CONFIG_MODULES ++static struct module *its_mod; ++static void *its_page; ++static unsigned int its_offset; ++ ++/* Initialize a thunk with the "jmp *reg; int3" instructions. */ ++static void *its_init_thunk(void *thunk, int reg) ++{ ++ u8 *bytes = thunk; ++ int i = 0; ++ ++ if (reg >= 8) { ++ bytes[i++] = 0x41; /* REX.B prefix */ ++ reg -= 8; ++ } ++ bytes[i++] = 0xff; ++ bytes[i++] = 0xe0 + reg; /* jmp *reg */ ++ bytes[i++] = 0xcc; ++ ++ return thunk; ++} ++ ++void its_init_mod(struct module *mod) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return; ++ ++ mutex_lock(&text_mutex); ++ its_mod = mod; ++ its_page = NULL; ++} ++ ++void its_fini_mod(struct module *mod) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return; ++ ++ WARN_ON_ONCE(its_mod != mod); ++ ++ its_mod = NULL; ++ its_page = NULL; ++ mutex_unlock(&text_mutex); ++ ++ for (int i = 0; i < mod->its_num_pages; i++) { ++ void *page = mod->its_page_array[i]; ++ set_memory_rox((unsigned long)page, 1); ++ } ++} ++ ++void its_free_mod(struct module *mod) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return; ++ ++ for (int i = 0; i < mod->its_num_pages; i++) { ++ void *page = mod->its_page_array[i]; ++ module_memfree(page); ++ } ++ kfree(mod->its_page_array); ++} ++ ++DEFINE_FREE(its_execmem, void *, if (_T) module_memfree(_T)); ++ ++static void *its_alloc(void) ++{ ++ void *page __free(its_execmem) = module_alloc(PAGE_SIZE); ++ ++ if (!page) ++ return NULL; ++ ++ if (its_mod) { ++ void *tmp = krealloc(its_mod->its_page_array, ++ (its_mod->its_num_pages+1) * sizeof(void *), ++ GFP_KERNEL); ++ if (!tmp) ++ return NULL; ++ ++ its_mod->its_page_array = tmp; ++ its_mod->its_page_array[its_mod->its_num_pages++] = page; ++ } ++ ++ return no_free_ptr(page); ++} ++ ++static void *its_allocate_thunk(int reg) ++{ ++ int size = 3 + (reg / 8); ++ void *thunk; ++ ++ if (!its_page || (its_offset + size - 1) >= PAGE_SIZE) { ++ its_page = its_alloc(); ++ if (!its_page) { ++ pr_err("ITS page allocation failed\n"); ++ return NULL; ++ } ++ memset(its_page, INT3_INSN_OPCODE, PAGE_SIZE); ++ its_offset = 32; ++ } ++ ++ /* ++ * If the indirect branch instruction will be in the lower half ++ * of a cacheline, then update the offset to reach the upper half. ++ */ ++ if ((its_offset + size - 1) % 64 < 32) ++ its_offset = ((its_offset - 1) | 0x3F) + 33; ++ ++ thunk = its_page + its_offset; ++ its_offset += size; ++ ++ set_memory_rw((unsigned long)its_page, 1); ++ thunk = its_init_thunk(thunk, reg); ++ set_memory_rox((unsigned long)its_page, 1); ++ ++ return thunk; ++} ++ ++#else /* CONFIG_MODULES */ ++ ++static void *its_allocate_thunk(int reg) ++{ ++ return NULL; ++} ++ ++#endif /* CONFIG_MODULES */ ++ ++#endif /* CONFIG_MITIGATION_ITS */ ++ + /* + * Fill the buffer with a single effective instruction of size @len. + * +@@ -521,7 +654,8 @@ static int emit_indirect(int op, int reg, u8 *bytes) + return i; + } + +-static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 *bytes) ++static int __emit_trampoline(void *addr, struct insn *insn, u8 *bytes, ++ void *call_dest, void *jmp_dest) + { + u8 op = insn->opcode.bytes[0]; + int i = 0; +@@ -542,7 +676,7 @@ static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 + switch (op) { + case CALL_INSN_OPCODE: + __text_gen_insn(bytes+i, op, addr+i, +- __x86_indirect_call_thunk_array[reg], ++ call_dest, + CALL_INSN_SIZE); + i += CALL_INSN_SIZE; + break; +@@ -550,7 +684,7 @@ static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 + case JMP32_INSN_OPCODE: + clang_jcc: + __text_gen_insn(bytes+i, op, addr+i, +- __x86_indirect_jump_thunk_array[reg], ++ jmp_dest, + JMP32_INSN_SIZE); + i += JMP32_INSN_SIZE; + break; +@@ -565,6 +699,39 @@ static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 + return i; + } + ++static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 *bytes) ++{ ++ return __emit_trampoline(addr, insn, bytes, ++ __x86_indirect_call_thunk_array[reg], ++ __x86_indirect_jump_thunk_array[reg]); ++} ++ ++#ifdef CONFIG_MITIGATION_ITS ++static int emit_its_trampoline(void *addr, struct insn *insn, int reg, u8 *bytes) ++{ ++ u8 *thunk = __x86_indirect_its_thunk_array[reg]; ++ u8 *tmp = its_allocate_thunk(reg); ++ ++ if (tmp) ++ thunk = tmp; ++ ++ return __emit_trampoline(addr, insn, bytes, thunk, thunk); ++} ++ ++/* Check if an indirect branch is at ITS-unsafe address */ ++static bool cpu_wants_indirect_its_thunk_at(unsigned long addr, int reg) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) ++ return false; ++ ++ /* Indirect branch opcode is 2 or 3 bytes depending on reg */ ++ addr += 1 + reg / 8; ++ ++ /* Lower-half of the cacheline? */ ++ return !(addr & 0x20); ++} ++#endif ++ + /* + * Rewrite the compiler generated retpoline thunk calls. + * +@@ -639,6 +806,15 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes) + bytes[i++] = 0xe8; /* LFENCE */ + } + ++#ifdef CONFIG_MITIGATION_ITS ++ /* ++ * Check if the address of last byte of emitted-indirect is in ++ * lower-half of the cacheline. Such branches need ITS mitigation. ++ */ ++ if (cpu_wants_indirect_its_thunk_at((unsigned long)addr + i, reg)) ++ return emit_its_trampoline(addr, insn, reg, bytes); ++#endif ++ + ret = emit_indirect(op, reg, bytes + i); + if (ret < 0) + return ret; +@@ -710,6 +886,21 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) + + #ifdef CONFIG_RETHUNK + ++bool cpu_wants_rethunk(void) ++{ ++ return cpu_feature_enabled(X86_FEATURE_RETHUNK); ++} ++ ++bool cpu_wants_rethunk_at(void *addr) ++{ ++ if (!cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ return false; ++ if (x86_return_thunk != its_return_thunk) ++ return true; ++ ++ return !((unsigned long)addr & 0x20); ++} ++ + /* + * Rewrite the compiler generated return thunk tail-calls. + * +@@ -726,7 +917,7 @@ static int patch_return(void *addr, struct insn *insn, u8 *bytes) + int i = 0; + + /* Patch the custom return thunks... */ +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) { ++ if (cpu_wants_rethunk_at(addr)) { + i = JMP32_INSN_SIZE; + __text_gen_insn(bytes, JMP32_INSN_OPCODE, addr, x86_return_thunk, i); + } else { +@@ -743,7 +934,7 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end) + { + s32 *s; + +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk()) + static_call_force_reinit(); + + for (s = start; s < end; s++) { +@@ -1258,6 +1449,13 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, + static void poison_cfi(void *addr) { } + #endif + ++u8 *its_static_thunk(int reg) ++{ ++ u8 *thunk = __x86_indirect_its_thunk_array[reg]; ++ ++ return thunk; ++} ++ + #endif + + void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, +@@ -1575,6 +1773,8 @@ static noinline void __init alt_reloc_selftest(void) + + void __init alternative_instructions(void) + { ++ u64 ibt; ++ + int3_selftest(); + + /* +@@ -1612,6 +1812,9 @@ void __init alternative_instructions(void) + */ + paravirt_set_cap(); + ++ /* Keep CET-IBT disabled until caller/callee are patched */ ++ ibt = ibt_save(/*disable*/ true); ++ + /* + * First patch paravirt functions, such that we overwrite the indirect + * call with the direct call. +@@ -1645,6 +1848,8 @@ void __init alternative_instructions(void) + */ + apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end); + ++ ibt_restore(ibt); ++ + #ifdef CONFIG_SMP + /* Patch to UP if other cpus not imminent. */ + if (!noreplace_smp && (num_present_cpus() == 1 || setup_max_cpus <= 1)) { +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 78545f7e9cc6ca..07b45bbf6348de 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -49,6 +49,7 @@ static void __init srbds_select_mitigation(void); + static void __init l1d_flush_select_mitigation(void); + static void __init srso_select_mitigation(void); + static void __init gds_select_mitigation(void); ++static void __init its_select_mitigation(void); + + /* The base value of the SPEC_CTRL MSR without task-specific bits set */ + u64 x86_spec_ctrl_base; +@@ -67,6 +68,14 @@ static DEFINE_MUTEX(spec_ctrl_mutex); + + void (*x86_return_thunk)(void) __ro_after_init = __x86_return_thunk; + ++static void __init set_return_thunk(void *thunk) ++{ ++ if (x86_return_thunk != __x86_return_thunk) ++ pr_warn("x86/bugs: return thunk changed\n"); ++ ++ x86_return_thunk = thunk; ++} ++ + /* Update SPEC_CTRL MSR and its cached copy unconditionally */ + static void update_spec_ctrl(u64 val) + { +@@ -175,6 +184,7 @@ void __init cpu_select_mitigations(void) + */ + srso_select_mitigation(); + gds_select_mitigation(); ++ its_select_mitigation(); + } + + /* +@@ -1102,7 +1112,7 @@ static void __init retbleed_select_mitigation(void) + setup_force_cpu_cap(X86_FEATURE_RETHUNK); + setup_force_cpu_cap(X86_FEATURE_UNRET); + +- x86_return_thunk = retbleed_return_thunk; ++ set_return_thunk(retbleed_return_thunk); + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && + boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) +@@ -1136,7 +1146,9 @@ static void __init retbleed_select_mitigation(void) + case RETBLEED_MITIGATION_STUFF: + setup_force_cpu_cap(X86_FEATURE_RETHUNK); + setup_force_cpu_cap(X86_FEATURE_CALL_DEPTH); +- x86_set_skl_return_thunk(); ++#ifdef CONFIG_CALL_DEPTH_TRACKING ++ set_return_thunk(&__x86_return_skl); ++#endif + break; + + default: +@@ -1170,6 +1182,146 @@ static void __init retbleed_select_mitigation(void) + pr_info("%s\n", retbleed_strings[retbleed_mitigation]); + } + ++#undef pr_fmt ++#define pr_fmt(fmt) "ITS: " fmt ++ ++enum its_mitigation_cmd { ++ ITS_CMD_OFF, ++ ITS_CMD_ON, ++ ITS_CMD_VMEXIT, ++ ITS_CMD_RSB_STUFF, ++}; ++ ++enum its_mitigation { ++ ITS_MITIGATION_OFF, ++ ITS_MITIGATION_VMEXIT_ONLY, ++ ITS_MITIGATION_ALIGNED_THUNKS, ++ ITS_MITIGATION_RETPOLINE_STUFF, ++}; ++ ++static const char * const its_strings[] = { ++ [ITS_MITIGATION_OFF] = "Vulnerable", ++ [ITS_MITIGATION_VMEXIT_ONLY] = "Mitigation: Vulnerable, KVM: Not affected", ++ [ITS_MITIGATION_ALIGNED_THUNKS] = "Mitigation: Aligned branch/return thunks", ++ [ITS_MITIGATION_RETPOLINE_STUFF] = "Mitigation: Retpolines, Stuffing RSB", ++}; ++ ++static enum its_mitigation its_mitigation __ro_after_init = ITS_MITIGATION_ALIGNED_THUNKS; ++ ++static enum its_mitigation_cmd its_cmd __ro_after_init = ++ IS_ENABLED(CONFIG_MITIGATION_ITS) ? ITS_CMD_ON : ITS_CMD_OFF; ++ ++static int __init its_parse_cmdline(char *str) ++{ ++ if (!str) ++ return -EINVAL; ++ ++ if (!IS_ENABLED(CONFIG_MITIGATION_ITS)) { ++ pr_err("Mitigation disabled at compile time, ignoring option (%s)", str); ++ return 0; ++ } ++ ++ if (!strcmp(str, "off")) { ++ its_cmd = ITS_CMD_OFF; ++ } else if (!strcmp(str, "on")) { ++ its_cmd = ITS_CMD_ON; ++ } else if (!strcmp(str, "force")) { ++ its_cmd = ITS_CMD_ON; ++ setup_force_cpu_bug(X86_BUG_ITS); ++ } else if (!strcmp(str, "vmexit")) { ++ its_cmd = ITS_CMD_VMEXIT; ++ } else if (!strcmp(str, "stuff")) { ++ its_cmd = ITS_CMD_RSB_STUFF; ++ } else { ++ pr_err("Ignoring unknown indirect_target_selection option (%s).", str); ++ } ++ ++ return 0; ++} ++early_param("indirect_target_selection", its_parse_cmdline); ++ ++static void __init its_select_mitigation(void) ++{ ++ enum its_mitigation_cmd cmd = its_cmd; ++ ++ if (!boot_cpu_has_bug(X86_BUG_ITS) || cpu_mitigations_off()) { ++ its_mitigation = ITS_MITIGATION_OFF; ++ return; ++ } ++ ++ /* Retpoline+CDT mitigates ITS, bail out */ ++ if (boot_cpu_has(X86_FEATURE_RETPOLINE) && ++ boot_cpu_has(X86_FEATURE_CALL_DEPTH)) { ++ its_mitigation = ITS_MITIGATION_RETPOLINE_STUFF; ++ goto out; ++ } ++ ++ /* Exit early to avoid irrelevant warnings */ ++ if (cmd == ITS_CMD_OFF) { ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (spectre_v2_enabled == SPECTRE_V2_NONE) { ++ pr_err("WARNING: Spectre-v2 mitigation is off, disabling ITS\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (!IS_ENABLED(CONFIG_RETPOLINE) || !IS_ENABLED(CONFIG_RETHUNK)) { ++ pr_err("WARNING: ITS mitigation depends on retpoline and rethunk support\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (IS_ENABLED(CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B)) { ++ pr_err("WARNING: ITS mitigation is not compatible with CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ if (boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) { ++ pr_err("WARNING: ITS mitigation is not compatible with lfence mitigation\n"); ++ its_mitigation = ITS_MITIGATION_OFF; ++ goto out; ++ } ++ ++ if (cmd == ITS_CMD_RSB_STUFF && ++ (!boot_cpu_has(X86_FEATURE_RETPOLINE) || !IS_ENABLED(CONFIG_CALL_DEPTH_TRACKING))) { ++ pr_err("RSB stuff mitigation not supported, using default\n"); ++ cmd = ITS_CMD_ON; ++ } ++ ++ switch (cmd) { ++ case ITS_CMD_OFF: ++ its_mitigation = ITS_MITIGATION_OFF; ++ break; ++ case ITS_CMD_VMEXIT: ++ if (boot_cpu_has_bug(X86_BUG_ITS_NATIVE_ONLY)) { ++ its_mitigation = ITS_MITIGATION_VMEXIT_ONLY; ++ goto out; ++ } ++ fallthrough; ++ case ITS_CMD_ON: ++ its_mitigation = ITS_MITIGATION_ALIGNED_THUNKS; ++ if (!boot_cpu_has(X86_FEATURE_RETPOLINE)) ++ setup_force_cpu_cap(X86_FEATURE_INDIRECT_THUNK_ITS); ++ setup_force_cpu_cap(X86_FEATURE_RETHUNK); ++ set_return_thunk(its_return_thunk); ++ break; ++ case ITS_CMD_RSB_STUFF: ++ its_mitigation = ITS_MITIGATION_RETPOLINE_STUFF; ++ setup_force_cpu_cap(X86_FEATURE_RETHUNK); ++ setup_force_cpu_cap(X86_FEATURE_CALL_DEPTH); ++#ifdef CONFIG_CALL_DEPTH_TRACKING ++ set_return_thunk(&__x86_return_skl); ++#endif ++ if (retbleed_mitigation == RETBLEED_MITIGATION_NONE) { ++ retbleed_mitigation = RETBLEED_MITIGATION_STUFF; ++ pr_info("Retbleed mitigation updated to stuffing\n"); ++ } ++ break; ++ } ++out: ++ pr_info("%s\n", its_strings[its_mitigation]); ++} ++ + #undef pr_fmt + #define pr_fmt(fmt) "Spectre V2 : " fmt + +@@ -1677,10 +1829,11 @@ static void __init bhi_select_mitigation(void) + return; + } + +- if (spec_ctrl_bhi_dis()) ++ if (!IS_ENABLED(CONFIG_X86_64)) + return; + +- if (!IS_ENABLED(CONFIG_X86_64)) ++ /* Mitigate in hardware if supported */ ++ if (spec_ctrl_bhi_dis()) + return; + + /* Mitigate KVM by default */ +@@ -2606,10 +2759,10 @@ static void __init srso_select_mitigation(void) + + if (boot_cpu_data.x86 == 0x19) { + setup_force_cpu_cap(X86_FEATURE_SRSO_ALIAS); +- x86_return_thunk = srso_alias_return_thunk; ++ set_return_thunk(srso_alias_return_thunk); + } else { + setup_force_cpu_cap(X86_FEATURE_SRSO); +- x86_return_thunk = srso_return_thunk; ++ set_return_thunk(srso_return_thunk); + } + if (has_microcode) + srso_mitigation = SRSO_MITIGATION_SAFE_RET; +@@ -2793,6 +2946,11 @@ static ssize_t rfds_show_state(char *buf) + return sysfs_emit(buf, "%s\n", rfds_strings[rfds_mitigation]); + } + ++static ssize_t its_show_state(char *buf) ++{ ++ return sysfs_emit(buf, "%s\n", its_strings[its_mitigation]); ++} ++ + static char *stibp_state(void) + { + if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) && +@@ -2975,6 +3133,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr + case X86_BUG_RFDS: + return rfds_show_state(buf); + ++ case X86_BUG_ITS: ++ return its_show_state(buf); ++ + default: + break; + } +@@ -3054,4 +3215,9 @@ ssize_t cpu_show_reg_file_data_sampling(struct device *dev, struct device_attrib + { + return cpu_show_common(dev, attr, buf, X86_BUG_RFDS); + } ++ ++ssize_t cpu_show_indirect_target_selection(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return cpu_show_common(dev, attr, buf, X86_BUG_ITS); ++} + #endif +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index a844110691f978..067e31fb9e165d 100644 +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -1272,6 +1272,10 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { + #define GDS BIT(6) + /* CPU is affected by Register File Data Sampling */ + #define RFDS BIT(7) ++/* CPU is affected by Indirect Target Selection */ ++#define ITS BIT(8) ++/* CPU is affected by Indirect Target Selection, but guest-host isolation is not affected */ ++#define ITS_NATIVE_ONLY BIT(9) + + static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { + VULNBL_INTEL_STEPPINGS(IVYBRIDGE, X86_STEPPING_ANY, SRBDS), +@@ -1283,22 +1287,25 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { + VULNBL_INTEL_STEPPINGS(BROADWELL_G, X86_STEPPING_ANY, SRBDS), + VULNBL_INTEL_STEPPINGS(BROADWELL_X, X86_STEPPING_ANY, MMIO), + VULNBL_INTEL_STEPPINGS(BROADWELL, X86_STEPPING_ANY, SRBDS), +- VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), ++ VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x0, 0x5), MMIO | RETBLEED | GDS), ++ VULNBL_INTEL_STEPPINGS(SKYLAKE_X, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | ITS), + VULNBL_INTEL_STEPPINGS(SKYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), + VULNBL_INTEL_STEPPINGS(SKYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), +- VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), +- VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPINGS(0x0, 0xb), MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE_L, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS | ITS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPINGS(0x0, 0xc), MMIO | RETBLEED | GDS | SRBDS), ++ VULNBL_INTEL_STEPPINGS(KABYLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | SRBDS | ITS), + VULNBL_INTEL_STEPPINGS(CANNONLAKE_L, X86_STEPPING_ANY, RETBLEED), +- VULNBL_INTEL_STEPPINGS(ICELAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(ICELAKE_D, X86_STEPPING_ANY, MMIO | GDS), +- VULNBL_INTEL_STEPPINGS(ICELAKE_X, X86_STEPPING_ANY, MMIO | GDS), +- VULNBL_INTEL_STEPPINGS(COMETLAKE, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPINGS(0x0, 0x0), MMIO | RETBLEED), +- VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(TIGERLAKE_L, X86_STEPPING_ANY, GDS), +- VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS), ++ VULNBL_INTEL_STEPPINGS(ICELAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(ICELAKE_D, X86_STEPPING_ANY, MMIO | GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(ICELAKE_X, X86_STEPPING_ANY, MMIO | GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(COMETLAKE, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS | ITS), ++ VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPINGS(0x0, 0x0), MMIO | RETBLEED | ITS), ++ VULNBL_INTEL_STEPPINGS(COMETLAKE_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED | GDS | ITS), ++ VULNBL_INTEL_STEPPINGS(TIGERLAKE_L, X86_STEPPING_ANY, GDS | ITS | ITS_NATIVE_ONLY), ++ VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS | ITS | ITS_NATIVE_ONLY), + VULNBL_INTEL_STEPPINGS(LAKEFIELD, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED), +- VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), ++ VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS | ITS | ITS_NATIVE_ONLY), + VULNBL_INTEL_STEPPINGS(ALDERLAKE, X86_STEPPING_ANY, RFDS), + VULNBL_INTEL_STEPPINGS(ALDERLAKE_L, X86_STEPPING_ANY, RFDS), + VULNBL_INTEL_STEPPINGS(RAPTORLAKE, X86_STEPPING_ANY, RFDS), +@@ -1362,6 +1369,32 @@ static bool __init vulnerable_to_rfds(u64 x86_arch_cap_msr) + return cpu_matches(cpu_vuln_blacklist, RFDS); + } + ++static bool __init vulnerable_to_its(u64 x86_arch_cap_msr) ++{ ++ /* The "immunity" bit trumps everything else: */ ++ if (x86_arch_cap_msr & ARCH_CAP_ITS_NO) ++ return false; ++ if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ return false; ++ ++ /* None of the affected CPUs have BHI_CTRL */ ++ if (boot_cpu_has(X86_FEATURE_BHI_CTRL)) ++ return false; ++ ++ /* ++ * If a VMM did not expose ITS_NO, assume that a guest could ++ * be running on a vulnerable hardware or may migrate to such ++ * hardware. ++ */ ++ if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) ++ return true; ++ ++ if (cpu_matches(cpu_vuln_blacklist, ITS)) ++ return true; ++ ++ return false; ++} ++ + static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + { + u64 x86_arch_cap_msr = x86_read_arch_cap_msr(); +@@ -1476,9 +1509,12 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + if (vulnerable_to_rfds(x86_arch_cap_msr)) + setup_force_cpu_bug(X86_BUG_RFDS); + +- /* When virtualized, eIBRS could be hidden, assume vulnerable */ +- if (!(x86_arch_cap_msr & ARCH_CAP_BHI_NO) && +- !cpu_matches(cpu_vuln_whitelist, NO_BHI) && ++ /* ++ * Intel parts with eIBRS are vulnerable to BHI attacks. Parts with ++ * BHI_NO still need to use the BHI mitigation to prevent Intra-mode ++ * attacks. When virtualized, eIBRS could be hidden, assume vulnerable. ++ */ ++ if (!cpu_matches(cpu_vuln_whitelist, NO_BHI) && + (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED) || + boot_cpu_has(X86_FEATURE_HYPERVISOR))) + setup_force_cpu_bug(X86_BUG_BHI); +@@ -1486,6 +1522,12 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + if (cpu_has(c, X86_FEATURE_AMD_IBPB) && !cpu_has(c, X86_FEATURE_AMD_IBPB_RET)) + setup_force_cpu_bug(X86_BUG_IBPB_NO_RET); + ++ if (vulnerable_to_its(x86_arch_cap_msr)) { ++ setup_force_cpu_bug(X86_BUG_ITS); ++ if (cpu_matches(cpu_vuln_blacklist, ITS_NATIVE_ONLY)) ++ setup_force_cpu_bug(X86_BUG_ITS_NATIVE_ONLY); ++ } ++ + if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN)) + return; + +diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c +index ce78e39004e0ea..9b0570f769eb3d 100644 +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -1102,15 +1102,17 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz + + static int __init save_microcode_in_initrd(void) + { +- unsigned int cpuid_1_eax = native_cpuid_eax(1); + struct cpuinfo_x86 *c = &boot_cpu_data; + struct cont_desc desc = { 0 }; ++ unsigned int cpuid_1_eax; + enum ucode_state ret; + struct cpio_data cp; + +- if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) ++ if (microcode_loader_disabled() || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) + return 0; + ++ cpuid_1_eax = native_cpuid_eax(1); ++ + if (!find_blobs_in_containers(&cp)) + return -EINVAL; + +diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c +index c15c7b862bec1c..5b47c320f17a6d 100644 +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -43,8 +43,8 @@ + + #define DRIVER_VERSION "2.2" + +-static struct microcode_ops *microcode_ops; +-bool dis_ucode_ldr = true; ++static struct microcode_ops *microcode_ops; ++static bool dis_ucode_ldr = false; + + bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV); + module_param(force_minrev, bool, S_IRUSR | S_IWUSR); +@@ -91,6 +91,9 @@ static bool amd_check_current_patch_level(void) + u32 lvl, dummy, i; + u32 *levels; + ++ if (x86_cpuid_vendor() != X86_VENDOR_AMD) ++ return false; ++ + native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); + + levels = final_levels; +@@ -102,27 +105,29 @@ static bool amd_check_current_patch_level(void) + return false; + } + +-static bool __init check_loader_disabled_bsp(void) ++bool __init microcode_loader_disabled(void) + { +- static const char *__dis_opt_str = "dis_ucode_ldr"; +- const char *cmdline = boot_command_line; +- const char *option = __dis_opt_str; ++ if (dis_ucode_ldr) ++ return true; + + /* +- * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not +- * completely accurate as xen pv guests don't see that CPUID bit set but +- * that's good enough as they don't land on the BSP path anyway. ++ * Disable when: ++ * ++ * 1) The CPU does not support CPUID. ++ * ++ * 2) Bit 31 in CPUID[1]:ECX is clear ++ * The bit is reserved for hypervisor use. This is still not ++ * completely accurate as XEN PV guests don't see that CPUID bit ++ * set, but that's good enough as they don't land on the BSP ++ * path anyway. ++ * ++ * 3) Certain AMD patch levels are not allowed to be ++ * overwritten. + */ +- if (native_cpuid_ecx(1) & BIT(31)) +- return true; +- +- if (x86_cpuid_vendor() == X86_VENDOR_AMD) { +- if (amd_check_current_patch_level()) +- return true; +- } +- +- if (cmdline_find_option_bool(cmdline, option) <= 0) +- dis_ucode_ldr = false; ++ if (!have_cpuid_p() || ++ native_cpuid_ecx(1) & BIT(31) || ++ amd_check_current_patch_level()) ++ dis_ucode_ldr = true; + + return dis_ucode_ldr; + } +@@ -132,7 +137,10 @@ void __init load_ucode_bsp(void) + unsigned int cpuid_1_eax; + bool intel = true; + +- if (!have_cpuid_p()) ++ if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0) ++ dis_ucode_ldr = true; ++ ++ if (microcode_loader_disabled()) + return; + + cpuid_1_eax = native_cpuid_eax(1); +@@ -153,9 +161,6 @@ void __init load_ucode_bsp(void) + return; + } + +- if (check_loader_disabled_bsp()) +- return; +- + if (intel) + load_ucode_intel_bsp(&early_data); + else +@@ -166,6 +171,11 @@ void load_ucode_ap(void) + { + unsigned int cpuid_1_eax; + ++ /* ++ * Can't use microcode_loader_disabled() here - .init section ++ * hell. It doesn't have to either - the BSP variant must've ++ * parsed cmdline already anyway. ++ */ + if (dis_ucode_ldr) + return; + +@@ -817,7 +827,7 @@ static int __init microcode_init(void) + struct cpuinfo_x86 *c = &boot_cpu_data; + int error; + +- if (dis_ucode_ldr) ++ if (microcode_loader_disabled()) + return -EINVAL; + + if (c->x86_vendor == X86_VENDOR_INTEL) +diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c +index 9d7baf2573bcde..4e5a71796fbdb1 100644 +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -389,7 +389,7 @@ static int __init save_builtin_microcode(void) + if (xchg(&ucode_patch_va, NULL) != UCODE_BSP_LOADED) + return 0; + +- if (dis_ucode_ldr || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ if (microcode_loader_disabled() || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return 0; + + uci.mc = get_microcode_blob(&uci, true); +diff --git a/arch/x86/kernel/cpu/microcode/internal.h b/arch/x86/kernel/cpu/microcode/internal.h +index 21776c529fa97a..54f2b9582a7cec 100644 +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -94,7 +94,6 @@ static inline unsigned int x86_cpuid_family(void) + return x86_family(eax); + } + +-extern bool dis_ucode_ldr; + extern bool force_minrev; + + #ifdef CONFIG_CPU_SUP_AMD +diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c +index 12df54ff0e8171..50f8c8a8483be2 100644 +--- a/arch/x86/kernel/ftrace.c ++++ b/arch/x86/kernel/ftrace.c +@@ -363,7 +363,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) + goto fail; + + ip = trampoline + size; +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk_at(ip)) + __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, x86_return_thunk, JMP32_INSN_SIZE); + else + memcpy(ip, retq, sizeof(retq)); +diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c +index de001b2146abf3..375f2d7f1762d4 100644 +--- a/arch/x86/kernel/head32.c ++++ b/arch/x86/kernel/head32.c +@@ -145,10 +145,6 @@ void __init __no_stack_protector mk_early_pgtbl_32(void) + *ptr = (unsigned long)ptep + PAGE_OFFSET; + + #ifdef CONFIG_MICROCODE_INITRD32 +- /* Running on a hypervisor? */ +- if (native_cpuid_ecx(1) & BIT(31)) +- return; +- + params = (struct boot_params *)__pa_nodebug(&boot_params); + if (!params->hdr.ramdisk_size || !params->hdr.ramdisk_image) + return; +diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c +index 5f71a0cf4399a5..cfb7163cf90e95 100644 +--- a/arch/x86/kernel/module.c ++++ b/arch/x86/kernel/module.c +@@ -312,6 +312,9 @@ int module_finalize(const Elf_Ehdr *hdr, + void *pseg = (void *)para->sh_addr; + apply_paravirt(pseg, pseg + para->sh_size); + } ++ ++ its_init_mod(me); ++ + if (retpolines || cfi) { + void *rseg = NULL, *cseg = NULL; + unsigned int rsize = 0, csize = 0; +@@ -332,6 +335,9 @@ int module_finalize(const Elf_Ehdr *hdr, + void *rseg = (void *)retpolines->sh_addr; + apply_retpolines(rseg, rseg + retpolines->sh_size); + } ++ ++ its_fini_mod(me); ++ + if (returns) { + void *rseg = (void *)returns->sh_addr; + apply_returns(rseg, rseg + returns->sh_size); +@@ -379,4 +385,5 @@ int module_finalize(const Elf_Ehdr *hdr, + void module_arch_cleanup(struct module *mod) + { + alternatives_smp_module_del(mod); ++ its_free_mod(mod); + } +diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c +index 07961b362e2a0c..bcea882e022f50 100644 +--- a/arch/x86/kernel/static_call.c ++++ b/arch/x86/kernel/static_call.c +@@ -81,7 +81,7 @@ static void __ref __static_call_transform(void *insn, enum insn_type type, + break; + + case RET: +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk_at(insn)) + code = text_gen_insn(JMP32_INSN_OPCODE, insn, x86_return_thunk); + else + code = &retinsn; +@@ -90,7 +90,7 @@ static void __ref __static_call_transform(void *insn, enum insn_type type, + case JCC: + if (!func) { + func = __static_call_return; +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) ++ if (cpu_wants_rethunk()) + func = x86_return_thunk; + } + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 60eb8baa44d7b7..c57d5df1abc603 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -541,4 +541,14 @@ INIT_PER_CPU(irq_stack_backing_store); + "SRSO function pair won't alias"); + #endif + ++#if defined(CONFIG_MITIGATION_ITS) && !defined(CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B) ++. = ASSERT(__x86_indirect_its_thunk_rax & 0x20, "__x86_indirect_thunk_rax not in second half of cacheline"); ++. = ASSERT(((__x86_indirect_its_thunk_rcx - __x86_indirect_its_thunk_rax) % 64) == 0, "Indirect thunks are not cacheline apart"); ++. = ASSERT(__x86_indirect_its_thunk_array == __x86_indirect_its_thunk_rax, "Gap in ITS thunk array"); ++#endif ++ ++#if defined(CONFIG_MITIGATION_ITS) && !defined(CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B) ++. = ASSERT(its_return_thunk & 0x20, "its_return_thunk not in second half of cacheline"); ++#endif ++ + #endif /* CONFIG_X86_64 */ +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 1eeb01afa40ba9..55185670e0e566 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1621,7 +1621,7 @@ static bool kvm_is_immutable_feature_msr(u32 msr) + ARCH_CAP_PSCHANGE_MC_NO | ARCH_CAP_TSX_CTRL_MSR | ARCH_CAP_TAA_NO | \ + ARCH_CAP_SBDR_SSDP_NO | ARCH_CAP_FBSDP_NO | ARCH_CAP_PSDP_NO | \ + ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO | ARCH_CAP_GDS_NO | \ +- ARCH_CAP_RFDS_NO | ARCH_CAP_RFDS_CLEAR | ARCH_CAP_BHI_NO) ++ ARCH_CAP_RFDS_NO | ARCH_CAP_RFDS_CLEAR | ARCH_CAP_BHI_NO | ARCH_CAP_ITS_NO) + + static u64 kvm_get_arch_capabilities(void) + { +@@ -1655,6 +1655,8 @@ static u64 kvm_get_arch_capabilities(void) + data |= ARCH_CAP_MDS_NO; + if (!boot_cpu_has_bug(X86_BUG_RFDS)) + data |= ARCH_CAP_RFDS_NO; ++ if (!boot_cpu_has_bug(X86_BUG_ITS)) ++ data |= ARCH_CAP_ITS_NO; + + if (!boot_cpu_has(X86_FEATURE_RTM)) { + /* +diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S +index ffa51f392e17a3..91ce427d5af191 100644 +--- a/arch/x86/lib/retpoline.S ++++ b/arch/x86/lib/retpoline.S +@@ -360,6 +360,45 @@ SYM_FUNC_END(__x86_return_skl) + + #endif /* CONFIG_CALL_DEPTH_TRACKING */ + ++#ifdef CONFIG_MITIGATION_ITS ++ ++.macro ITS_THUNK reg ++ ++SYM_INNER_LABEL(__x86_indirect_its_thunk_\reg, SYM_L_GLOBAL) ++ UNWIND_HINT_UNDEFINED ++ ANNOTATE_NOENDBR ++ ANNOTATE_RETPOLINE_SAFE ++ jmp *%\reg ++ int3 ++ .align 32, 0xcc /* fill to the end of the line */ ++ .skip 32, 0xcc /* skip to the next upper half */ ++.endm ++ ++/* ITS mitigation requires thunks be aligned to upper half of cacheline */ ++.align 64, 0xcc ++.skip 32, 0xcc ++SYM_CODE_START(__x86_indirect_its_thunk_array) ++ ++#define GEN(reg) ITS_THUNK reg ++#include ++#undef GEN ++ ++ .align 64, 0xcc ++SYM_CODE_END(__x86_indirect_its_thunk_array) ++ ++.align 64, 0xcc ++.skip 32, 0xcc ++SYM_CODE_START(its_return_thunk) ++ UNWIND_HINT_FUNC ++ ANNOTATE_NOENDBR ++ ANNOTATE_UNRET_SAFE ++ ret ++ int3 ++SYM_CODE_END(its_return_thunk) ++EXPORT_SYMBOL(its_return_thunk) ++ ++#endif /* CONFIG_MITIGATION_ITS */ ++ + /* + * This function name is magical and is used by -mfunction-return=thunk-extern + * for the compiler to generate JMPs to it. +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index 4872bb082b1935..20ce6a1bd6c57d 100644 +--- a/arch/x86/mm/tlb.c ++++ b/arch/x86/mm/tlb.c +@@ -630,7 +630,11 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, + + choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush); + +- /* Let nmi_uaccess_okay() know that we're changing CR3. */ ++ /* ++ * Indicate that CR3 is about to change. nmi_uaccess_okay() ++ * and others are sensitive to the window where mm_cpumask(), ++ * CR3 and cpu_tlbstate.loaded_mm are not all in sync. ++ */ + this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING); + barrier(); + } +@@ -900,8 +904,16 @@ static void flush_tlb_func(void *info) + + static bool should_flush_tlb(int cpu, void *data) + { ++ struct mm_struct *loaded_mm = per_cpu(cpu_tlbstate.loaded_mm, cpu); + struct flush_tlb_info *info = data; + ++ /* ++ * Order the 'loaded_mm' and 'is_lazy' against their ++ * write ordering in switch_mm_irqs_off(). Ensure ++ * 'is_lazy' is at least as new as 'loaded_mm'. ++ */ ++ smp_rmb(); ++ + /* Lazy TLB will get flushed at the next context switch. */ + if (per_cpu(cpu_tlbstate_shared.is_lazy, cpu)) + return false; +@@ -910,8 +922,15 @@ static bool should_flush_tlb(int cpu, void *data) + if (!info->mm) + return true; + ++ /* ++ * While switching, the remote CPU could have state from ++ * either the prev or next mm. Assume the worst and flush. ++ */ ++ if (loaded_mm == LOADED_MM_SWITCHING) ++ return true; ++ + /* The target mm is loaded, and the CPU is not lazy. */ +- if (per_cpu(cpu_tlbstate.loaded_mm, cpu) == info->mm) ++ if (loaded_mm == info->mm) + return true; + + /* In cpumask, but not the loaded mm? Periodically remove by flushing. */ +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index a50c99e9b5c01f..07592eef253c21 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -37,6 +37,8 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len) + #define EMIT2(b1, b2) EMIT((b1) + ((b2) << 8), 2) + #define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3) + #define EMIT4(b1, b2, b3, b4) EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4) ++#define EMIT5(b1, b2, b3, b4, b5) \ ++ do { EMIT1(b1); EMIT4(b2, b3, b4, b5); } while (0) + + #define EMIT1_off32(b1, off) \ + do { EMIT1(b1); EMIT(off, 4); } while (0) +@@ -470,7 +472,11 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip) + { + u8 *prog = *pprog; + +- if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) { ++ if (IS_ENABLED(CONFIG_MITIGATION_ITS) && ++ cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) { ++ OPTIMIZER_HIDE_VAR(reg); ++ emit_jump(&prog, its_static_thunk(reg), ip); ++ } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) { + EMIT_LFENCE(); + EMIT2(0xFF, 0xE0 + reg); + } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) { +@@ -492,7 +498,7 @@ static void emit_return(u8 **pprog, u8 *ip) + { + u8 *prog = *pprog; + +- if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) { ++ if (cpu_wants_rethunk()) { + emit_jump(&prog, x86_return_thunk, ip); + } else { + EMIT1(0xC3); /* ret */ +@@ -1072,6 +1078,48 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op) + #define RESTORE_TAIL_CALL_CNT(stack) \ + EMIT3_off32(0x48, 0x8B, 0x85, -round_up(stack, 8) - 8) + ++static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip, ++ struct bpf_prog *bpf_prog) ++{ ++ u8 *prog = *pprog; ++ u8 *func; ++ ++ if (cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP)) { ++ /* The clearing sequence clobbers eax and ecx. */ ++ EMIT1(0x50); /* push rax */ ++ EMIT1(0x51); /* push rcx */ ++ ip += 2; ++ ++ func = (u8 *)clear_bhb_loop; ++ ip += x86_call_depth_emit_accounting(&prog, func); ++ ++ if (emit_call(&prog, func, ip)) ++ return -EINVAL; ++ EMIT1(0x59); /* pop rcx */ ++ EMIT1(0x58); /* pop rax */ ++ } ++ /* Insert IBHF instruction */ ++ if ((cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP) && ++ cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) || ++ cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_HW)) { ++ /* ++ * Add an Indirect Branch History Fence (IBHF). IBHF acts as a ++ * fence preventing branch history from before the fence from ++ * affecting indirect branches after the fence. This is ++ * specifically used in cBPF jitted code to prevent Intra-mode ++ * BHI attacks. The IBHF instruction is designed to be a NOP on ++ * hardware that doesn't need or support it. The REP and REX.W ++ * prefixes are required by the microcode, and they also ensure ++ * that the NOP is unlikely to be used in existing code. ++ * ++ * IBHF is not a valid instruction in 32-bit mode. ++ */ ++ EMIT5(0xF3, 0x48, 0x0F, 0x1E, 0xF8); /* ibhf */ ++ } ++ *pprog = prog; ++ return 0; ++} ++ + static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image, + int oldproglen, struct jit_context *ctx, bool jmp_padding) + { +@@ -1945,6 +1993,15 @@ st: if (is_imm8(insn->off)) + seen_exit = true; + /* Update cleanup_addr */ + ctx->cleanup_addr = proglen; ++ ++ if (bpf_prog_was_classic(bpf_prog) && ++ !capable(CAP_SYS_ADMIN)) { ++ u8 *ip = image + addrs[i - 1]; ++ ++ if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog)) ++ return -EINVAL; ++ } ++ + pop_callee_regs(&prog, callee_regs_used); + EMIT1(0xC9); /* leave */ + emit_return(&prog, image + addrs[i - 1] + (prog - temp)); +diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c +index ef427ee787a99b..a5cfc1bfad51fb 100644 +--- a/drivers/base/cpu.c ++++ b/drivers/base/cpu.c +@@ -566,6 +566,7 @@ CPU_SHOW_VULN_FALLBACK(retbleed); + CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow); + CPU_SHOW_VULN_FALLBACK(gds); + CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling); ++CPU_SHOW_VULN_FALLBACK(indirect_target_selection); + + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); + static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); +@@ -581,6 +582,7 @@ static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); + static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL); + static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL); + static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL); ++static DEVICE_ATTR(indirect_target_selection, 0444, cpu_show_indirect_target_selection, NULL); + + static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_meltdown.attr, +@@ -597,6 +599,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_spec_rstack_overflow.attr, + &dev_attr_gather_data_sampling.attr, + &dev_attr_reg_file_data_sampling.attr, ++ &dev_attr_indirect_target_selection.attr, + NULL + }; + +diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c +index 39f7c2d736d169..b603c25f3dfaac 100644 +--- a/drivers/clocksource/i8253.c ++++ b/drivers/clocksource/i8253.c +@@ -103,7 +103,7 @@ int __init clocksource_i8253_init(void) + #ifdef CONFIG_CLKEVT_I8253 + void clockevent_i8253_disable(void) + { +- raw_spin_lock(&i8253_lock); ++ guard(raw_spinlock_irqsave)(&i8253_lock); + + /* + * Writing the MODE register should stop the counter, according to +@@ -132,8 +132,6 @@ void clockevent_i8253_disable(void) + outb_p(0, PIT_CH0); + + outb_p(0x30, PIT_MODE); +- +- raw_spin_unlock(&i8253_lock); + } + + static int pit_shutdown(struct clock_event_device *evt) +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c +index 30210613dc5c47..2f3054ed7b1b5b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c +@@ -42,7 +42,12 @@ static void hdp_v4_0_flush_hdp(struct amdgpu_device *adev, + { + if (!ring || !ring->funcs->emit_wreg) { + WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); +- RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); + } else { + amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c +index d3962d46908811..40705e13ca567b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c +@@ -33,7 +33,12 @@ static void hdp_v5_0_flush_hdp(struct amdgpu_device *adev, + { + if (!ring || !ring->funcs->emit_wreg) { + WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); +- RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); + } else { + amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c +index f52552c5fa27b6..6b9f2e1d9d690d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c +@@ -34,7 +34,17 @@ static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev, + if (!ring || !ring->funcs->emit_wreg) { + WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, + 0); +- RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ if (amdgpu_sriov_vf(adev)) { ++ /* this is fine because SR_IOV doesn't remap the register */ ++ RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ } else { ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); ++ } + } else { + amdgpu_ring_emit_wreg(ring, + (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, +diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c +index b6d71ec1debf9a..0d0c568f383931 100644 +--- a/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c +@@ -33,7 +33,12 @@ static void hdp_v6_0_flush_hdp(struct amdgpu_device *adev, + { + if (!ring || !ring->funcs->emit_wreg) { + WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); +- RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); ++ /* We just need to read back a register to post the write. ++ * Reading back the remapped register causes problems on ++ * some platforms so just read back the memory size register. ++ */ ++ if (adev->nbio.funcs->get_memsize) ++ adev->nbio.funcs->get_memsize(adev); + } else { + amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index e6bc590533194d..f6017be8f9957e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -610,15 +610,21 @@ static void dm_crtc_high_irq(void *interrupt_params) + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); + + if (acrtc->dm_irq_params.stream && +- acrtc->dm_irq_params.vrr_params.supported && +- acrtc->dm_irq_params.freesync_config.state == +- VRR_STATE_ACTIVE_VARIABLE) { ++ acrtc->dm_irq_params.vrr_params.supported) { ++ bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; ++ bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; ++ bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE; ++ + mod_freesync_handle_v_update(adev->dm.freesync_module, + acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params); + +- dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc->dm_irq_params.stream, +- &acrtc->dm_irq_params.vrr_params.adjust); ++ /* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */ ++ if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { ++ dc_stream_adjust_vmin_vmax(adev->dm.dc, ++ acrtc->dm_irq_params.stream, ++ &acrtc->dm_irq_params.vrr_params.adjust); ++ } + } + + /* +@@ -11049,7 +11055,7 @@ int amdgpu_dm_process_dmub_aux_transfer_sync( + * Transient states before tunneling is enabled could + * lead to this error. We can ignore this for now. + */ +- if (p_notify->result != AUX_RET_ERROR_PROTOCOL_ERROR) { ++ if (p_notify->result == AUX_RET_ERROR_PROTOCOL_ERROR) { + DRM_WARN("DPIA AUX failed on 0x%x(%d), error %d\n", + payload->address, payload->length, + p_notify->result); +@@ -11058,22 +11064,14 @@ int amdgpu_dm_process_dmub_aux_transfer_sync( + goto out; + } + ++ payload->reply[0] = adev->dm.dmub_notify->aux_reply.command & 0xF; ++ if (adev->dm.dmub_notify->aux_reply.command & 0xF0) ++ /* The reply is stored in the top nibble of the command. */ ++ payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF; + +- payload->reply[0] = adev->dm.dmub_notify->aux_reply.command; +- if (!payload->write && p_notify->aux_reply.length && +- (payload->reply[0] == AUX_TRANSACTION_REPLY_AUX_ACK)) { +- +- if (payload->length != p_notify->aux_reply.length) { +- DRM_WARN("invalid read length %d from DPIA AUX 0x%x(%d)!\n", +- p_notify->aux_reply.length, +- payload->address, payload->length); +- *operation_result = AUX_RET_ERROR_INVALID_REPLY; +- goto out; +- } +- ++ if (!payload->write && p_notify->aux_reply.length) + memcpy(payload->data, p_notify->aux_reply.data, + p_notify->aux_reply.length); +- } + + /* success */ + ret = p_notify->aux_reply.length; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index 5858e288b3fd66..c0cacd501c83eb 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -48,6 +48,9 @@ + + #define PEAK_FACTOR_X1000 1006 + ++/* ++ * This function handles both native AUX and I2C-Over-AUX transactions. ++ */ + static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) + { +@@ -84,15 +87,25 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + if (adev->dm.aux_hpd_discon_quirk) { + if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE && + operation_result == AUX_RET_ERROR_HPD_DISCON) { +- result = 0; ++ result = msg->size; + operation_result = AUX_RET_SUCCESS; + } + } + +- if (payload.write && result >= 0) +- result = msg->size; ++ /* ++ * result equals to 0 includes the cases of AUX_DEFER/I2C_DEFER ++ */ ++ if (payload.write && result >= 0) { ++ if (result) { ++ /*one byte indicating partially written bytes. Force 0 to retry*/ ++ drm_info(adev_to_drm(adev), "amdgpu: AUX partially written\n"); ++ result = 0; ++ } else if (!payload.reply[0]) ++ /*I2C_ACK|AUX_ACK*/ ++ result = msg->size; ++ } + +- if (result < 0) ++ if (result < 0) { + switch (operation_result) { + case AUX_RET_SUCCESS: + break; +@@ -111,6 +124,13 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + break; + } + ++ drm_info(adev_to_drm(adev), "amdgpu: DP AUX transfer fail:%d\n", operation_result); ++ } ++ ++ if (payload.reply[0]) ++ drm_info(adev_to_drm(adev), "amdgpu: AUX reply command not ACK: 0x%02x.", ++ payload.reply[0]); ++ + return result; + } + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 37fe54c34b141c..0d69098eddd90f 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -979,27 +979,28 @@ static const struct panel_desc auo_g070vvn01 = { + }, + }; + +-static const struct drm_display_mode auo_g101evn010_mode = { +- .clock = 68930, +- .hdisplay = 1280, +- .hsync_start = 1280 + 82, +- .hsync_end = 1280 + 82 + 2, +- .htotal = 1280 + 82 + 2 + 84, +- .vdisplay = 800, +- .vsync_start = 800 + 8, +- .vsync_end = 800 + 8 + 2, +- .vtotal = 800 + 8 + 2 + 6, ++static const struct display_timing auo_g101evn010_timing = { ++ .pixelclock = { 64000000, 68930000, 85000000 }, ++ .hactive = { 1280, 1280, 1280 }, ++ .hfront_porch = { 8, 64, 256 }, ++ .hback_porch = { 8, 64, 256 }, ++ .hsync_len = { 40, 168, 767 }, ++ .vactive = { 800, 800, 800 }, ++ .vfront_porch = { 4, 8, 100 }, ++ .vback_porch = { 4, 8, 100 }, ++ .vsync_len = { 8, 16, 223 }, + }; + + static const struct panel_desc auo_g101evn010 = { +- .modes = &auo_g101evn010_mode, +- .num_modes = 1, ++ .timings = &auo_g101evn010_timing, ++ .num_timings = 1, + .bpc = 6, + .size = { + .width = 216, + .height = 135, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, + }; + +diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c +index 5b729013fd26f5..41493cf3d03b81 100644 +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -289,11 +289,16 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +-/* If the current address or return address have changed, then the GPU +- * has probably made progress and we should delay the reset. This +- * could fail if the GPU got in an infinite loop in the CL, but that +- * is pretty unlikely outside of an i-g-t testcase. +- */ ++static void ++v3d_sched_skip_reset(struct drm_sched_job *sched_job) ++{ ++ struct drm_gpu_scheduler *sched = sched_job->sched; ++ ++ spin_lock(&sched->job_list_lock); ++ list_add(&sched_job->list, &sched->pending_list); ++ spin_unlock(&sched->job_list_lock); ++} ++ + static enum drm_gpu_sched_stat + v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q, + u32 *timedout_ctca, u32 *timedout_ctra) +@@ -303,9 +308,16 @@ v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q, + u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(q)); + u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(q)); + ++ /* If the current address or return address have changed, then the GPU ++ * has probably made progress and we should delay the reset. This ++ * could fail if the GPU got in an infinite loop in the CL, but that ++ * is pretty unlikely outside of an i-g-t testcase. ++ */ + if (*timedout_ctca != ctca || *timedout_ctra != ctra) { + *timedout_ctca = ctca; + *timedout_ctra = ctra; ++ ++ v3d_sched_skip_reset(sched_job); + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +@@ -345,11 +357,13 @@ v3d_csd_job_timedout(struct drm_sched_job *sched_job) + struct v3d_dev *v3d = job->base.v3d; + u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4); + +- /* If we've made progress, skip reset and let the timer get +- * rearmed. ++ /* If we've made progress, skip reset, add the job to the pending ++ * list, and let the timer get rearmed. + */ + if (job->timedout_batches != batches) { + job->timedout_batches = batches; ++ ++ v3d_sched_skip_reset(sched_job); + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c +index d054721859b3b5..99b05548b7bdbb 100644 +--- a/drivers/iio/accel/adis16201.c ++++ b/drivers/iio/accel/adis16201.c +@@ -211,9 +211,9 @@ static const struct iio_chan_spec adis16201_channels[] = { + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12), + ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X, +- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), ++ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), + ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y, +- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), ++ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), + IIO_CHAN_SOFT_TIMESTAMP(7) + }; + +diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c +index 0c9225d18fb29b..4973e8da5399d7 100644 +--- a/drivers/iio/accel/adxl355_core.c ++++ b/drivers/iio/accel/adxl355_core.c +@@ -231,7 +231,7 @@ struct adxl355_data { + u8 transf_buf[3]; + struct { + u8 buf[14]; +- s64 ts; ++ aligned_s64 ts; + } buffer; + } __aligned(IIO_DMA_MINALIGN); + }; +diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c +index 484fe2e9fb1742..3a55475691de39 100644 +--- a/drivers/iio/accel/adxl367.c ++++ b/drivers/iio/accel/adxl367.c +@@ -620,18 +620,14 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) + if (ret) + return ret; + ++ st->odr = odr; ++ + /* Activity timers depend on ODR */ + ret = _adxl367_set_act_time_ms(st, st->act_time_ms); + if (ret) + return ret; + +- ret = _adxl367_set_inact_time_ms(st, st->inact_time_ms); +- if (ret) +- return ret; +- +- st->odr = odr; +- +- return 0; ++ return _adxl367_set_inact_time_ms(st, st->inact_time_ms); + } + + static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) +diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c +index 287a0591533b6a..67c96572cecc40 100644 +--- a/drivers/iio/adc/ad7606_spi.c ++++ b/drivers/iio/adc/ad7606_spi.c +@@ -127,7 +127,7 @@ static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) + { + .tx_buf = &st->d16[0], + .len = 2, +- .cs_change = 0, ++ .cs_change = 1, + }, { + .rx_buf = &st->d16[1], + .len = 2, +diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c +index 97d162a3cba4ea..49a2588e7431ed 100644 +--- a/drivers/iio/adc/dln2-adc.c ++++ b/drivers/iio/adc/dln2-adc.c +@@ -483,7 +483,7 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p) + struct iio_dev *indio_dev = pf->indio_dev; + struct { + __le16 values[DLN2_ADC_MAX_CHANNELS]; +- int64_t timestamp_space; ++ aligned_s64 timestamp_space; + } data; + struct dln2_adc_get_all_vals dev_data; + struct dln2_adc *dln2 = iio_priv(indio_dev); +diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c +index 929cba215d99ab..7b4eb4a200df81 100644 +--- a/drivers/iio/adc/rockchip_saradc.c ++++ b/drivers/iio/adc/rockchip_saradc.c +@@ -485,15 +485,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev) + if (info->reset) + rockchip_saradc_reset_controller(info->reset); + +- /* +- * Use a default value for the converter clock. +- * This may become user-configurable in the future. +- */ +- ret = clk_set_rate(info->clk, info->data->clk_rate); +- if (ret < 0) +- return dev_err_probe(&pdev->dev, ret, +- "failed to set adc clk rate\n"); +- + ret = regulator_enable(info->vref); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, +@@ -520,6 +511,14 @@ static int rockchip_saradc_probe(struct platform_device *pdev) + if (IS_ERR(info->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), + "failed to get adc clock\n"); ++ /* ++ * Use a default value for the converter clock. ++ * This may become user-configurable in the future. ++ */ ++ ret = clk_set_rate(info->clk, info->data->clk_rate); ++ if (ret < 0) ++ return dev_err_probe(&pdev->dev, ret, ++ "failed to set adc clk rate\n"); + + platform_set_drvdata(pdev, indio_dev); + +diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +index 066fe561c5e88d..b8119fa4768eb8 100644 +--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c ++++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +@@ -370,6 +370,9 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) + if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK)) + return 0; + ++ if (!pattern_len) ++ pattern_len = ST_LSM6DSX_SAMPLE_SIZE; ++ + fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) * + ST_LSM6DSX_CHAN_SIZE; + fifo_len = (fifo_len / pattern_len) * pattern_len; +@@ -601,6 +604,9 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) + if (!fifo_len) + return 0; + ++ if (!pattern_len) ++ pattern_len = ST_LSM6DSX_TAGGED_SAMPLE_SIZE; ++ + for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { + err = st_lsm6dsx_read_block(hw, + ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR, +diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c +index c28a7a6dea5f12..555a61e2f3fdd1 100644 +--- a/drivers/iio/temperature/maxim_thermocouple.c ++++ b/drivers/iio/temperature/maxim_thermocouple.c +@@ -121,9 +121,9 @@ static const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = { + struct maxim_thermocouple_data { + struct spi_device *spi; + const struct maxim_thermocouple_chip *chip; ++ char tc_type; + + u8 buffer[16] __aligned(IIO_DMA_MINALIGN); +- char tc_type; + }; + + static int maxim_thermocouple_read(struct maxim_thermocouple_data *data, +diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c +index b91467c8e6c402..c65321964131cf 100644 +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -77,12 +77,13 @@ + * xbox d-pads should map to buttons, as is required for DDR pads + * but we map them to axes when possible to simplify things + */ +-#define MAP_DPAD_TO_BUTTONS (1 << 0) +-#define MAP_TRIGGERS_TO_BUTTONS (1 << 1) +-#define MAP_STICKS_TO_NULL (1 << 2) +-#define MAP_SELECT_BUTTON (1 << 3) +-#define MAP_PADDLES (1 << 4) +-#define MAP_PROFILE_BUTTON (1 << 5) ++#define MAP_DPAD_TO_BUTTONS BIT(0) ++#define MAP_TRIGGERS_TO_BUTTONS BIT(1) ++#define MAP_STICKS_TO_NULL BIT(2) ++#define MAP_SHARE_BUTTON BIT(3) ++#define MAP_PADDLES BIT(4) ++#define MAP_PROFILE_BUTTON BIT(5) ++#define MAP_SHARE_OFFSET BIT(6) + + #define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \ + MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL) +@@ -135,7 +136,7 @@ static const struct xpad_device { + { 0x03f0, 0x048D, "HyperX Clutch", 0, XTYPE_XBOX360 }, /* wireless */ + { 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, + { 0x03f0, 0x07A0, "HyperX Clutch Gladiate RGB", 0, XTYPE_XBOXONE }, +- { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, /* v2 */ ++ { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, /* v2 */ + { 0x03f0, 0x09B4, "HyperX Clutch Tanto", 0, XTYPE_XBOXONE }, + { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, + { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, +@@ -159,7 +160,7 @@ static const struct xpad_device { + { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, + { 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE }, + { 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE }, +- { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, ++ { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SHARE_BUTTON | MAP_SHARE_OFFSET, XTYPE_XBOXONE }, + { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, + { 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 }, + { 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 }, +@@ -205,13 +206,13 @@ static const struct xpad_device { + { 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 }, + { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 }, + { 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, +- { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, ++ { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", 0, XTYPE_XBOX360 }, + { 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, + { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, + { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 }, + { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, + { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 }, +- { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", 0, XTYPE_XBOXONE }, ++ { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x0b05, 0x1abb, "ASUS ROG RAIKIRI PRO", 0, XTYPE_XBOXONE }, + { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX }, + { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX }, +@@ -240,7 +241,7 @@ static const struct xpad_device { + { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, +- { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", XTYPE_XBOXONE }, ++ { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, +@@ -386,10 +387,11 @@ static const struct xpad_device { + { 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 }, ++ { 0x2dc8, 0x310b, "8BitDo Ultimate 2 Wireless Controller", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x6001, "8BitDo SN30 Pro", 0, XTYPE_XBOX360 }, + { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, + { 0x2e24, 0x1688, "Hyperkin X91 X-Box One pad", 0, XTYPE_XBOXONE }, +- { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, ++ { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, +@@ -1025,7 +1027,7 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha + * The report format was gleaned from + * https://github.com/kylelemons/xbox/blob/master/xbox.go + */ +-static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) ++static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, u32 len) + { + struct input_dev *dev = xpad->dev; + bool do_sync = false; +@@ -1066,8 +1068,12 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char + /* menu/view buttons */ + input_report_key(dev, BTN_START, data[4] & BIT(2)); + input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); +- if (xpad->mapping & MAP_SELECT_BUTTON) +- input_report_key(dev, KEY_RECORD, data[22] & BIT(0)); ++ if (xpad->mapping & MAP_SHARE_BUTTON) { ++ if (xpad->mapping & MAP_SHARE_OFFSET) ++ input_report_key(dev, KEY_RECORD, data[len - 26] & BIT(0)); ++ else ++ input_report_key(dev, KEY_RECORD, data[len - 18] & BIT(0)); ++ } + + /* buttons A,B,X,Y */ + input_report_key(dev, BTN_A, data[4] & BIT(4)); +@@ -1215,7 +1221,7 @@ static void xpad_irq_in(struct urb *urb) + xpad360w_process_packet(xpad, 0, xpad->idata); + break; + case XTYPE_XBOXONE: +- xpadone_process_packet(xpad, 0, xpad->idata); ++ xpadone_process_packet(xpad, 0, xpad->idata, urb->actual_length); + break; + default: + xpad_process_packet(xpad, 0, xpad->idata); +@@ -1972,7 +1978,7 @@ static int xpad_init_input(struct usb_xpad *xpad) + xpad->xtype == XTYPE_XBOXONE) { + for (i = 0; xpad360_btn[i] >= 0; i++) + input_set_capability(input_dev, EV_KEY, xpad360_btn[i]); +- if (xpad->mapping & MAP_SELECT_BUTTON) ++ if (xpad->mapping & MAP_SHARE_BUTTON) + input_set_capability(input_dev, EV_KEY, KEY_RECORD); + } else { + for (i = 0; xpad_btn[i] >= 0; i++) +diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c +index 4364c3401ff1c6..486ca8ff86f830 100644 +--- a/drivers/input/keyboard/mtk-pmic-keys.c ++++ b/drivers/input/keyboard/mtk-pmic-keys.c +@@ -147,8 +147,8 @@ static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys, + u32 value, mask; + int error; + +- kregs_home = keys->keys[MTK_PMIC_HOMEKEY_INDEX].regs; +- kregs_pwr = keys->keys[MTK_PMIC_PWRKEY_INDEX].regs; ++ kregs_home = ®s->keys_regs[MTK_PMIC_HOMEKEY_INDEX]; ++ kregs_pwr = ®s->keys_regs[MTK_PMIC_PWRKEY_INDEX]; + + error = of_property_read_u32(keys->dev->of_node, "power-off-time-sec", + &long_press_debounce); +diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c +index 26677432ac8361..3ca6642601c7d5 100644 +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -163,6 +163,7 @@ static const char * const topbuttonpad_pnp_ids[] = { + + static const char * const smbus_pnp_ids[] = { + /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ ++ "DLL060d", /* Dell Precision M3800 */ + "LEN0048", /* X1 Carbon 3 */ + "LEN0046", /* X250 */ + "LEN0049", /* Yoga 11e */ +@@ -189,11 +190,15 @@ static const char * const smbus_pnp_ids[] = { + "LEN2054", /* E480 */ + "LEN2055", /* E580 */ + "LEN2068", /* T14 Gen 1 */ ++ "SYN1221", /* TUXEDO InfinityBook Pro 14 v5 */ ++ "SYN3003", /* HP EliteBook 850 G1 */ + "SYN3015", /* HP EliteBook 840 G2 */ + "SYN3052", /* HP EliteBook 840 G4 */ + "SYN3221", /* HP 15-ay000 */ + "SYN323d", /* HP Spectre X360 13-w013dx */ + "SYN3257", /* HP Envy 13-ad105ng */ ++ "TOS01f6", /* Dynabook Portege X30L-G */ ++ "TOS0213", /* Dynabook Portege X30-D */ + NULL + }; + +diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c +index db5a885ecd7285..a74b34d8df2a22 100644 +--- a/drivers/input/touchscreen/cyttsp5.c ++++ b/drivers/input/touchscreen/cyttsp5.c +@@ -580,7 +580,7 @@ static int cyttsp5_power_control(struct cyttsp5 *ts, bool on) + int rc; + + SET_CMD_REPORT_TYPE(cmd[0], 0); +- SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP); ++ SET_CMD_REPORT_ID(cmd[0], state); + SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER); + + rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd)); +@@ -865,13 +865,16 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq, + ts->input->phys = ts->phys; + input_set_drvdata(ts->input, ts); + +- /* Reset the gpio to be in a reset state */ ++ /* Assert gpio to be in a reset state */ + ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(dev, "Failed to request reset gpio, error %d\n", error); + return error; + } ++ ++ fsleep(10); /* Ensure long-enough reset pulse (minimum 10us). */ ++ + gpiod_set_value_cansleep(ts->reset_gpio, 0); + + /* Need a delay to have device up */ +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 319bd10548e9ad..7a33da2dd64b12 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -1242,7 +1242,7 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile, + + t = dm_get_live_table(md, &srcu_idx); + if (!t) +- return 0; ++ goto put_live_table; + + for (unsigned int i = 0; i < t->num_targets; i++) { + struct dm_target *ti = dm_table_get_target(t, i); +@@ -1253,6 +1253,7 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile, + (void *)key); + } + ++put_live_table: + dm_put_live_table(md, srcu_idx); + return 0; + } +diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c +index 2a258986eed02b..ba7f7de25c8529 100644 +--- a/drivers/net/can/m_can/m_can.c ++++ b/drivers/net/can/m_can/m_can.c +@@ -2125,9 +2125,9 @@ EXPORT_SYMBOL_GPL(m_can_class_register); + + void m_can_class_unregister(struct m_can_classdev *cdev) + { ++ unregister_candev(cdev->net); + if (cdev->is_peripheral) + can_rx_offload_del(&cdev->offload); +- unregister_candev(cdev->net); + } + EXPORT_SYMBOL_GPL(m_can_class_unregister); + +diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +index 6fecfe4cd08041..21ae3a89924e97 100644 +--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c ++++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +@@ -75,6 +75,24 @@ static const struct can_bittiming_const mcp251xfd_data_bittiming_const = { + .brp_inc = 1, + }; + ++/* The datasheet of the mcp2518fd (DS20006027B) specifies a range of ++ * [-64,63] for TDCO, indicating a relative TDCO. ++ * ++ * Manual tests have shown, that using a relative TDCO configuration ++ * results in bus off, while an absolute configuration works. ++ * ++ * For TDCO use the max value (63) from the data sheet, but 0 as the ++ * minimum. ++ */ ++static const struct can_tdc_const mcp251xfd_tdc_const = { ++ .tdcv_min = 0, ++ .tdcv_max = 63, ++ .tdco_min = 0, ++ .tdco_max = 63, ++ .tdcf_min = 0, ++ .tdcf_max = 0, ++}; ++ + static const char *__mcp251xfd_get_model_str(enum mcp251xfd_model model) + { + switch (model) { +@@ -510,8 +528,7 @@ static int mcp251xfd_set_bittiming(const struct mcp251xfd_priv *priv) + { + const struct can_bittiming *bt = &priv->can.bittiming; + const struct can_bittiming *dbt = &priv->can.data_bittiming; +- u32 val = 0; +- s8 tdco; ++ u32 tdcmod, val = 0; + int err; + + /* CAN Control Register +@@ -575,11 +592,16 @@ static int mcp251xfd_set_bittiming(const struct mcp251xfd_priv *priv) + return err; + + /* Transmitter Delay Compensation */ +- tdco = clamp_t(int, dbt->brp * (dbt->prop_seg + dbt->phase_seg1), +- -64, 63); +- val = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, +- MCP251XFD_REG_TDC_TDCMOD_AUTO) | +- FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, tdco); ++ if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_AUTO) ++ tdcmod = MCP251XFD_REG_TDC_TDCMOD_AUTO; ++ else if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_MANUAL) ++ tdcmod = MCP251XFD_REG_TDC_TDCMOD_MANUAL; ++ else ++ tdcmod = MCP251XFD_REG_TDC_TDCMOD_DISABLED; ++ ++ val = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, tdcmod) | ++ FIELD_PREP(MCP251XFD_REG_TDC_TDCV_MASK, priv->can.tdc.tdcv) | ++ FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, priv->can.tdc.tdco); + + return regmap_write(priv->map_reg, MCP251XFD_REG_TDC, val); + } +@@ -2083,10 +2105,12 @@ static int mcp251xfd_probe(struct spi_device *spi) + priv->can.do_get_berr_counter = mcp251xfd_get_berr_counter; + priv->can.bittiming_const = &mcp251xfd_bittiming_const; + priv->can.data_bittiming_const = &mcp251xfd_data_bittiming_const; ++ priv->can.tdc_const = &mcp251xfd_tdc_const; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO | +- CAN_CTRLMODE_CC_LEN8_DLC; ++ CAN_CTRLMODE_CC_LEN8_DLC | CAN_CTRLMODE_TDC_AUTO | ++ CAN_CTRLMODE_TDC_MANUAL; + set_bit(MCP251XFD_FLAGS_DOWN, priv->flags); + priv->ndev = ndev; + priv->spi = spi; +@@ -2179,8 +2203,8 @@ static void mcp251xfd_remove(struct spi_device *spi) + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); + struct net_device *ndev = priv->ndev; + +- can_rx_offload_del(&priv->offload); + mcp251xfd_unregister(priv); ++ can_rx_offload_del(&priv->offload); + spi->max_speed_hz = priv->spi_max_speed_hz_orig; + free_candev(ndev); + } +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index cfcda893f1a16d..d2ff2c2fcbbfc4 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -373,15 +373,17 @@ static void b53_enable_vlan(struct b53_device *dev, int port, bool enable, + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); + } + ++ vc1 &= ~VC1_RX_MCST_FWD_EN; ++ + if (enable) { + vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; +- vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; ++ vc1 |= VC1_RX_MCST_UNTAG_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + if (enable_filtering) { + vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; + vc5 |= VC5_DROP_VTABLE_MISS; + } else { +- vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; ++ vc4 |= VC4_NO_ING_VID_CHK << VC4_ING_VID_CHECK_S; + vc5 &= ~VC5_DROP_VTABLE_MISS; + } + +@@ -393,7 +395,7 @@ static void b53_enable_vlan(struct b53_device *dev, int port, bool enable, + + } else { + vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); +- vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); ++ vc1 &= ~VC1_RX_MCST_UNTAG_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc5 &= ~VC5_DROP_VTABLE_MISS; + +@@ -1519,12 +1521,21 @@ int b53_vlan_add(struct dsa_switch *ds, int port, + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + struct b53_vlan *vl; ++ u16 old_pvid, new_pvid; + int err; + + err = b53_vlan_prepare(ds, port, vlan); + if (err) + return err; + ++ b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &old_pvid); ++ if (pvid) ++ new_pvid = vlan->vid; ++ else if (!pvid && vlan->vid == old_pvid) ++ new_pvid = b53_default_pvid(dev); ++ else ++ new_pvid = old_pvid; ++ + vl = &dev->vlans[vlan->vid]; + + b53_get_vlan_entry(dev, vlan->vid, vl); +@@ -1541,10 +1552,10 @@ int b53_vlan_add(struct dsa_switch *ds, int port, + b53_set_vlan_entry(dev, vlan->vid, vl); + b53_fast_age_vlan(dev, vlan->vid); + +- if (pvid && !dsa_is_cpu_port(ds, port)) { ++ if (!dsa_is_cpu_port(ds, port) && new_pvid != old_pvid) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), +- vlan->vid); +- b53_fast_age_vlan(dev, vlan->vid); ++ new_pvid); ++ b53_fast_age_vlan(dev, old_pvid); + } + + return 0; +@@ -1956,7 +1967,7 @@ EXPORT_SYMBOL(b53_br_join); + void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) + { + struct b53_device *dev = ds->priv; +- struct b53_vlan *vl = &dev->vlans[0]; ++ struct b53_vlan *vl; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; + unsigned int i; + u16 pvlan, reg, pvid; +@@ -1982,6 +1993,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) + dev->ports[port].vlan_ctl_mask = pvlan; + + pvid = b53_default_pvid(dev); ++ vl = &dev->vlans[pvid]; + + /* Make this port join all VLANs without VLAN entries */ + if (is58xx(dev)) { +@@ -1990,12 +2002,12 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) + if (!(reg & BIT(cpu_port))) + reg |= BIT(cpu_port); + b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, reg); +- } else { +- b53_get_vlan_entry(dev, pvid, vl); +- vl->members |= BIT(port) | BIT(cpu_port); +- vl->untag |= BIT(port) | BIT(cpu_port); +- b53_set_vlan_entry(dev, pvid, vl); + } ++ ++ b53_get_vlan_entry(dev, pvid, vl); ++ vl->members |= BIT(port) | BIT(cpu_port); ++ vl->untag |= BIT(port) | BIT(cpu_port); ++ b53_set_vlan_entry(dev, pvid, vl); + } + EXPORT_SYMBOL(b53_br_leave); + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index d2ec8f642c2fa0..c6ccfbd4226570 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3117,11 +3117,19 @@ static int mtk_dma_init(struct mtk_eth *eth) + static void mtk_dma_free(struct mtk_eth *eth) + { + const struct mtk_soc_data *soc = eth->soc; +- int i; ++ int i, j, txqs = 1; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) ++ txqs = MTK_QDMA_NUM_QUEUES; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ ++ for (j = 0; j < txqs; j++) ++ netdev_tx_reset_subqueue(eth->netdev[i], j); ++ } + +- for (i = 0; i < MTK_MAX_DEVS; i++) +- if (eth->netdev[i]) +- netdev_reset_queue(eth->netdev[i]); + if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) { + dma_free_coherent(eth->dma_dev, + MTK_QDMA_RING_SIZE * soc->txrx.txd_size, +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index c6b0637e61debd..6e2d0fda3ba4aa 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -4156,7 +4156,8 @@ static void nvme_fw_act_work(struct work_struct *work) + msleep(100); + } + +- if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) ++ if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING) || ++ !nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) + return; + + nvme_unquiesce_io_queues(ctrl); +diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c +index 727b956aa23172..f667b3b62f1883 100644 +--- a/drivers/staging/axis-fifo/axis-fifo.c ++++ b/drivers/staging/axis-fifo/axis-fifo.c +@@ -398,16 +398,14 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, + + bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET); + if (!bytes_available) { +- dev_err(fifo->dt_device, "received a packet of length 0 - fifo core will be reset\n"); +- reset_ip_core(fifo); ++ dev_err(fifo->dt_device, "received a packet of length 0\n"); + ret = -EIO; + goto end_unlock; + } + + if (bytes_available > len) { +- dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu) - fifo core will be reset\n", ++ dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n", + bytes_available, len); +- reset_ip_core(fifo); + ret = -EINVAL; + goto end_unlock; + } +@@ -416,8 +414,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, + /* this probably can't happen unless IP + * registers were previously mishandled + */ +- dev_err(fifo->dt_device, "received a packet that isn't word-aligned - fifo core will be reset\n"); +- reset_ip_core(fifo); ++ dev_err(fifo->dt_device, "received a packet that isn't word-aligned\n"); + ret = -EIO; + goto end_unlock; + } +@@ -438,7 +435,6 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, + + if (copy_to_user(buf + copied * sizeof(u32), tmp_buf, + copy * sizeof(u32))) { +- reset_ip_core(fifo); + ret = -EFAULT; + goto end_unlock; + } +@@ -547,7 +543,6 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf, + + if (copy_from_user(tmp_buf, buf + copied * sizeof(u32), + copy * sizeof(u32))) { +- reset_ip_core(fifo); + ret = -EFAULT; + goto end_unlock; + } +@@ -780,9 +775,6 @@ static int axis_fifo_parse_dt(struct axis_fifo *fifo) + goto end; + } + +- /* IP sets TDFV to fifo depth - 4 so we will do the same */ +- fifo->tx_fifo_depth -= 4; +- + ret = get_dts_property(fifo, "xlnx,use-rx-data", &fifo->has_rx_fifo); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,use-rx-data property\n"); +diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c +index 6c14d7bcdd6750..081b17f498638b 100644 +--- a/drivers/staging/iio/adc/ad7816.c ++++ b/drivers/staging/iio/adc/ad7816.c +@@ -136,7 +136,7 @@ static ssize_t ad7816_store_mode(struct device *dev, + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7816_chip_info *chip = iio_priv(indio_dev); + +- if (strcmp(buf, "full")) { ++ if (strcmp(buf, "full") == 0) { + gpiod_set_value(chip->rdwr_pin, 1); + chip->mode = AD7816_FULL; + } else { +diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c +index 4b67749edb9974..601a60a2802240 100644 +--- a/drivers/usb/cdns3/cdnsp-gadget.c ++++ b/drivers/usb/cdns3/cdnsp-gadget.c +@@ -138,6 +138,26 @@ static void cdnsp_clear_port_change_bit(struct cdnsp_device *pdev, + (portsc & PORT_CHANGE_BITS), port_regs); + } + ++static void cdnsp_set_apb_timeout_value(struct cdnsp_device *pdev) ++{ ++ struct cdns *cdns = dev_get_drvdata(pdev->dev); ++ __le32 __iomem *reg; ++ void __iomem *base; ++ u32 offset = 0; ++ u32 val; ++ ++ if (!cdns->override_apb_timeout) ++ return; ++ ++ base = &pdev->cap_regs->hc_capbase; ++ offset = cdnsp_find_next_ext_cap(base, offset, D_XEC_PRE_REGS_CAP); ++ reg = base + offset + REG_CHICKEN_BITS_3_OFFSET; ++ ++ val = le32_to_cpu(readl(reg)); ++ val = CHICKEN_APB_TIMEOUT_SET(val, cdns->override_apb_timeout); ++ writel(cpu_to_le32(val), reg); ++} ++ + static void cdnsp_set_chicken_bits_2(struct cdnsp_device *pdev, u32 bit) + { + __le32 __iomem *reg; +@@ -1776,6 +1796,8 @@ static void cdnsp_get_rev_cap(struct cdnsp_device *pdev) + reg += cdnsp_find_next_ext_cap(reg, 0, RTL_REV_CAP); + pdev->rev_cap = reg; + ++ pdev->rtl_revision = readl(&pdev->rev_cap->rtl_revision); ++ + dev_info(pdev->dev, "Rev: %08x/%08x, eps: %08x, buff: %08x/%08x\n", + readl(&pdev->rev_cap->ctrl_revision), + readl(&pdev->rev_cap->rtl_revision), +@@ -1801,6 +1823,15 @@ static int cdnsp_gen_setup(struct cdnsp_device *pdev) + pdev->hci_version = HC_VERSION(pdev->hcc_params); + pdev->hcc_params = readl(&pdev->cap_regs->hcc_params); + ++ /* ++ * Override the APB timeout value to give the controller more time for ++ * enabling UTMI clock and synchronizing APB and UTMI clock domains. ++ * This fix is platform specific and is required to fixes issue with ++ * reading incorrect value from PORTSC register after resuming ++ * from L1 state. ++ */ ++ cdnsp_set_apb_timeout_value(pdev); ++ + cdnsp_get_rev_cap(pdev); + + /* Make sure the Device Controller is halted. */ +diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h +index 9a5577a772af62..ed84dbb9fd6fbc 100644 +--- a/drivers/usb/cdns3/cdnsp-gadget.h ++++ b/drivers/usb/cdns3/cdnsp-gadget.h +@@ -520,6 +520,9 @@ struct cdnsp_rev_cap { + #define REG_CHICKEN_BITS_2_OFFSET 0x48 + #define CHICKEN_XDMA_2_TP_CACHE_DIS BIT(28) + ++#define REG_CHICKEN_BITS_3_OFFSET 0x4C ++#define CHICKEN_APB_TIMEOUT_SET(p, val) (((p) & ~GENMASK(21, 0)) | (val)) ++ + /* XBUF Extended Capability ID. */ + #define XBUF_CAP_ID 0xCB + #define XBUF_RX_TAG_MASK_0_OFFSET 0x1C +@@ -1359,6 +1362,7 @@ struct cdnsp_port { + * @rev_cap: Controller Capabilities Registers. + * @hcs_params1: Cached register copies of read-only HCSPARAMS1 + * @hcc_params: Cached register copies of read-only HCCPARAMS1 ++ * @rtl_revision: Cached controller rtl revision. + * @setup: Temporary buffer for setup packet. + * @ep0_preq: Internal allocated request used during enumeration. + * @ep0_stage: ep0 stage during enumeration process. +@@ -1413,6 +1417,8 @@ struct cdnsp_device { + __u32 hcs_params1; + __u32 hcs_params3; + __u32 hcc_params; ++ #define RTL_REVISION_NEW_LPM 0x2700 ++ __u32 rtl_revision; + /* Lock used in interrupt thread context. */ + spinlock_t lock; + struct usb_ctrlrequest setup; +diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c +index 0725668ffea4c8..159c2eae26608c 100644 +--- a/drivers/usb/cdns3/cdnsp-pci.c ++++ b/drivers/usb/cdns3/cdnsp-pci.c +@@ -33,6 +33,8 @@ + #define CDNS_DRD_ID 0x0100 + #define CDNS_DRD_IF (PCI_CLASS_SERIAL_USB << 8 | 0x80) + ++#define CHICKEN_APB_TIMEOUT_VALUE 0x1C20 ++ + static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev) + { + /* +@@ -144,6 +146,14 @@ static int cdnsp_pci_probe(struct pci_dev *pdev, + cdnsp->otg_irq = pdev->irq; + } + ++ /* ++ * Cadence PCI based platform require some longer timeout for APB ++ * to fixes domain clock synchronization issue after resuming ++ * controller from L1 state. ++ */ ++ cdnsp->override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE; ++ pci_set_drvdata(pdev, cdnsp); ++ + if (pci_is_enabled(func)) { + cdnsp->dev = dev; + cdnsp->gadget_init = cdnsp_gadget_init; +@@ -153,8 +163,6 @@ static int cdnsp_pci_probe(struct pci_dev *pdev, + goto free_cdnsp; + } + +- pci_set_drvdata(pdev, cdnsp); +- + device_wakeup_enable(&pdev->dev); + if (pci_dev_run_wake(pdev)) + pm_runtime_put_noidle(&pdev->dev); +diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c +index 1d18d5002ef01d..080a3f17a35dd7 100644 +--- a/drivers/usb/cdns3/cdnsp-ring.c ++++ b/drivers/usb/cdns3/cdnsp-ring.c +@@ -308,7 +308,8 @@ static bool cdnsp_ring_ep_doorbell(struct cdnsp_device *pdev, + + writel(db_value, reg_addr); + +- cdnsp_force_l0_go(pdev); ++ if (pdev->rtl_revision < RTL_REVISION_NEW_LPM) ++ cdnsp_force_l0_go(pdev); + + /* Doorbell was set. */ + return true; +diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h +index 57d47348dc193b..ac30ee21309d02 100644 +--- a/drivers/usb/cdns3/core.h ++++ b/drivers/usb/cdns3/core.h +@@ -79,6 +79,8 @@ struct cdns3_platform_data { + * @pdata: platform data from glue layer + * @lock: spinlock structure + * @xhci_plat_data: xhci private data structure pointer ++ * @override_apb_timeout: hold value of APB timeout. For value 0 the default ++ * value in CHICKEN_BITS_3 will be preserved. + * @gadget_init: pointer to gadget initialization function + */ + struct cdns { +@@ -117,6 +119,7 @@ struct cdns { + struct cdns3_platform_data *pdata; + spinlock_t lock; + struct xhci_plat_priv *xhci_plat_data; ++ u32 override_apb_timeout; + + int (*gadget_init)(struct cdns *cdns); + }; +diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c +index c2e666e82857c1..2f92905e05cad0 100644 +--- a/drivers/usb/class/usbtmc.c ++++ b/drivers/usb/class/usbtmc.c +@@ -482,6 +482,7 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) + u8 *buffer; + u8 tag; + int rv; ++ long wait_rv; + + dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", + data->iin_ep_present); +@@ -511,16 +512,17 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) + } + + if (data->iin_ep_present) { +- rv = wait_event_interruptible_timeout( ++ wait_rv = wait_event_interruptible_timeout( + data->waitq, + atomic_read(&data->iin_data_valid) != 0, + file_data->timeout); +- if (rv < 0) { +- dev_dbg(dev, "wait interrupted %d\n", rv); ++ if (wait_rv < 0) { ++ dev_dbg(dev, "wait interrupted %ld\n", wait_rv); ++ rv = wait_rv; + goto exit; + } + +- if (rv == 0) { ++ if (wait_rv == 0) { + dev_dbg(dev, "wait timed out\n"); + rv = -ETIMEDOUT; + goto exit; +@@ -539,6 +541,8 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) + + dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)*stb, rv); + ++ rv = 0; ++ + exit: + /* bump interrupt bTag */ + data->iin_bTag += 1; +@@ -602,9 +606,9 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, + { + struct usbtmc_device_data *data = file_data->data; + struct device *dev = &data->intf->dev; +- int rv; + u32 timeout; + unsigned long expire; ++ long wait_rv; + + if (!data->iin_ep_present) { + dev_dbg(dev, "no interrupt endpoint present\n"); +@@ -618,25 +622,24 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, + + mutex_unlock(&data->io_mutex); + +- rv = wait_event_interruptible_timeout( +- data->waitq, +- atomic_read(&file_data->srq_asserted) != 0 || +- atomic_read(&file_data->closing), +- expire); ++ wait_rv = wait_event_interruptible_timeout( ++ data->waitq, ++ atomic_read(&file_data->srq_asserted) != 0 || ++ atomic_read(&file_data->closing), ++ expire); + + mutex_lock(&data->io_mutex); + + /* Note! disconnect or close could be called in the meantime */ + if (atomic_read(&file_data->closing) || data->zombie) +- rv = -ENODEV; ++ return -ENODEV; + +- if (rv < 0) { +- /* dev can be invalid now! */ +- pr_debug("%s - wait interrupted %d\n", __func__, rv); +- return rv; ++ if (wait_rv < 0) { ++ dev_dbg(dev, "%s - wait interrupted %ld\n", __func__, wait_rv); ++ return wait_rv; + } + +- if (rv == 0) { ++ if (wait_rv == 0) { + dev_dbg(dev, "%s - wait timed out\n", __func__); + return -ETIMEDOUT; + } +@@ -830,6 +833,7 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, + unsigned long expire; + int bufcount = 1; + int again = 0; ++ long wait_rv; + + /* mutex already locked */ + +@@ -942,19 +946,24 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, + if (!(flags & USBTMC_FLAG_ASYNC)) { + dev_dbg(dev, "%s: before wait time %lu\n", + __func__, expire); +- retval = wait_event_interruptible_timeout( ++ wait_rv = wait_event_interruptible_timeout( + file_data->wait_bulk_in, + usbtmc_do_transfer(file_data), + expire); + +- dev_dbg(dev, "%s: wait returned %d\n", +- __func__, retval); ++ dev_dbg(dev, "%s: wait returned %ld\n", ++ __func__, wait_rv); ++ ++ if (wait_rv < 0) { ++ retval = wait_rv; ++ goto error; ++ } + +- if (retval <= 0) { +- if (retval == 0) +- retval = -ETIMEDOUT; ++ if (wait_rv == 0) { ++ retval = -ETIMEDOUT; + goto error; + } ++ + } + + urb = usb_get_from_anchor(&file_data->in_anchor); +@@ -1380,7 +1389,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, + if (!buffer) + return -ENOMEM; + +- mutex_lock(&data->io_mutex); ++ retval = mutex_lock_interruptible(&data->io_mutex); ++ if (retval < 0) ++ goto exit_nolock; ++ + if (data->zombie) { + retval = -ENODEV; + goto exit; +@@ -1503,6 +1515,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, + + exit: + mutex_unlock(&data->io_mutex); ++exit_nolock: + kfree(buffer); + return retval; + } +diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c +index 69ce7d384ba8bb..4f326988be867c 100644 +--- a/drivers/usb/gadget/composite.c ++++ b/drivers/usb/gadget/composite.c +@@ -2011,15 +2011,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + + if (f->get_status) { + status = f->get_status(f); ++ + if (status < 0) + break; +- } else { +- /* Set D0 and D1 bits based on func wakeup capability */ +- if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { +- status |= USB_INTRF_STAT_FUNC_RW_CAP; +- if (f->func_wakeup_armed) +- status |= USB_INTRF_STAT_FUNC_RW; +- } ++ ++ /* if D5 is not set, then device is not wakeup capable */ ++ if (!(f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP)) ++ status &= ~(USB_INTRF_STAT_FUNC_RW_CAP | USB_INTRF_STAT_FUNC_RW); + } + + put_unaligned_le16(status & 0x0000ffff, req->buf); +diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c +index f55f60639e4251..2afc30de54ce2d 100644 +--- a/drivers/usb/gadget/function/f_ecm.c ++++ b/drivers/usb/gadget/function/f_ecm.c +@@ -892,6 +892,12 @@ static void ecm_resume(struct usb_function *f) + gether_resume(&ecm->port); + } + ++static int ecm_get_status(struct usb_function *f) ++{ ++ return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) | ++ USB_INTRF_STAT_FUNC_RW_CAP; ++} ++ + static void ecm_free(struct usb_function *f) + { + struct f_ecm *ecm; +@@ -960,6 +966,7 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) + ecm->port.func.disable = ecm_disable; + ecm->port.func.free_func = ecm_free; + ecm->port.func.suspend = ecm_suspend; ++ ecm->port.func.get_status = ecm_get_status; + ecm->port.func.resume = ecm_resume; + + return &ecm->port.func; +diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c +index 7aa46d426f31b2..9bb54da8a6ae15 100644 +--- a/drivers/usb/gadget/udc/tegra-xudc.c ++++ b/drivers/usb/gadget/udc/tegra-xudc.c +@@ -1749,6 +1749,10 @@ static int __tegra_xudc_ep_disable(struct tegra_xudc_ep *ep) + val = xudc_readl(xudc, CTRL); + val &= ~CTRL_RUN; + xudc_writel(xudc, val, CTRL); ++ ++ val = xudc_readl(xudc, ST); ++ if (val & ST_RC) ++ xudc_writel(xudc, ST_RC, ST); + } + + dev_info(xudc->dev, "ep %u disabled\n", ep->index); +diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c +index 3dec5dd3a0d5ca..712389599d468c 100644 +--- a/drivers/usb/host/uhci-platform.c ++++ b/drivers/usb/host/uhci-platform.c +@@ -121,7 +121,7 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) + } + + /* Get and enable clock if any specified */ +- uhci->clk = devm_clk_get(&pdev->dev, NULL); ++ uhci->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(uhci->clk)) { + ret = PTR_ERR(uhci->clk); + goto err_rmr; +diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c +index 76f228e7443cb6..89b3079194d7b3 100644 +--- a/drivers/usb/host/xhci-tegra.c ++++ b/drivers/usb/host/xhci-tegra.c +@@ -1363,6 +1363,7 @@ static void tegra_xhci_id_work(struct work_struct *work) + tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(tegra->padctl, + tegra->otg_usb2_port); + ++ pm_runtime_get_sync(tegra->dev); + if (tegra->host_mode) { + /* switch to host mode */ + if (tegra->otg_usb3_port >= 0) { +@@ -1392,6 +1393,7 @@ static void tegra_xhci_id_work(struct work_struct *work) + } + + tegra_xhci_set_port_power(tegra, true, true); ++ pm_runtime_mark_last_busy(tegra->dev); + + } else { + if (tegra->otg_usb3_port >= 0) +@@ -1399,6 +1401,7 @@ static void tegra_xhci_id_work(struct work_struct *work) + + tegra_xhci_set_port_power(tegra, true, false); + } ++ pm_runtime_put_autosuspend(tegra->dev); + } + + #if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_PM_SLEEP) +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 790aadab72a31b..bfcbccb400c3a8 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -5102,7 +5102,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, + case SNK_TRY_WAIT_DEBOUNCE: + if (!tcpm_port_is_sink(port)) { + port->max_wait = 0; +- tcpm_set_state(port, SRC_TRYWAIT, 0); ++ tcpm_set_state(port, SRC_TRYWAIT, PD_T_PD_DEBOUNCE); + } + break; + case SRC_TRY_WAIT: +diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c +index 2431febc461516..8c19081c325542 100644 +--- a/drivers/usb/typec/ucsi/displayport.c ++++ b/drivers/usb/typec/ucsi/displayport.c +@@ -296,6 +296,8 @@ void ucsi_displayport_remove_partner(struct typec_altmode *alt) + if (!dp) + return; + ++ cancel_work_sync(&dp->work); ++ + dp->data.conf = 0; + dp->data.status = 0; + dp->initialized = false; +diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c +index 0b3bd9a7575e5f..5770f3b374ece3 100644 +--- a/drivers/xen/swiotlb-xen.c ++++ b/drivers/xen/swiotlb-xen.c +@@ -216,6 +216,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, + * buffering it. + */ + if (dma_capable(dev, dev_addr, size, true) && ++ !dma_kmalloc_needs_bounce(dev, size, dir) && + !range_straddles_page_boundary(phys, size) && + !xen_arch_need_swiotlb(dev, phys, dev_addr) && + !is_swiotlb_force_bounce(dev)) +diff --git a/drivers/xen/xenbus/xenbus.h b/drivers/xen/xenbus/xenbus.h +index 2754bdfadcb89c..4ba73320694a4c 100644 +--- a/drivers/xen/xenbus/xenbus.h ++++ b/drivers/xen/xenbus/xenbus.h +@@ -77,6 +77,7 @@ enum xb_req_state { + struct xb_req_data { + struct list_head list; + wait_queue_head_t wq; ++ struct kref kref; + struct xsd_sockmsg msg; + uint32_t caller_req_id; + enum xsd_sockmsg_type type; +@@ -103,6 +104,7 @@ int xb_init_comms(void); + void xb_deinit_comms(void); + int xs_watch_msg(struct xs_watch_event *event); + void xs_request_exit(struct xb_req_data *req); ++void xs_free_req(struct kref *kref); + + int xenbus_match(struct device *_dev, struct device_driver *_drv); + int xenbus_dev_probe(struct device *_dev); +diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c +index e5fda0256feb3d..82df2da1b880b8 100644 +--- a/drivers/xen/xenbus/xenbus_comms.c ++++ b/drivers/xen/xenbus/xenbus_comms.c +@@ -309,8 +309,8 @@ static int process_msg(void) + virt_wmb(); + req->state = xb_req_state_got_reply; + req->cb(req); +- } else +- kfree(req); ++ } ++ kref_put(&req->kref, xs_free_req); + } + + mutex_unlock(&xs_response_mutex); +@@ -386,14 +386,13 @@ static int process_writes(void) + state.req->msg.type = XS_ERROR; + state.req->err = err; + list_del(&state.req->list); +- if (state.req->state == xb_req_state_aborted) +- kfree(state.req); +- else { ++ if (state.req->state != xb_req_state_aborted) { + /* write err, then update state */ + virt_wmb(); + state.req->state = xb_req_state_got_reply; + wake_up(&state.req->wq); + } ++ kref_put(&state.req->kref, xs_free_req); + + mutex_unlock(&xb_write_mutex); + +diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c +index 0792fda49a15f3..c495cff3da308b 100644 +--- a/drivers/xen/xenbus/xenbus_dev_frontend.c ++++ b/drivers/xen/xenbus/xenbus_dev_frontend.c +@@ -406,7 +406,7 @@ void xenbus_dev_queue_reply(struct xb_req_data *req) + mutex_unlock(&u->reply_mutex); + + kfree(req->body); +- kfree(req); ++ kref_put(&req->kref, xs_free_req); + + kref_put(&u->kref, xenbus_file_free); + +diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c +index 028a182bcc9e83..f84c87ee283958 100644 +--- a/drivers/xen/xenbus/xenbus_xs.c ++++ b/drivers/xen/xenbus/xenbus_xs.c +@@ -112,6 +112,12 @@ static void xs_suspend_exit(void) + wake_up_all(&xs_state_enter_wq); + } + ++void xs_free_req(struct kref *kref) ++{ ++ struct xb_req_data *req = container_of(kref, struct xb_req_data, kref); ++ kfree(req); ++} ++ + static uint32_t xs_request_enter(struct xb_req_data *req) + { + uint32_t rq_id; +@@ -237,6 +243,12 @@ static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg) + req->caller_req_id = req->msg.req_id; + req->msg.req_id = xs_request_enter(req); + ++ /* ++ * Take 2nd ref. One for this thread, and the second for the ++ * xenbus_thread. ++ */ ++ kref_get(&req->kref); ++ + mutex_lock(&xb_write_mutex); + list_add_tail(&req->list, &xb_write_list); + notify = list_is_singular(&xb_write_list); +@@ -261,8 +273,8 @@ static void *xs_wait_for_reply(struct xb_req_data *req, struct xsd_sockmsg *msg) + if (req->state == xb_req_state_queued || + req->state == xb_req_state_wait_reply) + req->state = xb_req_state_aborted; +- else +- kfree(req); ++ ++ kref_put(&req->kref, xs_free_req); + mutex_unlock(&xb_write_mutex); + + return ret; +@@ -291,6 +303,7 @@ int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void *par) + req->cb = xenbus_dev_queue_reply; + req->par = par; + req->user_req = true; ++ kref_init(&req->kref); + + xs_send(req, msg); + +@@ -319,6 +332,7 @@ static void *xs_talkv(struct xenbus_transaction t, + req->num_vecs = num_vecs; + req->cb = xs_wake_up; + req->user_req = false; ++ kref_init(&req->kref); + + msg.req_id = 0; + msg.tx_id = t.id; +diff --git a/fs/namespace.c b/fs/namespace.c +index 5a885d35efe937..450f4198b8cdd8 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -633,7 +633,7 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq) + return 0; + mnt = real_mount(bastard); + mnt_add_count(mnt, 1); +- smp_mb(); // see mntput_no_expire() ++ smp_mb(); // see mntput_no_expire() and do_umount() + if (likely(!read_seqretry(&mount_lock, seq))) + return 0; + if (bastard->mnt_flags & MNT_SYNC_UMOUNT) { +@@ -1786,6 +1786,7 @@ static int do_umount(struct mount *mnt, int flags) + umount_tree(mnt, UMOUNT_PROPAGATE); + retval = 0; + } else { ++ smp_mb(); // paired with __legitimize_mnt() + shrink_submounts(mnt); + retval = -EBUSY; + if (!propagate_mount_busy(mnt, 2)) { +diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c +index cbe3c12ff5f75c..b246e53271114d 100644 +--- a/fs/ocfs2/journal.c ++++ b/fs/ocfs2/journal.c +@@ -174,7 +174,7 @@ int ocfs2_recovery_init(struct ocfs2_super *osb) + struct ocfs2_recovery_map *rm; + + mutex_init(&osb->recovery_lock); +- osb->disable_recovery = 0; ++ osb->recovery_state = OCFS2_REC_ENABLED; + osb->recovery_thread_task = NULL; + init_waitqueue_head(&osb->recovery_event); + +@@ -190,31 +190,53 @@ int ocfs2_recovery_init(struct ocfs2_super *osb) + return 0; + } + +-/* we can't grab the goofy sem lock from inside wait_event, so we use +- * memory barriers to make sure that we'll see the null task before +- * being woken up */ + static int ocfs2_recovery_thread_running(struct ocfs2_super *osb) + { +- mb(); + return osb->recovery_thread_task != NULL; + } + +-void ocfs2_recovery_exit(struct ocfs2_super *osb) ++static void ocfs2_recovery_disable(struct ocfs2_super *osb, ++ enum ocfs2_recovery_state state) + { +- struct ocfs2_recovery_map *rm; +- +- /* disable any new recovery threads and wait for any currently +- * running ones to exit. Do this before setting the vol_state. */ + mutex_lock(&osb->recovery_lock); +- osb->disable_recovery = 1; ++ /* ++ * If recovery thread is not running, we can directly transition to ++ * final state. ++ */ ++ if (!ocfs2_recovery_thread_running(osb)) { ++ osb->recovery_state = state + 1; ++ goto out_lock; ++ } ++ osb->recovery_state = state; ++ /* Wait for recovery thread to acknowledge state transition */ ++ wait_event_cmd(osb->recovery_event, ++ !ocfs2_recovery_thread_running(osb) || ++ osb->recovery_state >= state + 1, ++ mutex_unlock(&osb->recovery_lock), ++ mutex_lock(&osb->recovery_lock)); ++out_lock: + mutex_unlock(&osb->recovery_lock); +- wait_event(osb->recovery_event, !ocfs2_recovery_thread_running(osb)); + +- /* At this point, we know that no more recovery threads can be +- * launched, so wait for any recovery completion work to +- * complete. */ ++ /* ++ * At this point we know that no more recovery work can be queued so ++ * wait for any recovery completion work to complete. ++ */ + if (osb->ocfs2_wq) + flush_workqueue(osb->ocfs2_wq); ++} ++ ++void ocfs2_recovery_disable_quota(struct ocfs2_super *osb) ++{ ++ ocfs2_recovery_disable(osb, OCFS2_REC_QUOTA_WANT_DISABLE); ++} ++ ++void ocfs2_recovery_exit(struct ocfs2_super *osb) ++{ ++ struct ocfs2_recovery_map *rm; ++ ++ /* disable any new recovery threads and wait for any currently ++ * running ones to exit. Do this before setting the vol_state. */ ++ ocfs2_recovery_disable(osb, OCFS2_REC_WANT_DISABLE); + + /* + * Now that recovery is shut down, and the osb is about to be +@@ -1472,6 +1494,18 @@ static int __ocfs2_recovery_thread(void *arg) + } + } + restart: ++ if (quota_enabled) { ++ mutex_lock(&osb->recovery_lock); ++ /* Confirm that recovery thread will no longer recover quotas */ ++ if (osb->recovery_state == OCFS2_REC_QUOTA_WANT_DISABLE) { ++ osb->recovery_state = OCFS2_REC_QUOTA_DISABLED; ++ wake_up(&osb->recovery_event); ++ } ++ if (osb->recovery_state >= OCFS2_REC_QUOTA_DISABLED) ++ quota_enabled = 0; ++ mutex_unlock(&osb->recovery_lock); ++ } ++ + status = ocfs2_super_lock(osb, 1); + if (status < 0) { + mlog_errno(status); +@@ -1569,27 +1603,29 @@ static int __ocfs2_recovery_thread(void *arg) + + ocfs2_free_replay_slots(osb); + osb->recovery_thread_task = NULL; +- mb(); /* sync with ocfs2_recovery_thread_running */ ++ if (osb->recovery_state == OCFS2_REC_WANT_DISABLE) ++ osb->recovery_state = OCFS2_REC_DISABLED; + wake_up(&osb->recovery_event); + + mutex_unlock(&osb->recovery_lock); + +- if (quota_enabled) +- kfree(rm_quota); ++ kfree(rm_quota); + + return status; + } + + void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num) + { ++ int was_set = -1; ++ + mutex_lock(&osb->recovery_lock); ++ if (osb->recovery_state < OCFS2_REC_WANT_DISABLE) ++ was_set = ocfs2_recovery_map_set(osb, node_num); + + trace_ocfs2_recovery_thread(node_num, osb->node_num, +- osb->disable_recovery, osb->recovery_thread_task, +- osb->disable_recovery ? +- -1 : ocfs2_recovery_map_set(osb, node_num)); ++ osb->recovery_state, osb->recovery_thread_task, was_set); + +- if (osb->disable_recovery) ++ if (osb->recovery_state >= OCFS2_REC_WANT_DISABLE) + goto out; + + if (osb->recovery_thread_task) +diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h +index e3c3a35dc5e0e7..6397170f302f22 100644 +--- a/fs/ocfs2/journal.h ++++ b/fs/ocfs2/journal.h +@@ -148,6 +148,7 @@ void ocfs2_wait_for_recovery(struct ocfs2_super *osb); + + int ocfs2_recovery_init(struct ocfs2_super *osb); + void ocfs2_recovery_exit(struct ocfs2_super *osb); ++void ocfs2_recovery_disable_quota(struct ocfs2_super *osb); + + int ocfs2_compute_replay_slots(struct ocfs2_super *osb); + void ocfs2_free_replay_slots(struct ocfs2_super *osb); +diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h +index 8fe826143d7bf4..5e3ebbab698ad1 100644 +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -308,6 +308,21 @@ enum ocfs2_journal_trigger_type { + void ocfs2_initialize_journal_triggers(struct super_block *sb, + struct ocfs2_triggers triggers[]); + ++enum ocfs2_recovery_state { ++ OCFS2_REC_ENABLED = 0, ++ OCFS2_REC_QUOTA_WANT_DISABLE, ++ /* ++ * Must be OCFS2_REC_QUOTA_WANT_DISABLE + 1 for ++ * ocfs2_recovery_disable_quota() to work. ++ */ ++ OCFS2_REC_QUOTA_DISABLED, ++ OCFS2_REC_WANT_DISABLE, ++ /* ++ * Must be OCFS2_REC_WANT_DISABLE + 1 for ocfs2_recovery_exit() to work ++ */ ++ OCFS2_REC_DISABLED, ++}; ++ + struct ocfs2_journal; + struct ocfs2_slot_info; + struct ocfs2_recovery_map; +@@ -370,7 +385,7 @@ struct ocfs2_super + struct ocfs2_recovery_map *recovery_map; + struct ocfs2_replay_map *replay_map; + struct task_struct *recovery_thread_task; +- int disable_recovery; ++ enum ocfs2_recovery_state recovery_state; + wait_queue_head_t checkpoint_event; + struct ocfs2_journal *journal; + unsigned long osb_commit_interval; +diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c +index 4b4fa58cd32ff0..0ca8975a1df479 100644 +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -453,8 +453,7 @@ struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery( + + /* Sync changes in local quota file into global quota file and + * reinitialize local quota file. +- * The function expects local quota file to be already locked and +- * s_umount locked in shared mode. */ ++ * The function expects local quota file to be already locked. */ + static int ocfs2_recover_local_quota_file(struct inode *lqinode, + int type, + struct ocfs2_quota_recovery *rec) +@@ -585,7 +584,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, + { + unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, + LOCAL_GROUP_QUOTA_SYSTEM_INODE }; +- struct super_block *sb = osb->sb; + struct ocfs2_local_disk_dqinfo *ldinfo; + struct buffer_head *bh; + handle_t *handle; +@@ -597,7 +595,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, + printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for " + "slot %u\n", osb->dev_str, slot_num); + +- down_read(&sb->s_umount); + for (type = 0; type < OCFS2_MAXQUOTAS; type++) { + if (list_empty(&(rec->r_list[type]))) + continue; +@@ -674,7 +671,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, + break; + } + out: +- up_read(&sb->s_umount); + kfree(rec); + return status; + } +@@ -840,8 +836,7 @@ static int ocfs2_local_free_info(struct super_block *sb, int type) + ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); + + /* +- * s_umount held in exclusive mode protects us against racing with +- * recovery thread... ++ * ocfs2_dismount_volume() has already aborted quota recovery... + */ + if (oinfo->dqi_rec) { + ocfs2_free_quota_recovery(oinfo->dqi_rec); +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index 84fa585c6513a5..e585e77cdc88e1 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -1870,6 +1870,9 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) + /* Orphan scan should be stopped as early as possible */ + ocfs2_orphan_scan_stop(osb); + ++ /* Stop quota recovery so that we can disable quotas */ ++ ocfs2_recovery_disable_quota(osb); ++ + ocfs2_disable_quotas(osb); + + /* All dquots should be freed by now */ +diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c +index 9c0ef4195b5829..74979466729535 100644 +--- a/fs/smb/client/cached_dir.c ++++ b/fs/smb/client/cached_dir.c +@@ -29,7 +29,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, + { + struct cached_fid *cfid; + +- spin_lock(&cfids->cfid_list_lock); + list_for_each_entry(cfid, &cfids->entries, entry) { + if (!strcmp(cfid->path, path)) { + /* +@@ -38,25 +37,20 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, + * being deleted due to a lease break. + */ + if (!cfid->time || !cfid->has_lease) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + kref_get(&cfid->refcount); +- spin_unlock(&cfids->cfid_list_lock); + return cfid; + } + } + if (lookup_only) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + if (cfids->num_entries >= max_cached_dirs) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + cfid = init_cached_dir(path); + if (cfid == NULL) { +- spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + cfid->cfids = cfids; +@@ -74,7 +68,6 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, + */ + cfid->has_lease = true; + +- spin_unlock(&cfids->cfid_list_lock); + return cfid; + } + +@@ -185,8 +178,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + if (!utf16_path) + return -ENOMEM; + ++ spin_lock(&cfids->cfid_list_lock); + cfid = find_or_create_cached_dir(cfids, path, lookup_only, tcon->max_cached_dirs); + if (cfid == NULL) { ++ spin_unlock(&cfids->cfid_list_lock); + kfree(utf16_path); + return -ENOENT; + } +@@ -195,7 +190,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + * Otherwise, it is either a new entry or laundromat worker removed it + * from @cfids->entries. Caller will put last reference if the latter. + */ +- spin_lock(&cfids->cfid_list_lock); + if (cfid->has_lease && cfid->time) { + spin_unlock(&cfids->cfid_list_lock); + *ret_cfid = cfid; +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index 5a5277b4b53b11..72294764d4c20c 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -1496,7 +1496,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req) + + if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) < + sizeof(struct create_lease_v2) - 4) +- return NULL; ++ goto err_out; + + memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); + lreq->req_state = lc->lcontext.LeaseState; +@@ -1512,7 +1512,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req) + + if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) < + sizeof(struct create_lease)) +- return NULL; ++ goto err_out; + + memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); + lreq->req_state = lc->lcontext.LeaseState; +@@ -1521,6 +1521,9 @@ struct lease_ctx_info *parse_lease_state(void *open_req) + lreq->version = 1; + } + return lreq; ++err_out: ++ kfree(lreq); ++ return NULL; + } + + /** +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 13750a5e5ba02e..9bd817427a345a 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -632,6 +632,11 @@ smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls) + return name; + } + ++ if (*name == '\0') { ++ kfree(name); ++ return ERR_PTR(-EINVAL); ++ } ++ + if (*name == '\\') { + pr_err("not allow directory name included leading slash\n"); + kfree(name); +diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c +index fa5b7e63eb832e..f6616d687365a3 100644 +--- a/fs/smb/server/vfs.c ++++ b/fs/smb/server/vfs.c +@@ -443,6 +443,13 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + goto out; + } + ++ if (v_len <= *pos) { ++ pr_err("stream write position %lld is out of bounds (stream length: %zd)\n", ++ *pos, v_len); ++ err = -EINVAL; ++ goto out; ++ } ++ + if (v_len < size) { + wbuf = kvzalloc(size, GFP_KERNEL); + if (!wbuf) { +diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c +index 271a23abc82fdd..002f0864abee62 100644 +--- a/fs/smb/server/vfs_cache.c ++++ b/fs/smb/server/vfs_cache.c +@@ -644,21 +644,40 @@ __close_file_table_ids(struct ksmbd_file_table *ft, + bool (*skip)(struct ksmbd_tree_connect *tcon, + struct ksmbd_file *fp)) + { +- unsigned int id; +- struct ksmbd_file *fp; +- int num = 0; ++ struct ksmbd_file *fp; ++ unsigned int id = 0; ++ int num = 0; ++ ++ while (1) { ++ write_lock(&ft->lock); ++ fp = idr_get_next(ft->idr, &id); ++ if (!fp) { ++ write_unlock(&ft->lock); ++ break; ++ } + +- idr_for_each_entry(ft->idr, fp, id) { +- if (skip(tcon, fp)) ++ if (skip(tcon, fp) || ++ !atomic_dec_and_test(&fp->refcount)) { ++ id++; ++ write_unlock(&ft->lock); + continue; ++ } + + set_close_state_blocked_works(fp); ++ idr_remove(ft->idr, fp->volatile_id); ++ fp->volatile_id = KSMBD_NO_FID; ++ write_unlock(&ft->lock); ++ ++ down_write(&fp->f_ci->m_lock); ++ list_del_init(&fp->node); ++ up_write(&fp->f_ci->m_lock); + +- if (!atomic_dec_and_test(&fp->refcount)) +- continue; + __ksmbd_close_fd(ft, fp); ++ + num++; ++ id++; + } ++ + return num; + } + +diff --git a/include/linux/cpu.h b/include/linux/cpu.h +index a7d91a167a8b64..20db7fc0651f3c 100644 +--- a/include/linux/cpu.h ++++ b/include/linux/cpu.h +@@ -77,6 +77,8 @@ extern ssize_t cpu_show_gds(struct device *dev, + struct device_attribute *attr, char *buf); + extern ssize_t cpu_show_reg_file_data_sampling(struct device *dev, + struct device_attribute *attr, char *buf); ++extern ssize_t cpu_show_indirect_target_selection(struct device *dev, ++ struct device_attribute *attr, char *buf); + + extern __printf(4, 5) + struct device *cpu_device_create(struct device *parent, void *drvdata, +diff --git a/include/linux/module.h b/include/linux/module.h +index f2a8624eef1eca..f58d1eb260fa9e 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -572,6 +572,11 @@ struct module { + atomic_t refcnt; + #endif + ++#ifdef CONFIG_MITIGATION_ITS ++ int its_num_pages; ++ void **its_page_array; ++#endif ++ + #ifdef CONFIG_CONSTRUCTORS + /* Constructor functions. */ + ctor_fn_t *ctors; +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 337a9d1c558f3c..0b0a172337dbac 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -3614,6 +3614,17 @@ static inline void netdev_tx_reset_queue(struct netdev_queue *q) + #endif + } + ++/** ++ * netdev_tx_reset_subqueue - reset the BQL stats and state of a netdev queue ++ * @dev: network device ++ * @qid: stack index of the queue to reset ++ */ ++static inline void netdev_tx_reset_subqueue(const struct net_device *dev, ++ u32 qid) ++{ ++ netdev_tx_reset_queue(netdev_get_tx_queue(dev, qid)); ++} ++ + /** + * netdev_reset_queue - reset the packets and bytes count of a network device + * @dev_queue: network device +@@ -3623,7 +3634,7 @@ static inline void netdev_tx_reset_queue(struct netdev_queue *q) + */ + static inline void netdev_reset_queue(struct net_device *dev_queue) + { +- netdev_tx_reset_queue(netdev_get_tx_queue(dev_queue, 0)); ++ netdev_tx_reset_subqueue(dev_queue, 0); + } + + /** +diff --git a/include/linux/types.h b/include/linux/types.h +index 253168bb3fe15c..78d87c751ff58c 100644 +--- a/include/linux/types.h ++++ b/include/linux/types.h +@@ -115,8 +115,9 @@ typedef u64 u_int64_t; + typedef s64 int64_t; + #endif + +-/* this is a special 64bit data type that is 8-byte aligned */ ++/* These are the special 64-bit data types that are 8-byte aligned */ + #define aligned_u64 __aligned_u64 ++#define aligned_s64 __aligned_s64 + #define aligned_be64 __aligned_be64 + #define aligned_le64 __aligned_le64 + +diff --git a/include/uapi/linux/types.h b/include/uapi/linux/types.h +index 6375a06840520d..48b933938877d9 100644 +--- a/include/uapi/linux/types.h ++++ b/include/uapi/linux/types.h +@@ -53,6 +53,7 @@ typedef __u32 __bitwise __wsum; + * No conversions are necessary between 32-bit user-space and a 64-bit kernel. + */ + #define __aligned_u64 __u64 __attribute__((aligned(8))) ++#define __aligned_s64 __s64 __attribute__((aligned(8))) + #define __aligned_be64 __be64 __attribute__((aligned(8))) + #define __aligned_le64 __le64 __attribute__((aligned(8))) + +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index 3ce93418e0151d..db592fa549b738 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -422,24 +422,6 @@ static struct io_kiocb *__io_prep_linked_timeout(struct io_kiocb *req) + return req->link; + } + +-static inline struct io_kiocb *io_prep_linked_timeout(struct io_kiocb *req) +-{ +- if (likely(!(req->flags & REQ_F_ARM_LTIMEOUT))) +- return NULL; +- return __io_prep_linked_timeout(req); +-} +- +-static noinline void __io_arm_ltimeout(struct io_kiocb *req) +-{ +- io_queue_linked_timeout(__io_prep_linked_timeout(req)); +-} +- +-static inline void io_arm_ltimeout(struct io_kiocb *req) +-{ +- if (unlikely(req->flags & REQ_F_ARM_LTIMEOUT)) +- __io_arm_ltimeout(req); +-} +- + static void io_prep_async_work(struct io_kiocb *req) + { + const struct io_issue_def *def = &io_issue_defs[req->opcode]; +@@ -493,7 +475,6 @@ static void io_prep_async_link(struct io_kiocb *req) + + static void io_queue_iowq(struct io_kiocb *req) + { +- struct io_kiocb *link = io_prep_linked_timeout(req); + struct io_uring_task *tctx = req->task->io_uring; + + BUG_ON(!tctx); +@@ -518,8 +499,6 @@ static void io_queue_iowq(struct io_kiocb *req) + + trace_io_uring_queue_async_work(req, io_wq_is_hashed(&req->work)); + io_wq_enqueue(tctx->io_wq, &req->work); +- if (link) +- io_queue_linked_timeout(link); + } + + static __cold void io_queue_deferred(struct io_ring_ctx *ctx) +@@ -940,6 +919,14 @@ static bool __io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u + { + bool filled; + ++ /* ++ * If multishot has already posted deferred completions, ensure that ++ * those are flushed first before posting this one. If not, CQEs ++ * could get reordered. ++ */ ++ if (!wq_list_empty(&ctx->submit_state.compl_reqs)) ++ __io_submit_flush_completions(ctx); ++ + io_cq_lock(ctx); + filled = io_fill_cqe_aux(ctx, user_data, res, cflags); + if (!filled && allow_overflow) +@@ -1863,17 +1850,24 @@ static bool io_assign_file(struct io_kiocb *req, const struct io_issue_def *def, + return !!req->file; + } + ++#define REQ_ISSUE_SLOW_FLAGS (REQ_F_CREDS | REQ_F_ARM_LTIMEOUT) ++ + static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags) + { + const struct io_issue_def *def = &io_issue_defs[req->opcode]; + const struct cred *creds = NULL; ++ struct io_kiocb *link = NULL; + int ret; + + if (unlikely(!io_assign_file(req, def, issue_flags))) + return -EBADF; + +- if (unlikely((req->flags & REQ_F_CREDS) && req->creds != current_cred())) +- creds = override_creds(req->creds); ++ if (unlikely(req->flags & REQ_ISSUE_SLOW_FLAGS)) { ++ if ((req->flags & REQ_F_CREDS) && req->creds != current_cred()) ++ creds = override_creds(req->creds); ++ if (req->flags & REQ_F_ARM_LTIMEOUT) ++ link = __io_prep_linked_timeout(req); ++ } + + if (!def->audit_skip) + audit_uring_entry(req->opcode); +@@ -1883,8 +1877,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags) + if (!def->audit_skip) + audit_uring_exit(!ret, ret); + +- if (creds) +- revert_creds(creds); ++ if (unlikely(creds || link)) { ++ if (creds) ++ revert_creds(creds); ++ if (link) ++ io_queue_linked_timeout(link); ++ } + + if (ret == IOU_OK) { + if (issue_flags & IO_URING_F_COMPLETE_DEFER) +@@ -1939,8 +1937,6 @@ void io_wq_submit_work(struct io_wq_work *work) + else + req_ref_get(req); + +- io_arm_ltimeout(req); +- + /* either cancelled or io-wq is dying, so don't touch tctx->iowq */ + if (work->flags & IO_WQ_WORK_CANCEL) { + fail: +@@ -2036,15 +2032,11 @@ struct file *io_file_get_normal(struct io_kiocb *req, int fd) + static void io_queue_async(struct io_kiocb *req, int ret) + __must_hold(&req->ctx->uring_lock) + { +- struct io_kiocb *linked_timeout; +- + if (ret != -EAGAIN || (req->flags & REQ_F_NOWAIT)) { + io_req_defer_failed(req, ret); + return; + } + +- linked_timeout = io_prep_linked_timeout(req); +- + switch (io_arm_poll_handler(req, 0)) { + case IO_APOLL_READY: + io_kbuf_recycle(req, 0); +@@ -2057,9 +2049,6 @@ static void io_queue_async(struct io_kiocb *req, int ret) + case IO_APOLL_OK: + break; + } +- +- if (linked_timeout) +- io_queue_linked_timeout(linked_timeout); + } + + static inline void io_queue_sqe(struct io_kiocb *req) +@@ -2073,9 +2062,7 @@ static inline void io_queue_sqe(struct io_kiocb *req) + * We async punt it if the file wasn't marked NOWAIT, or if the file + * doesn't support non-blocking read/write attempts + */ +- if (likely(!ret)) +- io_arm_ltimeout(req); +- else ++ if (unlikely(ret)) + io_queue_async(req, ret); + } + +diff --git a/kernel/params.c b/kernel/params.c +index c7aed3c51cd538..e39ac5420cd6dc 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -945,7 +945,9 @@ struct kset *module_kset; + static void module_kobj_release(struct kobject *kobj) + { + struct module_kobject *mk = to_module_kobject(kobj); +- complete(mk->kobj_completion); ++ ++ if (mk->kobj_completion) ++ complete(mk->kobj_completion); + } + + const struct kobj_type module_ktype = { +diff --git a/net/can/gw.c b/net/can/gw.c +index 37528826935e74..e65500c52bf5c7 100644 +--- a/net/can/gw.c ++++ b/net/can/gw.c +@@ -130,7 +130,7 @@ struct cgw_job { + u32 handled_frames; + u32 dropped_frames; + u32 deleted_frames; +- struct cf_mod mod; ++ struct cf_mod __rcu *cf_mod; + union { + /* CAN frame data source */ + struct net_device *dev; +@@ -459,6 +459,7 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + struct cgw_job *gwj = (struct cgw_job *)data; + struct canfd_frame *cf; + struct sk_buff *nskb; ++ struct cf_mod *mod; + int modidx = 0; + + /* process strictly Classic CAN or CAN FD frames */ +@@ -506,7 +507,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + * When there is at least one modification function activated, + * we need to copy the skb as we want to modify skb->data. + */ +- if (gwj->mod.modfunc[0]) ++ mod = rcu_dereference(gwj->cf_mod); ++ if (mod->modfunc[0]) + nskb = skb_copy(skb, GFP_ATOMIC); + else + nskb = skb_clone(skb, GFP_ATOMIC); +@@ -529,8 +531,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + cf = (struct canfd_frame *)nskb->data; + + /* perform preprocessed modification functions if there are any */ +- while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx]) +- (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod); ++ while (modidx < MAX_MODFUNCTIONS && mod->modfunc[modidx]) ++ (*mod->modfunc[modidx++])(cf, mod); + + /* Has the CAN frame been modified? */ + if (modidx) { +@@ -546,11 +548,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) + } + + /* check for checksum updates */ +- if (gwj->mod.csumfunc.crc8) +- (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8); ++ if (mod->csumfunc.crc8) ++ (*mod->csumfunc.crc8)(cf, &mod->csum.crc8); + +- if (gwj->mod.csumfunc.xor) +- (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); ++ if (mod->csumfunc.xor) ++ (*mod->csumfunc.xor)(cf, &mod->csum.xor); + } + + /* clear the skb timestamp if not configured the other way */ +@@ -581,9 +583,20 @@ static void cgw_job_free_rcu(struct rcu_head *rcu_head) + { + struct cgw_job *gwj = container_of(rcu_head, struct cgw_job, rcu); + ++ /* cgw_job::cf_mod is always accessed from the same cgw_job object within ++ * the same RCU read section. Once cgw_job is scheduled for removal, ++ * cf_mod can also be removed without mandating an additional grace period. ++ */ ++ kfree(rcu_access_pointer(gwj->cf_mod)); + kmem_cache_free(cgw_cache, gwj); + } + ++/* Return cgw_job::cf_mod with RTNL protected section */ ++static struct cf_mod *cgw_job_cf_mod(struct cgw_job *gwj) ++{ ++ return rcu_dereference_protected(gwj->cf_mod, rtnl_is_locked()); ++} ++ + static int cgw_notifier(struct notifier_block *nb, + unsigned long msg, void *ptr) + { +@@ -616,6 +629,7 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, + { + struct rtcanmsg *rtcan; + struct nlmsghdr *nlh; ++ struct cf_mod *mod; + + nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtcan), flags); + if (!nlh) +@@ -650,82 +664,83 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, + goto cancel; + } + ++ mod = cgw_job_cf_mod(gwj); + if (gwj->flags & CGW_FLAGS_CAN_FD) { + struct cgw_fdframe_mod mb; + +- if (gwj->mod.modtype.and) { +- memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.and; ++ if (mod->modtype.and) { ++ memcpy(&mb.cf, &mod->modframe.and, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.and; + if (nla_put(skb, CGW_FDMOD_AND, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.or) { +- memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.or; ++ if (mod->modtype.or) { ++ memcpy(&mb.cf, &mod->modframe.or, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.or; + if (nla_put(skb, CGW_FDMOD_OR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.xor) { +- memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.xor; ++ if (mod->modtype.xor) { ++ memcpy(&mb.cf, &mod->modframe.xor, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.xor; + if (nla_put(skb, CGW_FDMOD_XOR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.set) { +- memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.set; ++ if (mod->modtype.set) { ++ memcpy(&mb.cf, &mod->modframe.set, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.set; + if (nla_put(skb, CGW_FDMOD_SET, sizeof(mb), &mb) < 0) + goto cancel; + } + } else { + struct cgw_frame_mod mb; + +- if (gwj->mod.modtype.and) { +- memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.and; ++ if (mod->modtype.and) { ++ memcpy(&mb.cf, &mod->modframe.and, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.and; + if (nla_put(skb, CGW_MOD_AND, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.or) { +- memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.or; ++ if (mod->modtype.or) { ++ memcpy(&mb.cf, &mod->modframe.or, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.or; + if (nla_put(skb, CGW_MOD_OR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.xor) { +- memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.xor; ++ if (mod->modtype.xor) { ++ memcpy(&mb.cf, &mod->modframe.xor, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.xor; + if (nla_put(skb, CGW_MOD_XOR, sizeof(mb), &mb) < 0) + goto cancel; + } + +- if (gwj->mod.modtype.set) { +- memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf)); +- mb.modtype = gwj->mod.modtype.set; ++ if (mod->modtype.set) { ++ memcpy(&mb.cf, &mod->modframe.set, sizeof(mb.cf)); ++ mb.modtype = mod->modtype.set; + if (nla_put(skb, CGW_MOD_SET, sizeof(mb), &mb) < 0) + goto cancel; + } + } + +- if (gwj->mod.uid) { +- if (nla_put_u32(skb, CGW_MOD_UID, gwj->mod.uid) < 0) ++ if (mod->uid) { ++ if (nla_put_u32(skb, CGW_MOD_UID, mod->uid) < 0) + goto cancel; + } + +- if (gwj->mod.csumfunc.crc8) { ++ if (mod->csumfunc.crc8) { + if (nla_put(skb, CGW_CS_CRC8, CGW_CS_CRC8_LEN, +- &gwj->mod.csum.crc8) < 0) ++ &mod->csum.crc8) < 0) + goto cancel; + } + +- if (gwj->mod.csumfunc.xor) { ++ if (mod->csumfunc.xor) { + if (nla_put(skb, CGW_CS_XOR, CGW_CS_XOR_LEN, +- &gwj->mod.csum.xor) < 0) ++ &mod->csum.xor) < 0) + goto cancel; + } + +@@ -1059,7 +1074,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + struct net *net = sock_net(skb->sk); + struct rtcanmsg *r; + struct cgw_job *gwj; +- struct cf_mod mod; ++ struct cf_mod *mod; + struct can_can_gw ccgw; + u8 limhops = 0; + int err = 0; +@@ -1078,37 +1093,48 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + if (r->gwtype != CGW_TYPE_CAN_CAN) + return -EINVAL; + +- err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops); ++ mod = kmalloc(sizeof(*mod), GFP_KERNEL); ++ if (!mod) ++ return -ENOMEM; ++ ++ err = cgw_parse_attr(nlh, mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops); + if (err < 0) +- return err; ++ goto out_free_cf; + +- if (mod.uid) { ++ if (mod->uid) { + ASSERT_RTNL(); + + /* check for updating an existing job with identical uid */ + hlist_for_each_entry(gwj, &net->can.cgw_list, list) { +- if (gwj->mod.uid != mod.uid) ++ struct cf_mod *old_cf; ++ ++ old_cf = cgw_job_cf_mod(gwj); ++ if (old_cf->uid != mod->uid) + continue; + + /* interfaces & filters must be identical */ +- if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw))) +- return -EINVAL; ++ if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw))) { ++ err = -EINVAL; ++ goto out_free_cf; ++ } + +- /* update modifications with disabled softirq & quit */ +- local_bh_disable(); +- memcpy(&gwj->mod, &mod, sizeof(mod)); +- local_bh_enable(); ++ rcu_assign_pointer(gwj->cf_mod, mod); ++ kfree_rcu_mightsleep(old_cf); + return 0; + } + } + + /* ifindex == 0 is not allowed for job creation */ +- if (!ccgw.src_idx || !ccgw.dst_idx) +- return -ENODEV; ++ if (!ccgw.src_idx || !ccgw.dst_idx) { ++ err = -ENODEV; ++ goto out_free_cf; ++ } + + gwj = kmem_cache_alloc(cgw_cache, GFP_KERNEL); +- if (!gwj) +- return -ENOMEM; ++ if (!gwj) { ++ err = -ENOMEM; ++ goto out_free_cf; ++ } + + gwj->handled_frames = 0; + gwj->dropped_frames = 0; +@@ -1118,7 +1144,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + gwj->limit_hops = limhops; + + /* insert already parsed information */ +- memcpy(&gwj->mod, &mod, sizeof(mod)); ++ RCU_INIT_POINTER(gwj->cf_mod, mod); + memcpy(&gwj->ccgw, &ccgw, sizeof(ccgw)); + + err = -ENODEV; +@@ -1152,9 +1178,11 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, + if (!err) + hlist_add_head_rcu(&gwj->list, &net->can.cgw_list); + out: +- if (err) ++ if (err) { + kmem_cache_free(cgw_cache, gwj); +- ++out_free_cf: ++ kfree(mod); ++ } + return err; + } + +@@ -1214,19 +1242,22 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, + + /* remove only the first matching entry */ + hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) { ++ struct cf_mod *cf_mod; ++ + if (gwj->flags != r->flags) + continue; + + if (gwj->limit_hops != limhops) + continue; + ++ cf_mod = cgw_job_cf_mod(gwj); + /* we have a match when uid is enabled and identical */ +- if (gwj->mod.uid || mod.uid) { +- if (gwj->mod.uid != mod.uid) ++ if (cf_mod->uid || mod.uid) { ++ if (cf_mod->uid != mod.uid) + continue; + } else { + /* no uid => check for identical modifications */ +- if (memcmp(&gwj->mod, &mod, sizeof(mod))) ++ if (memcmp(cf_mod, &mod, sizeof(mod))) + continue; + } + +diff --git a/net/core/filter.c b/net/core/filter.c +index 066277b91a1be8..5143c8a9e52cab 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -2507,6 +2507,7 @@ int skb_do_redirect(struct sk_buff *skb) + goto out_drop; + skb->dev = dev; + dev_sw_netstats_rx_add(dev, skb->len); ++ skb_scrub_packet(skb, false); + return -EAGAIN; + } + return flags & BPF_F_NEIGH ? +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index bb9add46e382a6..231fa4dc6cde4a 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3189,16 +3189,13 @@ static void add_v4_addrs(struct inet6_dev *idev) + struct in6_addr addr; + struct net_device *dev; + struct net *net = dev_net(idev->dev); +- int scope, plen, offset = 0; ++ int scope, plen; + u32 pflags = 0; + + ASSERT_RTNL(); + + memset(&addr, 0, sizeof(struct in6_addr)); +- /* in case of IP6GRE the dev_addr is an IPv6 and therefore we use only the last 4 bytes */ +- if (idev->dev->addr_len == sizeof(struct in6_addr)) +- offset = sizeof(struct in6_addr) - 4; +- memcpy(&addr.s6_addr32[3], idev->dev->dev_addr + offset, 4); ++ memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4); + + if (!(idev->dev->flags & IFF_POINTOPOINT) && idev->dev->type == ARPHRD_SIT) { + scope = IPV6_ADDR_COMPATv4; +@@ -3508,7 +3505,13 @@ static void addrconf_gre_config(struct net_device *dev) + return; + } + +- if (dev->type == ARPHRD_ETHER) { ++ /* Generate the IPv6 link-local address using addrconf_addr_gen(), ++ * unless we have an IPv4 GRE device not bound to an IP address and ++ * which is in EUI64 mode (as __ipv6_isatap_ifid() would fail in this ++ * case). Such devices fall back to add_v4_addrs() instead. ++ */ ++ if (!(dev->type == ARPHRD_IPGRE && *(__be32 *)dev->dev_addr == 0 && ++ idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64)) { + addrconf_addr_gen(idev, true); + return; + } +diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h +index 20aad81fcad7e6..c2d88b1b06b872 100644 +--- a/net/netfilter/ipset/ip_set_hash_gen.h ++++ b/net/netfilter/ipset/ip_set_hash_gen.h +@@ -63,7 +63,7 @@ struct hbucket { + #define ahash_sizeof_regions(htable_bits) \ + (ahash_numof_locks(htable_bits) * sizeof(struct ip_set_region)) + #define ahash_region(n, htable_bits) \ +- ((n) % ahash_numof_locks(htable_bits)) ++ ((n) / jhash_size(HTABLE_REGION_BITS)) + #define ahash_bucket_start(h, htable_bits) \ + ((htable_bits) < HTABLE_REGION_BITS ? 0 \ + : (h) * jhash_size(HTABLE_REGION_BITS)) +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index 5cd511162bc038..0103c4a4d10a55 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -119,13 +119,12 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + return false; + } + +-/* Get route to daddr, update *saddr, optionally bind route to saddr */ ++/* Get route to daddr, optionally bind route to saddr */ + static struct rtable *do_output_route4(struct net *net, __be32 daddr, +- int rt_mode, __be32 *saddr) ++ int rt_mode, __be32 *ret_saddr) + { + struct flowi4 fl4; + struct rtable *rt; +- bool loop = false; + + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = daddr; +@@ -135,23 +134,17 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr, + retry: + rt = ip_route_output_key(net, &fl4); + if (IS_ERR(rt)) { +- /* Invalid saddr ? */ +- if (PTR_ERR(rt) == -EINVAL && *saddr && +- rt_mode & IP_VS_RT_MODE_CONNECT && !loop) { +- *saddr = 0; +- flowi4_update_output(&fl4, 0, daddr, 0); +- goto retry; +- } + IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", &daddr); + return NULL; +- } else if (!*saddr && rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) { ++ } ++ if (rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) { + ip_rt_put(rt); +- *saddr = fl4.saddr; + flowi4_update_output(&fl4, 0, daddr, fl4.saddr); +- loop = true; ++ rt_mode = 0; + goto retry; + } +- *saddr = fl4.saddr; ++ if (ret_saddr) ++ *ret_saddr = fl4.saddr; + return rt; + } + +@@ -344,19 +337,15 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb, + if (ret_saddr) + *ret_saddr = dest_dst->dst_saddr.ip; + } else { +- __be32 saddr = htonl(INADDR_ANY); +- + noref = 0; + + /* For such unconfigured boxes avoid many route lookups + * for performance reasons because we do not remember saddr + */ + rt_mode &= ~IP_VS_RT_MODE_CONNECT; +- rt = do_output_route4(net, daddr, rt_mode, &saddr); ++ rt = do_output_route4(net, daddr, rt_mode, ret_saddr); + if (!rt) + goto err_unreach; +- if (ret_saddr) +- *ret_saddr = saddr; + } + + local = (rt->rt_flags & RTCF_LOCAL) ? 1 : 0; +diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c +index 6c5afb4ad67bb6..10c646b32b9d08 100644 +--- a/net/openvswitch/actions.c ++++ b/net/openvswitch/actions.c +@@ -959,8 +959,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, + upcall.cmd = OVS_PACKET_CMD_ACTION; + upcall.mru = OVS_CB(skb)->mru; + +- for (a = nla_data(attr), rem = nla_len(attr); rem > 0; +- a = nla_next(a, &rem)) { ++ nla_for_each_nested(a, attr, rem) { + switch (nla_type(a)) { + case OVS_USERSPACE_ATTR_USERDATA: + upcall.userdata = a; +diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c +index 9a3f7ea80b34b9..716da8c6b3def3 100644 +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -348,7 +348,8 @@ static void htb_add_to_wait_tree(struct htb_sched *q, + */ + static inline void htb_next_rb_node(struct rb_node **n) + { +- *n = rb_next(*n); ++ if (*n) ++ *n = rb_next(*n); + } + + /** +@@ -609,8 +610,8 @@ static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) + */ + static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) + { +- WARN_ON(!cl->prio_activity); +- ++ if (!cl->prio_activity) ++ return; + htb_deactivate_prios(q, cl); + cl->prio_activity = 0; + } +@@ -1485,8 +1486,6 @@ static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) + { + struct htb_class *cl = (struct htb_class *)arg; + +- if (!cl->prio_activity) +- return; + htb_deactivate(qdisc_priv(sch), cl); + } + +@@ -1740,8 +1739,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg, + if (cl->parent) + cl->parent->children--; + +- if (cl->prio_activity) +- htb_deactivate(q, cl); ++ htb_deactivate(q, cl); + + if (cl->cmode != HTB_CAN_SEND) + htb_safe_rb_erase(&cl->pq_node, +@@ -1949,8 +1947,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, + /* turn parent into inner node */ + qdisc_purge_queue(parent->leaf.q); + parent_qdisc = parent->leaf.q; +- if (parent->prio_activity) +- htb_deactivate(q, parent); ++ htb_deactivate(q, parent); + + /* remove from evt list because of level change */ + if (parent->cmode != HTB_CAN_SEND) { +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index ce622a287abc6b..6db8c9a2a7a2b8 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -2511,7 +2511,7 @@ cfg80211_defrag_mle(const struct element *mle, const u8 *ie, size_t ielen, + /* Required length for first defragmentation */ + buf_len = mle->datalen - 1; + for_each_element(elem, mle->data + mle->datalen, +- ielen - sizeof(*mle) + mle->datalen) { ++ ie + ielen - mle->data - mle->datalen) { + if (elem->id != WLAN_EID_FRAGMENT) + break; + diff --git a/patch/kernel/archive/spacemit-6.6/patch-6.6.91-92.patch b/patch/kernel/archive/spacemit-6.6/patch-6.6.91-92.patch new file mode 100644 index 000000000000..08903ea07d30 --- /dev/null +++ b/patch/kernel/archive/spacemit-6.6/patch-6.6.91-92.patch @@ -0,0 +1,4627 @@ +diff --git a/Makefile b/Makefile +index a6a1942e2d00a9..51d975b3555195 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 91 ++SUBLEVEL = 92 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 75523c1be07350..d8012d1a2e152d 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -2001,7 +2001,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, + emit(A64_STR64I(A64_R(20), A64_SP, regs_off + 8), ctx); + + if (flags & BPF_TRAMP_F_CALL_ORIG) { +- emit_addr_mov_i64(A64_R(0), (const u64)im, ctx); ++ /* for the first pass, assume the worst case */ ++ if (!ctx->image) ++ ctx->idx += 4; ++ else ++ emit_a64_mov_i64(A64_R(0), (const u64)im, ctx); + emit_call((const u64)__bpf_tramp_enter, ctx); + } + +@@ -2045,7 +2049,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, + + if (flags & BPF_TRAMP_F_CALL_ORIG) { + im->ip_epilogue = ctx->image + ctx->idx; +- emit_addr_mov_i64(A64_R(0), (const u64)im, ctx); ++ /* for the first pass, assume the worst case */ ++ if (!ctx->image) ++ ctx->idx += 4; ++ else ++ emit_a64_mov_i64(A64_R(0), (const u64)im, ctx); + emit_call((const u64)__bpf_tramp_exit, ctx); + } + +diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile +index 81e8089c9c4f18..9c6aff9376ec0b 100644 +--- a/arch/loongarch/Makefile ++++ b/arch/loongarch/Makefile +@@ -43,7 +43,7 @@ endif + + ifdef CONFIG_64BIT + ld-emul = $(64bit-emul) +-cflags-y += -mabi=lp64s ++cflags-y += -mabi=lp64s -mcmodel=normal + endif + + cflags-y += -pipe -msoft-float +diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h +index a5b63c84f8541a..e5d21e836d993c 100644 +--- a/arch/loongarch/include/asm/ptrace.h ++++ b/arch/loongarch/include/asm/ptrace.h +@@ -55,7 +55,7 @@ static inline void instruction_pointer_set(struct pt_regs *regs, unsigned long v + + /* Query offset/name of register from its name/offset */ + extern int regs_query_register_offset(const char *name); +-#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) ++#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last) - sizeof(unsigned long)) + + /** + * regs_get_register() - get register value from its offset +diff --git a/arch/loongarch/include/asm/uprobes.h b/arch/loongarch/include/asm/uprobes.h +index c8f59983f702df..d01b6704e1d8e6 100644 +--- a/arch/loongarch/include/asm/uprobes.h ++++ b/arch/loongarch/include/asm/uprobes.h +@@ -15,7 +15,6 @@ typedef u32 uprobe_opcode_t; + #define UPROBE_XOLBP_INSN larch_insn_gen_break(BRK_UPROBE_XOLBP) + + struct arch_uprobe { +- unsigned long resume_era; + u32 insn[2]; + u32 ixol[2]; + bool simulate; +diff --git a/arch/loongarch/kernel/kfpu.c b/arch/loongarch/kernel/kfpu.c +index ec5b28e570c963..4c476904227f95 100644 +--- a/arch/loongarch/kernel/kfpu.c ++++ b/arch/loongarch/kernel/kfpu.c +@@ -18,11 +18,28 @@ static unsigned int euen_mask = CSR_EUEN_FPEN; + static DEFINE_PER_CPU(bool, in_kernel_fpu); + static DEFINE_PER_CPU(unsigned int, euen_current); + ++static inline void fpregs_lock(void) ++{ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); ++ else ++ local_bh_disable(); ++} ++ ++static inline void fpregs_unlock(void) ++{ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); ++ else ++ local_bh_enable(); ++} ++ + void kernel_fpu_begin(void) + { + unsigned int *euen_curr; + +- preempt_disable(); ++ if (!irqs_disabled()) ++ fpregs_lock(); + + WARN_ON(this_cpu_read(in_kernel_fpu)); + +@@ -73,7 +90,8 @@ void kernel_fpu_end(void) + + this_cpu_write(in_kernel_fpu, false); + +- preempt_enable(); ++ if (!irqs_disabled()) ++ fpregs_unlock(); + } + EXPORT_SYMBOL_GPL(kernel_fpu_end); + +diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c +index e7015f7b70e37c..a3732f754b5d8f 100644 +--- a/arch/loongarch/kernel/time.c ++++ b/arch/loongarch/kernel/time.c +@@ -110,7 +110,7 @@ static unsigned long __init get_loops_per_jiffy(void) + return lpj; + } + +-static long init_offset __nosavedata; ++static long init_offset; + + void save_counter(void) + { +diff --git a/arch/loongarch/kernel/uprobes.c b/arch/loongarch/kernel/uprobes.c +index 87abc7137b738e..6022eb0f71dbce 100644 +--- a/arch/loongarch/kernel/uprobes.c ++++ b/arch/loongarch/kernel/uprobes.c +@@ -42,7 +42,6 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) + utask->autask.saved_trap_nr = current->thread.trap_nr; + current->thread.trap_nr = UPROBE_TRAP_NR; + instruction_pointer_set(regs, utask->xol_vaddr); +- user_enable_single_step(current); + + return 0; + } +@@ -53,13 +52,7 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) + + WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); + current->thread.trap_nr = utask->autask.saved_trap_nr; +- +- if (auprobe->simulate) +- instruction_pointer_set(regs, auprobe->resume_era); +- else +- instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE); +- +- user_disable_single_step(current); ++ instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE); + + return 0; + } +@@ -70,7 +63,6 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) + + current->thread.trap_nr = utask->autask.saved_trap_nr; + instruction_pointer_set(regs, utask->vaddr); +- user_disable_single_step(current); + } + + bool arch_uprobe_xol_was_trapped(struct task_struct *t) +@@ -90,7 +82,6 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) + + insn.word = auprobe->insn[0]; + arch_simulate_insn(insn, regs); +- auprobe->resume_era = regs->csr_era; + + return true; + } +diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c +index 1e0590542f987c..e7b7346592cb2a 100644 +--- a/arch/loongarch/power/hibernate.c ++++ b/arch/loongarch/power/hibernate.c +@@ -2,6 +2,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -14,6 +15,7 @@ struct pt_regs saved_regs; + + void save_processor_state(void) + { ++ save_counter(); + saved_crmd = csr_read32(LOONGARCH_CSR_CRMD); + saved_prmd = csr_read32(LOONGARCH_CSR_PRMD); + saved_euen = csr_read32(LOONGARCH_CSR_EUEN); +@@ -26,6 +28,7 @@ void save_processor_state(void) + + void restore_processor_state(void) + { ++ sync_counter(); + csr_write32(saved_crmd, LOONGARCH_CSR_CRMD); + csr_write32(saved_prmd, LOONGARCH_CSR_PRMD); + csr_write32(saved_euen, LOONGARCH_CSR_EUEN); +diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c +index 4817e424d69658..8e6cad42b296ee 100644 +--- a/arch/x86/kernel/alternative.c ++++ b/arch/x86/kernel/alternative.c +@@ -730,7 +730,15 @@ static bool cpu_wants_indirect_its_thunk_at(unsigned long addr, int reg) + /* Lower-half of the cacheline? */ + return !(addr & 0x20); + } +-#endif ++ ++u8 *its_static_thunk(int reg) ++{ ++ u8 *thunk = __x86_indirect_its_thunk_array[reg]; ++ ++ return thunk; ++} ++ ++#endif /* CONFIG_MITIGATION_ITS */ + + /* + * Rewrite the compiler generated retpoline thunk calls. +@@ -1449,13 +1457,6 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, + static void poison_cfi(void *addr) { } + #endif + +-u8 *its_static_thunk(int reg) +-{ +- u8 *thunk = __x86_indirect_its_thunk_array[reg]; +- +- return thunk; +-} +- + #endif + + void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, +diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c +index b42111a24cc28d..8e38c51359d05a 100644 +--- a/arch/x86/kvm/smm.c ++++ b/arch/x86/kvm/smm.c +@@ -131,6 +131,7 @@ void kvm_smm_changed(struct kvm_vcpu *vcpu, bool entering_smm) + + kvm_mmu_reset_context(vcpu); + } ++EXPORT_SYMBOL_GPL(kvm_smm_changed); + + void process_smi(struct kvm_vcpu *vcpu) + { +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index 29c1be65cb71a0..c84a1451f194c4 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -2211,12 +2211,6 @@ static int shutdown_interception(struct kvm_vcpu *vcpu) + struct kvm_run *kvm_run = vcpu->run; + struct vcpu_svm *svm = to_svm(vcpu); + +- /* +- * The VM save area has already been encrypted so it +- * cannot be reinitialized - just terminate. +- */ +- if (sev_es_guest(vcpu->kvm)) +- return -EINVAL; + + /* + * VMCB is undefined after a SHUTDOWN intercept. INIT the vCPU to put +@@ -2225,9 +2219,18 @@ static int shutdown_interception(struct kvm_vcpu *vcpu) + * userspace. At a platform view, INIT is acceptable behavior as + * there exist bare metal platforms that automatically INIT the CPU + * in response to shutdown. ++ * ++ * The VM save area for SEV-ES guests has already been encrypted so it ++ * cannot be reinitialized, i.e. synthesizing INIT is futile. + */ +- clear_page(svm->vmcb); +- kvm_vcpu_reset(vcpu, true); ++ if (!sev_es_guest(vcpu->kvm)) { ++ clear_page(svm->vmcb); ++#ifdef CONFIG_KVM_SMM ++ if (is_smm(vcpu)) ++ kvm_smm_changed(vcpu, false); ++#endif ++ kvm_vcpu_reset(vcpu, true); ++ } + + kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; + return 0; +diff --git a/block/bio.c b/block/bio.c +index 4a8e7616995718..b197abbaebc464 100644 +--- a/block/bio.c ++++ b/block/bio.c +@@ -600,7 +600,7 @@ struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask) + { + struct bio *bio; + +- if (nr_vecs > UIO_MAXIOV) ++ if (nr_vecs > BIO_MAX_INLINE_VECS) + return NULL; + return kmalloc(struct_size(bio, bi_inline_vecs, nr_vecs), gfp_mask); + } +diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c +index f73ce6e13065dd..54676e3d82dd59 100644 +--- a/drivers/acpi/pptt.c ++++ b/drivers/acpi/pptt.c +@@ -231,16 +231,18 @@ static int acpi_pptt_leaf_node(struct acpi_table_header *table_hdr, + sizeof(struct acpi_table_pptt)); + proc_sz = sizeof(struct acpi_pptt_processor); + +- while ((unsigned long)entry + proc_sz < table_end) { ++ /* ignore subtable types that are smaller than a processor node */ ++ while ((unsigned long)entry + proc_sz <= table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; ++ + if (entry->type == ACPI_PPTT_TYPE_PROCESSOR && + cpu_node->parent == node_entry) + return 0; + if (entry->length == 0) + return 0; ++ + entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry, + entry->length); +- + } + return 1; + } +@@ -273,15 +275,18 @@ static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_he + proc_sz = sizeof(struct acpi_pptt_processor); + + /* find the processor structure associated with this cpuid */ +- while ((unsigned long)entry + proc_sz < table_end) { ++ while ((unsigned long)entry + proc_sz <= table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; + + if (entry->length == 0) { + pr_warn("Invalid zero length subtable\n"); + break; + } ++ /* entry->length may not equal proc_sz, revalidate the processor structure length */ + if (entry->type == ACPI_PPTT_TYPE_PROCESSOR && + acpi_cpu_id == cpu_node->acpi_processor_id && ++ (unsigned long)entry + entry->length <= table_end && ++ entry->length == proc_sz + cpu_node->number_of_priv_resources * sizeof(u32) && + acpi_pptt_leaf_node(table_hdr, cpu_node)) { + return (struct acpi_pptt_processor *)entry; + } +diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c +index a4274d8c7faaf3..f0d0c5a6d5127a 100644 +--- a/drivers/bluetooth/btnxpuart.c ++++ b/drivers/bluetooth/btnxpuart.c +@@ -601,8 +601,10 @@ static int nxp_download_firmware(struct hci_dev *hdev) + &nxpdev->tx_state), + msecs_to_jiffies(60000)); + +- release_firmware(nxpdev->fw); +- memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); ++ if (nxpdev->fw && strlen(nxpdev->fw_name)) { ++ release_firmware(nxpdev->fw); ++ memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); ++ } + + if (err == 0) { + bt_dev_err(hdev, "FW Download Timeout. offset: %d", +diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h +index 369496a6aebf13..27e61ddfb62298 100644 +--- a/drivers/char/tpm/tpm_tis_core.h ++++ b/drivers/char/tpm/tpm_tis_core.h +@@ -54,7 +54,7 @@ enum tis_int_flags { + enum tis_defaults { + TIS_MEM_LEN = 0x5000, + TIS_SHORT_TIMEOUT = 750, /* ms */ +- TIS_LONG_TIMEOUT = 2000, /* 2 sec */ ++ TIS_LONG_TIMEOUT = 4000, /* 4 secs */ + TIS_TIMEOUT_MIN_ATML = 14700, /* usecs */ + TIS_TIMEOUT_MAX_ATML = 15000, /* usecs */ + }; +diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c +index eb8b733065b24d..9093f751f1336a 100644 +--- a/drivers/dma-buf/dma-resv.c ++++ b/drivers/dma-buf/dma-resv.c +@@ -313,8 +313,9 @@ void dma_resv_add_fence(struct dma_resv *obj, struct dma_fence *fence, + count++; + + dma_resv_list_set(fobj, i, fence, usage); +- /* pointer update must be visible before we extend the num_fences */ +- smp_store_mb(fobj->num_fences, count); ++ /* fence update must be visible before we extend the num_fences */ ++ smp_wmb(); ++ fobj->num_fences = count; + } + EXPORT_SYMBOL(dma_resv_add_fence); + +diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c +index 78b8a97b236376..ffe621695e472b 100644 +--- a/drivers/dma/dmatest.c ++++ b/drivers/dma/dmatest.c +@@ -827,9 +827,9 @@ static int dmatest_func(void *data) + } else { + dma_async_issue_pending(chan); + +- wait_event_timeout(thread->done_wait, +- done->done, +- msecs_to_jiffies(params->timeout)); ++ wait_event_freezable_timeout(thread->done_wait, ++ done->done, ++ msecs_to_jiffies(params->timeout)); + + status = dma_async_is_tx_complete(chan, cookie, NULL, + NULL); +diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c +index 786afb256b6e0d..92e86ae9db29d7 100644 +--- a/drivers/dma/idxd/init.c ++++ b/drivers/dma/idxd/init.c +@@ -145,6 +145,25 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd) + pci_free_irq_vectors(pdev); + } + ++static void idxd_clean_wqs(struct idxd_device *idxd) ++{ ++ struct idxd_wq *wq; ++ struct device *conf_dev; ++ int i; ++ ++ for (i = 0; i < idxd->max_wqs; i++) { ++ wq = idxd->wqs[i]; ++ if (idxd->hw.wq_cap.op_config) ++ bitmap_free(wq->opcap_bmap); ++ kfree(wq->wqcfg); ++ conf_dev = wq_confdev(wq); ++ put_device(conf_dev); ++ kfree(wq); ++ } ++ bitmap_free(idxd->wq_enable_map); ++ kfree(idxd->wqs); ++} ++ + static int idxd_setup_wqs(struct idxd_device *idxd) + { + struct device *dev = &idxd->pdev->dev; +@@ -159,8 +178,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + + idxd->wq_enable_map = bitmap_zalloc_node(idxd->max_wqs, GFP_KERNEL, dev_to_node(dev)); + if (!idxd->wq_enable_map) { +- kfree(idxd->wqs); +- return -ENOMEM; ++ rc = -ENOMEM; ++ goto err_bitmap; + } + + for (i = 0; i < idxd->max_wqs; i++) { +@@ -179,10 +198,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + conf_dev->bus = &dsa_bus_type; + conf_dev->type = &idxd_wq_device_type; + rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id); +- if (rc < 0) { +- put_device(conf_dev); ++ if (rc < 0) + goto err; +- } + + mutex_init(&wq->wq_lock); + init_waitqueue_head(&wq->err_queue); +@@ -193,7 +210,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; + wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev)); + if (!wq->wqcfg) { +- put_device(conf_dev); + rc = -ENOMEM; + goto err; + } +@@ -201,9 +217,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + if (idxd->hw.wq_cap.op_config) { + wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL); + if (!wq->opcap_bmap) { +- put_device(conf_dev); + rc = -ENOMEM; +- goto err; ++ goto err_opcap_bmap; + } + bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS); + } +@@ -214,15 +229,46 @@ static int idxd_setup_wqs(struct idxd_device *idxd) + + return 0; + +- err: ++err_opcap_bmap: ++ kfree(wq->wqcfg); ++ ++err: ++ put_device(conf_dev); ++ kfree(wq); ++ + while (--i >= 0) { + wq = idxd->wqs[i]; ++ if (idxd->hw.wq_cap.op_config) ++ bitmap_free(wq->opcap_bmap); ++ kfree(wq->wqcfg); + conf_dev = wq_confdev(wq); + put_device(conf_dev); ++ kfree(wq); ++ + } ++ bitmap_free(idxd->wq_enable_map); ++ ++err_bitmap: ++ kfree(idxd->wqs); ++ + return rc; + } + ++static void idxd_clean_engines(struct idxd_device *idxd) ++{ ++ struct idxd_engine *engine; ++ struct device *conf_dev; ++ int i; ++ ++ for (i = 0; i < idxd->max_engines; i++) { ++ engine = idxd->engines[i]; ++ conf_dev = engine_confdev(engine); ++ put_device(conf_dev); ++ kfree(engine); ++ } ++ kfree(idxd->engines); ++} ++ + static int idxd_setup_engines(struct idxd_device *idxd) + { + struct idxd_engine *engine; +@@ -253,6 +299,7 @@ static int idxd_setup_engines(struct idxd_device *idxd) + rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id); + if (rc < 0) { + put_device(conf_dev); ++ kfree(engine); + goto err; + } + +@@ -266,10 +313,26 @@ static int idxd_setup_engines(struct idxd_device *idxd) + engine = idxd->engines[i]; + conf_dev = engine_confdev(engine); + put_device(conf_dev); ++ kfree(engine); + } ++ kfree(idxd->engines); ++ + return rc; + } + ++static void idxd_clean_groups(struct idxd_device *idxd) ++{ ++ struct idxd_group *group; ++ int i; ++ ++ for (i = 0; i < idxd->max_groups; i++) { ++ group = idxd->groups[i]; ++ put_device(group_confdev(group)); ++ kfree(group); ++ } ++ kfree(idxd->groups); ++} ++ + static int idxd_setup_groups(struct idxd_device *idxd) + { + struct device *dev = &idxd->pdev->dev; +@@ -300,6 +363,7 @@ static int idxd_setup_groups(struct idxd_device *idxd) + rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id); + if (rc < 0) { + put_device(conf_dev); ++ kfree(group); + goto err; + } + +@@ -324,20 +388,18 @@ static int idxd_setup_groups(struct idxd_device *idxd) + while (--i >= 0) { + group = idxd->groups[i]; + put_device(group_confdev(group)); ++ kfree(group); + } ++ kfree(idxd->groups); ++ + return rc; + } + + static void idxd_cleanup_internals(struct idxd_device *idxd) + { +- int i; +- +- for (i = 0; i < idxd->max_groups; i++) +- put_device(group_confdev(idxd->groups[i])); +- for (i = 0; i < idxd->max_engines; i++) +- put_device(engine_confdev(idxd->engines[i])); +- for (i = 0; i < idxd->max_wqs; i++) +- put_device(wq_confdev(idxd->wqs[i])); ++ idxd_clean_groups(idxd); ++ idxd_clean_engines(idxd); ++ idxd_clean_wqs(idxd); + destroy_workqueue(idxd->wq); + } + +@@ -380,7 +442,7 @@ static int idxd_init_evl(struct idxd_device *idxd) + static int idxd_setup_internals(struct idxd_device *idxd) + { + struct device *dev = &idxd->pdev->dev; +- int rc, i; ++ int rc; + + init_waitqueue_head(&idxd->cmd_waitq); + +@@ -411,14 +473,11 @@ static int idxd_setup_internals(struct idxd_device *idxd) + err_evl: + destroy_workqueue(idxd->wq); + err_wkq_create: +- for (i = 0; i < idxd->max_groups; i++) +- put_device(group_confdev(idxd->groups[i])); ++ idxd_clean_groups(idxd); + err_group: +- for (i = 0; i < idxd->max_engines; i++) +- put_device(engine_confdev(idxd->engines[i])); ++ idxd_clean_engines(idxd); + err_engine: +- for (i = 0; i < idxd->max_wqs; i++) +- put_device(wq_confdev(idxd->wqs[i])); ++ idxd_clean_wqs(idxd); + err_wqs: + return rc; + } +@@ -518,6 +577,17 @@ static void idxd_read_caps(struct idxd_device *idxd) + idxd->hw.iaa_cap.bits = ioread64(idxd->reg_base + IDXD_IAACAP_OFFSET); + } + ++static void idxd_free(struct idxd_device *idxd) ++{ ++ if (!idxd) ++ return; ++ ++ put_device(idxd_confdev(idxd)); ++ bitmap_free(idxd->opcap_bmap); ++ ida_free(&idxd_ida, idxd->id); ++ kfree(idxd); ++} ++ + static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_data *data) + { + struct device *dev = &pdev->dev; +@@ -535,28 +605,34 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_d + idxd_dev_set_type(&idxd->idxd_dev, idxd->data->type); + idxd->id = ida_alloc(&idxd_ida, GFP_KERNEL); + if (idxd->id < 0) +- return NULL; ++ goto err_ida; + + idxd->opcap_bmap = bitmap_zalloc_node(IDXD_MAX_OPCAP_BITS, GFP_KERNEL, dev_to_node(dev)); +- if (!idxd->opcap_bmap) { +- ida_free(&idxd_ida, idxd->id); +- return NULL; +- } ++ if (!idxd->opcap_bmap) ++ goto err_opcap; + + device_initialize(conf_dev); + conf_dev->parent = dev; + conf_dev->bus = &dsa_bus_type; + conf_dev->type = idxd->data->dev_type; + rc = dev_set_name(conf_dev, "%s%d", idxd->data->name_prefix, idxd->id); +- if (rc < 0) { +- put_device(conf_dev); +- return NULL; +- } ++ if (rc < 0) ++ goto err_name; + + spin_lock_init(&idxd->dev_lock); + spin_lock_init(&idxd->cmd_lock); + + return idxd; ++ ++err_name: ++ put_device(conf_dev); ++ bitmap_free(idxd->opcap_bmap); ++err_opcap: ++ ida_free(&idxd_ida, idxd->id); ++err_ida: ++ kfree(idxd); ++ ++ return NULL; + } + + static int idxd_enable_system_pasid(struct idxd_device *idxd) +@@ -778,7 +854,7 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + err: + pci_iounmap(pdev, idxd->reg_base); + err_iomap: +- put_device(idxd_confdev(idxd)); ++ idxd_free(idxd); + err_idxd_alloc: + pci_disable_device(pdev); + return rc; +@@ -815,7 +891,6 @@ static void idxd_shutdown(struct pci_dev *pdev) + static void idxd_remove(struct pci_dev *pdev) + { + struct idxd_device *idxd = pci_get_drvdata(pdev); +- struct idxd_irq_entry *irq_entry; + + idxd_unregister_devices(idxd); + /* +@@ -828,20 +903,12 @@ static void idxd_remove(struct pci_dev *pdev) + get_device(idxd_confdev(idxd)); + device_unregister(idxd_confdev(idxd)); + idxd_shutdown(pdev); +- if (device_pasid_enabled(idxd)) +- idxd_disable_system_pasid(idxd); + idxd_device_remove_debugfs(idxd); +- +- irq_entry = idxd_get_ie(idxd, 0); +- free_irq(irq_entry->vector, irq_entry); +- pci_free_irq_vectors(pdev); ++ idxd_cleanup(idxd); + pci_iounmap(pdev, idxd->reg_base); +- if (device_user_pasid_enabled(idxd)) +- idxd_disable_sva(pdev); +- pci_disable_device(pdev); +- destroy_workqueue(idxd->wq); +- perfmon_pmu_remove(idxd); + put_device(idxd_confdev(idxd)); ++ idxd_free(idxd); ++ pci_disable_device(pdev); + } + + static struct pci_driver idxd_pci_driver = { +diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c +index 02a1ab04f498e5..418e1774af1e5e 100644 +--- a/drivers/dma/ti/k3-udma.c ++++ b/drivers/dma/ti/k3-udma.c +@@ -1091,8 +1091,11 @@ static void udma_check_tx_completion(struct work_struct *work) + u32 residue_diff; + ktime_t time_diff; + unsigned long delay; ++ unsigned long flags; + + while (1) { ++ spin_lock_irqsave(&uc->vc.lock, flags); ++ + if (uc->desc) { + /* Get previous residue and time stamp */ + residue_diff = uc->tx_drain.residue; +@@ -1127,6 +1130,8 @@ static void udma_check_tx_completion(struct work_struct *work) + break; + } + ++ spin_unlock_irqrestore(&uc->vc.lock, flags); ++ + usleep_range(ktime_to_us(delay), + ktime_to_us(delay) + 10); + continue; +@@ -1143,6 +1148,8 @@ static void udma_check_tx_completion(struct work_struct *work) + + break; + } ++ ++ spin_unlock_irqrestore(&uc->vc.lock, flags); + } + + static irqreturn_t udma_ring_irq_handler(int irq, void *data) +@@ -4214,7 +4221,6 @@ static struct dma_chan *udma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) + { + struct udma_dev *ud = ofdma->of_dma_data; +- dma_cap_mask_t mask = ud->ddev.cap_mask; + struct udma_filter_param filter_param; + struct dma_chan *chan; + +@@ -4246,7 +4252,7 @@ static struct dma_chan *udma_of_xlate(struct of_phandle_args *dma_spec, + } + } + +- chan = __dma_request_channel(&mask, udma_dma_filter_fn, &filter_param, ++ chan = __dma_request_channel(&ud->ddev.cap_mask, udma_dma_filter_fn, &filter_param, + ofdma->of_node); + if (!chan) { + dev_err(ud->dev, "get channel fail in %s.\n", __func__); +diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig +index ea0f5083ac47f1..9a41c1c91f71af 100644 +--- a/drivers/firmware/arm_scmi/Kconfig ++++ b/drivers/firmware/arm_scmi/Kconfig +@@ -55,6 +55,20 @@ config ARM_SCMI_RAW_MODE_SUPPORT_COEX + operate normally, thing which could make an SCMI test suite using the + SCMI Raw mode support unreliable. If unsure, say N. + ++config ARM_SCMI_DEBUG_COUNTERS ++ bool "Enable SCMI communication debug metrics tracking" ++ select ARM_SCMI_NEED_DEBUGFS ++ depends on DEBUG_FS ++ default n ++ help ++ Enables tracking of some key communication metrics for debug ++ purposes. It may track metrics like how many messages were sent ++ or received, were there any failures, what kind of failures, ..etc. ++ ++ Enable this option to create a new debugfs directory which contains ++ such useful debug counters. This can be helpful for debugging and ++ SCMI monitoring. ++ + config ARM_SCMI_HAVE_TRANSPORT + bool + help +diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h +index 039f686f4580d1..6c223487121544 100644 +--- a/drivers/firmware/arm_scmi/common.h ++++ b/drivers/firmware/arm_scmi/common.h +@@ -303,6 +303,41 @@ extern const struct scmi_desc scmi_optee_desc; + + void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); + ++enum debug_counters { ++ SENT_OK, ++ SENT_FAIL, ++ SENT_FAIL_POLLING_UNSUPPORTED, ++ SENT_FAIL_CHANNEL_NOT_FOUND, ++ RESPONSE_OK, ++ NOTIFICATION_OK, ++ DELAYED_RESPONSE_OK, ++ XFERS_RESPONSE_TIMEOUT, ++ XFERS_RESPONSE_POLLED_TIMEOUT, ++ RESPONSE_POLLED_OK, ++ ERR_MSG_UNEXPECTED, ++ ERR_MSG_INVALID, ++ ERR_MSG_NOMEM, ++ ERR_PROTOCOL, ++ SCMI_DEBUG_COUNTERS_LAST ++}; ++ ++static inline void scmi_inc_count(atomic_t *arr, int stat) ++{ ++ if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) ++ atomic_inc(&arr[stat]); ++} ++ ++enum scmi_bad_msg { ++ MSG_UNEXPECTED = -1, ++ MSG_INVALID = -2, ++ MSG_UNKNOWN = -3, ++ MSG_NOMEM = -4, ++ MSG_MBOX_SPURIOUS = -5, ++}; ++ ++void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, ++ enum scmi_bad_msg err); ++ + /* shmem related declarations */ + struct scmi_shared_mem; + +diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c +index efa9698c876a09..65d1e66a347d75 100644 +--- a/drivers/firmware/arm_scmi/driver.c ++++ b/drivers/firmware/arm_scmi/driver.c +@@ -108,12 +108,14 @@ struct scmi_protocol_instance { + * @name: Name of this SCMI instance + * @type: Type of this SCMI instance + * @is_atomic: Flag to state if the transport of this instance is atomic ++ * @counters: An array of atomic_c's used for tracking statistics (if enabled) + */ + struct scmi_debug_info { + struct dentry *top_dentry; + const char *name; + const char *type; + bool is_atomic; ++ atomic_t counters[SCMI_DEBUG_COUNTERS_LAST]; + }; + + /** +@@ -687,6 +689,45 @@ scmi_xfer_lookup_unlocked(struct scmi_xfers_info *minfo, u16 xfer_id) + return xfer ?: ERR_PTR(-EINVAL); + } + ++/** ++ * scmi_bad_message_trace - A helper to trace weird messages ++ * ++ * @cinfo: A reference to the channel descriptor on which the message was ++ * received ++ * @msg_hdr: Message header to track ++ * @err: A specific error code used as a status value in traces. ++ * ++ * This helper can be used to trace any kind of weird, incomplete, unexpected, ++ * timed-out message that arrives and as such, can be traced only referring to ++ * the header content, since the payload is missing/unreliable. ++ */ ++void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, ++ enum scmi_bad_msg err) ++{ ++ char *tag; ++ struct scmi_info *info = handle_to_scmi_info(cinfo->handle); ++ ++ switch (MSG_XTRACT_TYPE(msg_hdr)) { ++ case MSG_TYPE_COMMAND: ++ tag = "!RESP"; ++ break; ++ case MSG_TYPE_DELAYED_RESP: ++ tag = "!DLYD"; ++ break; ++ case MSG_TYPE_NOTIFICATION: ++ tag = "!NOTI"; ++ break; ++ default: ++ tag = "!UNKN"; ++ break; ++ } ++ ++ trace_scmi_msg_dump(info->id, cinfo->id, ++ MSG_XTRACT_PROT_ID(msg_hdr), ++ MSG_XTRACT_ID(msg_hdr), tag, ++ MSG_XTRACT_TOKEN(msg_hdr), err, NULL, 0); ++} ++ + /** + * scmi_msg_response_validate - Validate message type against state of related + * xfer +@@ -813,6 +854,10 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) + "Message for %d type %d is not expected!\n", + xfer_id, msg_type); + spin_unlock_irqrestore(&minfo->xfer_lock, flags); ++ ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNEXPECTED); ++ scmi_inc_count(info->dbg->counters, ERR_MSG_UNEXPECTED); ++ + return xfer; + } + refcount_inc(&xfer->users); +@@ -837,6 +882,11 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) + dev_err(cinfo->dev, + "Invalid message type:%d for %d - HDR:0x%X state:%d\n", + msg_type, xfer_id, msg_hdr, xfer->state); ++ ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_INVALID); ++ scmi_inc_count(info->dbg->counters, ERR_MSG_INVALID); ++ ++ + /* On error the refcount incremented above has to be dropped */ + __scmi_xfer_put(minfo, xfer); + xfer = ERR_PTR(-EINVAL); +@@ -878,6 +928,10 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, + if (IS_ERR(xfer)) { + dev_err(dev, "failed to get free message slot (%ld)\n", + PTR_ERR(xfer)); ++ ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_NOMEM); ++ scmi_inc_count(info->dbg->counters, ERR_MSG_NOMEM); ++ + scmi_clear_channel(info, cinfo); + return; + } +@@ -892,6 +946,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, + trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, + xfer->hdr.id, "NOTI", xfer->hdr.seq, + xfer->hdr.status, xfer->rx.buf, xfer->rx.len); ++ scmi_inc_count(info->dbg->counters, NOTIFICATION_OK); + + scmi_notify(cinfo->handle, xfer->hdr.protocol_id, + xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts); +@@ -951,8 +1006,10 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo, + if (xfer->hdr.type == MSG_TYPE_DELAYED_RESP) { + scmi_clear_channel(info, cinfo); + complete(xfer->async_done); ++ scmi_inc_count(info->dbg->counters, DELAYED_RESPONSE_OK); + } else { + complete(&xfer->done); ++ scmi_inc_count(info->dbg->counters, RESPONSE_OK); + } + + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { +@@ -997,6 +1054,7 @@ void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv) + break; + default: + WARN_ONCE(1, "received unknown msg_type:%d\n", msg_type); ++ scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNKNOWN); + break; + } + } +@@ -1017,7 +1075,8 @@ static void xfer_put(const struct scmi_protocol_handle *ph, + } + + static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, +- struct scmi_xfer *xfer, ktime_t stop) ++ struct scmi_xfer *xfer, ktime_t stop, ++ bool *ooo) + { + struct scmi_info *info = handle_to_scmi_info(cinfo->handle); + +@@ -1026,7 +1085,7 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, + * in case of out-of-order receptions of delayed responses + */ + return info->desc->ops->poll_done(cinfo, xfer) || +- try_wait_for_completion(&xfer->done) || ++ (*ooo = try_wait_for_completion(&xfer->done)) || + ktime_after(ktime_get(), stop); + } + +@@ -1035,6 +1094,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + struct scmi_xfer *xfer, unsigned int timeout_ms) + { + int ret = 0; ++ struct scmi_info *info = handle_to_scmi_info(cinfo->handle); + + if (xfer->hdr.poll_completion) { + /* +@@ -1042,26 +1102,27 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + * itself to support synchronous commands replies. + */ + if (!desc->sync_cmds_completed_on_ret) { ++ bool ooo = false; ++ + /* + * Poll on xfer using transport provided .poll_done(); + * assumes no completion interrupt was available. + */ + ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms); + +- spin_until_cond(scmi_xfer_done_no_timeout(cinfo, +- xfer, stop)); +- if (ktime_after(ktime_get(), stop)) { ++ spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer, ++ stop, &ooo)); ++ if (!ooo && !info->desc->ops->poll_done(cinfo, xfer)) { + dev_err(dev, + "timed out in resp(caller: %pS) - polling\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; ++ scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_POLLED_TIMEOUT); + } + } + + if (!ret) { + unsigned long flags; +- struct scmi_info *info = +- handle_to_scmi_info(cinfo->handle); + + /* + * Do not fetch_response if an out-of-order delayed +@@ -1081,6 +1142,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + "RESP" : "resp", + xfer->hdr.seq, xfer->hdr.status, + xfer->rx.buf, xfer->rx.len); ++ scmi_inc_count(info->dbg->counters, RESPONSE_POLLED_OK); + + if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { + struct scmi_info *info = +@@ -1098,6 +1160,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, + dev_err(dev, "timed out in resp(caller: %pS)\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; ++ scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_TIMEOUT); + } + } + +@@ -1181,13 +1244,15 @@ static int do_xfer(const struct scmi_protocol_handle *ph, + !is_transport_polling_capable(info->desc)) { + dev_warn_once(dev, + "Polling mode is not supported by transport.\n"); ++ scmi_inc_count(info->dbg->counters, SENT_FAIL_POLLING_UNSUPPORTED); + return -EINVAL; + } + + cinfo = idr_find(&info->tx_idr, pi->proto->id); +- if (unlikely(!cinfo)) ++ if (unlikely(!cinfo)) { ++ scmi_inc_count(info->dbg->counters, SENT_FAIL_CHANNEL_NOT_FOUND); + return -EINVAL; +- ++ } + /* True ONLY if also supported by transport. */ + if (is_polling_enabled(cinfo, info->desc)) + xfer->hdr.poll_completion = true; +@@ -1219,16 +1284,20 @@ static int do_xfer(const struct scmi_protocol_handle *ph, + ret = info->desc->ops->send_message(cinfo, xfer); + if (ret < 0) { + dev_dbg(dev, "Failed to send message %d\n", ret); ++ scmi_inc_count(info->dbg->counters, SENT_FAIL); + return ret; + } + + trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, + xfer->hdr.id, "CMND", xfer->hdr.seq, + xfer->hdr.status, xfer->tx.buf, xfer->tx.len); ++ scmi_inc_count(info->dbg->counters, SENT_OK); + + ret = scmi_wait_for_message_response(cinfo, xfer); +- if (!ret && xfer->hdr.status) ++ if (!ret && xfer->hdr.status) { + ret = scmi_to_linux_errno(xfer->hdr.status); ++ scmi_inc_count(info->dbg->counters, ERR_PROTOCOL); ++ } + + if (info->desc->ops->mark_txdone) + info->desc->ops->mark_txdone(cinfo, ret, xfer); +diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c +index 8e513f70b75d4c..f1d5e3fba35e07 100644 +--- a/drivers/firmware/arm_scmi/mailbox.c ++++ b/drivers/firmware/arm_scmi/mailbox.c +@@ -58,6 +58,9 @@ static void rx_callback(struct mbox_client *cl, void *m) + */ + if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { + dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); ++ scmi_bad_message_trace(smbox->cinfo, ++ shmem_read_header(smbox->shmem), ++ MSG_MBOX_SPURIOUS); + return; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index d59e8536192ca9..c5d706a4c7b4a7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -788,6 +788,7 @@ struct amdgpu_device { + bool need_swiotlb; + bool accel_working; + struct notifier_block acpi_nb; ++ struct notifier_block pm_nb; + struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS]; + struct debugfs_blob_wrapper debugfs_vbios_blob; + struct debugfs_blob_wrapper debugfs_discovery_blob; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 10f5a3d0f59163..f8058dd5356a13 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -141,6 +141,10 @@ const char *amdgpu_asic_name[] = { + "LAST", + }; + ++static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev); ++static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode, ++ void *data); ++ + /** + * DOC: pcie_replay_count + * +@@ -3920,6 +3924,11 @@ int amdgpu_device_init(struct amdgpu_device *adev, + + amdgpu_device_check_iommu_direct_map(adev); + ++ adev->pm_nb.notifier_call = amdgpu_device_pm_notifier; ++ r = register_pm_notifier(&adev->pm_nb); ++ if (r) ++ goto failed; ++ + return 0; + + release_ras_con: +@@ -3981,6 +3990,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) + flush_delayed_work(&adev->delayed_init_work); + adev->shutdown = true; + ++ unregister_pm_notifier(&adev->pm_nb); ++ + /* make sure IB test finished before entering exclusive mode + * to avoid preemption on IB test + */ +@@ -4107,6 +4118,33 @@ static int amdgpu_device_evict_resources(struct amdgpu_device *adev) + /* + * Suspend & resume. + */ ++/** ++ * amdgpu_device_pm_notifier - Notification block for Suspend/Hibernate events ++ * @nb: notifier block ++ * @mode: suspend mode ++ * @data: data ++ * ++ * This function is called when the system is about to suspend or hibernate. ++ * It is used to set the appropriate flags so that eviction can be optimized ++ * in the pm prepare callback. ++ */ ++static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode, ++ void *data) ++{ ++ struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, pm_nb); ++ ++ switch (mode) { ++ case PM_HIBERNATION_PREPARE: ++ adev->in_s4 = true; ++ break; ++ case PM_POST_HIBERNATION: ++ adev->in_s4 = false; ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++ + /** + * amdgpu_device_prepare - prepare for device suspend + * +@@ -4551,6 +4589,8 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, + retry: + amdgpu_amdkfd_pre_reset(adev); + ++ amdgpu_device_stop_pending_resets(adev); ++ + if (from_hypervisor) + r = amdgpu_virt_request_full_gpu(adev, true); + else +@@ -5347,11 +5387,12 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, + tmp_adev->asic_reset_res = r; + } + +- /* +- * Drop all pending non scheduler resets. Scheduler resets +- * were already dropped during drm_sched_stop +- */ +- amdgpu_device_stop_pending_resets(tmp_adev); ++ if (!amdgpu_sriov_vf(tmp_adev)) ++ /* ++ * Drop all pending non scheduler resets. Scheduler resets ++ * were already dropped during drm_sched_stop ++ */ ++ amdgpu_device_stop_pending_resets(tmp_adev); + } + + /* Actual ASIC resets if needed.*/ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index bacf2e5de2abce..940411f8e99be0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -2463,7 +2463,6 @@ static int amdgpu_pmops_freeze(struct device *dev) + struct amdgpu_device *adev = drm_to_adev(drm_dev); + int r; + +- adev->in_s4 = true; + r = amdgpu_device_suspend(drm_dev, true); + if (r) + return r; +@@ -2476,13 +2475,8 @@ static int amdgpu_pmops_freeze(struct device *dev) + static int amdgpu_pmops_thaw(struct device *dev) + { + struct drm_device *drm_dev = dev_get_drvdata(dev); +- struct amdgpu_device *adev = drm_to_adev(drm_dev); +- int r; +- +- r = amdgpu_device_resume(drm_dev, true); +- adev->in_s4 = false; + +- return r; ++ return amdgpu_device_resume(drm_dev, true); + } + + static int amdgpu_pmops_poweroff(struct device *dev) +@@ -2495,9 +2489,6 @@ static int amdgpu_pmops_poweroff(struct device *dev) + static int amdgpu_pmops_restore(struct device *dev) + { + struct drm_device *drm_dev = dev_get_drvdata(dev); +- struct amdgpu_device *adev = drm_to_adev(drm_dev); +- +- adev->in_s4 = false; + + return amdgpu_device_resume(drm_dev, true); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +index 22575422ca7ec1..7cb4b4118335a6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +@@ -32,6 +32,7 @@ + + #include "amdgpu.h" + #include "amdgpu_ras.h" ++#include "amdgpu_reset.h" + #include "vi.h" + #include "soc15.h" + #include "nv.h" +@@ -468,7 +469,7 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + return -EINVAL; + + if (pf2vf_info->size > 1024) { +- DRM_ERROR("invalid pf2vf message size\n"); ++ dev_err(adev->dev, "invalid pf2vf message size: 0x%x\n", pf2vf_info->size); + return -EINVAL; + } + +@@ -479,7 +480,9 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + adev->virt.fw_reserve.p_pf2vf, pf2vf_info->size, + adev->virt.fw_reserve.checksum_key, checksum); + if (checksum != checkval) { +- DRM_ERROR("invalid pf2vf message\n"); ++ dev_err(adev->dev, ++ "invalid pf2vf message: header checksum=0x%x calculated checksum=0x%x\n", ++ checksum, checkval); + return -EINVAL; + } + +@@ -493,7 +496,9 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + adev->virt.fw_reserve.p_pf2vf, pf2vf_info->size, + 0, checksum); + if (checksum != checkval) { +- DRM_ERROR("invalid pf2vf message\n"); ++ dev_err(adev->dev, ++ "invalid pf2vf message: header checksum=0x%x calculated checksum=0x%x\n", ++ checksum, checkval); + return -EINVAL; + } + +@@ -529,7 +534,7 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) + ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->uuid; + break; + default: +- DRM_ERROR("invalid pf2vf version\n"); ++ dev_err(adev->dev, "invalid pf2vf version: 0x%x\n", pf2vf_info->version); + return -EINVAL; + } + +@@ -628,8 +633,21 @@ static void amdgpu_virt_update_vf2pf_work_item(struct work_struct *work) + int ret; + + ret = amdgpu_virt_read_pf2vf_data(adev); +- if (ret) ++ if (ret) { ++ adev->virt.vf2pf_update_retry_cnt++; ++ if ((adev->virt.vf2pf_update_retry_cnt >= AMDGPU_VF2PF_UPDATE_MAX_RETRY_LIMIT) && ++ amdgpu_sriov_runtime(adev) && !amdgpu_in_reset(adev)) { ++ if (amdgpu_reset_domain_schedule(adev->reset_domain, ++ &adev->virt.flr_work)) ++ return; ++ else ++ dev_err(adev->dev, "Failed to queue work! at %s", __func__); ++ } ++ + goto out; ++ } ++ ++ adev->virt.vf2pf_update_retry_cnt = 0; + amdgpu_virt_write_vf2pf_data(adev); + + out: +@@ -650,6 +668,7 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) + adev->virt.fw_reserve.p_pf2vf = NULL; + adev->virt.fw_reserve.p_vf2pf = NULL; + adev->virt.vf2pf_update_interval_ms = 0; ++ adev->virt.vf2pf_update_retry_cnt = 0; + + if (adev->mman.fw_vram_usage_va && adev->mman.drv_vram_usage_va) { + DRM_WARN("Currently fw_vram and drv_vram should not have values at the same time!"); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +index 23b6efa9d25df8..891713757a8f5a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +@@ -51,6 +51,8 @@ + /* tonga/fiji use this offset */ + #define mmBIF_IOV_FUNC_IDENTIFIER 0x1503 + ++#define AMDGPU_VF2PF_UPDATE_MAX_RETRY_LIMIT 30 ++ + enum amdgpu_sriov_vf_mode { + SRIOV_VF_MODE_BARE_METAL = 0, + SRIOV_VF_MODE_ONE_VF, +@@ -253,6 +255,7 @@ struct amdgpu_virt { + /* vf2pf message */ + struct delayed_work vf2pf_work; + uint32_t vf2pf_update_interval_ms; ++ int vf2pf_update_retry_cnt; + + /* multimedia bandwidth config */ + bool is_mm_bw_enabled; +diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +index 63725b2ebc0373..37ac6d8ff81362 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c ++++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +@@ -276,6 +276,8 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work) + timeout -= 10; + } while (timeout > 1); + ++ dev_warn(adev->dev, "waiting IDH_FLR_NOTIFICATION_CMPL timeout\n"); ++ + flr_done: + atomic_set(&adev->reset_domain->in_gpu_reset, 0); + up_write(&adev->reset_domain->sem); +diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +index 6a68ee946f1cc3..96edd5d11326dd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c ++++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +@@ -298,6 +298,8 @@ static void xgpu_nv_mailbox_flr_work(struct work_struct *work) + timeout -= 10; + } while (timeout > 1); + ++ dev_warn(adev->dev, "waiting IDH_FLR_NOTIFICATION_CMPL timeout\n"); ++ + flr_done: + atomic_set(&adev->reset_domain->in_gpu_reset, 0); + up_write(&adev->reset_domain->sem); +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index f6017be8f9957e..bcf0dc05c76765 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -11069,7 +11069,8 @@ int amdgpu_dm_process_dmub_aux_transfer_sync( + /* The reply is stored in the top nibble of the command. */ + payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF; + +- if (!payload->write && p_notify->aux_reply.length) ++ /*write req may receive a byte indicating partially written number as well*/ ++ if (p_notify->aux_reply.length) + memcpy(payload->data, p_notify->aux_reply.data, + p_notify->aux_reply.length); + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index c0cacd501c83eb..2698e5c74ddfda 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -59,6 +59,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + enum aux_return_code_type operation_result; + struct amdgpu_device *adev; + struct ddc_service *ddc; ++ uint8_t copy[16]; + + if (WARN_ON(msg->size > 16)) + return -E2BIG; +@@ -74,6 +75,11 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + (msg->request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0; + payload.defer_delay = 0; + ++ if (payload.write) { ++ memcpy(copy, msg->buffer, msg->size); ++ payload.data = copy; ++ } ++ + result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, + &operation_result); + +@@ -97,9 +103,9 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + */ + if (payload.write && result >= 0) { + if (result) { +- /*one byte indicating partially written bytes. Force 0 to retry*/ +- drm_info(adev_to_drm(adev), "amdgpu: AUX partially written\n"); +- result = 0; ++ /*one byte indicating partially written bytes*/ ++ drm_dbg_dp(adev_to_drm(adev), "amdgpu: AUX partially written\n"); ++ result = payload.data[0]; + } else if (!payload.reply[0]) + /*I2C_ACK|AUX_ACK*/ + result = msg->size; +@@ -124,11 +130,11 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + break; + } + +- drm_info(adev_to_drm(adev), "amdgpu: DP AUX transfer fail:%d\n", operation_result); ++ drm_dbg_dp(adev_to_drm(adev), "amdgpu: DP AUX transfer fail:%d\n", operation_result); + } + + if (payload.reply[0]) +- drm_info(adev_to_drm(adev), "amdgpu: AUX reply command not ACK: 0x%02x.", ++ drm_dbg_dp(adev_to_drm(adev), "amdgpu: AUX reply command not ACK: 0x%02x.", + payload.reply[0]); + + return result; +diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c +index 3b81468a1df297..0bf70664c35ee1 100644 +--- a/drivers/hid/hid-thrustmaster.c ++++ b/drivers/hid/hid-thrustmaster.c +@@ -174,6 +174,7 @@ static void thrustmaster_interrupts(struct hid_device *hdev) + u8 ep_addr[2] = {b_ep, 0}; + + if (!usb_check_int_endpoints(usbif, ep_addr)) { ++ kfree(send_buf); + hid_err(hdev, "Unexpected non-int endpoint\n"); + return; + } +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index ad74cbc9a0aa59..45de01dea4b1c0 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -142,11 +142,12 @@ static int uclogic_input_configured(struct hid_device *hdev, + suffix = "System Control"; + break; + } +- } +- +- if (suffix) ++ } else { + hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s %s", hdev->name, suffix); ++ if (!hi->input->name) ++ return -ENOMEM; ++ } + + return 0; + } +diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c +index 47e1bd8de9fcf0..53026356475ac1 100644 +--- a/drivers/hv/channel.c ++++ b/drivers/hv/channel.c +@@ -1113,68 +1113,10 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, + EXPORT_SYMBOL(vmbus_sendpacket); + + /* +- * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer +- * packets using a GPADL Direct packet type. This interface allows you +- * to control notifying the host. This will be useful for sending +- * batched data. Also the sender can control the send flags +- * explicitly. +- */ +-int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, +- struct hv_page_buffer pagebuffers[], +- u32 pagecount, void *buffer, u32 bufferlen, +- u64 requestid) +-{ +- int i; +- struct vmbus_channel_packet_page_buffer desc; +- u32 descsize; +- u32 packetlen; +- u32 packetlen_aligned; +- struct kvec bufferlist[3]; +- u64 aligned_data = 0; +- +- if (pagecount > MAX_PAGE_BUFFER_COUNT) +- return -EINVAL; +- +- /* +- * Adjust the size down since vmbus_channel_packet_page_buffer is the +- * largest size we support +- */ +- descsize = sizeof(struct vmbus_channel_packet_page_buffer) - +- ((MAX_PAGE_BUFFER_COUNT - pagecount) * +- sizeof(struct hv_page_buffer)); +- packetlen = descsize + bufferlen; +- packetlen_aligned = ALIGN(packetlen, sizeof(u64)); +- +- /* Setup the descriptor */ +- desc.type = VM_PKT_DATA_USING_GPA_DIRECT; +- desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; +- desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ +- desc.length8 = (u16)(packetlen_aligned >> 3); +- desc.transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */ +- desc.reserved = 0; +- desc.rangecount = pagecount; +- +- for (i = 0; i < pagecount; i++) { +- desc.range[i].len = pagebuffers[i].len; +- desc.range[i].offset = pagebuffers[i].offset; +- desc.range[i].pfn = pagebuffers[i].pfn; +- } +- +- bufferlist[0].iov_base = &desc; +- bufferlist[0].iov_len = descsize; +- bufferlist[1].iov_base = buffer; +- bufferlist[1].iov_len = bufferlen; +- bufferlist[2].iov_base = &aligned_data; +- bufferlist[2].iov_len = (packetlen_aligned - packetlen); +- +- return hv_ringbuffer_write(channel, bufferlist, 3, requestid, NULL); +-} +-EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); +- +-/* +- * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet ++ * vmbus_sendpacket_mpb_desc - Send one or more multi-page buffer packets + * using a GPADL Direct packet type. +- * The buffer includes the vmbus descriptor. ++ * The desc argument must include space for the VMBus descriptor. The ++ * rangecount field must already be set. + */ + int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + struct vmbus_packet_mpb_array *desc, +@@ -1196,7 +1138,6 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + desc->length8 = (u16)(packetlen_aligned >> 3); + desc->transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */ + desc->reserved = 0; +- desc->rangecount = 1; + + bufferlist[0].iov_base = desc; + bufferlist[0].iov_len = desc_size; +diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c +index 98648c679a55c1..2ace3aafe49788 100644 +--- a/drivers/iio/adc/ad7266.c ++++ b/drivers/iio/adc/ad7266.c +@@ -44,7 +44,7 @@ struct ad7266_state { + */ + struct { + __be16 sample[2]; +- s64 timestamp; ++ aligned_s64 timestamp; + } data __aligned(IIO_DMA_MINALIGN); + }; + +diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c +index 74b0c85944bd61..967f06cd3f94e7 100644 +--- a/drivers/iio/adc/ad7768-1.c ++++ b/drivers/iio/adc/ad7768-1.c +@@ -169,7 +169,7 @@ struct ad7768_state { + union { + struct { + __be32 chan; +- s64 timestamp; ++ aligned_s64 timestamp; + } scan; + __be32 d32; + u8 d8[2]; +diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c +index 814ce0aad1cccd..4085a36cd1db75 100644 +--- a/drivers/iio/chemical/sps30.c ++++ b/drivers/iio/chemical/sps30.c +@@ -108,7 +108,7 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p) + int ret; + struct { + s32 data[4]; /* PM1, PM2P5, PM4, PM10 */ +- s64 ts; ++ aligned_s64 ts; + } scan; + + mutex_lock(&state->lock); +diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c +index fec87c9030abdc..fffd144d509eb0 100644 +--- a/drivers/infiniband/sw/rxe/rxe_cq.c ++++ b/drivers/infiniband/sw/rxe/rxe_cq.c +@@ -56,11 +56,8 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, + + err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, udata, + cq->queue->buf, cq->queue->buf_size, &cq->queue->ip); +- if (err) { +- vfree(cq->queue->buf); +- kfree(cq->queue); ++ if (err) + return err; +- } + + cq->is_user = uresp; + +diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c +index 1a367e64bc3b1d..843e50b5a0ec57 100644 +--- a/drivers/net/dsa/sja1105/sja1105_main.c ++++ b/drivers/net/dsa/sja1105/sja1105_main.c +@@ -2076,6 +2076,7 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port, + switch (state) { + case BR_STATE_DISABLED: + case BR_STATE_BLOCKING: ++ case BR_STATE_LISTENING: + /* From UM10944 description of DRPDTAG (why put this there?): + * "Management traffic flows to the port regardless of the state + * of the INGRESS flag". So BPDUs are still be allowed to pass. +@@ -2085,11 +2086,6 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port, + mac[port].egress = false; + mac[port].dyn_learn = false; + break; +- case BR_STATE_LISTENING: +- mac[port].ingress = true; +- mac[port].egress = false; +- mac[port].dyn_learn = false; +- break; + case BR_STATE_LEARNING: + mac[port].ingress = true; + mac[port].egress = false; +diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c +index 4325d0ace1f268..6f45f4d9fba71f 100644 +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -1016,22 +1016,15 @@ static void macb_update_stats(struct macb *bp) + + static int macb_halt_tx(struct macb *bp) + { +- unsigned long halt_time, timeout; +- u32 status; ++ u32 status; + + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT)); + +- timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT); +- do { +- halt_time = jiffies; +- status = macb_readl(bp, TSR); +- if (!(status & MACB_BIT(TGO))) +- return 0; +- +- udelay(250); +- } while (time_before(halt_time, timeout)); +- +- return -ETIMEDOUT; ++ /* Poll TSR until TGO is cleared or timeout. */ ++ return read_poll_timeout_atomic(macb_readl, status, ++ !(status & MACB_BIT(TGO)), ++ 250, MACB_HALT_TIMEOUT, false, ++ bp, TSR); + } + + static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budget) +diff --git a/drivers/net/ethernet/engleder/tsnep_hw.h b/drivers/net/ethernet/engleder/tsnep_hw.h +index 55e1caf193a69d..64c97eb66f6715 100644 +--- a/drivers/net/ethernet/engleder/tsnep_hw.h ++++ b/drivers/net/ethernet/engleder/tsnep_hw.h +@@ -181,6 +181,8 @@ struct tsnep_gcl_operation { + #define TSNEP_DESC_SIZE 256 + #define TSNEP_DESC_SIZE_DATA_AFTER 2048 + #define TSNEP_DESC_OFFSET 128 ++#define TSNEP_DESC_SIZE_DATA_AFTER_INLINE (64 - sizeof(struct tsnep_tx_desc) + \ ++ sizeof_field(struct tsnep_tx_desc, tx)) + #define TSNEP_DESC_OWNER_COUNTER_MASK 0xC0000000 + #define TSNEP_DESC_OWNER_COUNTER_SHIFT 30 + #define TSNEP_DESC_LENGTH_MASK 0x00003FFF +diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c +index 4f36b29d66c860..215ae6745932ae 100644 +--- a/drivers/net/ethernet/engleder/tsnep_main.c ++++ b/drivers/net/ethernet/engleder/tsnep_main.c +@@ -51,12 +51,24 @@ + #define TSNEP_COALESCE_USECS_MAX ((ECM_INT_DELAY_MASK >> ECM_INT_DELAY_SHIFT) * \ + ECM_INT_DELAY_BASE_US + ECM_INT_DELAY_BASE_US - 1) + +-#define TSNEP_TX_TYPE_SKB BIT(0) +-#define TSNEP_TX_TYPE_SKB_FRAG BIT(1) +-#define TSNEP_TX_TYPE_XDP_TX BIT(2) +-#define TSNEP_TX_TYPE_XDP_NDO BIT(3) +-#define TSNEP_TX_TYPE_XDP (TSNEP_TX_TYPE_XDP_TX | TSNEP_TX_TYPE_XDP_NDO) +-#define TSNEP_TX_TYPE_XSK BIT(4) ++/* mapping type */ ++#define TSNEP_TX_TYPE_MAP BIT(0) ++#define TSNEP_TX_TYPE_MAP_PAGE BIT(1) ++#define TSNEP_TX_TYPE_INLINE BIT(2) ++/* buffer type */ ++#define TSNEP_TX_TYPE_SKB BIT(8) ++#define TSNEP_TX_TYPE_SKB_MAP (TSNEP_TX_TYPE_SKB | TSNEP_TX_TYPE_MAP) ++#define TSNEP_TX_TYPE_SKB_INLINE (TSNEP_TX_TYPE_SKB | TSNEP_TX_TYPE_INLINE) ++#define TSNEP_TX_TYPE_SKB_FRAG BIT(9) ++#define TSNEP_TX_TYPE_SKB_FRAG_MAP_PAGE (TSNEP_TX_TYPE_SKB_FRAG | TSNEP_TX_TYPE_MAP_PAGE) ++#define TSNEP_TX_TYPE_SKB_FRAG_INLINE (TSNEP_TX_TYPE_SKB_FRAG | TSNEP_TX_TYPE_INLINE) ++#define TSNEP_TX_TYPE_XDP_TX BIT(10) ++#define TSNEP_TX_TYPE_XDP_NDO BIT(11) ++#define TSNEP_TX_TYPE_XDP_NDO_MAP_PAGE (TSNEP_TX_TYPE_XDP_NDO | TSNEP_TX_TYPE_MAP_PAGE) ++#define TSNEP_TX_TYPE_XDP (TSNEP_TX_TYPE_XDP_TX | TSNEP_TX_TYPE_XDP_NDO) ++#define TSNEP_TX_TYPE_XSK BIT(12) ++#define TSNEP_TX_TYPE_TSTAMP BIT(13) ++#define TSNEP_TX_TYPE_SKB_TSTAMP (TSNEP_TX_TYPE_SKB | TSNEP_TX_TYPE_TSTAMP) + + #define TSNEP_XDP_TX BIT(0) + #define TSNEP_XDP_REDIRECT BIT(1) +@@ -375,8 +387,7 @@ static void tsnep_tx_activate(struct tsnep_tx *tx, int index, int length, + if (entry->skb) { + entry->properties = length & TSNEP_DESC_LENGTH_MASK; + entry->properties |= TSNEP_DESC_INTERRUPT_FLAG; +- if ((entry->type & TSNEP_TX_TYPE_SKB) && +- (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS)) ++ if ((entry->type & TSNEP_TX_TYPE_SKB_TSTAMP) == TSNEP_TX_TYPE_SKB_TSTAMP) + entry->properties |= TSNEP_DESC_EXTENDED_WRITEBACK_FLAG; + + /* toggle user flag to prevent false acknowledge +@@ -416,6 +427,8 @@ static void tsnep_tx_activate(struct tsnep_tx *tx, int index, int length, + entry->properties |= TSNEP_TX_DESC_OWNER_USER_FLAG; + entry->desc->more_properties = + __cpu_to_le32(entry->len & TSNEP_DESC_LENGTH_MASK); ++ if (entry->type & TSNEP_TX_TYPE_INLINE) ++ entry->properties |= TSNEP_TX_DESC_DATA_AFTER_DESC_FLAG; + + /* descriptor properties shall be written last, because valid data is + * signaled there +@@ -433,39 +446,83 @@ static int tsnep_tx_desc_available(struct tsnep_tx *tx) + return tx->read - tx->write - 1; + } + +-static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count) ++static int tsnep_tx_map_frag(skb_frag_t *frag, struct tsnep_tx_entry *entry, ++ struct device *dmadev, dma_addr_t *dma) ++{ ++ unsigned int len; ++ int mapped; ++ ++ len = skb_frag_size(frag); ++ if (likely(len > TSNEP_DESC_SIZE_DATA_AFTER_INLINE)) { ++ *dma = skb_frag_dma_map(dmadev, frag, 0, len, DMA_TO_DEVICE); ++ if (dma_mapping_error(dmadev, *dma)) ++ return -ENOMEM; ++ entry->type = TSNEP_TX_TYPE_SKB_FRAG_MAP_PAGE; ++ mapped = 1; ++ } else { ++ void *fragdata = skb_frag_address_safe(frag); ++ ++ if (likely(fragdata)) { ++ memcpy(&entry->desc->tx, fragdata, len); ++ } else { ++ struct page *page = skb_frag_page(frag); ++ ++ fragdata = kmap_local_page(page); ++ memcpy(&entry->desc->tx, fragdata + skb_frag_off(frag), ++ len); ++ kunmap_local(fragdata); ++ } ++ entry->type = TSNEP_TX_TYPE_SKB_FRAG_INLINE; ++ mapped = 0; ++ } ++ ++ return mapped; ++} ++ ++static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count, ++ bool do_tstamp) + { + struct device *dmadev = tx->adapter->dmadev; + struct tsnep_tx_entry *entry; + unsigned int len; +- dma_addr_t dma; + int map_len = 0; +- int i; ++ dma_addr_t dma; ++ int i, mapped; + + for (i = 0; i < count; i++) { + entry = &tx->entry[(tx->write + i) & TSNEP_RING_MASK]; + + if (!i) { + len = skb_headlen(skb); +- dma = dma_map_single(dmadev, skb->data, len, +- DMA_TO_DEVICE); ++ if (likely(len > TSNEP_DESC_SIZE_DATA_AFTER_INLINE)) { ++ dma = dma_map_single(dmadev, skb->data, len, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dmadev, dma)) ++ return -ENOMEM; ++ entry->type = TSNEP_TX_TYPE_SKB_MAP; ++ mapped = 1; ++ } else { ++ memcpy(&entry->desc->tx, skb->data, len); ++ entry->type = TSNEP_TX_TYPE_SKB_INLINE; ++ mapped = 0; ++ } + +- entry->type = TSNEP_TX_TYPE_SKB; ++ if (do_tstamp) ++ entry->type |= TSNEP_TX_TYPE_TSTAMP; + } else { +- len = skb_frag_size(&skb_shinfo(skb)->frags[i - 1]); +- dma = skb_frag_dma_map(dmadev, +- &skb_shinfo(skb)->frags[i - 1], +- 0, len, DMA_TO_DEVICE); ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; + +- entry->type = TSNEP_TX_TYPE_SKB_FRAG; ++ len = skb_frag_size(frag); ++ mapped = tsnep_tx_map_frag(frag, entry, dmadev, &dma); ++ if (mapped < 0) ++ return mapped; + } +- if (dma_mapping_error(dmadev, dma)) +- return -ENOMEM; + + entry->len = len; +- dma_unmap_addr_set(entry, dma, dma); +- +- entry->desc->tx = __cpu_to_le64(dma); ++ if (likely(mapped)) { ++ dma_unmap_addr_set(entry, dma, dma); ++ entry->desc->tx = __cpu_to_le64(dma); ++ } + + map_len += len; + } +@@ -484,13 +541,12 @@ static int tsnep_tx_unmap(struct tsnep_tx *tx, int index, int count) + entry = &tx->entry[(index + i) & TSNEP_RING_MASK]; + + if (entry->len) { +- if (entry->type & TSNEP_TX_TYPE_SKB) ++ if (entry->type & TSNEP_TX_TYPE_MAP) + dma_unmap_single(dmadev, + dma_unmap_addr(entry, dma), + dma_unmap_len(entry, len), + DMA_TO_DEVICE); +- else if (entry->type & +- (TSNEP_TX_TYPE_SKB_FRAG | TSNEP_TX_TYPE_XDP_NDO)) ++ else if (entry->type & TSNEP_TX_TYPE_MAP_PAGE) + dma_unmap_page(dmadev, + dma_unmap_addr(entry, dma), + dma_unmap_len(entry, len), +@@ -506,11 +562,12 @@ static int tsnep_tx_unmap(struct tsnep_tx *tx, int index, int count) + static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, + struct tsnep_tx *tx) + { +- int count = 1; + struct tsnep_tx_entry *entry; ++ bool do_tstamp = false; ++ int count = 1; + int length; +- int i; + int retval; ++ int i; + + if (skb_shinfo(skb)->nr_frags > 0) + count += skb_shinfo(skb)->nr_frags; +@@ -527,7 +584,13 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, + entry = &tx->entry[tx->write]; + entry->skb = skb; + +- retval = tsnep_tx_map(skb, tx, count); ++ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && ++ tx->adapter->hwtstamp_config.tx_type == HWTSTAMP_TX_ON) { ++ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; ++ do_tstamp = true; ++ } ++ ++ retval = tsnep_tx_map(skb, tx, count, do_tstamp); + if (retval < 0) { + tsnep_tx_unmap(tx, tx->write, count); + dev_kfree_skb_any(entry->skb); +@@ -539,9 +602,6 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, + } + length = retval; + +- if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) +- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; +- + for (i = 0; i < count; i++) + tsnep_tx_activate(tx, (tx->write + i) & TSNEP_RING_MASK, length, + i == count - 1); +@@ -586,7 +646,7 @@ static int tsnep_xdp_tx_map(struct xdp_frame *xdpf, struct tsnep_tx *tx, + if (dma_mapping_error(dmadev, dma)) + return -ENOMEM; + +- entry->type = TSNEP_TX_TYPE_XDP_NDO; ++ entry->type = TSNEP_TX_TYPE_XDP_NDO_MAP_PAGE; + } else { + page = unlikely(frag) ? skb_frag_page(frag) : + virt_to_page(xdpf->data); +@@ -792,8 +852,7 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget) + + length = tsnep_tx_unmap(tx, tx->read, count); + +- if ((entry->type & TSNEP_TX_TYPE_SKB) && +- (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS) && ++ if (((entry->type & TSNEP_TX_TYPE_SKB_TSTAMP) == TSNEP_TX_TYPE_SKB_TSTAMP) && + (__le32_to_cpu(entry->desc_wb->properties) & + TSNEP_DESC_EXTENDED_WRITEBACK_FLAG)) { + struct skb_shared_hwtstamps hwtstamps; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +index 52792546fe00dd..339be6950c0395 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +@@ -707,6 +707,11 @@ int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) + + if (!is_lmac_valid(cgx, lmac_id)) + return -ENODEV; ++ ++ /* pass lmac as 0 for CGX_CMR_RX_STAT9-12 */ ++ if (idx >= CGX_RX_STAT_GLOBAL_INDEX) ++ lmac_id = 0; ++ + *rx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_STAT0 + (idx * 8)); + return 0; + } +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +index 6cc7a78968fc1c..74953f67a2bf9c 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +@@ -533,7 +533,8 @@ static int cn10k_mcs_write_tx_secy(struct otx2_nic *pfvf, + if (sw_tx_sc->encrypt) + sectag_tci |= (MCS_TCI_E | MCS_TCI_C); + +- policy = FIELD_PREP(MCS_TX_SECY_PLCY_MTU, secy->netdev->mtu); ++ policy = FIELD_PREP(MCS_TX_SECY_PLCY_MTU, ++ pfvf->netdev->mtu + OTX2_ETH_HLEN); + /* Write SecTag excluding AN bits(1..0) */ + policy |= FIELD_PREP(MCS_TX_SECY_PLCY_ST_TCI, sectag_tci >> 2); + policy |= FIELD_PREP(MCS_TX_SECY_PLCY_ST_OFFSET, tag_offset); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c6ccfbd4226570..cb8efc952dfda9 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4628,7 +4628,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + } + + if (mtk_is_netsys_v3_or_greater(mac->hw) && +- MTK_HAS_CAPS(mac->hw->soc->caps, MTK_ESW_BIT) && ++ MTK_HAS_CAPS(mac->hw->soc->caps, MTK_ESW) && + id == MTK_GMAC1_ID) { + mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | + MAC_SYM_PAUSE | +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 8a892614015cd9..d9dc7280302eb7 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -4136,6 +4136,10 @@ static netdev_features_t mlx5e_fix_uplink_rep_features(struct net_device *netdev + if (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + netdev_warn(netdev, "Disabling HW_VLAN CTAG FILTERING, not supported in switchdev mode\n"); + ++ features &= ~NETIF_F_HW_MACSEC; ++ if (netdev->features & NETIF_F_HW_MACSEC) ++ netdev_warn(netdev, "Disabling HW MACsec offload, not supported in switchdev mode\n"); ++ + return features; + } + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +index d15aa6b25a8884..0534b10e29c5c4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +@@ -3013,6 +3013,9 @@ static int mlxsw_sp_neigh_rif_made_sync(struct mlxsw_sp *mlxsw_sp, + .rif = rif, + }; + ++ if (!mlxsw_sp_dev_lower_is_port(mlxsw_sp_rif_dev(rif))) ++ return 0; ++ + neigh_for_each(&arp_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms); + if (rms.err) + goto err_arp; +diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c +index 99df00c30b8c6c..b5d744d2586f72 100644 +--- a/drivers/net/ethernet/qlogic/qede/qede_main.c ++++ b/drivers/net/ethernet/qlogic/qede/qede_main.c +@@ -203,7 +203,7 @@ static struct pci_driver qede_pci_driver = { + }; + + static struct qed_eth_cb_ops qede_ll_ops = { +- { ++ .common = { + #ifdef CONFIG_RFS_ACCEL + .arfs_filter_op = qede_arfs_filter_op, + #endif +diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +index 28d24d59efb84f..d57b976b904095 100644 +--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c ++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +@@ -1484,8 +1484,11 @@ static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_o + } + + cmd_op = (cmd.rsp.arg[0] & 0xff); +- if (cmd.rsp.arg[0] >> 25 == 2) +- return 2; ++ if (cmd.rsp.arg[0] >> 25 == 2) { ++ ret = 2; ++ goto out; ++ } ++ + if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) + set_bit(QLC_BC_VF_STATE, &vf->state); + else +diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h +index 810977952f950b..4c12067b07f05e 100644 +--- a/drivers/net/hyperv/hyperv_net.h ++++ b/drivers/net/hyperv/hyperv_net.h +@@ -158,7 +158,6 @@ struct hv_netvsc_packet { + u8 cp_partial; /* partial copy into send buffer */ + + u8 rmsg_size; /* RNDIS header and PPI size */ +- u8 rmsg_pgcnt; /* page count of RNDIS header and PPI */ + u8 page_buf_cnt; + + u16 q_idx; +@@ -893,6 +892,18 @@ struct nvsp_message { + sizeof(struct nvsp_message)) + #define NETVSC_MIN_IN_MSG_SIZE sizeof(struct vmpacket_descriptor) + ++/* Maximum # of contiguous data ranges that can make up a trasmitted packet. ++ * Typically it's the max SKB fragments plus 2 for the rndis packet and the ++ * linear portion of the SKB. But if MAX_SKB_FRAGS is large, the value may ++ * need to be limited to MAX_PAGE_BUFFER_COUNT, which is the max # of entries ++ * in a GPA direct packet sent to netvsp over VMBus. ++ */ ++#if MAX_SKB_FRAGS + 2 < MAX_PAGE_BUFFER_COUNT ++#define MAX_DATA_RANGES (MAX_SKB_FRAGS + 2) ++#else ++#define MAX_DATA_RANGES MAX_PAGE_BUFFER_COUNT ++#endif ++ + /* Estimated requestor size: + * out_ring_size/min_out_msg_size + in_ring_size/min_in_msg_size + */ +diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c +index b2f27e505f76c6..61584b40cb0386 100644 +--- a/drivers/net/hyperv/netvsc.c ++++ b/drivers/net/hyperv/netvsc.c +@@ -945,8 +945,7 @@ static void netvsc_copy_to_send_buf(struct netvsc_device *net_device, + + pend_size; + int i; + u32 padding = 0; +- u32 page_count = packet->cp_partial ? packet->rmsg_pgcnt : +- packet->page_buf_cnt; ++ u32 page_count = packet->cp_partial ? 1 : packet->page_buf_cnt; + u32 remain; + + /* Add padding */ +@@ -1047,6 +1046,42 @@ static int netvsc_dma_map(struct hv_device *hv_dev, + return 0; + } + ++/* Build an "array" of mpb entries describing the data to be transferred ++ * over VMBus. After the desc header fields, each "array" entry is variable ++ * size, and each entry starts after the end of the previous entry. The ++ * "offset" and "len" fields for each entry imply the size of the entry. ++ * ++ * The pfns are in HV_HYP_PAGE_SIZE, because all communication with Hyper-V ++ * uses that granularity, even if the system page size of the guest is larger. ++ * Each entry in the input "pb" array must describe a contiguous range of ++ * guest physical memory so that the pfns are sequential if the range crosses ++ * a page boundary. The offset field must be < HV_HYP_PAGE_SIZE. ++ */ ++static inline void netvsc_build_mpb_array(struct hv_page_buffer *pb, ++ u32 page_buffer_count, ++ struct vmbus_packet_mpb_array *desc, ++ u32 *desc_size) ++{ ++ struct hv_mpb_array *mpb_entry = &desc->range; ++ int i, j; ++ ++ for (i = 0; i < page_buffer_count; i++) { ++ u32 offset = pb[i].offset; ++ u32 len = pb[i].len; ++ ++ mpb_entry->offset = offset; ++ mpb_entry->len = len; ++ ++ for (j = 0; j < HVPFN_UP(offset + len); j++) ++ mpb_entry->pfn_array[j] = pb[i].pfn + j; ++ ++ mpb_entry = (struct hv_mpb_array *)&mpb_entry->pfn_array[j]; ++ } ++ ++ desc->rangecount = page_buffer_count; ++ *desc_size = (char *)mpb_entry - (char *)desc; ++} ++ + static inline int netvsc_send_pkt( + struct hv_device *device, + struct hv_netvsc_packet *packet, +@@ -1089,8 +1124,11 @@ static inline int netvsc_send_pkt( + + packet->dma_range = NULL; + if (packet->page_buf_cnt) { ++ struct vmbus_channel_packet_page_buffer desc; ++ u32 desc_size; ++ + if (packet->cp_partial) +- pb += packet->rmsg_pgcnt; ++ pb++; + + ret = netvsc_dma_map(ndev_ctx->device_ctx, packet, pb); + if (ret) { +@@ -1098,11 +1136,12 @@ static inline int netvsc_send_pkt( + goto exit; + } + +- ret = vmbus_sendpacket_pagebuffer(out_channel, +- pb, packet->page_buf_cnt, +- &nvmsg, sizeof(nvmsg), +- req_id); +- ++ netvsc_build_mpb_array(pb, packet->page_buf_cnt, ++ (struct vmbus_packet_mpb_array *)&desc, ++ &desc_size); ++ ret = vmbus_sendpacket_mpb_desc(out_channel, ++ (struct vmbus_packet_mpb_array *)&desc, ++ desc_size, &nvmsg, sizeof(nvmsg), req_id); + if (ret) + netvsc_dma_unmap(ndev_ctx->device_ctx, packet); + } else { +@@ -1251,7 +1290,7 @@ int netvsc_send(struct net_device *ndev, + packet->send_buf_index = section_index; + + if (packet->cp_partial) { +- packet->page_buf_cnt -= packet->rmsg_pgcnt; ++ packet->page_buf_cnt--; + packet->total_data_buflen = msd_len + packet->rmsg_size; + } else { + packet->page_buf_cnt = 0; +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index 8698d2db3dc8e1..ce6ac26131b347 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -325,43 +325,10 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, + return txq; + } + +-static u32 fill_pg_buf(unsigned long hvpfn, u32 offset, u32 len, +- struct hv_page_buffer *pb) +-{ +- int j = 0; +- +- hvpfn += offset >> HV_HYP_PAGE_SHIFT; +- offset = offset & ~HV_HYP_PAGE_MASK; +- +- while (len > 0) { +- unsigned long bytes; +- +- bytes = HV_HYP_PAGE_SIZE - offset; +- if (bytes > len) +- bytes = len; +- pb[j].pfn = hvpfn; +- pb[j].offset = offset; +- pb[j].len = bytes; +- +- offset += bytes; +- len -= bytes; +- +- if (offset == HV_HYP_PAGE_SIZE && len) { +- hvpfn++; +- offset = 0; +- j++; +- } +- } +- +- return j + 1; +-} +- + static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, + struct hv_netvsc_packet *packet, + struct hv_page_buffer *pb) + { +- u32 slots_used = 0; +- char *data = skb->data; + int frags = skb_shinfo(skb)->nr_frags; + int i; + +@@ -370,28 +337,27 @@ static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, + * 2. skb linear data + * 3. skb fragment data + */ +- slots_used += fill_pg_buf(virt_to_hvpfn(hdr), +- offset_in_hvpage(hdr), +- len, +- &pb[slots_used]); + ++ pb[0].offset = offset_in_hvpage(hdr); ++ pb[0].len = len; ++ pb[0].pfn = virt_to_hvpfn(hdr); + packet->rmsg_size = len; +- packet->rmsg_pgcnt = slots_used; + +- slots_used += fill_pg_buf(virt_to_hvpfn(data), +- offset_in_hvpage(data), +- skb_headlen(skb), +- &pb[slots_used]); ++ pb[1].offset = offset_in_hvpage(skb->data); ++ pb[1].len = skb_headlen(skb); ++ pb[1].pfn = virt_to_hvpfn(skb->data); + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; ++ struct hv_page_buffer *cur_pb = &pb[i + 2]; ++ u64 pfn = page_to_hvpfn(skb_frag_page(frag)); ++ u32 offset = skb_frag_off(frag); + +- slots_used += fill_pg_buf(page_to_hvpfn(skb_frag_page(frag)), +- skb_frag_off(frag), +- skb_frag_size(frag), +- &pb[slots_used]); ++ cur_pb->offset = offset_in_hvpage(offset); ++ cur_pb->len = skb_frag_size(frag); ++ cur_pb->pfn = pfn + (offset >> HV_HYP_PAGE_SHIFT); + } +- return slots_used; ++ return frags + 2; + } + + static int count_skb_frag_slots(struct sk_buff *skb) +@@ -482,7 +448,7 @@ static int netvsc_xmit(struct sk_buff *skb, struct net_device *net, bool xdp_tx) + struct net_device *vf_netdev; + u32 rndis_msg_size; + u32 hash; +- struct hv_page_buffer pb[MAX_PAGE_BUFFER_COUNT]; ++ struct hv_page_buffer pb[MAX_DATA_RANGES]; + + /* If VF is present and up then redirect packets to it. + * Skip the VF if it is marked down or has no carrier. +diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c +index af95947a87c552..09144f0ec2aa4f 100644 +--- a/drivers/net/hyperv/rndis_filter.c ++++ b/drivers/net/hyperv/rndis_filter.c +@@ -226,8 +226,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, + struct rndis_request *req) + { + struct hv_netvsc_packet *packet; +- struct hv_page_buffer page_buf[2]; +- struct hv_page_buffer *pb = page_buf; ++ struct hv_page_buffer pb; + int ret; + + /* Setup the packet to send it */ +@@ -236,27 +235,14 @@ static int rndis_filter_send_request(struct rndis_device *dev, + packet->total_data_buflen = req->request_msg.msg_len; + packet->page_buf_cnt = 1; + +- pb[0].pfn = virt_to_phys(&req->request_msg) >> +- HV_HYP_PAGE_SHIFT; +- pb[0].len = req->request_msg.msg_len; +- pb[0].offset = offset_in_hvpage(&req->request_msg); +- +- /* Add one page_buf when request_msg crossing page boundary */ +- if (pb[0].offset + pb[0].len > HV_HYP_PAGE_SIZE) { +- packet->page_buf_cnt++; +- pb[0].len = HV_HYP_PAGE_SIZE - +- pb[0].offset; +- pb[1].pfn = virt_to_phys((void *)&req->request_msg +- + pb[0].len) >> HV_HYP_PAGE_SHIFT; +- pb[1].offset = 0; +- pb[1].len = req->request_msg.msg_len - +- pb[0].len; +- } ++ pb.pfn = virt_to_phys(&req->request_msg) >> HV_HYP_PAGE_SHIFT; ++ pb.len = req->request_msg.msg_len; ++ pb.offset = offset_in_hvpage(&req->request_msg); + + trace_rndis_send(dev->ndev, 0, &req->request_msg); + + rcu_read_lock_bh(); +- ret = netvsc_send(dev->ndev, packet, NULL, pb, NULL, false); ++ ret = netvsc_send(dev->ndev, packet, NULL, &pb, NULL, false); + rcu_read_unlock_bh(); + + return ret; +diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c +index cd048659706436..b7e100710601a5 100644 +--- a/drivers/net/wireless/mediatek/mt76/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/dma.c +@@ -957,6 +957,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev) + int i; + + mt76_worker_disable(&dev->tx_worker); ++ napi_disable(&dev->tx_napi); + netif_napi_del(&dev->tx_napi); + + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index fdde38903ebcd5..1e5c8220e365ca 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -386,7 +386,7 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, __le32 *dbbuf_db, + * as it only leads to a small amount of wasted memory for the lifetime of + * the I/O. + */ +-static int nvme_pci_npages_prp(void) ++static __always_inline int nvme_pci_npages_prp(void) + { + unsigned max_bytes = (NVME_MAX_KB_SZ * 1024) + NVME_CTRL_PAGE_SIZE; + unsigned nprps = DIV_ROUND_UP(max_bytes, NVME_CTRL_PAGE_SIZE); +@@ -1107,7 +1107,9 @@ static void nvme_poll_irqdisable(struct nvme_queue *nvmeq) + WARN_ON_ONCE(test_bit(NVMEQ_POLLED, &nvmeq->flags)); + + disable_irq(pci_irq_vector(pdev, nvmeq->cq_vector)); ++ spin_lock(&nvmeq->cq_poll_lock); + nvme_poll_cq(nvmeq, NULL); ++ spin_unlock(&nvmeq->cq_poll_lock); + enable_irq(pci_irq_vector(pdev, nvmeq->cq_vector)); + } + +diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +index 6387c0d34c551c..aa578be2bcb6df 100644 +--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c ++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +@@ -101,7 +101,6 @@ struct rcar_gen3_phy { + struct rcar_gen3_chan *ch; + u32 int_enable_bits; + bool initialized; +- bool otg_initialized; + bool powered; + }; + +@@ -309,16 +308,15 @@ static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch) + return false; + } + +-static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch) ++static bool rcar_gen3_is_any_otg_rphy_initialized(struct rcar_gen3_chan *ch) + { +- int i; +- +- for (i = 0; i < NUM_OF_PHYS; i++) { +- if (ch->rphys[i].otg_initialized) +- return false; ++ for (enum rcar_gen3_phy_index i = PHY_INDEX_BOTH_HC; i <= PHY_INDEX_EHCI; ++ i++) { ++ if (ch->rphys[i].initialized) ++ return true; + } + +- return true; ++ return false; + } + + static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch) +@@ -340,7 +338,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, + bool is_b_device; + enum phy_mode cur_mode, new_mode; + +- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) ++ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) + return -EIO; + + if (sysfs_streq(buf, "host")) +@@ -378,7 +376,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, + { + struct rcar_gen3_chan *ch = dev_get_drvdata(dev); + +- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) ++ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) + return -EIO; + + return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : +@@ -391,6 +389,9 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) + void __iomem *usb2_base = ch->base; + u32 val; + ++ if (!ch->is_otg_channel || rcar_gen3_is_any_otg_rphy_initialized(ch)) ++ return; ++ + /* Should not use functions of read-modify-write a register */ + val = readl(usb2_base + USB2_LINECTRL1); + val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN | +@@ -451,16 +452,16 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) + val = readl(usb2_base + USB2_INT_ENABLE); + val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits; + writel(val, usb2_base + USB2_INT_ENABLE); +- writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); +- writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); +- +- /* Initialize otg part */ +- if (channel->is_otg_channel) { +- if (rcar_gen3_needs_init_otg(channel)) +- rcar_gen3_init_otg(channel); +- rphy->otg_initialized = true; ++ ++ if (!rcar_gen3_is_any_rphy_initialized(channel)) { ++ writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); ++ writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); + } + ++ /* Initialize otg part (only if we initialize a PHY with IRQs). */ ++ if (rphy->int_enable_bits) ++ rcar_gen3_init_otg(channel); ++ + rphy->initialized = true; + + return 0; +@@ -475,9 +476,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) + + rphy->initialized = false; + +- if (channel->is_otg_channel) +- rphy->otg_initialized = false; +- + val = readl(usb2_base + USB2_INT_ENABLE); + val &= ~rphy->int_enable_bits; + if (!rcar_gen3_is_any_rphy_initialized(channel)) +diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c +index fae6242aa730e0..23a23f2d64e586 100644 +--- a/drivers/phy/tegra/xusb-tegra186.c ++++ b/drivers/phy/tegra/xusb-tegra186.c +@@ -237,6 +237,8 @@ + #define DATA0_VAL_PD BIT(1) + #define USE_XUSB_AO BIT(4) + ++#define TEGRA_UTMI_PAD_MAX 4 ++ + #define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \ + { \ + .name = _name, \ +@@ -269,7 +271,7 @@ struct tegra186_xusb_padctl { + + /* UTMI bias and tracking */ + struct clk *usb2_trk_clk; +- unsigned int bias_pad_enable; ++ DECLARE_BITMAP(utmi_pad_enabled, TEGRA_UTMI_PAD_MAX); + + /* padctl context */ + struct tegra186_xusb_padctl_context context; +@@ -603,12 +605,8 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) + u32 value; + int err; + +- mutex_lock(&padctl->lock); +- +- if (priv->bias_pad_enable++ > 0) { +- mutex_unlock(&padctl->lock); ++ if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX)) + return; +- } + + err = clk_prepare_enable(priv->usb2_trk_clk); + if (err < 0) +@@ -658,8 +656,6 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) + } else { + clk_disable_unprepare(priv->usb2_trk_clk); + } +- +- mutex_unlock(&padctl->lock); + } + + static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) +@@ -667,17 +663,8 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) + struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); + u32 value; + +- mutex_lock(&padctl->lock); +- +- if (WARN_ON(priv->bias_pad_enable == 0)) { +- mutex_unlock(&padctl->lock); +- return; +- } +- +- if (--priv->bias_pad_enable > 0) { +- mutex_unlock(&padctl->lock); ++ if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX)) + return; +- } + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + value |= USB2_PD_TRK; +@@ -690,13 +677,13 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) + clk_disable_unprepare(priv->usb2_trk_clk); + } + +- mutex_unlock(&padctl->lock); + } + + static void tegra186_utmi_pad_power_on(struct phy *phy) + { + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; ++ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); + struct tegra_xusb_usb2_port *port; + struct device *dev = padctl->dev; + unsigned int index = lane->index; +@@ -705,9 +692,16 @@ static void tegra186_utmi_pad_power_on(struct phy *phy) + if (!phy) + return; + ++ mutex_lock(&padctl->lock); ++ if (test_bit(index, priv->utmi_pad_enabled)) { ++ mutex_unlock(&padctl->lock); ++ return; ++ } ++ + port = tegra_xusb_find_usb2_port(padctl, index); + if (!port) { + dev_err(dev, "no port found for USB2 lane %u\n", index); ++ mutex_unlock(&padctl->lock); + return; + } + +@@ -724,18 +718,28 @@ static void tegra186_utmi_pad_power_on(struct phy *phy) + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + value &= ~USB2_OTG_PD_DR; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); ++ ++ set_bit(index, priv->utmi_pad_enabled); ++ mutex_unlock(&padctl->lock); + } + + static void tegra186_utmi_pad_power_down(struct phy *phy) + { + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; ++ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); + unsigned int index = lane->index; + u32 value; + + if (!phy) + return; + ++ mutex_lock(&padctl->lock); ++ if (!test_bit(index, priv->utmi_pad_enabled)) { ++ mutex_unlock(&padctl->lock); ++ return; ++ } ++ + dev_dbg(padctl->dev, "power down UTMI pad %u\n", index); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); +@@ -748,7 +752,11 @@ static void tegra186_utmi_pad_power_down(struct phy *phy) + + udelay(2); + ++ clear_bit(index, priv->utmi_pad_enabled); ++ + tegra186_utmi_bias_pad_power_off(padctl); ++ ++ mutex_unlock(&padctl->lock); + } + + static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl, +diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c +index 983a6e6173bd21..3a04a56ca52de9 100644 +--- a/drivers/phy/tegra/xusb.c ++++ b/drivers/phy/tegra/xusb.c +@@ -548,16 +548,16 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port, + + err = dev_set_name(&port->dev, "%s-%u", name, index); + if (err < 0) +- goto unregister; ++ goto put_device; + + err = device_add(&port->dev); + if (err < 0) +- goto unregister; ++ goto put_device; + + return 0; + +-unregister: +- device_unregister(&port->dev); ++put_device: ++ put_device(&port->dev); + return err; + } + +diff --git a/drivers/platform/x86/amd/pmc/pmc-quirks.c b/drivers/platform/x86/amd/pmc/pmc-quirks.c +index b4f49720c87f62..2e3f6fc67c568d 100644 +--- a/drivers/platform/x86/amd/pmc/pmc-quirks.c ++++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c +@@ -217,6 +217,13 @@ static const struct dmi_system_id fwbug_list[] = { + DMI_MATCH(DMI_BIOS_VERSION, "03.05"), + } + }, ++ { ++ .ident = "MECHREVO Wujie 14X (GX4HRXL)", ++ .driver_data = &quirk_spurious_8042, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"), ++ } ++ }, + {} + }; + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 222e429931ef9e..2c894ea8aa8174 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -4404,7 +4404,8 @@ static int asus_wmi_add(struct platform_device *pdev) + goto fail_leds; + + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result); +- if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) ++ if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) == ++ (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) + asus->driver->wlan_ctrl_by_user = 1; + + if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) { +diff --git a/drivers/regulator/max20086-regulator.c b/drivers/regulator/max20086-regulator.c +index 32f47b896fd1e2..ebfbcadbca5295 100644 +--- a/drivers/regulator/max20086-regulator.c ++++ b/drivers/regulator/max20086-regulator.c +@@ -132,7 +132,7 @@ static int max20086_regulators_register(struct max20086 *chip) + + static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on) + { +- struct of_regulator_match matches[MAX20086_MAX_REGULATORS] = { }; ++ struct of_regulator_match *matches; + struct device_node *node; + unsigned int i; + int ret; +@@ -143,6 +143,11 @@ static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on) + return -ENODEV; + } + ++ matches = devm_kcalloc(chip->dev, chip->info->num_outputs, ++ sizeof(*matches), GFP_KERNEL); ++ if (!matches) ++ return -ENOMEM; ++ + for (i = 0; i < chip->info->num_outputs; ++i) + matches[i].name = max20086_output_names[i]; + +diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c +index 203df5e53b1a84..9bbabae253e53b 100644 +--- a/drivers/scsi/sd_zbc.c ++++ b/drivers/scsi/sd_zbc.c +@@ -202,6 +202,7 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, + unsigned int nr_zones, size_t *buflen) + { + struct request_queue *q = sdkp->disk->queue; ++ unsigned int max_segments; + size_t bufsize; + void *buf; + +@@ -213,12 +214,15 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, + * Furthermore, since the report zone command cannot be split, make + * sure that the allocated buffer can always be mapped by limiting the + * number of pages allocated to the HBA max segments limit. ++ * Since max segments can be larger than the max inline bio vectors, ++ * further limit the allocated buffer to BIO_MAX_INLINE_VECS. + */ + nr_zones = min(nr_zones, sdkp->zone_info.nr_zones); + bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE); + bufsize = min_t(size_t, bufsize, + queue_max_hw_sectors(q) << SECTOR_SHIFT); +- bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); ++ max_segments = min(BIO_MAX_INLINE_VECS, queue_max_segments(q)); ++ bufsize = min_t(size_t, bufsize, max_segments << PAGE_SHIFT); + + while (bufsize >= SECTOR_SIZE) { + buf = kvzalloc(bufsize, GFP_KERNEL | __GFP_NORETRY); +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index b8186feccdf5aa..48b0ca92b44fb3 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1819,6 +1819,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) + return SCSI_MLQUEUE_DEVICE_BUSY; + } + ++ payload->rangecount = 1; + payload->range.len = length; + payload->range.offset = offset_in_hvpg; + +diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c +index bbf2015d8e5cce..69b6c87c5525e0 100644 +--- a/drivers/spi/spi-loopback-test.c ++++ b/drivers/spi/spi-loopback-test.c +@@ -421,7 +421,7 @@ MODULE_LICENSE("GPL"); + static void spi_test_print_hex_dump(char *pre, const void *ptr, size_t len) + { + /* limit the hex_dump */ +- if (len < 1024) { ++ if (len <= 1024) { + print_hex_dump(KERN_INFO, pre, + DUMP_PREFIX_OFFSET, 16, 1, + ptr, len, 0); +diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c +index 147d7052794f77..8d7ce4c556aa1d 100644 +--- a/drivers/spi/spi-tegra114.c ++++ b/drivers/spi/spi-tegra114.c +@@ -728,9 +728,9 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi) + u32 inactive_cycles; + u8 cs_state; + +- if ((setup->unit && setup->unit != SPI_DELAY_UNIT_SCK) || +- (hold->unit && hold->unit != SPI_DELAY_UNIT_SCK) || +- (inactive->unit && inactive->unit != SPI_DELAY_UNIT_SCK)) { ++ if ((setup->value && setup->unit != SPI_DELAY_UNIT_SCK) || ++ (hold->value && hold->unit != SPI_DELAY_UNIT_SCK) || ++ (inactive->value && inactive->unit != SPI_DELAY_UNIT_SCK)) { + dev_err(&spi->dev, + "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n", + SPI_DELAY_UNIT_SCK); +diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c +index b7dada064890bd..90536f47906c33 100644 +--- a/drivers/usb/gadget/function/f_midi2.c ++++ b/drivers/usb/gadget/function/f_midi2.c +@@ -475,7 +475,7 @@ static void reply_ump_stream_ep_info(struct f_midi2_ep *ep) + /* reply a UMP EP device info */ + static void reply_ump_stream_ep_device(struct f_midi2_ep *ep) + { +- struct snd_ump_stream_msg_devince_info rep = { ++ struct snd_ump_stream_msg_device_info rep = { + .type = UMP_MSG_TYPE_STREAM, + .status = UMP_STREAM_MSG_STATUS_DEVICE_INFO, + .manufacture_id = ep->info.manufacturer, +diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c +index 8c19081c325542..e3b5fa3b5f955d 100644 +--- a/drivers/usb/typec/ucsi/displayport.c ++++ b/drivers/usb/typec/ucsi/displayport.c +@@ -54,7 +54,8 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) + u8 cur = 0; + int ret; + +- mutex_lock(&dp->con->lock); ++ if (!ucsi_con_mutex_lock(dp->con)) ++ return -ENOTCONN; + + if (!dp->override && dp->initialized) { + const struct typec_altmode *p = typec_altmode_get_partner(alt); +@@ -100,7 +101,7 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) + schedule_work(&dp->work); + ret = 0; + err_unlock: +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + + return ret; + } +@@ -112,7 +113,8 @@ static int ucsi_displayport_exit(struct typec_altmode *alt) + u64 command; + int ret = 0; + +- mutex_lock(&dp->con->lock); ++ if (!ucsi_con_mutex_lock(dp->con)) ++ return -ENOTCONN; + + if (!dp->override) { + const struct typec_altmode *p = typec_altmode_get_partner(alt); +@@ -144,7 +146,7 @@ static int ucsi_displayport_exit(struct typec_altmode *alt) + schedule_work(&dp->work); + + out_unlock: +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + + return ret; + } +@@ -202,20 +204,21 @@ static int ucsi_displayport_vdm(struct typec_altmode *alt, + int cmd = PD_VDO_CMD(header); + int svdm_version; + +- mutex_lock(&dp->con->lock); ++ if (!ucsi_con_mutex_lock(dp->con)) ++ return -ENOTCONN; + + if (!dp->override && dp->initialized) { + const struct typec_altmode *p = typec_altmode_get_partner(alt); + + dev_warn(&p->dev, + "firmware doesn't support alternate mode overriding\n"); +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + return -EOPNOTSUPP; + } + + svdm_version = typec_altmode_get_svdm_version(alt); + if (svdm_version < 0) { +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + return svdm_version; + } + +@@ -259,7 +262,7 @@ static int ucsi_displayport_vdm(struct typec_altmode *alt, + break; + } + +- mutex_unlock(&dp->con->lock); ++ ucsi_con_mutex_unlock(dp->con); + + return 0; + } +diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c +index 29a04d6795012d..ea98bc5674940d 100644 +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -1559,6 +1559,40 @@ void ucsi_set_drvdata(struct ucsi *ucsi, void *data) + } + EXPORT_SYMBOL_GPL(ucsi_set_drvdata); + ++/** ++ * ucsi_con_mutex_lock - Acquire the connector mutex ++ * @con: The connector interface to lock ++ * ++ * Returns true on success, false if the connector is disconnected ++ */ ++bool ucsi_con_mutex_lock(struct ucsi_connector *con) ++{ ++ bool mutex_locked = false; ++ bool connected = true; ++ ++ while (connected && !mutex_locked) { ++ mutex_locked = mutex_trylock(&con->lock) != 0; ++ connected = con->status.flags & UCSI_CONSTAT_CONNECTED; ++ if (connected && !mutex_locked) ++ msleep(20); ++ } ++ ++ connected = connected && con->partner; ++ if (!connected && mutex_locked) ++ mutex_unlock(&con->lock); ++ ++ return connected; ++} ++ ++/** ++ * ucsi_con_mutex_unlock - Release the connector mutex ++ * @con: The connector interface to unlock ++ */ ++void ucsi_con_mutex_unlock(struct ucsi_connector *con) ++{ ++ mutex_unlock(&con->lock); ++} ++ + /** + * ucsi_create - Allocate UCSI instance + * @dev: Device interface to the PPM (Platform Policy Manager) +diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h +index 921ef0e115cffc..3bb23a2ea547ac 100644 +--- a/drivers/usb/typec/ucsi/ucsi.h ++++ b/drivers/usb/typec/ucsi/ucsi.h +@@ -79,6 +79,8 @@ int ucsi_register(struct ucsi *ucsi); + void ucsi_unregister(struct ucsi *ucsi); + void *ucsi_get_drvdata(struct ucsi *ucsi); + void ucsi_set_drvdata(struct ucsi *ucsi, void *data); ++bool ucsi_con_mutex_lock(struct ucsi_connector *con); ++void ucsi_con_mutex_unlock(struct ucsi_connector *con); + + void ucsi_connector_change(struct ucsi *ucsi, u8 num); + +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index fb2c8d14327ae1..3ff7d2e47c7e90 100644 +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -110,25 +110,6 @@ static struct linux_binfmt elf_format = { + + #define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE)) + +-static int set_brk(unsigned long start, unsigned long end, int prot) +-{ +- start = ELF_PAGEALIGN(start); +- end = ELF_PAGEALIGN(end); +- if (end > start) { +- /* +- * Map the last of the bss segment. +- * If the header is requesting these pages to be +- * executable, honour that (ppc32 needs this). +- */ +- int error = vm_brk_flags(start, end - start, +- prot & PROT_EXEC ? VM_EXEC : 0); +- if (error) +- return error; +- } +- current->mm->start_brk = current->mm->brk = end; +- return 0; +-} +- + /* We need to explicitly zero any fractional pages + after the data section (i.e. bss). This would + contain the junk from the file that should not +@@ -406,6 +387,51 @@ static unsigned long elf_map(struct file *filep, unsigned long addr, + return(map_addr); + } + ++static unsigned long elf_load(struct file *filep, unsigned long addr, ++ const struct elf_phdr *eppnt, int prot, int type, ++ unsigned long total_size) ++{ ++ unsigned long zero_start, zero_end; ++ unsigned long map_addr; ++ ++ if (eppnt->p_filesz) { ++ map_addr = elf_map(filep, addr, eppnt, prot, type, total_size); ++ if (BAD_ADDR(map_addr)) ++ return map_addr; ++ if (eppnt->p_memsz > eppnt->p_filesz) { ++ zero_start = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) + ++ eppnt->p_filesz; ++ zero_end = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) + ++ eppnt->p_memsz; ++ ++ /* Zero the end of the last mapped page */ ++ padzero(zero_start); ++ } ++ } else { ++ map_addr = zero_start = ELF_PAGESTART(addr); ++ zero_end = zero_start + ELF_PAGEOFFSET(eppnt->p_vaddr) + ++ eppnt->p_memsz; ++ } ++ if (eppnt->p_memsz > eppnt->p_filesz) { ++ /* ++ * Map the last of the segment. ++ * If the header is requesting these pages to be ++ * executable, honour that (ppc32 needs this). ++ */ ++ int error; ++ ++ zero_start = ELF_PAGEALIGN(zero_start); ++ zero_end = ELF_PAGEALIGN(zero_end); ++ ++ error = vm_brk_flags(zero_start, zero_end - zero_start, ++ prot & PROT_EXEC ? VM_EXEC : 0); ++ if (error) ++ map_addr = error; ++ } ++ return map_addr; ++} ++ ++ + static unsigned long total_mapping_size(const struct elf_phdr *phdr, int nr) + { + elf_addr_t min_addr = -1; +@@ -828,8 +854,8 @@ static int load_elf_binary(struct linux_binprm *bprm) + unsigned long error; + struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; + struct elf_phdr *elf_property_phdata = NULL; +- unsigned long elf_bss, elf_brk; +- int bss_prot = 0; ++ unsigned long elf_brk; ++ bool brk_moved = false; + int retval, i; + unsigned long elf_entry; + unsigned long e_entry; +@@ -1021,7 +1047,6 @@ static int load_elf_binary(struct linux_binprm *bprm) + if (retval < 0) + goto out_free_dentry; + +- elf_bss = 0; + elf_brk = 0; + + start_code = ~0UL; +@@ -1041,33 +1066,6 @@ static int load_elf_binary(struct linux_binprm *bprm) + if (elf_ppnt->p_type != PT_LOAD) + continue; + +- if (unlikely (elf_brk > elf_bss)) { +- unsigned long nbyte; +- +- /* There was a PT_LOAD segment with p_memsz > p_filesz +- before this one. Map anonymous pages, if needed, +- and clear the area. */ +- retval = set_brk(elf_bss + load_bias, +- elf_brk + load_bias, +- bss_prot); +- if (retval) +- goto out_free_dentry; +- nbyte = ELF_PAGEOFFSET(elf_bss); +- if (nbyte) { +- nbyte = ELF_MIN_ALIGN - nbyte; +- if (nbyte > elf_brk - elf_bss) +- nbyte = elf_brk - elf_bss; +- if (clear_user((void __user *)elf_bss + +- load_bias, nbyte)) { +- /* +- * This bss-zeroing can fail if the ELF +- * file specifies odd protections. So +- * we don't check the return value +- */ +- } +- } +- } +- + elf_prot = make_prot(elf_ppnt->p_flags, &arch_state, + !!interpreter, false); + +@@ -1095,15 +1093,49 @@ static int load_elf_binary(struct linux_binprm *bprm) + * Header for ET_DYN binaries to calculate the + * randomization (load_bias) for all the LOAD + * Program Headers. ++ */ ++ ++ /* ++ * Calculate the entire size of the ELF mapping ++ * (total_size), used for the initial mapping, ++ * due to load_addr_set which is set to true later ++ * once the initial mapping is performed. ++ * ++ * Note that this is only sensible when the LOAD ++ * segments are contiguous (or overlapping). If ++ * used for LOADs that are far apart, this would ++ * cause the holes between LOADs to be mapped, ++ * running the risk of having the mapping fail, ++ * as it would be larger than the ELF file itself. ++ * ++ * As a result, only ET_DYN does this, since ++ * some ET_EXEC (e.g. ia64) may have large virtual ++ * memory holes between LOADs. ++ * ++ */ ++ total_size = total_mapping_size(elf_phdata, ++ elf_ex->e_phnum); ++ if (!total_size) { ++ retval = -EINVAL; ++ goto out_free_dentry; ++ } ++ ++ /* Calculate any requested alignment. */ ++ alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); ++ ++ /** ++ * DOC: PIE handling + * +- * There are effectively two types of ET_DYN +- * binaries: programs (i.e. PIE: ET_DYN with INTERP) +- * and loaders (ET_DYN without INTERP, since they +- * _are_ the ELF interpreter). The loaders must +- * be loaded away from programs since the program +- * may otherwise collide with the loader (especially +- * for ET_EXEC which does not have a randomized +- * position). For example to handle invocations of ++ * There are effectively two types of ET_DYN ELF ++ * binaries: programs (i.e. PIE: ET_DYN with ++ * PT_INTERP) and loaders (i.e. static PIE: ET_DYN ++ * without PT_INTERP, usually the ELF interpreter ++ * itself). Loaders must be loaded away from programs ++ * since the program may otherwise collide with the ++ * loader (especially for ET_EXEC which does not have ++ * a randomized position). ++ * ++ * For example, to handle invocations of + * "./ld.so someprog" to test out a new version of + * the loader, the subsequent program that the + * loader loads must avoid the loader itself, so +@@ -1116,17 +1148,49 @@ static int load_elf_binary(struct linux_binprm *bprm) + * ELF_ET_DYN_BASE and loaders are loaded into the + * independently randomized mmap region (0 load_bias + * without MAP_FIXED nor MAP_FIXED_NOREPLACE). ++ * ++ * See below for "brk" handling details, which is ++ * also affected by program vs loader and ASLR. + */ + if (interpreter) { ++ /* On ET_DYN with PT_INTERP, we do the ASLR. */ + load_bias = ELF_ET_DYN_BASE; + if (current->flags & PF_RANDOMIZE) + load_bias += arch_mmap_rnd(); +- alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); ++ /* Adjust alignment as requested. */ + if (alignment) + load_bias &= ~(alignment - 1); + elf_flags |= MAP_FIXED_NOREPLACE; +- } else +- load_bias = 0; ++ } else { ++ /* ++ * For ET_DYN without PT_INTERP, we rely on ++ * the architectures's (potentially ASLR) mmap ++ * base address (via a load_bias of 0). ++ * ++ * When a large alignment is requested, we ++ * must do the allocation at address "0" right ++ * now to discover where things will load so ++ * that we can adjust the resulting alignment. ++ * In this case (load_bias != 0), we can use ++ * MAP_FIXED_NOREPLACE to make sure the mapping ++ * doesn't collide with anything. ++ */ ++ if (alignment > ELF_MIN_ALIGN) { ++ load_bias = elf_load(bprm->file, 0, elf_ppnt, ++ elf_prot, elf_flags, total_size); ++ if (BAD_ADDR(load_bias)) { ++ retval = IS_ERR_VALUE(load_bias) ? ++ PTR_ERR((void*)load_bias) : -EINVAL; ++ goto out_free_dentry; ++ } ++ vm_munmap(load_bias, total_size); ++ /* Adjust alignment as requested. */ ++ if (alignment) ++ load_bias &= ~(alignment - 1); ++ elf_flags |= MAP_FIXED_NOREPLACE; ++ } else ++ load_bias = 0; ++ } + + /* + * Since load_bias is used for all subsequent loading +@@ -1136,34 +1200,9 @@ static int load_elf_binary(struct linux_binprm *bprm) + * is then page aligned. + */ + load_bias = ELF_PAGESTART(load_bias - vaddr); +- +- /* +- * Calculate the entire size of the ELF mapping +- * (total_size), used for the initial mapping, +- * due to load_addr_set which is set to true later +- * once the initial mapping is performed. +- * +- * Note that this is only sensible when the LOAD +- * segments are contiguous (or overlapping). If +- * used for LOADs that are far apart, this would +- * cause the holes between LOADs to be mapped, +- * running the risk of having the mapping fail, +- * as it would be larger than the ELF file itself. +- * +- * As a result, only ET_DYN does this, since +- * some ET_EXEC (e.g. ia64) may have large virtual +- * memory holes between LOADs. +- * +- */ +- total_size = total_mapping_size(elf_phdata, +- elf_ex->e_phnum); +- if (!total_size) { +- retval = -EINVAL; +- goto out_free_dentry; +- } + } + +- error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, ++ error = elf_load(bprm->file, load_bias + vaddr, elf_ppnt, + elf_prot, elf_flags, total_size); + if (BAD_ADDR(error)) { + retval = IS_ERR_VALUE(error) ? +@@ -1211,41 +1250,23 @@ static int load_elf_binary(struct linux_binprm *bprm) + + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + +- if (k > elf_bss) +- elf_bss = k; + if ((elf_ppnt->p_flags & PF_X) && end_code < k) + end_code = k; + if (end_data < k) + end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; +- if (k > elf_brk) { +- bss_prot = elf_prot; ++ if (k > elf_brk) + elf_brk = k; +- } + } + + e_entry = elf_ex->e_entry + load_bias; + phdr_addr += load_bias; +- elf_bss += load_bias; + elf_brk += load_bias; + start_code += load_bias; + end_code += load_bias; + start_data += load_bias; + end_data += load_bias; + +- /* Calling set_brk effectively mmaps the pages that we need +- * for the bss and break sections. We must do this before +- * mapping in the interpreter, to make sure it doesn't wind +- * up getting placed where the bss needs to go. +- */ +- retval = set_brk(elf_bss, elf_brk, bss_prot); +- if (retval) +- goto out_free_dentry; +- if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { +- retval = -EFAULT; /* Nobody gets to see this, but.. */ +- goto out_free_dentry; +- } +- + if (interpreter) { + elf_entry = load_elf_interp(interp_elf_ex, + interpreter, +@@ -1301,24 +1322,44 @@ static int load_elf_binary(struct linux_binprm *bprm) + mm->end_data = end_data; + mm->start_stack = bprm->p; + +- if ((current->flags & PF_RANDOMIZE) && (snapshot_randomize_va_space > 1)) { ++ /** ++ * DOC: "brk" handling ++ * ++ * For architectures with ELF randomization, when executing a ++ * loader directly (i.e. static PIE: ET_DYN without PT_INTERP), ++ * move the brk area out of the mmap region and into the unused ++ * ELF_ET_DYN_BASE region. Since "brk" grows up it may collide ++ * early with the stack growing down or other regions being put ++ * into the mmap region by the kernel (e.g. vdso). ++ * ++ * In the CONFIG_COMPAT_BRK case, though, everything is turned ++ * off because we're not allowed to move the brk at all. ++ */ ++ if (!IS_ENABLED(CONFIG_COMPAT_BRK) && ++ IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && ++ elf_ex->e_type == ET_DYN && !interpreter) { ++ elf_brk = ELF_ET_DYN_BASE; ++ /* This counts as moving the brk, so let brk(2) know. */ ++ brk_moved = true; ++ } ++ mm->start_brk = mm->brk = ELF_PAGEALIGN(elf_brk); ++ ++ if ((current->flags & PF_RANDOMIZE) && snapshot_randomize_va_space > 1) { + /* +- * For architectures with ELF randomization, when executing +- * a loader directly (i.e. no interpreter listed in ELF +- * headers), move the brk area out of the mmap region +- * (since it grows up, and may collide early with the stack +- * growing down), and into the unused ELF_ET_DYN_BASE region. ++ * If we didn't move the brk to ELF_ET_DYN_BASE (above), ++ * leave a gap between .bss and brk. + */ +- if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && +- elf_ex->e_type == ET_DYN && !interpreter) { +- mm->brk = mm->start_brk = ELF_ET_DYN_BASE; +- } ++ if (!brk_moved) ++ mm->brk = mm->start_brk = mm->brk + PAGE_SIZE; + + mm->brk = mm->start_brk = arch_randomize_brk(mm); ++ brk_moved = true; ++ } ++ + #ifdef compat_brk_randomized ++ if (brk_moved) + current->brk_randomized = 1; + #endif +- } + + if (current->personality & MMAP_PAGE_ZERO) { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index af03a1c6ba768c..ef77d420851040 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -164,6 +164,14 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, + ei = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_extent_item); + num_refs = btrfs_extent_refs(leaf, ei); ++ if (unlikely(num_refs == 0)) { ++ ret = -EUCLEAN; ++ btrfs_err(fs_info, ++ "unexpected zero reference count for extent item (%llu %u %llu)", ++ key.objectid, key.type, key.offset); ++ btrfs_abort_transaction(trans, ret); ++ goto out_free; ++ } + extent_flags = btrfs_extent_flags(leaf, ei); + } else { + ret = -EUCLEAN; +@@ -177,8 +185,6 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, + + goto out_free; + } +- +- BUG_ON(num_refs == 0); + } else { + num_refs = 0; + extent_flags = 0; +@@ -208,10 +214,19 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, + goto search_again; + } + spin_lock(&head->lock); +- if (head->extent_op && head->extent_op->update_flags) ++ if (head->extent_op && head->extent_op->update_flags) { + extent_flags |= head->extent_op->flags_to_set; +- else +- BUG_ON(num_refs == 0); ++ } else if (unlikely(num_refs == 0)) { ++ spin_unlock(&head->lock); ++ mutex_unlock(&head->mutex); ++ spin_unlock(&delayed_refs->lock); ++ ret = -EUCLEAN; ++ btrfs_err(fs_info, ++ "unexpected zero reference count for extent %llu (%s)", ++ bytenr, metadata ? "metadata" : "data"); ++ btrfs_abort_transaction(trans, ret); ++ goto out_free; ++ } + + num_refs += head->ref_mod; + spin_unlock(&head->lock); +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 4b12e45f575394..c140427e322ced 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -6880,10 +6880,18 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, + struct nfs4_unlockdata *p; + struct nfs4_state *state = lsp->ls_state; + struct inode *inode = state->inode; ++ struct nfs_lock_context *l_ctx; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) + return NULL; ++ l_ctx = nfs_get_lock_context(ctx); ++ if (!IS_ERR(l_ctx)) { ++ p->l_ctx = l_ctx; ++ } else { ++ kfree(p); ++ return NULL; ++ } + p->arg.fh = NFS_FH(inode); + p->arg.fl = &p->fl; + p->arg.seqid = seqid; +@@ -6891,7 +6899,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, + p->lsp = lsp; + /* Ensure we don't close file until we're done freeing locks! */ + p->ctx = get_nfs_open_context(ctx); +- p->l_ctx = nfs_get_lock_context(ctx); + locks_init_lock(&p->fl); + locks_copy_lock(&p->fl, fl); + p->server = NFS_SERVER(inode); +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index fe83c681e3fe03..73aa5a63afe3fb 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -732,6 +732,14 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, + return remaining; + } + ++static void pnfs_reset_return_info(struct pnfs_layout_hdr *lo) ++{ ++ struct pnfs_layout_segment *lseg; ++ ++ list_for_each_entry(lseg, &lo->plh_return_segs, pls_list) ++ pnfs_set_plh_return_info(lo, lseg->pls_range.iomode, 0); ++} ++ + static void + pnfs_free_returned_lsegs(struct pnfs_layout_hdr *lo, + struct list_head *free_me, +@@ -1180,6 +1188,7 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo, + pnfs_mark_matching_lsegs_invalid(lo, &freeme, range, seq); + pnfs_free_returned_lsegs(lo, &freeme, range, seq); + pnfs_set_layout_stateid(lo, stateid, NULL, true); ++ pnfs_reset_return_info(lo); + } else + pnfs_mark_layout_stateid_invalid(lo, &freeme); + out_unlock: +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index 4536b6fcfa0256..3e88e8b3c16ec2 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -2979,7 +2979,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, + /* Eventually save off posix specific response info and timestaps */ + + err_free_rsp_buf: +- free_rsp_buf(resp_buftype, rsp); ++ free_rsp_buf(resp_buftype, rsp_iov.iov_base); + kfree(pc_buf); + err_free_req: + cifs_small_buf_release(req); +diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c +index 4f33a4a4888613..b4071c9cf8c951 100644 +--- a/fs/udf/truncate.c ++++ b/fs/udf/truncate.c +@@ -115,7 +115,7 @@ void udf_truncate_tail_extent(struct inode *inode) + } + /* This inode entry is in-memory only and thus we don't have to mark + * the inode dirty */ +- if (ret == 0) ++ if (ret >= 0) + iinfo->i_lenExtents = inode->i_size; + brelse(epos.bh); + } +diff --git a/fs/xattr.c b/fs/xattr.c +index c20046548f218e..5fed22c22a2be8 100644 +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -1291,6 +1291,15 @@ static bool xattr_is_trusted(const char *name) + return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); + } + ++static bool xattr_is_maclabel(const char *name) ++{ ++ const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; ++ ++ return !strncmp(name, XATTR_SECURITY_PREFIX, ++ XATTR_SECURITY_PREFIX_LEN) && ++ security_ismaclabel(suffix); ++} ++ + /** + * simple_xattr_list - list all xattr objects + * @inode: inode from which to get the xattrs +@@ -1323,6 +1332,17 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, + if (err) + return err; + ++ err = security_inode_listsecurity(inode, buffer, remaining_size); ++ if (err < 0) ++ return err; ++ ++ if (buffer) { ++ if (remaining_size < err) ++ return -ERANGE; ++ buffer += err; ++ } ++ remaining_size -= err; ++ + read_lock(&xattrs->lock); + for (rbp = rb_first(&xattrs->rb_root); rbp; rbp = rb_next(rbp)) { + xattr = rb_entry(rbp, struct simple_xattr, rb_node); +@@ -1331,6 +1351,10 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, + if (!trusted && xattr_is_trusted(xattr->name)) + continue; + ++ /* skip MAC labels; these are provided by LSM above */ ++ if (xattr_is_maclabel(xattr->name)) ++ continue; ++ + err = xattr_list_one(&buffer, &remaining_size, xattr->name); + if (err) + break; +diff --git a/include/linux/bio.h b/include/linux/bio.h +index 0286bada25ce72..b893418c3cc022 100644 +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -11,6 +11,7 @@ + #include + + #define BIO_MAX_VECS 256U ++#define BIO_MAX_INLINE_VECS UIO_MAXIOV + + struct queue_limits; + +diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h +index 3e7fc905478984..b5bf5315ca8c10 100644 +--- a/include/linux/hyperv.h ++++ b/include/linux/hyperv.h +@@ -1224,13 +1224,6 @@ extern int vmbus_sendpacket(struct vmbus_channel *channel, + enum vmbus_packet_type type, + u32 flags); + +-extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, +- struct hv_page_buffer pagebuffers[], +- u32 pagecount, +- void *buffer, +- u32 bufferlen, +- u64 requestid); +- + extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + struct vmbus_packet_mpb_array *mpb, + u32 desc_size, +diff --git a/include/linux/tpm.h b/include/linux/tpm.h +index 5f4998626a9889..bf8a4ec8a01c1f 100644 +--- a/include/linux/tpm.h ++++ b/include/linux/tpm.h +@@ -181,7 +181,7 @@ enum tpm2_const { + + enum tpm2_timeouts { + TPM2_TIMEOUT_A = 750, +- TPM2_TIMEOUT_B = 2000, ++ TPM2_TIMEOUT_B = 4000, + TPM2_TIMEOUT_C = 200, + TPM2_TIMEOUT_D = 30, + TPM2_DURATION_SHORT = 20, +diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h +index 4ec2a948ae3dbb..3287988a6a9878 100644 +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -1029,6 +1029,21 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct qdisc_skb_head *qh) + return skb; + } + ++static inline struct sk_buff *qdisc_dequeue_internal(struct Qdisc *sch, bool direct) ++{ ++ struct sk_buff *skb; ++ ++ skb = __skb_dequeue(&sch->gso_skb); ++ if (skb) { ++ sch->q.qlen--; ++ return skb; ++ } ++ if (direct) ++ return __qdisc_dequeue_head(&sch->q); ++ else ++ return sch->dequeue(sch); ++} ++ + static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch) + { + struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); +diff --git a/include/sound/ump_msg.h b/include/sound/ump_msg.h +index 72f60ddfea7535..9556b4755a1ed8 100644 +--- a/include/sound/ump_msg.h ++++ b/include/sound/ump_msg.h +@@ -604,7 +604,7 @@ struct snd_ump_stream_msg_ep_info { + } __packed; + + /* UMP Stream Message: Device Info Notification (128bit) */ +-struct snd_ump_stream_msg_devince_info { ++struct snd_ump_stream_msg_device_info { + #ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; +@@ -754,7 +754,7 @@ struct snd_ump_stream_msg_fb_name { + union snd_ump_stream_msg { + struct snd_ump_stream_msg_ep_discovery ep_discovery; + struct snd_ump_stream_msg_ep_info ep_info; +- struct snd_ump_stream_msg_devince_info device_info; ++ struct snd_ump_stream_msg_device_info device_info; + struct snd_ump_stream_msg_stream_cfg stream_cfg; + struct snd_ump_stream_msg_fb_discovery fb_discovery; + struct snd_ump_stream_msg_fb_info fb_info; +diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c +index 3646426c69e253..ad8b62202bdc46 100644 +--- a/kernel/cgroup/cpuset.c ++++ b/kernel/cgroup/cpuset.c +@@ -1229,9 +1229,11 @@ static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus) + + if (top_cs) { + /* +- * Percpu kthreads in top_cpuset are ignored ++ * PF_NO_SETAFFINITY tasks are ignored. ++ * All per cpu kthreads should have PF_NO_SETAFFINITY ++ * flag set, see kthread_set_per_cpu(). + */ +- if (kthread_is_per_cpu(task)) ++ if (task->flags & PF_NO_SETAFFINITY) + continue; + cpumask_andnot(new_cpus, possible_mask, cs->subparts_cpus); + } else { +diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c +index 4376887e0d8aab..c9b0533407edeb 100644 +--- a/kernel/trace/trace_dynevent.c ++++ b/kernel/trace/trace_dynevent.c +@@ -16,7 +16,7 @@ + #include "trace_output.h" /* for trace_event_sem */ + #include "trace_dynevent.h" + +-static DEFINE_MUTEX(dyn_event_ops_mutex); ++DEFINE_MUTEX(dyn_event_ops_mutex); + static LIST_HEAD(dyn_event_ops_list); + + bool trace_event_dyn_try_get_ref(struct trace_event_call *dyn_call) +@@ -125,6 +125,20 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type + return ret; + } + ++/* ++ * Locked version of event creation. The event creation must be protected by ++ * dyn_event_ops_mutex because of protecting trace_probe_log. ++ */ ++int dyn_event_create(const char *raw_command, struct dyn_event_operations *type) ++{ ++ int ret; ++ ++ mutex_lock(&dyn_event_ops_mutex); ++ ret = type->create(raw_command); ++ mutex_unlock(&dyn_event_ops_mutex); ++ return ret; ++} ++ + static int create_dyn_event(const char *raw_command) + { + struct dyn_event_operations *ops; +diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h +index 936477a111d3e7..beee3f8d754444 100644 +--- a/kernel/trace/trace_dynevent.h ++++ b/kernel/trace/trace_dynevent.h +@@ -100,6 +100,7 @@ void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos); + void dyn_event_seq_stop(struct seq_file *m, void *v); + int dyn_events_release_all(struct dyn_event_operations *type); + int dyn_event_release(const char *raw_command, struct dyn_event_operations *type); ++int dyn_event_create(const char *raw_command, struct dyn_event_operations *type); + + /* + * for_each_dyn_event - iterate over the dyn_event list +diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c +index 76abc9a45f971a..2c233c0d38fa95 100644 +--- a/kernel/trace/trace_events_trigger.c ++++ b/kernel/trace/trace_events_trigger.c +@@ -1554,7 +1554,7 @@ stacktrace_trigger(struct event_trigger_data *data, + struct trace_event_file *file = data->private_data; + + if (file) +- __trace_stack(file->tr, tracing_gen_ctx(), STACK_SKIP); ++ __trace_stack(file->tr, tracing_gen_ctx_dec(), STACK_SKIP); + else + trace_dump_stack(STACK_SKIP); + } +diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c +index 69e92c7359fb9a..44ae51d1dc45d8 100644 +--- a/kernel/trace/trace_functions.c ++++ b/kernel/trace/trace_functions.c +@@ -561,11 +561,7 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip, + + static __always_inline void trace_stack(struct trace_array *tr) + { +- unsigned int trace_ctx; +- +- trace_ctx = tracing_gen_ctx(); +- +- __trace_stack(tr, trace_ctx, FTRACE_STACK_SKIP); ++ __trace_stack(tr, tracing_gen_ctx_dec(), FTRACE_STACK_SKIP); + } + + static void +diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c +index 508c10414a9343..46491f3c1569cd 100644 +--- a/kernel/trace/trace_kprobe.c ++++ b/kernel/trace/trace_kprobe.c +@@ -1004,7 +1004,7 @@ static int create_or_delete_trace_kprobe(const char *raw_command) + if (raw_command[0] == '-') + return dyn_event_release(raw_command, &trace_kprobe_ops); + +- ret = trace_kprobe_create(raw_command); ++ ret = dyn_event_create(raw_command, &trace_kprobe_ops); + return ret == -ECANCELED ? -EINVAL : ret; + } + +diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c +index 606190239c8776..694f32d843d90c 100644 +--- a/kernel/trace/trace_probe.c ++++ b/kernel/trace/trace_probe.c +@@ -153,9 +153,12 @@ static const struct fetch_type *find_fetch_type(const char *type, unsigned long + } + + static struct trace_probe_log trace_probe_log; ++extern struct mutex dyn_event_ops_mutex; + + void trace_probe_log_init(const char *subsystem, int argc, const char **argv) + { ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + trace_probe_log.subsystem = subsystem; + trace_probe_log.argc = argc; + trace_probe_log.argv = argv; +@@ -164,11 +167,15 @@ void trace_probe_log_init(const char *subsystem, int argc, const char **argv) + + void trace_probe_log_clear(void) + { ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + memset(&trace_probe_log, 0, sizeof(trace_probe_log)); + } + + void trace_probe_log_set_index(int index) + { ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + trace_probe_log.index = index; + } + +@@ -177,6 +184,8 @@ void __trace_probe_log_err(int offset, int err_type) + char *command, *p; + int i, len = 0, pos = 0; + ++ lockdep_assert_held(&dyn_event_ops_mutex); ++ + if (!trace_probe_log.argv) + return; + +diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c +index 79f8da7e3cd492..ecf04e81ddf705 100644 +--- a/kernel/trace/trace_uprobe.c ++++ b/kernel/trace/trace_uprobe.c +@@ -730,7 +730,7 @@ static int create_or_delete_trace_uprobe(const char *raw_command) + if (raw_command[0] == '-') + return dyn_event_release(raw_command, &trace_uprobe_ops); + +- ret = trace_uprobe_create(raw_command); ++ ret = dyn_event_create(raw_command, &trace_uprobe_ops); + return ret == -ECANCELED ? -EINVAL : ret; + } + +diff --git a/mm/memblock.c b/mm/memblock.c +index 047dce35cf6e0e..0695284232f3c6 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -460,7 +460,14 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, + min(new_area_start, memblock.current_limit), + new_alloc_size, PAGE_SIZE); + +- new_array = addr ? __va(addr) : NULL; ++ if (addr) { ++ /* The memory may not have been accepted, yet. */ ++ accept_memory(addr, addr + new_alloc_size); ++ ++ new_array = __va(addr); ++ } else { ++ new_array = NULL; ++ } + } + if (!addr) { + pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", +diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c +index 9beed7c71a8e91..aab16690545207 100644 +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -1735,8 +1735,12 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) + if (PageHWPoison(page)) { + if (WARN_ON(folio_test_lru(folio))) + folio_isolate_lru(folio); +- if (folio_mapped(folio)) ++ if (folio_mapped(folio)) { ++ folio_lock(folio); + try_to_unmap(folio, TTU_IGNORE_MLOCK); ++ folio_unlock(folio); ++ } ++ + continue; + } + +diff --git a/mm/migrate.c b/mm/migrate.c +index 1004b1def1c201..4ed47088521746 100644 +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -1504,6 +1504,7 @@ struct migrate_pages_stats { + int nr_thp_succeeded; /* THP migrated successfully */ + int nr_thp_failed; /* THP failed to be migrated */ + int nr_thp_split; /* THP split before migrating */ ++ int nr_split; /* Large folio (include THP) split before migrating */ + }; + + /* +@@ -1623,6 +1624,7 @@ static int migrate_pages_batch(struct list_head *from, + int nr_retry_pages = 0; + int pass = 0; + bool is_thp = false; ++ bool is_large = false; + struct folio *folio, *folio2, *dst = NULL, *dst2; + int rc, rc_saved = 0, nr_pages; + LIST_HEAD(unmap_folios); +@@ -1638,7 +1640,8 @@ static int migrate_pages_batch(struct list_head *from, + nr_retry_pages = 0; + + list_for_each_entry_safe(folio, folio2, from, lru) { +- is_thp = folio_test_large(folio) && folio_test_pmd_mappable(folio); ++ is_large = folio_test_large(folio); ++ is_thp = is_large && folio_test_pmd_mappable(folio); + nr_pages = folio_nr_pages(folio); + + cond_resched(); +@@ -1658,6 +1661,7 @@ static int migrate_pages_batch(struct list_head *from, + stats->nr_thp_failed++; + if (!try_split_folio(folio, split_folios)) { + stats->nr_thp_split++; ++ stats->nr_split++; + continue; + } + stats->nr_failed_pages += nr_pages; +@@ -1686,11 +1690,12 @@ static int migrate_pages_batch(struct list_head *from, + nr_failed++; + stats->nr_thp_failed += is_thp; + /* Large folio NUMA faulting doesn't split to retry. */ +- if (folio_test_large(folio) && !nosplit) { ++ if (is_large && !nosplit) { + int ret = try_split_folio(folio, split_folios); + + if (!ret) { + stats->nr_thp_split += is_thp; ++ stats->nr_split += is_large; + break; + } else if (reason == MR_LONGTERM_PIN && + ret == -EAGAIN) { +@@ -1836,6 +1841,7 @@ static int migrate_pages_sync(struct list_head *from, new_folio_t get_new_folio, + stats->nr_succeeded += astats.nr_succeeded; + stats->nr_thp_succeeded += astats.nr_thp_succeeded; + stats->nr_thp_split += astats.nr_thp_split; ++ stats->nr_split += astats.nr_split; + if (rc < 0) { + stats->nr_failed_pages += astats.nr_failed_pages; + stats->nr_thp_failed += astats.nr_thp_failed; +@@ -1843,7 +1849,11 @@ static int migrate_pages_sync(struct list_head *from, new_folio_t get_new_folio, + return rc; + } + stats->nr_thp_failed += astats.nr_thp_split; +- nr_failed += astats.nr_thp_split; ++ /* ++ * Do not count rc, as pages will be retried below. ++ * Count nr_split only, since it includes nr_thp_split. ++ */ ++ nr_failed += astats.nr_split; + /* + * Fall back to migrate all failed folios one by one synchronously. All + * failed folios except split THPs will be retried, so their failure +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index bc62bb2a3b132e..74737c35082b45 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -303,7 +303,6 @@ EXPORT_SYMBOL(nr_online_nodes); + static bool page_contains_unaccepted(struct page *page, unsigned int order); + static void accept_page(struct page *page, unsigned int order); + static bool cond_accept_memory(struct zone *zone, unsigned int order); +-static inline bool has_unaccepted_memory(void); + static bool __free_unaccepted(struct page *page); + + int page_group_by_mobility_disabled __read_mostly; +@@ -6586,9 +6585,6 @@ bool has_managed_dma(void) + + #ifdef CONFIG_UNACCEPTED_MEMORY + +-/* Counts number of zones with unaccepted pages. */ +-static DEFINE_STATIC_KEY_FALSE(zones_with_unaccepted_pages); +- + static bool lazy_accept = true; + + static int __init accept_memory_parse(char *p) +@@ -6624,7 +6620,6 @@ static bool try_to_accept_memory_one(struct zone *zone) + { + unsigned long flags; + struct page *page; +- bool last; + + spin_lock_irqsave(&zone->lock, flags); + page = list_first_entry_or_null(&zone->unaccepted_pages, +@@ -6635,7 +6630,6 @@ static bool try_to_accept_memory_one(struct zone *zone) + } + + list_del(&page->lru); +- last = list_empty(&zone->unaccepted_pages); + + __mod_zone_freepage_state(zone, -MAX_ORDER_NR_PAGES, MIGRATE_MOVABLE); + __mod_zone_page_state(zone, NR_UNACCEPTED, -MAX_ORDER_NR_PAGES); +@@ -6645,9 +6639,6 @@ static bool try_to_accept_memory_one(struct zone *zone) + + __free_pages_ok(page, MAX_ORDER, FPI_TO_TAIL); + +- if (last) +- static_branch_dec(&zones_with_unaccepted_pages); +- + return true; + } + +@@ -6656,9 +6647,6 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order) + long to_accept, wmark; + bool ret = false; + +- if (!has_unaccepted_memory()) +- return false; +- + if (list_empty(&zone->unaccepted_pages)) + return false; + +@@ -6688,30 +6676,20 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order) + return ret; + } + +-static inline bool has_unaccepted_memory(void) +-{ +- return static_branch_unlikely(&zones_with_unaccepted_pages); +-} +- + static bool __free_unaccepted(struct page *page) + { + struct zone *zone = page_zone(page); + unsigned long flags; +- bool first = false; + + if (!lazy_accept) + return false; + + spin_lock_irqsave(&zone->lock, flags); +- first = list_empty(&zone->unaccepted_pages); + list_add_tail(&page->lru, &zone->unaccepted_pages); + __mod_zone_freepage_state(zone, MAX_ORDER_NR_PAGES, MIGRATE_MOVABLE); + __mod_zone_page_state(zone, NR_UNACCEPTED, MAX_ORDER_NR_PAGES); + spin_unlock_irqrestore(&zone->lock, flags); + +- if (first) +- static_branch_inc(&zones_with_unaccepted_pages); +- + return true; + } + +@@ -6731,11 +6709,6 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order) + return false; + } + +-static inline bool has_unaccepted_memory(void) +-{ +- return false; +-} +- + static bool __free_unaccepted(struct page *page) + { + BUILD_BUG(); +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 29e420e9754bb3..589c3a481e4c10 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -7605,11 +7605,16 @@ static void add_device_complete(struct hci_dev *hdev, void *data, int err) + struct mgmt_cp_add_device *cp = cmd->param; + + if (!err) { ++ struct hci_conn_params *params; ++ ++ params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, ++ le_addr_type(cp->addr.type)); ++ + device_added(cmd->sk, hdev, &cp->addr.bdaddr, cp->addr.type, + cp->action); + device_flags_changed(NULL, hdev, &cp->addr.bdaddr, + cp->addr.type, hdev->conn_flags, +- PTR_UINT(cmd->user_data)); ++ params ? params->flags : 0); + } + + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_ADD_DEVICE, +@@ -7712,8 +7717,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, + goto unlock; + } + +- cmd->user_data = UINT_PTR(current_flags); +- + err = hci_cmd_sync_queue(hdev, add_device_sync, cmd, + add_device_complete); + if (err < 0) { +diff --git a/net/mac80211/main.c b/net/mac80211/main.c +index d1046f495e63ff..3a6fff98748b86 100644 +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1186,10 +1186,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) + return -EINVAL; + } + +- local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + +- sizeof(void *) * channels, GFP_KERNEL); ++ local->int_scan_req = kzalloc(struct_size(local->int_scan_req, ++ channels, channels), ++ GFP_KERNEL); + if (!local->int_scan_req) + return -ENOMEM; ++ local->int_scan_req->n_channels = channels; + + eth_broadcast_addr(local->int_scan_req->bssid); + +diff --git a/net/mctp/device.c b/net/mctp/device.c +index 85cc5f31f1e7c0..8d1386601bbe06 100644 +--- a/net/mctp/device.c ++++ b/net/mctp/device.c +@@ -20,8 +20,7 @@ + #include + + struct mctp_dump_cb { +- int h; +- int idx; ++ unsigned long ifindex; + size_t a_idx; + }; + +@@ -115,43 +114,36 @@ static int mctp_dump_addrinfo(struct sk_buff *skb, struct netlink_callback *cb) + { + struct mctp_dump_cb *mcb = (void *)cb->ctx; + struct net *net = sock_net(skb->sk); +- struct hlist_head *head; + struct net_device *dev; + struct ifaddrmsg *hdr; + struct mctp_dev *mdev; +- int ifindex; +- int idx = 0, rc; +- +- hdr = nlmsg_data(cb->nlh); +- // filter by ifindex if requested +- ifindex = hdr->ifa_index; ++ int ifindex = 0, rc; ++ ++ /* Filter by ifindex if a header is provided */ ++ if (cb->nlh->nlmsg_len >= nlmsg_msg_size(sizeof(*hdr))) { ++ hdr = nlmsg_data(cb->nlh); ++ ifindex = hdr->ifa_index; ++ } else { ++ if (cb->strict_check) { ++ NL_SET_ERR_MSG(cb->extack, "mctp: Invalid header for addr dump request"); ++ return -EINVAL; ++ } ++ } + + rcu_read_lock(); +- for (; mcb->h < NETDEV_HASHENTRIES; mcb->h++, mcb->idx = 0) { +- idx = 0; +- head = &net->dev_index_head[mcb->h]; +- hlist_for_each_entry_rcu(dev, head, index_hlist) { +- if (idx >= mcb->idx && +- (ifindex == 0 || ifindex == dev->ifindex)) { +- mdev = __mctp_dev_get(dev); +- if (mdev) { +- rc = mctp_dump_dev_addrinfo(mdev, +- skb, cb); +- mctp_dev_put(mdev); +- // Error indicates full buffer, this +- // callback will get retried. +- if (rc < 0) +- goto out; +- } +- } +- idx++; +- // reset for next iteration +- mcb->a_idx = 0; +- } ++ for_each_netdev_dump(net, dev, mcb->ifindex) { ++ if (ifindex && ifindex != dev->ifindex) ++ continue; ++ mdev = __mctp_dev_get(dev); ++ if (!mdev) ++ continue; ++ rc = mctp_dump_dev_addrinfo(mdev, skb, cb); ++ mctp_dev_put(mdev); ++ if (rc < 0) ++ break; ++ mcb->a_idx = 0; + } +-out: + rcu_read_unlock(); +- mcb->idx = idx; + + return skb->len; + } +@@ -525,9 +517,12 @@ static struct notifier_block mctp_dev_nb = { + }; + + static const struct rtnl_msg_handler mctp_device_rtnl_msg_handlers[] = { +- {THIS_MODULE, PF_MCTP, RTM_NEWADDR, mctp_rtm_newaddr, NULL, 0}, +- {THIS_MODULE, PF_MCTP, RTM_DELADDR, mctp_rtm_deladdr, NULL, 0}, +- {THIS_MODULE, PF_MCTP, RTM_GETADDR, NULL, mctp_dump_addrinfo, 0}, ++ {.owner = THIS_MODULE, .protocol = PF_MCTP, .msgtype = RTM_NEWADDR, ++ .doit = mctp_rtm_newaddr}, ++ {.owner = THIS_MODULE, .protocol = PF_MCTP, .msgtype = RTM_DELADDR, ++ .doit = mctp_rtm_deladdr}, ++ {.owner = THIS_MODULE, .protocol = PF_MCTP, .msgtype = RTM_GETADDR, ++ .dumpit = mctp_dump_addrinfo}, + }; + + int __init mctp_device_init(void) +diff --git a/net/mctp/route.c b/net/mctp/route.c +index d3c1f54386efc1..009ba5edbd5254 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -274,8 +274,10 @@ static void mctp_flow_prepare_output(struct sk_buff *skb, struct mctp_dev *dev) + + key = flow->key; + +- if (WARN_ON(key->dev && key->dev != dev)) ++ if (key->dev) { ++ WARN_ON(key->dev != dev); + return; ++ } + + mctp_dev_set_key(dev, key); + } +diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c +index 5f2e0681574567..63c02040b426ae 100644 +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -168,7 +168,7 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt, + + qlen = sch->q.qlen; + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, true); + + dropped += qdisc_pkt_len(skb); + qdisc_qstats_backlog_dec(sch, skb); +diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c +index f59a2cb2c803d7..91f5ef6be0f231 100644 +--- a/net/sched/sch_fq.c ++++ b/net/sched/sch_fq.c +@@ -901,7 +901,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt, + sch_tree_lock(sch); + } + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = fq_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + if (!skb) + break; +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 9330923a624c02..47b5a056165cb0 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -431,7 +431,7 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt, + + while (sch->q.qlen > sch->limit || + q->memory_usage > q->memory_limit) { +- struct sk_buff *skb = fq_codel_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + q->cstats.drop_len += qdisc_pkt_len(skb); + rtnl_kfree_skbs(skb, skb); +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index 68e6acd0f130d9..607c580d75e4b6 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -357,7 +357,7 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt, + + /* Drop excess packets if new limit is lower */ + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = fq_pie_qdisc_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + len_dropped += qdisc_pkt_len(skb); + num_dropped += 1; +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index d26cd436cbe31b..83fc44f20e31cb 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -560,7 +560,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt, + qlen = sch->q.qlen; + prev_backlog = sch->qstats.backlog; + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = hhf_dequeue(sch); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + + rtnl_kfree_skbs(skb, skb); + } +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index 2da6250ec34636..48c5ab8ec143c1 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -190,7 +190,7 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt, + /* Drop excess packets if new limit is lower */ + qlen = sch->q.qlen; + while (sch->q.qlen > sch->limit) { +- struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); ++ struct sk_buff *skb = qdisc_dequeue_internal(sch, true); + + dropped += qdisc_pkt_len(skb); + qdisc_qstats_backlog_dec(sch, skb); +diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c +index fd73be940f4607..77a76634014a5a 100644 +--- a/net/sctp/sysctl.c ++++ b/net/sctp/sysctl.c +@@ -529,6 +529,8 @@ static int proc_sctp_do_auth(struct ctl_table *ctl, int write, + return ret; + } + ++static DEFINE_MUTEX(sctp_sysctl_mutex); ++ + static int proc_sctp_do_udp_port(struct ctl_table *ctl, int write, + void *buffer, size_t *lenp, loff_t *ppos) + { +@@ -553,6 +555,7 @@ static int proc_sctp_do_udp_port(struct ctl_table *ctl, int write, + if (new_value > max || new_value < min) + return -EINVAL; + ++ mutex_lock(&sctp_sysctl_mutex); + net->sctp.udp_port = new_value; + sctp_udp_sock_stop(net); + if (new_value) { +@@ -565,6 +568,7 @@ static int proc_sctp_do_udp_port(struct ctl_table *ctl, int write, + lock_sock(sk); + sctp_sk(sk)->udp_port = htons(net->sctp.udp_port); + release_sock(sk); ++ mutex_unlock(&sctp_sysctl_mutex); + } + + return ret; +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index 5df08d848b5c9c..1852fac3e72b76 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -395,7 +395,6 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) + return 0; + + shinfo = skb_shinfo(strp->anchor); +- shinfo->frag_list = NULL; + + /* If we don't know the length go max plus page for cipher overhead */ + need_spc = strp->stm.full_len ?: TLS_MAX_PAYLOAD_SIZE + PAGE_SIZE; +@@ -411,6 +410,8 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) + page, 0, 0); + } + ++ shinfo->frag_list = NULL; ++ + strp->copy_mode = 1; + strp->stm.offset = 0; + +diff --git a/samples/ftrace/sample-trace-array.c b/samples/ftrace/sample-trace-array.c +index d0ee9001c7b376..aaa8fa92e24d52 100644 +--- a/samples/ftrace/sample-trace-array.c ++++ b/samples/ftrace/sample-trace-array.c +@@ -112,7 +112,7 @@ static int __init sample_trace_array_init(void) + /* + * If context specific per-cpu buffers havent already been allocated. + */ +- trace_printk_init_buffers(); ++ trace_array_init_printk(tr); + + simple_tsk = kthread_run(simple_thread, NULL, "sample-instance"); + if (IS_ERR(simple_tsk)) { +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 6195fe9dda1799..49f6763c3250dd 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -736,15 +736,21 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, + */ + static int __deliver_to_subscribers(struct snd_seq_client *client, + struct snd_seq_event *event, +- struct snd_seq_client_port *src_port, +- int atomic, int hop) ++ int port, int atomic, int hop) + { ++ struct snd_seq_client_port *src_port; + struct snd_seq_subscribers *subs; + int err, result = 0, num_ev = 0; + union __snd_seq_event event_saved; + size_t saved_size; + struct snd_seq_port_subs_info *grp; + ++ if (port < 0) ++ return 0; ++ src_port = snd_seq_port_use_ptr(client, port); ++ if (!src_port) ++ return 0; ++ + /* save original event record */ + saved_size = snd_seq_event_packet_size(event); + memcpy(&event_saved, event, saved_size); +@@ -780,6 +786,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, + read_unlock(&grp->list_lock); + else + up_read(&grp->list_mutex); ++ snd_seq_port_unlock(src_port); + memcpy(event, &event_saved, saved_size); + return (result < 0) ? result : num_ev; + } +@@ -788,25 +795,32 @@ static int deliver_to_subscribers(struct snd_seq_client *client, + struct snd_seq_event *event, + int atomic, int hop) + { +- struct snd_seq_client_port *src_port; +- int ret = 0, ret2; +- +- src_port = snd_seq_port_use_ptr(client, event->source.port); +- if (src_port) { +- ret = __deliver_to_subscribers(client, event, src_port, atomic, hop); +- snd_seq_port_unlock(src_port); +- } +- +- if (client->ump_endpoint_port < 0 || +- event->source.port == client->ump_endpoint_port) +- return ret; ++ int ret; ++#if IS_ENABLED(CONFIG_SND_SEQ_UMP) ++ int ret2; ++#endif + +- src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port); +- if (!src_port) ++ ret = __deliver_to_subscribers(client, event, ++ event->source.port, atomic, hop); ++#if IS_ENABLED(CONFIG_SND_SEQ_UMP) ++ if (!snd_seq_client_is_ump(client) || client->ump_endpoint_port < 0) + return ret; +- ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop); +- snd_seq_port_unlock(src_port); +- return ret2 < 0 ? ret2 : ret; ++ /* If it's an event from EP port (and with a UMP group), ++ * deliver to subscribers of the corresponding UMP group port, too. ++ * Or, if it's from non-EP port, deliver to subscribers of EP port, too. ++ */ ++ if (event->source.port == client->ump_endpoint_port) ++ ret2 = __deliver_to_subscribers(client, event, ++ snd_seq_ump_group_port(event), ++ atomic, hop); ++ else ++ ret2 = __deliver_to_subscribers(client, event, ++ client->ump_endpoint_port, ++ atomic, hop); ++ if (ret2 < 0) ++ return ret2; ++#endif ++ return ret; + } + + /* deliver an event to the destination port(s). +diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c +index 4dd540cbb1cbbc..83a27362b7a066 100644 +--- a/sound/core/seq/seq_ump_convert.c ++++ b/sound/core/seq/seq_ump_convert.c +@@ -1284,3 +1284,21 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source, + else + return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop); + } ++ ++/* return the UMP group-port number of the event; ++ * return -1 if groupless or non-UMP event ++ */ ++int snd_seq_ump_group_port(const struct snd_seq_event *event) ++{ ++ const struct snd_seq_ump_event *ump_ev = ++ (const struct snd_seq_ump_event *)event; ++ unsigned char type; ++ ++ if (!snd_seq_ev_is_ump(event)) ++ return -1; ++ type = ump_message_type(ump_ev->ump[0]); ++ if (ump_is_groupless_msg(type)) ++ return -1; ++ /* group-port number starts from 1 */ ++ return ump_message_group(ump_ev->ump[0]) + 1; ++} +diff --git a/sound/core/seq/seq_ump_convert.h b/sound/core/seq/seq_ump_convert.h +index 6c146d8032804f..4abf0a7637d701 100644 +--- a/sound/core/seq/seq_ump_convert.h ++++ b/sound/core/seq/seq_ump_convert.h +@@ -18,5 +18,6 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop); ++int snd_seq_ump_group_port(const struct snd_seq_event *event); + + #endif /* __SEQ_UMP_CONVERT_H */ +diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c +index 4bc0f53c223b79..bc9203da35fb6f 100644 +--- a/sound/pci/es1968.c ++++ b/sound/pci/es1968.c +@@ -1569,7 +1569,7 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) + struct snd_pcm_runtime *runtime = substream->runtime; + struct es1968 *chip = snd_pcm_substream_chip(substream); + struct esschan *es; +- int apu1, apu2; ++ int err, apu1, apu2; + + apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE); + if (apu1 < 0) +@@ -1613,7 +1613,9 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) + runtime->hw = snd_es1968_capture; + runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = + calc_available_memory_size(chip) - 1024; /* keep MIXBUF size */ +- snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); ++ err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); ++ if (err < 0) ++ return err; + + spin_lock_irq(&chip->substream_lock); + list_add(&es->list, &chip->substream_list); +diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig +index b75fbb3236a7b9..f5fa09d740b4c9 100644 +--- a/sound/sh/Kconfig ++++ b/sound/sh/Kconfig +@@ -14,7 +14,7 @@ if SND_SUPERH + + config SND_AICA + tristate "Dreamcast Yamaha AICA sound" +- depends on SH_DREAMCAST ++ depends on SH_DREAMCAST && SH_DMA_API + select SND_PCM + select G2_DMA + help +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index d9d4c5922a50bb..0b8b20550ab381 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2140,6 +2140,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */ + QUIRK_FLAG_GET_SAMPLE_RATE), ++ DEVICE_FLG(0x0c45, 0x636b, /* Microdia JP001 USB Camera */ ++ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x0d8c, 0x0014, /* USB Audio Device */ + QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ +@@ -2148,6 +2150,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_FIXED_RATE), + DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */ + QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), ++ DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ ++ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), + DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ +diff --git a/tools/net/ynl/ethtool.py b/tools/net/ynl/ethtool.py +index 6c9f7e31250cdb..ffd8eb6d190483 100755 +--- a/tools/net/ynl/ethtool.py ++++ b/tools/net/ynl/ethtool.py +@@ -320,20 +320,37 @@ def main(): + return + + if args.show_time_stamping: +- tsinfo = dumpit(ynl, args, 'tsinfo-get') ++ req = { ++ 'header': { ++ 'flags': 'stats', ++ }, ++ } ++ ++ tsinfo = dumpit(ynl, args, 'tsinfo-get', req) + + print(f'Time stamping parameters for {args.device}:') + + print('Capabilities:') + [print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])] + +- print(f'PTP Hardware Clock: {tsinfo["phc-index"]}') ++ print(f'PTP Hardware Clock: {tsinfo.get("phc-index", "none")}') ++ ++ if 'tx-types' in tsinfo: ++ print('Hardware Transmit Timestamp Modes:') ++ [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] ++ else: ++ print('Hardware Transmit Timestamp Modes: none') ++ ++ if 'rx-filters' in tsinfo: ++ print('Hardware Receive Filter Modes:') ++ [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] ++ else: ++ print('Hardware Receive Filter Modes: none') + +- print('Hardware Transmit Timestamp Modes:') +- [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] ++ if 'stats' in tsinfo and tsinfo['stats']: ++ print('Statistics:') ++ [print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()] + +- print('Hardware Receive Filter Modes:') +- [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] + return + + print(f'Settings for {args.device}:') +diff --git a/tools/testing/selftests/exec/Makefile b/tools/testing/selftests/exec/Makefile +index a0b8688b083694..a705493c04bb73 100644 +--- a/tools/testing/selftests/exec/Makefile ++++ b/tools/testing/selftests/exec/Makefile +@@ -3,8 +3,13 @@ CFLAGS = -Wall + CFLAGS += -Wno-nonnull + CFLAGS += -D_GNU_SOURCE + ++ALIGNS := 0x1000 0x200000 0x1000000 ++ALIGN_PIES := $(patsubst %,load_address.%,$(ALIGNS)) ++ALIGN_STATIC_PIES := $(patsubst %,load_address.static.%,$(ALIGNS)) ++ALIGNMENT_TESTS := $(ALIGN_PIES) $(ALIGN_STATIC_PIES) ++ + TEST_PROGS := binfmt_script.py +-TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216 non-regular ++TEST_GEN_PROGS := execveat non-regular $(ALIGNMENT_TESTS) + TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir + # Makefile is a run-time dependency, since it's accessed by the execveat test + TEST_FILES := Makefile +@@ -28,9 +33,9 @@ $(OUTPUT)/execveat.symlink: $(OUTPUT)/execveat + $(OUTPUT)/execveat.denatured: $(OUTPUT)/execveat + cp $< $@ + chmod -x $@ +-$(OUTPUT)/load_address_4096: load_address.c +- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000 -pie -static $< -o $@ +-$(OUTPUT)/load_address_2097152: load_address.c +- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x200000 -pie -static $< -o $@ +-$(OUTPUT)/load_address_16777216: load_address.c +- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000000 -pie -static $< -o $@ ++$(OUTPUT)/load_address.0x%: load_address.c ++ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \ ++ -fPIE -pie $< -o $@ ++$(OUTPUT)/load_address.static.0x%: load_address.c ++ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \ ++ -fPIE -static-pie $< -o $@ +diff --git a/tools/testing/selftests/exec/load_address.c b/tools/testing/selftests/exec/load_address.c +index d487c2f6a61509..8257fddba8c8db 100644 +--- a/tools/testing/selftests/exec/load_address.c ++++ b/tools/testing/selftests/exec/load_address.c +@@ -5,10 +5,13 @@ + #include + #include + #include ++#include ++#include "../kselftest.h" + + struct Statistics { + unsigned long long load_address; + unsigned long long alignment; ++ bool interp; + }; + + int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data) +@@ -25,11 +28,20 @@ int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data) + stats->alignment = 0; + + for (i = 0; i < info->dlpi_phnum; i++) { ++ unsigned long long align; ++ ++ if (info->dlpi_phdr[i].p_type == PT_INTERP) { ++ stats->interp = true; ++ continue; ++ } ++ + if (info->dlpi_phdr[i].p_type != PT_LOAD) + continue; + +- if (info->dlpi_phdr[i].p_align > stats->alignment) +- stats->alignment = info->dlpi_phdr[i].p_align; ++ align = info->dlpi_phdr[i].p_align; ++ ++ if (align > stats->alignment) ++ stats->alignment = align; + } + + return 1; // Terminate dl_iterate_phdr. +@@ -37,32 +49,57 @@ int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data) + + int main(int argc, char **argv) + { +- struct Statistics extracted; +- unsigned long long misalign; ++ struct Statistics extracted = { }; ++ unsigned long long misalign, pow2; ++ bool interp_needed; ++ char buf[1024]; ++ FILE *maps; + int ret; + +- ret = dl_iterate_phdr(ExtractStatistics, &extracted); +- if (ret != 1) { +- fprintf(stderr, "FAILED\n"); +- return 1; +- } ++ ksft_print_header(); ++ ksft_set_plan(4); + +- if (extracted.alignment == 0) { +- fprintf(stderr, "No alignment found\n"); +- return 1; +- } else if (extracted.alignment & (extracted.alignment - 1)) { +- fprintf(stderr, "Alignment is not a power of 2\n"); +- return 1; ++ /* Dump maps file for debugging reference. */ ++ maps = fopen("/proc/self/maps", "r"); ++ if (!maps) ++ ksft_exit_fail_msg("FAILED: /proc/self/maps: %s\n", strerror(errno)); ++ while (fgets(buf, sizeof(buf), maps)) { ++ ksft_print_msg("%s", buf); + } ++ fclose(maps); ++ ++ /* Walk the program headers. */ ++ ret = dl_iterate_phdr(ExtractStatistics, &extracted); ++ if (ret != 1) ++ ksft_exit_fail_msg("FAILED: dl_iterate_phdr\n"); ++ ++ /* Report our findings. */ ++ ksft_print_msg("load_address=%#llx alignment=%#llx\n", ++ extracted.load_address, extracted.alignment); ++ ++ /* If we're named with ".static." we expect no INTERP. */ ++ interp_needed = strstr(argv[0], ".static.") == NULL; ++ ++ /* Were we built as expected? */ ++ ksft_test_result(interp_needed == extracted.interp, ++ "%s INTERP program header %s\n", ++ interp_needed ? "Wanted" : "Unwanted", ++ extracted.interp ? "seen" : "missing"); + ++ /* Did we find an alignment? */ ++ ksft_test_result(extracted.alignment != 0, ++ "Alignment%s found\n", extracted.alignment ? "" : " NOT"); ++ ++ /* Is the alignment sane? */ ++ pow2 = extracted.alignment & (extracted.alignment - 1); ++ ksft_test_result(pow2 == 0, ++ "Alignment is%s a power of 2: %#llx\n", ++ pow2 == 0 ? "" : " NOT", extracted.alignment); ++ ++ /* Is the load address aligned? */ + misalign = extracted.load_address & (extracted.alignment - 1); +- if (misalign) { +- printf("alignment = %llu, load_address = %llu\n", +- extracted.alignment, extracted.load_address); +- fprintf(stderr, "FAILED\n"); +- return 1; +- } ++ ksft_test_result(misalign == 0, "Load Address is %saligned (%#llx)\n", ++ misalign ? "MIS" : "", misalign); + +- fprintf(stderr, "PASS\n"); +- return 0; ++ ksft_finished(); + } +diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c +index 309b3750e57e13..38fec412206b9a 100644 +--- a/tools/testing/selftests/mm/compaction_test.c ++++ b/tools/testing/selftests/mm/compaction_test.c +@@ -89,6 +89,8 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size) + int compaction_index = 0; + char initial_nr_hugepages[20] = {0}; + char nr_hugepages[20] = {0}; ++ char target_nr_hugepages[24] = {0}; ++ int slen; + + /* We want to test with 80% of available memory. Else, OOM killer comes + in to play */ +@@ -119,11 +121,18 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size) + + lseek(fd, 0, SEEK_SET); + +- /* Request a large number of huge pages. The Kernel will allocate +- as much as it can */ +- if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { +- ksft_print_msg("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); ++ /* ++ * Request huge pages for about half of the free memory. The Kernel ++ * will allocate as much as it can, and we expect it will get at least 1/3 ++ */ ++ nr_hugepages_ul = mem_free / hugepage_size / 2; ++ snprintf(target_nr_hugepages, sizeof(target_nr_hugepages), ++ "%lu", nr_hugepages_ul); ++ ++ slen = strlen(target_nr_hugepages); ++ if (write(fd, target_nr_hugepages, slen) != slen) { ++ ksft_print_msg("Failed to write %lu to /proc/sys/vm/nr_hugepages: %s\n", ++ nr_hugepages_ul, strerror(errno)); + goto close_fd; + } + diff --git a/patch/kernel/archive/spacemit-6.6/patch-6.6.92-93.patch b/patch/kernel/archive/spacemit-6.6/patch-6.6.92-93.patch new file mode 100644 index 000000000000..24359d6adb34 --- /dev/null +++ b/patch/kernel/archive/spacemit-6.6/patch-6.6.92-93.patch @@ -0,0 +1,20602 @@ +diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd +index 825e619250bf2e..f2ec42949a54d7 100644 +--- a/Documentation/ABI/stable/sysfs-driver-dma-idxd ++++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd +@@ -270,6 +270,12 @@ Description: Shows the operation capability bits displayed in bitmap format + correlates to the operations allowed. It's visible only + on platforms that support the capability. + ++What: /sys/bus/dsa/devices/wq./driver_name ++Date: Sept 8, 2023 ++KernelVersion: 6.7.0 ++Contact: dmaengine@vger.kernel.org ++Description: Name of driver to be bounded to the wq. ++ + What: /sys/bus/dsa/devices/engine./group_id + Date: Oct 25, 2019 + KernelVersion: 5.6.0 +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index f95734ceb82b86..315a817e338042 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -5978,6 +5978,8 @@ + + Selecting 'on' will also enable the mitigation + against user space to user space task attacks. ++ Selecting specific mitigation does not force enable ++ user mitigations. + + Selecting 'off' will disable both the kernel and + the user space protections. +diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst +index 84b43061c11be2..60434f2b028637 100644 +--- a/Documentation/driver-api/serial/driver.rst ++++ b/Documentation/driver-api/serial/driver.rst +@@ -103,4 +103,4 @@ Some helpers are provided in order to set/get modem control lines via GPIO. + .. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c + :identifiers: mctrl_gpio_init mctrl_gpio_free mctrl_gpio_to_gpiod + mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms +- mctrl_gpio_disable_ms ++ mctrl_gpio_disable_ms_sync mctrl_gpio_disable_ms_no_sync +diff --git a/Documentation/hwmon/dell-smm-hwmon.rst b/Documentation/hwmon/dell-smm-hwmon.rst +index d8f1d6859b964b..1c12fbba440bca 100644 +--- a/Documentation/hwmon/dell-smm-hwmon.rst ++++ b/Documentation/hwmon/dell-smm-hwmon.rst +@@ -32,12 +32,12 @@ Temperature sensors and fans can be queried and set via the standard + =============================== ======= ======================================= + Name Perm Description + =============================== ======= ======================================= +-fan[1-3]_input RO Fan speed in RPM. +-fan[1-3]_label RO Fan label. +-fan[1-3]_min RO Minimal Fan speed in RPM +-fan[1-3]_max RO Maximal Fan speed in RPM +-fan[1-3]_target RO Expected Fan speed in RPM +-pwm[1-3] RW Control the fan PWM duty-cycle. ++fan[1-4]_input RO Fan speed in RPM. ++fan[1-4]_label RO Fan label. ++fan[1-4]_min RO Minimal Fan speed in RPM ++fan[1-4]_max RO Maximal Fan speed in RPM ++fan[1-4]_target RO Expected Fan speed in RPM ++pwm[1-4] RW Control the fan PWM duty-cycle. + pwm1_enable WO Enable or disable automatic BIOS fan + control (not supported on all laptops, + see below for details). +@@ -93,7 +93,7 @@ Again, when you find new codes, we'd be happy to have your patches! + --------------------------- + + The driver also exports the fans as thermal cooling devices with +-``type`` set to ``dell-smm-fan[1-3]``. This allows for easy fan control ++``type`` set to ``dell-smm-fan[1-4]``. This allows for easy fan control + using one of the thermal governors. + + Module parameters +diff --git a/Makefile b/Makefile +index 51d975b3555195..c9a1e2286b3a79 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 92 ++SUBLEVEL = 93 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/arm/boot/dts/nvidia/tegra114.dtsi b/arch/arm/boot/dts/nvidia/tegra114.dtsi +index 86f14e2fd29f3a..6c057b50695140 100644 +--- a/arch/arm/boot/dts/nvidia/tegra114.dtsi ++++ b/arch/arm/boot/dts/nvidia/tegra114.dtsi +@@ -139,7 +139,7 @@ dsib: dsi@54400000 { + reg = <0x54400000 0x00040000>; + clocks = <&tegra_car TEGRA114_CLK_DSIB>, + <&tegra_car TEGRA114_CLK_DSIBLP>, +- <&tegra_car TEGRA114_CLK_PLL_D2_OUT0>; ++ <&tegra_car TEGRA114_CLK_PLL_D_OUT0>; + clock-names = "dsi", "lp", "parent"; + resets = <&tegra_car 82>; + reset-names = "dsi"; +diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c +index 22ecaf09d00f96..f635ad29511f6a 100644 +--- a/arch/arm/mach-at91/pm.c ++++ b/arch/arm/mach-at91/pm.c +@@ -538,11 +538,12 @@ extern u32 at91_pm_suspend_in_sram_sz; + + static int at91_suspend_finish(unsigned long val) + { +- unsigned char modified_gray_code[] = { +- 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0c, 0x0d, +- 0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, 0x18, 0x19, 0x1a, 0x1b, +- 0x1e, 0x1f, 0x1c, 0x1d, 0x14, 0x15, 0x16, 0x17, 0x12, 0x13, +- 0x10, 0x11, ++ /* SYNOPSYS workaround to fix a bug in the calibration logic */ ++ unsigned char modified_fix_code[] = { ++ 0x00, 0x01, 0x01, 0x06, 0x07, 0x0c, 0x06, 0x07, 0x0b, 0x18, ++ 0x0a, 0x0b, 0x0c, 0x0d, 0x0d, 0x0a, 0x13, 0x13, 0x12, 0x13, ++ 0x14, 0x15, 0x15, 0x12, 0x18, 0x19, 0x19, 0x1e, 0x1f, 0x14, ++ 0x1e, 0x1f, + }; + unsigned int tmp, index; + int i; +@@ -553,25 +554,25 @@ static int at91_suspend_finish(unsigned long val) + * restore the ZQ0SR0 with the value saved here. But the + * calibration is buggy and restoring some values from ZQ0SR0 + * is forbidden and risky thus we need to provide processed +- * values for these (modified gray code values). ++ * values for these. + */ + tmp = readl(soc_pm.data.ramc_phy + DDR3PHY_ZQ0SR0); + + /* Store pull-down output impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PDO_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] = modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] = modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDO_OFF; + + /* Store pull-up output impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PUO_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PUO_OFF; + + /* Store pull-down on-die termination impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SR0_PDODT_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDODT_OFF; + + /* Store pull-up on-die termination impedance select. */ + index = (tmp >> DDR3PHY_ZQ0SRO_PUODT_OFF) & 0x1f; +- soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index]; ++ soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SRO_PUODT_OFF; + + /* + * The 1st 8 words of memory might get corrupted in the process +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +index 381d58cea092d9..c854c7e3105196 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +@@ -151,28 +151,12 @@ &pio { + vcc-pg-supply = <®_aldo1>; + }; + +-&r_ir { +- linux,rc-map-name = "rc-beelink-gs1"; +- status = "okay"; +-}; +- +-&r_pio { +- /* +- * FIXME: We can't add that supply for now since it would +- * create a circular dependency between pinctrl, the regulator +- * and the RSB Bus. +- * +- * vcc-pl-supply = <®_aldo1>; +- */ +- vcc-pm-supply = <®_aldo1>; +-}; +- +-&r_rsb { ++&r_i2c { + status = "okay"; + +- axp805: pmic@745 { ++ axp805: pmic@36 { + compatible = "x-powers,axp805", "x-powers,axp806"; +- reg = <0x745>; ++ reg = <0x36>; + interrupt-parent = <&r_intc>; + interrupts = ; + interrupt-controller; +@@ -290,6 +274,22 @@ sw { + }; + }; + ++&r_ir { ++ linux,rc-map-name = "rc-beelink-gs1"; ++ status = "okay"; ++}; ++ ++&r_pio { ++ /* ++ * PL0 and PL1 are used for PMIC I2C ++ * don't enable the pl-supply else ++ * it will fail at boot ++ * ++ * vcc-pl-supply = <®_aldo1>; ++ */ ++ vcc-pm-supply = <®_aldo1>; ++}; ++ + &spdif { + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx_pin>; +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +index 6fc65e8db22068..8c476e089185b5 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +@@ -175,16 +175,12 @@ &pio { + vcc-pg-supply = <®_vcc_wifi_io>; + }; + +-&r_ir { +- status = "okay"; +-}; +- +-&r_rsb { ++&r_i2c { + status = "okay"; + +- axp805: pmic@745 { ++ axp805: pmic@36 { + compatible = "x-powers,axp805", "x-powers,axp806"; +- reg = <0x745>; ++ reg = <0x36>; + interrupt-parent = <&r_intc>; + interrupts = ; + interrupt-controller; +@@ -295,6 +291,10 @@ sw { + }; + }; + ++&r_ir { ++ status = "okay"; ++}; ++ + &rtc { + clocks = <&ext_osc32k>; + }; +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi +index 92745128fcfebd..4ec4996592befb 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi +@@ -112,20 +112,12 @@ &pio { + vcc-pg-supply = <®_aldo1>; + }; + +-&r_ir { +- status = "okay"; +-}; +- +-&r_pio { +- vcc-pm-supply = <®_bldo3>; +-}; +- +-&r_rsb { ++&r_i2c { + status = "okay"; + +- axp805: pmic@745 { ++ axp805: pmic@36 { + compatible = "x-powers,axp805", "x-powers,axp806"; +- reg = <0x745>; ++ reg = <0x36>; + interrupt-parent = <&r_intc>; + interrupts = ; + interrupt-controller; +@@ -240,6 +232,14 @@ sw { + }; + }; + ++&r_ir { ++ status = "okay"; ++}; ++ ++&r_pio { ++ vcc-pm-supply = <®_bldo3>; ++}; ++ + &rtc { + clocks = <&ext_osc32k>; + }; +diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +index 3f79923376fb28..37244e8816d9e8 100644 +--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +@@ -26,6 +26,8 @@ memory@0 { + + leds { + compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi_quad_pins>; + + led-power1 { + label = "udpu:green:power"; +@@ -82,8 +84,6 @@ &sdhci0 { + + &spi0 { + status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&spi_quad_pins>; + + flash@0 { + compatible = "jedec,spi-nor"; +@@ -108,6 +108,10 @@ partition@180000 { + }; + }; + ++&spi_quad_pins { ++ function = "gpio"; ++}; ++ + &pinctrl_nb { + i2c2_recovery_pins: i2c2-recovery-pins { + groups = "i2c2"; +diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi +index b4a1108c2dd74f..0639f5ce1bd9e4 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi +@@ -1635,7 +1635,7 @@ vdd_1v8_dis: regulator-vdd-1v8-dis { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; +- gpio = <&exp1 14 GPIO_ACTIVE_HIGH>; ++ gpio = <&exp1 9 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_1v8>; + }; +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts +index bac611d735c589..2fa48972b2a91f 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dts +@@ -102,6 +102,16 @@ pcie@14160000 { + }; + + pcie@141a0000 { ++ reg = <0x00 0x141a0000 0x0 0x00020000 /* appl registers (128K) */ ++ 0x00 0x3a000000 0x0 0x00040000 /* configuration space (256K) */ ++ 0x00 0x3a040000 0x0 0x00040000 /* iATU_DMA reg space (256K) */ ++ 0x00 0x3a080000 0x0 0x00040000 /* DBI reg space (256K) */ ++ 0x2e 0x20000000 0x0 0x10000000>; /* ECAM (256MB) */ ++ ++ ranges = <0x81000000 0x00 0x3a100000 0x00 0x3a100000 0x0 0x00100000 /* downstream I/O (1MB) */ ++ 0x82000000 0x00 0x40000000 0x2e 0x30000000 0x0 0x08000000 /* non-prefetchable memory (128MB) */ ++ 0xc3000000 0x28 0x00000000 0x28 0x00000000 0x6 0x20000000>; /* prefetchable memory (25088MB) */ ++ + status = "okay"; + vddio-pex-ctl-supply = <&vdd_1v8_ls>; + phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>, +diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi +index 8a72ad4afd0320..82e4fd5eb388ff 100644 +--- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi +@@ -231,6 +231,8 @@ cryptobam: dma-controller@704000 { + interrupts = ; + #dma-cells = <1>; + qcom,ee = <1>; ++ qcom,num-ees = <4>; ++ num-channels = <16>; + qcom,controlled-remotely; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi +index 2a4d950ac02bfe..5376c0a00fab65 100644 +--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi +@@ -442,7 +442,7 @@ cdsp_secure_heap: memory@80c00000 { + no-map; + }; + +- pil_camera_mem: mmeory@85200000 { ++ pil_camera_mem: memory@85200000 { + reg = <0x0 0x85200000 0x0 0x500000>; + no-map; + }; +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 3b4d7882300897..c1ed39cac8c5b7 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -4233,6 +4233,8 @@ cryptobam: dma-controller@1dc4000 { + interrupts = ; + #dma-cells = <1>; + qcom,ee = <0>; ++ qcom,num-ees = <4>; ++ num-channels = <16>; + qcom,controlled-remotely; + iommus = <&apps_smmu 0x584 0x11>, + <&apps_smmu 0x588 0x0>, +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index bc9a1fca2db3ae..c14c6f8583d548 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -1866,6 +1866,8 @@ cryptobam: dma-controller@1dc4000 { + interrupts = ; + #dma-cells = <1>; + qcom,ee = <0>; ++ qcom,num-ees = <4>; ++ num-channels = <20>; + qcom,controlled-remotely; + iommus = <&apps_smmu 0x480 0x0>, + <&apps_smmu 0x481 0x0>; +diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +index 5df5946687b348..2e92f4174b3cf0 100644 +--- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts ++++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +@@ -43,6 +43,17 @@ vusb_main: regulator-vusb-main5v0 { + regulator-boot-on; + }; + ++ vsys_5v0: regulator-vsys5v0 { ++ /* Output of LM61460 */ ++ compatible = "regulator-fixed"; ++ regulator-name = "vsys_5v0"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vusb_main>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ + vsys_3v3: regulator-vsys3v3 { + /* Output of LM5141 */ + compatible = "regulator-fixed"; +@@ -75,7 +86,7 @@ vdd_sd_dv: regulator-tlv71033 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; +- vin-supply = <&vsys_3v3>; ++ vin-supply = <&vsys_5v0>; + gpios = <&main_gpio0 49 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; +diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi +index ccaca29200bb93..995bd8ce9d43af 100644 +--- a/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi ++++ b/arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi +@@ -10,39 +10,44 @@ + + #include + / { +- pss_ref_clk: pss_ref_clk { ++ pss_ref_clk: pss-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <33333333>; ++ clock-output-names = "pss_ref_clk"; + }; + +- video_clk: video_clk { ++ video_clk: video-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; ++ clock-output-names = "video_clk"; + }; + +- pss_alt_ref_clk: pss_alt_ref_clk { ++ pss_alt_ref_clk: pss-alt-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; ++ clock-output-names = "pss_alt_ref_clk"; + }; + +- gt_crx_ref_clk: gt_crx_ref_clk { ++ gt_crx_ref_clk: gt-crx-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <108000000>; ++ clock-output-names = "gt_crx_ref_clk"; + }; + +- aux_ref_clk: aux_ref_clk { ++ aux_ref_clk: aux-ref-clk { + bootph-all; + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; ++ clock-output-names = "aux_ref_clk"; + }; + }; + +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index 8a6b7feca3e428..d92a0203e5a93d 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -132,6 +132,7 @@ + #define FUJITSU_CPU_PART_A64FX 0x001 + + #define HISI_CPU_PART_TSV110 0xD01 ++#define HISI_CPU_PART_HIP09 0xD02 + + #define APPLE_CPU_PART_M1_ICESTORM 0x022 + #define APPLE_CPU_PART_M1_FIRESTORM 0x023 +@@ -208,6 +209,7 @@ + #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL) + #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX) + #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110) ++#define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09) + #define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) + #define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) + #define MIDR_APPLE_M1_ICESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO) +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index 07bdf5dd8ebef5..0212129b13d074 100644 +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -679,7 +679,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) + pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e)) + + #define pud_none(pud) (!pud_val(pud)) +-#define pud_bad(pud) (!pud_table(pud)) ++#define pud_bad(pud) ((pud_val(pud) & PUD_TYPE_MASK) != \ ++ PUD_TYPE_TABLE) + #define pud_present(pud) pte_present(pud_pte(pud)) + #define pud_leaf(pud) (pud_present(pud) && !pud_table(pud)) + #define pud_valid(pud) pte_valid(pud_pte(pud)) +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index 28c48bc9c09538..2c81e0efaf378e 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -904,6 +904,7 @@ static u8 spectre_bhb_loop_affected(void) + MIDR_ALL_VERSIONS(MIDR_CORTEX_A77), + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), + MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_GOLD), ++ MIDR_ALL_VERSIONS(MIDR_HISI_HIP09), + {}, + }; + static const struct midr_range spectre_bhb_k11_list[] = { +diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h +index db497a8167da29..e3212f44446fa9 100644 +--- a/arch/mips/include/asm/ftrace.h ++++ b/arch/mips/include/asm/ftrace.h +@@ -87,4 +87,20 @@ struct dyn_arch_ftrace { + #endif /* CONFIG_DYNAMIC_FTRACE */ + #endif /* __ASSEMBLY__ */ + #endif /* CONFIG_FUNCTION_TRACER */ ++ ++#ifdef CONFIG_FTRACE_SYSCALLS ++#ifndef __ASSEMBLY__ ++/* ++ * Some syscall entry functions on mips start with "__sys_" (fork and clone, ++ * for instance). We should also match the sys_ variant with those. ++ */ ++#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME ++static inline bool arch_syscall_match_sym_name(const char *sym, ++ const char *name) ++{ ++ return !strcmp(sym, name) || ++ (!strncmp(sym, "__sys_", 6) && !strcmp(sym + 6, name + 4)); ++} ++#endif /* __ASSEMBLY__ */ ++#endif /* CONFIG_FTRACE_SYSCALLS */ + #endif /* _ASM_MIPS_FTRACE_H */ +diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c +index 9bf60d7d44d362..a7bcf2b814c865 100644 +--- a/arch/mips/kernel/pm-cps.c ++++ b/arch/mips/kernel/pm-cps.c +@@ -56,10 +56,7 @@ static DEFINE_PER_CPU_ALIGNED(u32*, ready_count); + /* Indicates online CPUs coupled with the current CPU */ + static DEFINE_PER_CPU_ALIGNED(cpumask_t, online_coupled); + +-/* +- * Used to synchronize entry to deep idle states. Actually per-core rather +- * than per-CPU. +- */ ++/* Used to synchronize entry to deep idle states */ + static DEFINE_PER_CPU_ALIGNED(atomic_t, pm_barrier); + + /* Saved CPU state across the CPS_PM_POWER_GATED state */ +@@ -118,9 +115,10 @@ int cps_pm_enter_state(enum cps_pm_state state) + cps_nc_entry_fn entry; + struct core_boot_config *core_cfg; + struct vpe_boot_config *vpe_cfg; ++ atomic_t *barrier; + + /* Check that there is an entry function for this state */ +- entry = per_cpu(nc_asm_enter, core)[state]; ++ entry = per_cpu(nc_asm_enter, cpu)[state]; + if (!entry) + return -EINVAL; + +@@ -156,7 +154,7 @@ int cps_pm_enter_state(enum cps_pm_state state) + smp_mb__after_atomic(); + + /* Create a non-coherent mapping of the core ready_count */ +- core_ready_count = per_cpu(ready_count, core); ++ core_ready_count = per_cpu(ready_count, cpu); + nc_addr = kmap_noncoherent(virt_to_page(core_ready_count), + (unsigned long)core_ready_count); + nc_addr += ((unsigned long)core_ready_count & ~PAGE_MASK); +@@ -164,7 +162,8 @@ int cps_pm_enter_state(enum cps_pm_state state) + + /* Ensure ready_count is zero-initialised before the assembly runs */ + WRITE_ONCE(*nc_core_ready_count, 0); +- coupled_barrier(&per_cpu(pm_barrier, core), online); ++ barrier = &per_cpu(pm_barrier, cpumask_first(&cpu_sibling_map[cpu])); ++ coupled_barrier(barrier, online); + + /* Run the generated entry code */ + left = entry(online, nc_core_ready_count); +@@ -635,12 +634,14 @@ static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) + + static int cps_pm_online_cpu(unsigned int cpu) + { +- enum cps_pm_state state; +- unsigned core = cpu_core(&cpu_data[cpu]); ++ unsigned int sibling, core; + void *entry_fn, *core_rc; ++ enum cps_pm_state state; ++ ++ core = cpu_core(&cpu_data[cpu]); + + for (state = CPS_PM_NC_WAIT; state < CPS_PM_STATE_COUNT; state++) { +- if (per_cpu(nc_asm_enter, core)[state]) ++ if (per_cpu(nc_asm_enter, cpu)[state]) + continue; + if (!test_bit(state, state_support)) + continue; +@@ -652,16 +653,19 @@ static int cps_pm_online_cpu(unsigned int cpu) + clear_bit(state, state_support); + } + +- per_cpu(nc_asm_enter, core)[state] = entry_fn; ++ for_each_cpu(sibling, &cpu_sibling_map[cpu]) ++ per_cpu(nc_asm_enter, sibling)[state] = entry_fn; + } + +- if (!per_cpu(ready_count, core)) { ++ if (!per_cpu(ready_count, cpu)) { + core_rc = kmalloc(sizeof(u32), GFP_KERNEL); + if (!core_rc) { + pr_err("Failed allocate core %u ready_count\n", core); + return -ENOMEM; + } +- per_cpu(ready_count, core) = core_rc; ++ ++ for_each_cpu(sibling, &cpu_sibling_map[cpu]) ++ per_cpu(ready_count, sibling) = core_rc; + } + + return 0; +diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h +index da827d2d08666e..f2c4457c94c397 100644 +--- a/arch/powerpc/include/asm/mmzone.h ++++ b/arch/powerpc/include/asm/mmzone.h +@@ -35,6 +35,7 @@ extern cpumask_var_t node_to_cpumask_map[]; + #ifdef CONFIG_MEMORY_HOTPLUG + extern unsigned long max_pfn; + u64 memory_hotplug_max(void); ++u64 hot_add_drconf_memory_max(void); + #else + #define memory_hotplug_max() memblock_end_of_DRAM() + #endif +diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c +index a6090896f74979..ac669e58e20230 100644 +--- a/arch/powerpc/kernel/prom_init.c ++++ b/arch/powerpc/kernel/prom_init.c +@@ -2974,11 +2974,11 @@ static void __init fixup_device_tree_pmac(void) + char type[8]; + phandle node; + +- // Some pmacs are missing #size-cells on escc nodes ++ // Some pmacs are missing #size-cells on escc or i2s nodes + for (node = 0; prom_next_node(&node); ) { + type[0] = '\0'; + prom_getprop(node, "device_type", type, sizeof(type)); +- if (prom_strcmp(type, "escc")) ++ if (prom_strcmp(type, "escc") && prom_strcmp(type, "i2s")) + continue; + + if (prom_getproplen(node, "#size-cells") != PROM_ERROR) +diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c +index 28460e33408084..aff3b37e32d64e 100644 +--- a/arch/powerpc/mm/book3s64/radix_pgtable.c ++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c +@@ -912,7 +912,7 @@ int __meminit radix__vmemmap_create_mapping(unsigned long start, + return 0; + } + +- ++#ifdef CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP + bool vmemmap_can_optimize(struct vmem_altmap *altmap, struct dev_pagemap *pgmap) + { + if (radix_enabled()) +@@ -920,6 +920,7 @@ bool vmemmap_can_optimize(struct vmem_altmap *altmap, struct dev_pagemap *pgmap) + + return false; + } ++#endif + + int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node, + unsigned long addr, unsigned long next) +diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c +index f6c4ace3b22197..65a9df0b9e5a09 100644 +--- a/arch/powerpc/mm/numa.c ++++ b/arch/powerpc/mm/numa.c +@@ -1342,7 +1342,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr) + return nid; + } + +-static u64 hot_add_drconf_memory_max(void) ++u64 hot_add_drconf_memory_max(void) + { + struct device_node *memory = NULL; + struct device_node *dn = NULL; +diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c +index 10b946e9c6e756..4bb84dc4393fca 100644 +--- a/arch/powerpc/perf/core-book3s.c ++++ b/arch/powerpc/perf/core-book3s.c +@@ -2229,6 +2229,10 @@ static struct pmu power_pmu = { + #define PERF_SAMPLE_ADDR_TYPE (PERF_SAMPLE_ADDR | \ + PERF_SAMPLE_PHYS_ADDR | \ + PERF_SAMPLE_DATA_PAGE_SIZE) ++ ++#define SIER_TYPE_SHIFT 15 ++#define SIER_TYPE_MASK (0x7ull << SIER_TYPE_SHIFT) ++ + /* + * A counter has overflowed; update its count and record + * things if requested. Note that interrupts are hard-disabled +@@ -2297,6 +2301,22 @@ static void record_and_restart(struct perf_event *event, unsigned long val, + is_kernel_addr(mfspr(SPRN_SIAR))) + record = 0; + ++ /* ++ * SIER[46-48] presents instruction type of the sampled instruction. ++ * In ISA v3.0 and before values "0" and "7" are considered reserved. ++ * In ISA v3.1, value "7" has been used to indicate "larx/stcx". ++ * Drop the sample if "type" has reserved values for this field with a ++ * ISA version check. ++ */ ++ if (event->attr.sample_type & PERF_SAMPLE_DATA_SRC && ++ ppmu->get_mem_data_src) { ++ val = (regs->dar & SIER_TYPE_MASK) >> SIER_TYPE_SHIFT; ++ if (val == 0 || (val == 7 && !cpu_has_feature(CPU_FTR_ARCH_31))) { ++ record = 0; ++ atomic64_inc(&event->lost_samples); ++ } ++ } ++ + /* + * Finally record data if requested. + */ +diff --git a/arch/powerpc/perf/isa207-common.c b/arch/powerpc/perf/isa207-common.c +index 56301b2bc8ae87..031a2b63c171dc 100644 +--- a/arch/powerpc/perf/isa207-common.c ++++ b/arch/powerpc/perf/isa207-common.c +@@ -321,8 +321,10 @@ void isa207_get_mem_data_src(union perf_mem_data_src *dsrc, u32 flags, + + sier = mfspr(SPRN_SIER); + val = (sier & ISA207_SIER_TYPE_MASK) >> ISA207_SIER_TYPE_SHIFT; +- if (val != 1 && val != 2 && !(val == 7 && cpu_has_feature(CPU_FTR_ARCH_31))) ++ if (val != 1 && val != 2 && !(val == 7 && cpu_has_feature(CPU_FTR_ARCH_31))) { ++ dsrc->val = 0; + return; ++ } + + idx = (sier & ISA207_SIER_LDST_MASK) >> ISA207_SIER_LDST_SHIFT; + sub_idx = (sier & ISA207_SIER_DATA_SRC_MASK) >> ISA207_SIER_DATA_SRC_SHIFT; +diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c +index b1e6d275cda9eb..bf02f94a973dbd 100644 +--- a/arch/powerpc/platforms/pseries/iommu.c ++++ b/arch/powerpc/platforms/pseries/iommu.c +@@ -1183,17 +1183,13 @@ static LIST_HEAD(failed_ddw_pdn_list); + + static phys_addr_t ddw_memory_hotplug_max(void) + { +- resource_size_t max_addr = memory_hotplug_max(); +- struct device_node *memory; ++ resource_size_t max_addr; + +- for_each_node_by_type(memory, "memory") { +- struct resource res; +- +- if (of_address_to_resource(memory, 0, &res)) +- continue; +- +- max_addr = max_t(resource_size_t, max_addr, res.end + 1); +- } ++#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG) ++ max_addr = hot_add_drconf_memory_max(); ++#else ++ max_addr = memblock_end_of_DRAM(); ++#endif + + return max_addr; + } +@@ -1471,7 +1467,7 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) + window->direct = true; + + /* DDW maps the whole partition, so enable direct DMA mapping */ +- ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT, ++ ret = walk_system_ram_range(0, ddw_memory_hotplug_max() >> PAGE_SHIFT, + win64->value, tce_setrange_multi_pSeriesLP_walk); + if (ret) { + dev_info(&dev->dev, "failed to map DMA window for %pOF: %d\n", +@@ -1658,11 +1654,17 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, + struct memory_notify *arg = data; + int ret = 0; + ++ /* This notifier can get called when onlining persistent memory as well. ++ * TCEs are not pre-mapped for persistent memory. Persistent memory will ++ * always be above ddw_memory_hotplug_max() ++ */ ++ + switch (action) { + case MEM_GOING_ONLINE: + spin_lock(&dma_win_list_lock); + list_for_each_entry(window, &dma_win_list, list) { +- if (window->direct) { ++ if (window->direct && (arg->start_pfn << PAGE_SHIFT) < ++ ddw_memory_hotplug_max()) { + ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn, + arg->nr_pages, window->prop); + } +@@ -1674,7 +1676,8 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, + case MEM_OFFLINE: + spin_lock(&dma_win_list_lock); + list_for_each_entry(window, &dma_win_list, list) { +- if (window->direct) { ++ if (window->direct && (arg->start_pfn << PAGE_SHIFT) < ++ ddw_memory_hotplug_max()) { + ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn, + arg->nr_pages, window->prop); + } +diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h +index 4d1f58848129e8..dbb9d0d0f405e1 100644 +--- a/arch/riscv/include/asm/page.h ++++ b/arch/riscv/include/asm/page.h +@@ -26,12 +26,9 @@ + * When not using MMU this corresponds to the first free page in + * physical memory (aligned on a page boundary). + */ +-#ifdef CONFIG_64BIT + #ifdef CONFIG_MMU ++#ifdef CONFIG_64BIT + #define PAGE_OFFSET kernel_map.page_offset +-#else +-#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) +-#endif + /* + * By default, CONFIG_PAGE_OFFSET value corresponds to SV57 address space so + * define the PAGE_OFFSET value for SV48 and SV39. +@@ -41,6 +38,9 @@ + #else + #define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) + #endif /* CONFIG_64BIT */ ++#else ++#define PAGE_OFFSET ((unsigned long)phys_ram_base) ++#endif /* CONFIG_MMU */ + + #ifndef __ASSEMBLY__ + +@@ -97,11 +97,7 @@ typedef struct page *pgtable_t; + #define MIN_MEMBLOCK_ADDR 0 + #endif + +-#ifdef CONFIG_MMU + #define ARCH_PFN_OFFSET (PFN_DOWN((unsigned long)phys_ram_base)) +-#else +-#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) +-#endif /* CONFIG_MMU */ + + struct kernel_mapping { + unsigned long page_offset; +diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h +index f540b2625714d0..332a6bf72b1d54 100644 +--- a/arch/riscv/include/asm/pgtable.h ++++ b/arch/riscv/include/asm/pgtable.h +@@ -12,7 +12,7 @@ + #include + + #ifndef CONFIG_MMU +-#define KERNEL_LINK_ADDR PAGE_OFFSET ++#define KERNEL_LINK_ADDR _AC(CONFIG_PAGE_OFFSET, UL) + #define KERN_VIRT_SIZE (UL(-1)) + #else + +diff --git a/arch/s390/hypfs/hypfs_diag_fs.c b/arch/s390/hypfs/hypfs_diag_fs.c +index 00a6d370a28032..280266a74f378d 100644 +--- a/arch/s390/hypfs/hypfs_diag_fs.c ++++ b/arch/s390/hypfs/hypfs_diag_fs.c +@@ -208,6 +208,8 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info) + snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_get_info_type(), + cpu_info)); + cpu_dir = hypfs_mkdir(cpus_dir, buffer); ++ if (IS_ERR(cpu_dir)) ++ return PTR_ERR(cpu_dir); + rc = hypfs_create_u64(cpu_dir, "mgmtime", + cpu_info__acc_time(diag204_get_info_type(), cpu_info) - + cpu_info__lp_time(diag204_get_info_type(), cpu_info)); +diff --git a/arch/um/Makefile b/arch/um/Makefile +index 34957dcb88b9c3..744c5d0bdeb8fc 100644 +--- a/arch/um/Makefile ++++ b/arch/um/Makefile +@@ -151,5 +151,6 @@ MRPROPER_FILES += $(HOST_DIR)/include/generated + archclean: + @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ + -o -name '*.gcov' \) -type f -print | xargs rm -f ++ $(Q)$(MAKE) -f $(srctree)/Makefile ARCH=$(HEADER_ARCH) clean + + export HEADER_ARCH SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING DEV_NULL_PATH +diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c +index 38d5a71a579bcb..f6c766b2bdf5e4 100644 +--- a/arch/um/kernel/mem.c ++++ b/arch/um/kernel/mem.c +@@ -68,6 +68,7 @@ void __init mem_init(void) + map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); + memblock_free((void *)brk_end, uml_reserved - brk_end); + uml_reserved = brk_end; ++ min_low_pfn = PFN_UP(__pa(uml_reserved)); + + /* this will put all low memory onto the freelists */ + memblock_free_all(); +diff --git a/arch/x86/Makefile b/arch/x86/Makefile +index c83582b5a010de..6d593fb85a9e93 100644 +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -43,7 +43,7 @@ endif + + # How to compile the 16-bit code. Note we always compile for -march=i386; + # that way we can complain to the user if the CPU is insufficient. +-REALMODE_CFLAGS := -m16 -g -Os -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \ ++REALMODE_CFLAGS := -std=gnu11 -m16 -g -Os -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \ + -Wall -Wstrict-prototypes -march=i386 -mregparm=3 \ + -fno-strict-aliasing -fomit-frame-pointer -fno-pic \ + -mno-mmx -mno-sse $(call cc-option,-fcf-protection=none) +diff --git a/arch/x86/boot/genimage.sh b/arch/x86/boot/genimage.sh +index c9299aeb7333e6..3882ead513f742 100644 +--- a/arch/x86/boot/genimage.sh ++++ b/arch/x86/boot/genimage.sh +@@ -22,6 +22,7 @@ + # This script requires: + # bash + # syslinux ++# genisoimage + # mtools (for fdimage* and hdimage) + # edk2/OVMF (for hdimage) + # +@@ -251,7 +252,9 @@ geniso() { + cp "$isolinux" "$ldlinux" "$tmp_dir" + cp "$FBZIMAGE" "$tmp_dir"/linux + echo default linux "$KCMDLINE" > "$tmp_dir"/isolinux.cfg +- cp "${FDINITRDS[@]}" "$tmp_dir"/ ++ if [ ${#FDINITRDS[@]} -gt 0 ]; then ++ cp "${FDINITRDS[@]}" "$tmp_dir"/ ++ fi + genisoimage -J -r -appid 'LINUX_BOOT' -input-charset=utf-8 \ + -quiet -o "$FIMAGE" -b isolinux.bin \ + -c boot.cat -no-emul-boot -boot-load-size 4 \ +diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S +index 78fd2442b49dcd..ad292c0d971a3f 100644 +--- a/arch/x86/entry/entry.S ++++ b/arch/x86/entry/entry.S +@@ -59,7 +59,7 @@ EXPORT_SYMBOL_GPL(mds_verw_sel); + * entirely in the C code, and use an alias emitted by the linker script + * instead. + */ +-#ifdef CONFIG_STACKPROTECTOR ++#if defined(CONFIG_STACKPROTECTOR) && defined(CONFIG_SMP) + EXPORT_SYMBOL(__ref_stack_chk_guard); + #endif + #endif +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index f483874fa20f19..fac3d97111b098 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -272,7 +272,7 @@ static int perf_ibs_init(struct perf_event *event) + { + struct hw_perf_event *hwc = &event->hw; + struct perf_ibs *perf_ibs; +- u64 max_cnt, config; ++ u64 config; + int ret; + + perf_ibs = get_ibs_pmu(event->attr.type); +@@ -306,10 +306,19 @@ static int perf_ibs_init(struct perf_event *event) + if (!hwc->sample_period) + hwc->sample_period = 0x10; + } else { +- max_cnt = config & perf_ibs->cnt_mask; ++ u64 period = 0; ++ ++ if (perf_ibs == &perf_ibs_op) { ++ period = (config & IBS_OP_MAX_CNT) << 4; ++ if (ibs_caps & IBS_CAPS_OPCNTEXT) ++ period |= config & IBS_OP_MAX_CNT_EXT_MASK; ++ } else { ++ period = (config & IBS_FETCH_MAX_CNT) << 4; ++ } ++ + config &= ~perf_ibs->cnt_mask; +- event->attr.sample_period = max_cnt << 4; +- hwc->sample_period = event->attr.sample_period; ++ event->attr.sample_period = period; ++ hwc->sample_period = period; + } + + if (!hwc->sample_period) +@@ -1219,7 +1228,8 @@ static __init int perf_ibs_op_init(void) + if (ibs_caps & IBS_CAPS_OPCNTEXT) { + perf_ibs_op.max_period |= IBS_OP_MAX_CNT_EXT_MASK; + perf_ibs_op.config_mask |= IBS_OP_MAX_CNT_EXT_MASK; +- perf_ibs_op.cnt_mask |= IBS_OP_MAX_CNT_EXT_MASK; ++ perf_ibs_op.cnt_mask |= (IBS_OP_MAX_CNT_EXT_MASK | ++ IBS_OP_CUR_CNT_EXT_MASK); + } + + if (ibs_caps & IBS_CAPS_ZEN4) +diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h +index 806649c7f23dc6..9a0f29be1a9ea6 100644 +--- a/arch/x86/include/asm/bug.h ++++ b/arch/x86/include/asm/bug.h +@@ -22,8 +22,9 @@ + #define SECOND_BYTE_OPCODE_UD2 0x0b + + #define BUG_NONE 0xffff +-#define BUG_UD1 0xfffe +-#define BUG_UD2 0xfffd ++#define BUG_UD2 0xfffe ++#define BUG_UD1 0xfffd ++#define BUG_UD1_UBSAN 0xfffc + + #ifdef CONFIG_GENERIC_BUG + +diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h +index 1e59581d500ca9..b778ae6e67ee8c 100644 +--- a/arch/x86/include/asm/ibt.h ++++ b/arch/x86/include/asm/ibt.h +@@ -41,7 +41,7 @@ + _ASM_PTR fname "\n\t" \ + ".popsection\n\t" + +-static inline __attribute_const__ u32 gen_endbr(void) ++static __always_inline __attribute_const__ u32 gen_endbr(void) + { + u32 endbr; + +@@ -56,7 +56,7 @@ static inline __attribute_const__ u32 gen_endbr(void) + return endbr; + } + +-static inline __attribute_const__ u32 gen_endbr_poison(void) ++static __always_inline __attribute_const__ u32 gen_endbr_poison(void) + { + /* + * 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it +diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h +index 5c5f1e56c4048d..6f3d145670a957 100644 +--- a/arch/x86/include/asm/nmi.h ++++ b/arch/x86/include/asm/nmi.h +@@ -59,6 +59,8 @@ int __register_nmi_handler(unsigned int, struct nmiaction *); + + void unregister_nmi_handler(unsigned int, const char *); + ++void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler); ++ + void stop_nmi(void); + void restart_nmi(void); + void local_touch_nmi(void); +diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h +index 384e8a7db4827b..ba2a3935dc624d 100644 +--- a/arch/x86/include/asm/perf_event.h ++++ b/arch/x86/include/asm/perf_event.h +@@ -501,6 +501,7 @@ struct pebs_xmm { + */ + #define IBS_OP_CUR_CNT (0xFFF80ULL<<32) + #define IBS_OP_CUR_CNT_RAND (0x0007FULL<<32) ++#define IBS_OP_CUR_CNT_EXT_MASK (0x7FULL<<52) + #define IBS_OP_CNT_CTL (1ULL<<19) + #define IBS_OP_VAL (1ULL<<18) + #define IBS_OP_ENABLE (1ULL<<17) +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 07b45bbf6348de..e9c4bcb38f4586 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -1442,9 +1442,13 @@ static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd; + static enum spectre_v2_user_cmd __init + spectre_v2_parse_user_cmdline(void) + { ++ enum spectre_v2_user_cmd mode; + char arg[20]; + int ret, i; + ++ mode = IS_ENABLED(CONFIG_MITIGATION_SPECTRE_V2) ? ++ SPECTRE_V2_USER_CMD_AUTO : SPECTRE_V2_USER_CMD_NONE; ++ + switch (spectre_v2_cmd) { + case SPECTRE_V2_CMD_NONE: + return SPECTRE_V2_USER_CMD_NONE; +@@ -1457,7 +1461,7 @@ spectre_v2_parse_user_cmdline(void) + ret = cmdline_find_option(boot_command_line, "spectre_v2_user", + arg, sizeof(arg)); + if (ret < 0) +- return SPECTRE_V2_USER_CMD_AUTO; ++ return mode; + + for (i = 0; i < ARRAY_SIZE(v2_user_options); i++) { + if (match_option(arg, ret, v2_user_options[i].option)) { +@@ -1467,8 +1471,8 @@ spectre_v2_parse_user_cmdline(void) + } + } + +- pr_err("Unknown user space protection option (%s). Switching to AUTO select\n", arg); +- return SPECTRE_V2_USER_CMD_AUTO; ++ pr_err("Unknown user space protection option (%s). Switching to default\n", arg); ++ return mode; + } + + static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode) +diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c +index 6da2cfa23c2939..35fd5f1444fdb4 100644 +--- a/arch/x86/kernel/nmi.c ++++ b/arch/x86/kernel/nmi.c +@@ -39,8 +39,12 @@ + #define CREATE_TRACE_POINTS + #include + ++/* ++ * An emergency handler can be set in any context including NMI ++ */ + struct nmi_desc { + raw_spinlock_t lock; ++ nmi_handler_t emerg_handler; + struct list_head head; + }; + +@@ -131,9 +135,22 @@ static void nmi_check_duration(struct nmiaction *action, u64 duration) + static int nmi_handle(unsigned int type, struct pt_regs *regs) + { + struct nmi_desc *desc = nmi_to_desc(type); ++ nmi_handler_t ehandler; + struct nmiaction *a; + int handled=0; + ++ /* ++ * Call the emergency handler, if set ++ * ++ * In the case of crash_nmi_callback() emergency handler, it will ++ * return in the case of the crashing CPU to enable it to complete ++ * other necessary crashing actions ASAP. Other handlers in the ++ * linked list won't need to be run. ++ */ ++ ehandler = desc->emerg_handler; ++ if (ehandler) ++ return ehandler(type, regs); ++ + rcu_read_lock(); + + /* +@@ -223,6 +240,31 @@ void unregister_nmi_handler(unsigned int type, const char *name) + } + EXPORT_SYMBOL_GPL(unregister_nmi_handler); + ++/** ++ * set_emergency_nmi_handler - Set emergency handler ++ * @type: NMI type ++ * @handler: the emergency handler to be stored ++ * ++ * Set an emergency NMI handler which, if set, will preempt all the other ++ * handlers in the linked list. If a NULL handler is passed in, it will clear ++ * it. It is expected that concurrent calls to this function will not happen ++ * or the system is screwed beyond repair. ++ */ ++void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler) ++{ ++ struct nmi_desc *desc = nmi_to_desc(type); ++ ++ if (WARN_ON_ONCE(desc->emerg_handler == handler)) ++ return; ++ desc->emerg_handler = handler; ++ ++ /* ++ * Ensure the emergency handler is visible to other CPUs before ++ * function return ++ */ ++ smp_wmb(); ++} ++ + static void + pci_serr_error(unsigned char reason, struct pt_regs *regs) + { +diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c +index 830425e6d38e2f..456e61070a730b 100644 +--- a/arch/x86/kernel/reboot.c ++++ b/arch/x86/kernel/reboot.c +@@ -908,15 +908,11 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback) + shootdown_callback = callback; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); +- /* Would it be better to replace the trap vector here? */ +- if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback, +- NMI_FLAG_FIRST, "crash")) +- return; /* Return what? */ ++ + /* +- * Ensure the new callback function is set before sending +- * out the NMI ++ * Set emergency handler to preempt other handlers. + */ +- wmb(); ++ set_emergency_nmi_handler(NMI_LOCAL, crash_nmi_callback); + + apic_send_IPI_allbutself(NMI_VECTOR); + +diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c +index d8d9bc5a9b3280..8718d58dd0fbea 100644 +--- a/arch/x86/kernel/traps.c ++++ b/arch/x86/kernel/traps.c +@@ -92,10 +92,17 @@ __always_inline int is_valid_bugaddr(unsigned long addr) + + /* + * Check for UD1 or UD2, accounting for Address Size Override Prefixes. +- * If it's a UD1, get the ModRM byte to pass along to UBSan. ++ * If it's a UD1, further decode to determine its use: ++ * ++ * UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax ++ * UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax ++ * static_call: 0f b9 cc ud1 %esp,%ecx ++ * ++ * Notably UBSAN uses EAX, static_call uses ECX. + */ +-__always_inline int decode_bug(unsigned long addr, u32 *imm) ++__always_inline int decode_bug(unsigned long addr, s32 *imm, int *len) + { ++ unsigned long start = addr; + u8 v; + + if (addr < TASK_SIZE_MAX) +@@ -108,24 +115,42 @@ __always_inline int decode_bug(unsigned long addr, u32 *imm) + return BUG_NONE; + + v = *(u8 *)(addr++); +- if (v == SECOND_BYTE_OPCODE_UD2) ++ if (v == SECOND_BYTE_OPCODE_UD2) { ++ *len = addr - start; + return BUG_UD2; ++ } + +- if (!IS_ENABLED(CONFIG_UBSAN_TRAP) || v != SECOND_BYTE_OPCODE_UD1) ++ if (v != SECOND_BYTE_OPCODE_UD1) + return BUG_NONE; + +- /* Retrieve the immediate (type value) for the UBSAN UD1 */ +- v = *(u8 *)(addr++); +- if (X86_MODRM_RM(v) == 4) +- addr++; +- + *imm = 0; +- if (X86_MODRM_MOD(v) == 1) +- *imm = *(u8 *)addr; +- else if (X86_MODRM_MOD(v) == 2) +- *imm = *(u32 *)addr; +- else +- WARN_ONCE(1, "Unexpected MODRM_MOD: %u\n", X86_MODRM_MOD(v)); ++ v = *(u8 *)(addr++); /* ModRM */ ++ ++ if (X86_MODRM_MOD(v) != 3 && X86_MODRM_RM(v) == 4) ++ addr++; /* SIB */ ++ ++ /* Decode immediate, if present */ ++ switch (X86_MODRM_MOD(v)) { ++ case 0: if (X86_MODRM_RM(v) == 5) ++ addr += 4; /* RIP + disp32 */ ++ break; ++ ++ case 1: *imm = *(s8 *)addr; ++ addr += 1; ++ break; ++ ++ case 2: *imm = *(s32 *)addr; ++ addr += 4; ++ break; ++ ++ case 3: break; ++ } ++ ++ /* record instruction length */ ++ *len = addr - start; ++ ++ if (X86_MODRM_REG(v) == 0) /* EAX */ ++ return BUG_UD1_UBSAN; + + return BUG_UD1; + } +@@ -256,10 +281,10 @@ static inline void handle_invalid_op(struct pt_regs *regs) + static noinstr bool handle_bug(struct pt_regs *regs) + { + bool handled = false; +- int ud_type; +- u32 imm; ++ int ud_type, ud_len; ++ s32 ud_imm; + +- ud_type = decode_bug(regs->ip, &imm); ++ ud_type = decode_bug(regs->ip, &ud_imm, &ud_len); + if (ud_type == BUG_NONE) + return handled; + +@@ -279,15 +304,28 @@ static noinstr bool handle_bug(struct pt_regs *regs) + */ + if (regs->flags & X86_EFLAGS_IF) + raw_local_irq_enable(); +- if (ud_type == BUG_UD2) { ++ ++ switch (ud_type) { ++ case BUG_UD2: + if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN || + handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) { +- regs->ip += LEN_UD2; ++ regs->ip += ud_len; + handled = true; + } +- } else if (IS_ENABLED(CONFIG_UBSAN_TRAP)) { +- pr_crit("%s at %pS\n", report_ubsan_failure(regs, imm), (void *)regs->ip); ++ break; ++ ++ case BUG_UD1_UBSAN: ++ if (IS_ENABLED(CONFIG_UBSAN_TRAP)) { ++ pr_crit("%s at %pS\n", ++ report_ubsan_failure(regs, ud_imm), ++ (void *)regs->ip); ++ } ++ break; ++ ++ default: ++ break; + } ++ + if (regs->flags & X86_EFLAGS_IF) + raw_local_irq_disable(); + instrumentation_end(); +diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c +index 71d29dd7ad761e..6cbb5974e4f9ea 100644 +--- a/arch/x86/mm/init.c ++++ b/arch/x86/mm/init.c +@@ -644,8 +644,13 @@ static void __init memory_map_top_down(unsigned long map_start, + */ + addr = memblock_phys_alloc_range(PMD_SIZE, PMD_SIZE, map_start, + map_end); +- memblock_phys_free(addr, PMD_SIZE); +- real_end = addr + PMD_SIZE; ++ if (!addr) { ++ pr_warn("Failed to release memory for alloc_low_pages()"); ++ real_end = max(map_start, ALIGN_DOWN(map_end, PMD_SIZE)); ++ } else { ++ memblock_phys_free(addr, PMD_SIZE); ++ real_end = addr + PMD_SIZE; ++ } + + /* step_size need to be small so pgt_buf from BRK could cover it */ + step_size = PMD_SIZE; +diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c +index aa69353da49f24..11eb93e13ce175 100644 +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -959,9 +959,18 @@ int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages, + ret = __add_pages(nid, start_pfn, nr_pages, params); + WARN_ON_ONCE(ret); + +- /* update max_pfn, max_low_pfn and high_memory */ +- update_end_of_memory_vars(start_pfn << PAGE_SHIFT, +- nr_pages << PAGE_SHIFT); ++ /* ++ * Special case: add_pages() is called by memremap_pages() for adding device ++ * private pages. Do not bump up max_pfn in the device private path, ++ * because max_pfn changes affect dma_addressing_limited(). ++ * ++ * dma_addressing_limited() returning true when max_pfn is the device's ++ * addressable memory can force device drivers to use bounce buffers ++ * and impact their performance negatively: ++ */ ++ if (!params->pgmap) ++ /* update max_pfn, max_low_pfn and high_memory */ ++ update_end_of_memory_vars(start_pfn << PAGE_SHIFT, nr_pages << PAGE_SHIFT); + + return ret; + } +diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c +index 230f1dee4f0954..e0b0ec0f824574 100644 +--- a/arch/x86/mm/kaslr.c ++++ b/arch/x86/mm/kaslr.c +@@ -109,8 +109,14 @@ void __init kernel_randomize_memory(void) + memory_tb = DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) + + CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING; + +- /* Adapt physical memory region size based on available memory */ +- if (memory_tb < kaslr_regions[0].size_tb) ++ /* ++ * Adapt physical memory region size based on available memory, ++ * except when CONFIG_PCI_P2PDMA is enabled. P2PDMA exposes the ++ * device BAR space assuming the direct map space is large enough ++ * for creating a ZONE_DEVICE mapping in the direct map corresponding ++ * to the physical BAR address. ++ */ ++ if (!IS_ENABLED(CONFIG_PCI_P2PDMA) && (memory_tb < kaslr_regions[0].size_tb)) + kaslr_regions[0].size_tb = memory_tb; + + /* +diff --git a/arch/x86/um/os-Linux/mcontext.c b/arch/x86/um/os-Linux/mcontext.c +index 49c3744cac371b..81b9d1f9f4e68b 100644 +--- a/arch/x86/um/os-Linux/mcontext.c ++++ b/arch/x86/um/os-Linux/mcontext.c +@@ -26,7 +26,6 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc) + COPY(RIP); + COPY2(EFLAGS, EFL); + COPY2(CS, CSGSFS); +- regs->gp[CS / sizeof(unsigned long)] &= 0xffff; +- regs->gp[CS / sizeof(unsigned long)] |= 3; ++ regs->gp[SS / sizeof(unsigned long)] = mc->gregs[REG_CSGSFS] >> 48; + #endif + } +diff --git a/crypto/ahash.c b/crypto/ahash.c +index 709ef094079913..6168f3532f552a 100644 +--- a/crypto/ahash.c ++++ b/crypto/ahash.c +@@ -427,6 +427,7 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) + hash->setkey = ahash_nosetkey; + + crypto_ahash_set_statesize(hash, alg->halg.statesize); ++ crypto_ahash_set_reqsize(hash, alg->reqsize); + + if (tfm->__crt_alg->cra_type != &crypto_ahash_type) + return crypto_init_shash_ops_async(tfm); +@@ -599,6 +600,9 @@ static int ahash_prepare_alg(struct ahash_alg *alg) + if (alg->halg.statesize == 0) + return -EINVAL; + ++ if (alg->reqsize && alg->reqsize < alg->halg.statesize) ++ return -EINVAL; ++ + err = hash_prepare_alg(&alg->halg); + if (err) + return err; +diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c +index e24c829d7a0154..5ab7441734b8e0 100644 +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -265,10 +265,6 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags, + goto out_free_state; + + err = crypto_ahash_import(&ctx2->req, state); +- if (err) { +- sock_orphan(sk2); +- sock_put(sk2); +- } + + out_free_state: + kfree_sensitive(state); +diff --git a/crypto/lzo-rle.c b/crypto/lzo-rle.c +index 0631d975bfac11..0abc2d87f04200 100644 +--- a/crypto/lzo-rle.c ++++ b/crypto/lzo-rle.c +@@ -55,7 +55,7 @@ static int __lzorle_compress(const u8 *src, unsigned int slen, + size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ + int err; + +- err = lzorle1x_1_compress(src, slen, dst, &tmp_len, ctx); ++ err = lzorle1x_1_compress_safe(src, slen, dst, &tmp_len, ctx); + + if (err != LZO_E_OK) + return -EINVAL; +diff --git a/crypto/lzo.c b/crypto/lzo.c +index ebda132dd22bf5..8338851c7406a3 100644 +--- a/crypto/lzo.c ++++ b/crypto/lzo.c +@@ -55,7 +55,7 @@ static int __lzo_compress(const u8 *src, unsigned int slen, + size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ + int err; + +- err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx); ++ err = lzo1x_1_compress_safe(src, slen, dst, &tmp_len, ctx); + + if (err != LZO_E_OK) + return -EINVAL; +diff --git a/crypto/skcipher.c b/crypto/skcipher.c +index 7b275716cf4e3a..acc879ed6031a9 100644 +--- a/crypto/skcipher.c ++++ b/crypto/skcipher.c +@@ -811,6 +811,7 @@ struct crypto_sync_skcipher *crypto_alloc_sync_skcipher( + + /* Only sync algorithms allowed. */ + mask |= CRYPTO_ALG_ASYNC | CRYPTO_ALG_SKCIPHER_REQSIZE_LARGE; ++ type &= ~(CRYPTO_ALG_ASYNC | CRYPTO_ALG_SKCIPHER_REQSIZE_LARGE); + + tfm = crypto_alloc_tfm(alg_name, &crypto_skcipher_type, type, mask); + +diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c +index b5de82e6eb4d56..e69bfb30b44e07 100644 +--- a/drivers/accel/qaic/qaic_drv.c ++++ b/drivers/accel/qaic/qaic_drv.c +@@ -400,7 +400,7 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev) + int bars; + int ret; + +- bars = pci_select_bars(pdev, IORESOURCE_MEM); ++ bars = pci_select_bars(pdev, IORESOURCE_MEM) & 0x3f; + + /* make sure the device has the expected BARs */ + if (bars != (BIT(0) | BIT(2) | BIT(4))) { +diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +index cee82b473dc509..648228831f5e87 100644 +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -438,7 +438,7 @@ config ACPI_SBS + the modules will be called sbs and sbshc. + + config ACPI_HED +- tristate "Hardware Error Device" ++ bool "Hardware Error Device" + help + This driver supports the Hardware Error Device (PNP0C33), + which is used to report some hardware errors notified via +diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c +index 01abf26764b00c..3f5a1840f57330 100644 +--- a/drivers/acpi/acpi_pnp.c ++++ b/drivers/acpi/acpi_pnp.c +@@ -355,8 +355,10 @@ static bool acpi_pnp_match(const char *idstr, const struct acpi_device_id **matc + * device represented by it. + */ + static const struct acpi_device_id acpi_nonpnp_device_ids[] = { ++ {"INT3F0D"}, + {"INTC1080"}, + {"INTC1081"}, ++ {"INTC1099"}, + {""}, + }; + +diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c +index 46c6f8c35b4368..2e01eaa8d8cd51 100644 +--- a/drivers/acpi/hed.c ++++ b/drivers/acpi/hed.c +@@ -80,7 +80,12 @@ static struct acpi_driver acpi_hed_driver = { + .remove = acpi_hed_remove, + }, + }; +-module_acpi_driver(acpi_hed_driver); ++ ++static int __init acpi_hed_driver_init(void) ++{ ++ return acpi_bus_register_driver(&acpi_hed_driver); ++} ++subsys_initcall(acpi_hed_driver_init); + + MODULE_AUTHOR("Huang Ying"); + MODULE_DESCRIPTION("ACPI Hardware Error Device Driver"); +diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c +index 6d309e4971b617..e243291a7e77c9 100644 +--- a/drivers/auxdisplay/charlcd.c ++++ b/drivers/auxdisplay/charlcd.c +@@ -594,18 +594,19 @@ static int charlcd_init(struct charlcd *lcd) + return 0; + } + +-struct charlcd *charlcd_alloc(void) ++struct charlcd *charlcd_alloc(unsigned int drvdata_size) + { + struct charlcd_priv *priv; + struct charlcd *lcd; + +- priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ priv = kzalloc(sizeof(*priv) + drvdata_size, GFP_KERNEL); + if (!priv) + return NULL; + + priv->esc_seq.len = -1; + + lcd = &priv->lcd; ++ lcd->drvdata = priv->drvdata; + + return lcd; + } +diff --git a/drivers/auxdisplay/charlcd.h b/drivers/auxdisplay/charlcd.h +index eed80063a6d20d..4bbf106b2dd8a2 100644 +--- a/drivers/auxdisplay/charlcd.h ++++ b/drivers/auxdisplay/charlcd.h +@@ -49,7 +49,7 @@ struct charlcd { + unsigned long y; + } addr; + +- void *drvdata; ++ void *drvdata; /* Set by charlcd_alloc() */ + }; + + /** +@@ -93,7 +93,8 @@ struct charlcd_ops { + }; + + void charlcd_backlight(struct charlcd *lcd, enum charlcd_onoff on); +-struct charlcd *charlcd_alloc(void); ++ ++struct charlcd *charlcd_alloc(unsigned int drvdata_size); + void charlcd_free(struct charlcd *lcd); + + int charlcd_register(struct charlcd *lcd); +diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c +index 8b690f59df27d6..ebaf0ff518f4c2 100644 +--- a/drivers/auxdisplay/hd44780.c ++++ b/drivers/auxdisplay/hd44780.c +@@ -226,7 +226,7 @@ static int hd44780_probe(struct platform_device *pdev) + if (!hdc) + return -ENOMEM; + +- lcd = charlcd_alloc(); ++ lcd = charlcd_alloc(0); + if (!lcd) + goto fail1; + +diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c +index 6422be0dfe20e6..0ecf6a9469f24c 100644 +--- a/drivers/auxdisplay/lcd2s.c ++++ b/drivers/auxdisplay/lcd2s.c +@@ -307,7 +307,7 @@ static int lcd2s_i2c_probe(struct i2c_client *i2c) + if (err < 0) + return err; + +- lcd = charlcd_alloc(); ++ lcd = charlcd_alloc(0); + if (!lcd) + return -ENOMEM; + +diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c +index eba04c0de7eb3f..0f3999b665e70f 100644 +--- a/drivers/auxdisplay/panel.c ++++ b/drivers/auxdisplay/panel.c +@@ -835,7 +835,7 @@ static void lcd_init(void) + if (!hdc) + return; + +- charlcd = charlcd_alloc(); ++ charlcd = charlcd_alloc(0); + if (!charlcd) { + kfree(hdc); + return; +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index d6195565ef7aeb..e0dd6988960883 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -3525,9 +3525,8 @@ static void btusb_coredump_qca(struct hci_dev *hdev) + static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + { + int ret = 0; ++ unsigned int skip = 0; + u8 pkt_type; +- u8 *sk_ptr; +- unsigned int sk_len; + u16 seqno; + u32 dump_size; + +@@ -3536,18 +3535,13 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + struct usb_device *udev = btdata->udev; + + pkt_type = hci_skb_pkt_type(skb); +- sk_ptr = skb->data; +- sk_len = skb->len; ++ skip = sizeof(struct hci_event_hdr); ++ if (pkt_type == HCI_ACLDATA_PKT) ++ skip += sizeof(struct hci_acl_hdr); + +- if (pkt_type == HCI_ACLDATA_PKT) { +- sk_ptr += HCI_ACL_HDR_SIZE; +- sk_len -= HCI_ACL_HDR_SIZE; +- } +- +- sk_ptr += HCI_EVENT_HDR_SIZE; +- sk_len -= HCI_EVENT_HDR_SIZE; ++ skb_pull(skb, skip); ++ dump_hdr = (struct qca_dump_hdr *)skb->data; + +- dump_hdr = (struct qca_dump_hdr *)sk_ptr; + seqno = le16_to_cpu(dump_hdr->seqno); + if (seqno == 0) { + set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags); +@@ -3567,16 +3561,15 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + + btdata->qca_dump.ram_dump_size = dump_size; + btdata->qca_dump.ram_dump_seqno = 0; +- sk_ptr += offsetof(struct qca_dump_hdr, data0); +- sk_len -= offsetof(struct qca_dump_hdr, data0); ++ ++ skb_pull(skb, offsetof(struct qca_dump_hdr, data0)); + + usb_disable_autosuspend(udev); + bt_dev_info(hdev, "%s memdump size(%u)\n", + (pkt_type == HCI_ACLDATA_PKT) ? "ACL" : "event", + dump_size); + } else { +- sk_ptr += offsetof(struct qca_dump_hdr, data); +- sk_len -= offsetof(struct qca_dump_hdr, data); ++ skb_pull(skb, offsetof(struct qca_dump_hdr, data)); + } + + if (!btdata->qca_dump.ram_dump_size) { +@@ -3596,7 +3589,6 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + return ret; + } + +- skb_pull(skb, skb->len - sk_len); + hci_devcd_append(hdev, skb); + btdata->qca_dump.ram_dump_seqno++; + if (seqno == QCA_LAST_SEQUENCE_NUM) { +@@ -3624,68 +3616,58 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb) + /* Return: true if the ACL packet is a dump packet, false otherwise. */ + static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- u8 *sk_ptr; +- unsigned int sk_len; +- + struct hci_event_hdr *event_hdr; + struct hci_acl_hdr *acl_hdr; + struct qca_dump_hdr *dump_hdr; ++ struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); ++ bool is_dump = false; + +- sk_ptr = skb->data; +- sk_len = skb->len; +- +- acl_hdr = hci_acl_hdr(skb); +- if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE) ++ if (!clone) + return false; + +- sk_ptr += HCI_ACL_HDR_SIZE; +- sk_len -= HCI_ACL_HDR_SIZE; +- event_hdr = (struct hci_event_hdr *)sk_ptr; +- +- if ((event_hdr->evt != HCI_VENDOR_PKT) || +- (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) +- return false; ++ acl_hdr = skb_pull_data(clone, sizeof(*acl_hdr)); ++ if (!acl_hdr || (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)) ++ goto out; + +- sk_ptr += HCI_EVENT_HDR_SIZE; +- sk_len -= HCI_EVENT_HDR_SIZE; ++ event_hdr = skb_pull_data(clone, sizeof(*event_hdr)); ++ if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT)) ++ goto out; + +- dump_hdr = (struct qca_dump_hdr *)sk_ptr; +- if ((sk_len < offsetof(struct qca_dump_hdr, data)) || +- (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || +- (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) +- return false; ++ dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr)); ++ if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ goto out; + +- return true; ++ is_dump = true; ++out: ++ consume_skb(clone); ++ return is_dump; + } + + /* Return: true if the event packet is a dump packet, false otherwise. */ + static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb) + { +- u8 *sk_ptr; +- unsigned int sk_len; +- + struct hci_event_hdr *event_hdr; + struct qca_dump_hdr *dump_hdr; ++ struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); ++ bool is_dump = false; + +- sk_ptr = skb->data; +- sk_len = skb->len; +- +- event_hdr = hci_event_hdr(skb); +- +- if ((event_hdr->evt != HCI_VENDOR_PKT) +- || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE))) ++ if (!clone) + return false; + +- sk_ptr += HCI_EVENT_HDR_SIZE; +- sk_len -= HCI_EVENT_HDR_SIZE; ++ event_hdr = skb_pull_data(clone, sizeof(*event_hdr)); ++ if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT)) ++ goto out; + +- dump_hdr = (struct qca_dump_hdr *)sk_ptr; +- if ((sk_len < offsetof(struct qca_dump_hdr, data)) || +- (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || +- (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) +- return false; ++ dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr)); ++ if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) || ++ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE)) ++ goto out; + +- return true; ++ is_dump = true; ++out: ++ consume_skb(clone); ++ return is_dump; + } + + static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb) +diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c +index 38c456540d1b98..337144570fafa2 100644 +--- a/drivers/clk/clk-s2mps11.c ++++ b/drivers/clk/clk-s2mps11.c +@@ -137,6 +137,8 @@ static int s2mps11_clk_probe(struct platform_device *pdev) + if (!clk_data) + return -ENOMEM; + ++ clk_data->num = S2MPS11_CLKS_NUM; ++ + switch (hwid) { + case S2MPS11X: + s2mps11_reg = S2MPS11_REG_RTC_CTRL; +@@ -186,7 +188,6 @@ static int s2mps11_clk_probe(struct platform_device *pdev) + clk_data->hws[i] = &s2mps11_clks[i].hw; + } + +- clk_data->num = S2MPS11_CLKS_NUM; + of_clk_add_hw_provider(s2mps11_clks->clk_np, of_clk_hw_onecell_get, + clk_data); + +diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c +index 747f5397692e5f..2a0804dd4b8462 100644 +--- a/drivers/clk/imx/clk-imx8mp.c ++++ b/drivers/clk/imx/clk-imx8mp.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -406,11 +407,151 @@ static const char * const imx8mp_clkout_sels[] = {"audio_pll1_out", "audio_pll2_ + static struct clk_hw **hws; + static struct clk_hw_onecell_data *clk_hw_data; + ++struct imx8mp_clock_constraints { ++ unsigned int clkid; ++ u32 maxrate; ++}; ++ ++/* ++ * Below tables are taken from IMX8MPCEC Rev. 2.1, 07/2023 ++ * Table 13. Maximum frequency of modules. ++ * Probable typos fixed are marked with a comment. ++ */ ++static const struct imx8mp_clock_constraints imx8mp_clock_common_constraints[] = { ++ { IMX8MP_CLK_A53_DIV, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_AXI, 266666667 }, /* Datasheet claims 266MHz */ ++ { IMX8MP_CLK_NAND_USDHC_BUS, 266666667 }, /* Datasheet claims 266MHz */ ++ { IMX8MP_CLK_MEDIA_APB, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_APB, 133333333 }, /* Datasheet claims 133MHz */ ++ { IMX8MP_CLK_ML_AXI, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_AHB, 133333333 }, ++ { IMX8MP_CLK_IPG_ROOT, 66666667 }, ++ { IMX8MP_CLK_AUDIO_AHB, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_DISP2_PIX, 170 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_DRAM_ALT, 666666667 }, ++ { IMX8MP_CLK_DRAM_APB, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_CAN1, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_CAN2, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_PCIE_AUX, 10 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_I2C5, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C6, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI1, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI2, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI3, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI5, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_SAI6, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_ENET_QOS, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_QOS_TIMER, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_REF, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_TIMER, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ENET_PHY_REF, 125 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NAND, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_QSPI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_USDHC1, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_USDHC2, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_I2C1, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C2, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C3, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_I2C4, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_UART1, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_UART2, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_UART3, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_UART4, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ECSPI1, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ECSPI2, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_PWM1, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_PWM2, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_PWM3, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_PWM4, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_GPT1, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT2, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT3, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT4, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT5, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPT6, 100 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_WDOG, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_IPP_DO_CLKO1, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_IPP_DO_CLKO2, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_REF_266M, 266 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_USDHC3, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_MIPI_PHY1_REF, 300 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_DISP1_PIX, 250 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_CAM2_PIX, 277 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_LDB, 595 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_MIPI_TEST_BYTE, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ECSPI3, 80 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_PDM, 200 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_SAI7, 66666667 }, /* Datasheet claims 66MHz */ ++ { IMX8MP_CLK_MAIN_AXI, 400 * HZ_PER_MHZ }, ++ { /* Sentinel */ } ++}; ++ ++static const struct imx8mp_clock_constraints imx8mp_clock_nominal_constraints[] = { ++ { IMX8MP_CLK_M7_CORE, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ML_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_SHADER_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU2D_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_AUDIO_AXI_SRC, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HSIO_AXI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_ISP, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_BUS, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_AXI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_AXI, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AXI, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AHB, 300 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC_IO, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ML_AHB, 300 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G1, 600 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G2, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_CAM1_PIX, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_VC8000E, 400 * HZ_PER_MHZ }, /* Datasheet claims 500MHz */ ++ { IMX8MP_CLK_DRAM_CORE, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GIC, 400 * HZ_PER_MHZ }, ++ { /* Sentinel */ } ++}; ++ ++static const struct imx8mp_clock_constraints imx8mp_clock_overdrive_constraints[] = { ++ { IMX8MP_CLK_M7_CORE, 800 * HZ_PER_MHZ}, ++ { IMX8MP_CLK_ML_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU3D_SHADER_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU2D_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_AUDIO_AXI_SRC, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HSIO_AXI, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_ISP, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_BUS, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_AXI, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_HDMI_AXI, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AXI, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GPU_AHB, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_NOC_IO, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_ML_AHB, 400 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G1, 800 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_G2, 700 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_MEDIA_CAM1_PIX, 500 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_VPU_VC8000E, 500 * HZ_PER_MHZ }, /* Datasheet claims 400MHz */ ++ { IMX8MP_CLK_DRAM_CORE, 1000 * HZ_PER_MHZ }, ++ { IMX8MP_CLK_GIC, 500 * HZ_PER_MHZ }, ++ { /* Sentinel */ } ++}; ++ ++static void imx8mp_clocks_apply_constraints(const struct imx8mp_clock_constraints constraints[]) ++{ ++ const struct imx8mp_clock_constraints *constr; ++ ++ for (constr = constraints; constr->clkid; constr++) ++ clk_hw_set_rate_range(hws[constr->clkid], 0, constr->maxrate); ++} ++ + static int imx8mp_clocks_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct device_node *np; + void __iomem *anatop_base, *ccm_base; ++ const char *opmode; + int err; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mp-anatop"); +@@ -715,6 +856,16 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + + imx_check_clk_hws(hws, IMX8MP_CLK_END); + ++ imx8mp_clocks_apply_constraints(imx8mp_clock_common_constraints); ++ ++ err = of_property_read_string(np, "fsl,operating-mode", &opmode); ++ if (!err) { ++ if (!strcmp(opmode, "nominal")) ++ imx8mp_clocks_apply_constraints(imx8mp_clock_nominal_constraints); ++ else if (!strcmp(opmode, "overdrive")) ++ imx8mp_clocks_apply_constraints(imx8mp_clock_overdrive_constraints); ++ } ++ + err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); + if (err < 0) { + dev_err(dev, "failed to register hws for i.MX8MP\n"); +diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig +index 1de1661037b1b1..95cbea8d380c37 100644 +--- a/drivers/clk/qcom/Kconfig ++++ b/drivers/clk/qcom/Kconfig +@@ -148,7 +148,7 @@ config IPQ_GCC_4019 + + config IPQ_GCC_5018 + tristate "IPQ5018 Global Clock Controller" +- depends on ARM64 || COMPILE_TEST ++ depends on ARM || ARM64 || COMPILE_TEST + help + Support for global clock controller on ipq5018 devices. + Say Y if you want to use peripheral devices such as UART, SPI, +diff --git a/drivers/clk/qcom/camcc-sm8250.c b/drivers/clk/qcom/camcc-sm8250.c +index 9b32c56a5bc5af..e29706d7828707 100644 +--- a/drivers/clk/qcom/camcc-sm8250.c ++++ b/drivers/clk/qcom/camcc-sm8250.c +@@ -411,7 +411,7 @@ static struct clk_rcg2 cam_cc_bps_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -433,7 +433,7 @@ static struct clk_rcg2 cam_cc_camnoc_axi_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -454,7 +454,7 @@ static struct clk_rcg2 cam_cc_cci_0_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -469,7 +469,7 @@ static struct clk_rcg2 cam_cc_cci_1_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -490,7 +490,7 @@ static struct clk_rcg2 cam_cc_cphy_rx_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -511,7 +511,7 @@ static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -526,7 +526,7 @@ static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -556,7 +556,7 @@ static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -571,7 +571,7 @@ static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -586,7 +586,7 @@ static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -611,7 +611,7 @@ static struct clk_rcg2 cam_cc_fast_ahb_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -634,7 +634,7 @@ static struct clk_rcg2 cam_cc_fd_core_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -649,7 +649,7 @@ static struct clk_rcg2 cam_cc_icp_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -673,7 +673,7 @@ static struct clk_rcg2 cam_cc_ife_0_clk_src = { + .parent_data = cam_cc_parent_data_2, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -710,7 +710,7 @@ static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -734,7 +734,7 @@ static struct clk_rcg2 cam_cc_ife_1_clk_src = { + .parent_data = cam_cc_parent_data_3, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -749,7 +749,7 @@ static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -771,7 +771,7 @@ static struct clk_rcg2 cam_cc_ife_lite_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -786,7 +786,7 @@ static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -810,7 +810,7 @@ static struct clk_rcg2 cam_cc_ipe_0_clk_src = { + .parent_data = cam_cc_parent_data_4, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -825,7 +825,7 @@ static struct clk_rcg2 cam_cc_jpeg_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -847,7 +847,7 @@ static struct clk_rcg2 cam_cc_mclk0_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -862,7 +862,7 @@ static struct clk_rcg2 cam_cc_mclk1_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -877,7 +877,7 @@ static struct clk_rcg2 cam_cc_mclk2_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -892,7 +892,7 @@ static struct clk_rcg2 cam_cc_mclk3_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -907,7 +907,7 @@ static struct clk_rcg2 cam_cc_mclk4_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -922,7 +922,7 @@ static struct clk_rcg2 cam_cc_mclk5_clk_src = { + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -993,7 +993,7 @@ static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c +index 80aadafffacdb1..732ca46703ba30 100644 +--- a/drivers/clk/qcom/clk-alpha-pll.c ++++ b/drivers/clk/qcom/clk-alpha-pll.c +@@ -645,14 +645,19 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 alpha_width = pll_alpha_width(pll); + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) ++ return 0; + +- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); + if (ctl & PLL_ALPHA_EN) { +- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low); ++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low)) ++ return 0; + if (alpha_width > 32) { +- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), +- &high); ++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), ++ &high)) ++ return 0; + a = (u64)high << 32 | low; + } else { + a = low & GENMASK(alpha_width - 1, 0); +@@ -844,8 +849,11 @@ alpha_pll_huayra_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, alpha = 0, ctl, alpha_m, alpha_n; + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); +- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) ++ return 0; + + if (ctl & PLL_ALPHA_EN) { + regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &alpha); +@@ -1039,8 +1047,11 @@ clk_trion_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, frac, alpha_width = pll_alpha_width(pll); + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); +- regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac)) ++ return 0; + + return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); + } +@@ -1098,7 +1109,8 @@ clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + u32 ctl; + +- regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); ++ if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) ++ return 0; + + ctl >>= PLL_POST_DIV_SHIFT; + ctl &= PLL_POST_DIV_MASK(pll); +@@ -1314,8 +1326,11 @@ static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw, + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, frac, alpha_width = pll_alpha_width(pll); + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); +- regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; ++ ++ if (regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac)) ++ return 0; + + return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); + } +@@ -1465,7 +1480,8 @@ clk_trion_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + struct regmap *regmap = pll->clkr.regmap; + u32 i, div = 1, val; + +- regmap_read(regmap, PLL_USER_CTL(pll), &val); ++ if (regmap_read(regmap, PLL_USER_CTL(pll), &val)) ++ return 0; + + val >>= pll->post_div_shift; + val &= PLL_POST_DIV_MASK(pll); +@@ -2339,9 +2355,12 @@ static unsigned long alpha_pll_lucid_evo_recalc_rate(struct clk_hw *hw, + struct regmap *regmap = pll->clkr.regmap; + u32 l, frac; + +- regmap_read(regmap, PLL_L_VAL(pll), &l); ++ if (regmap_read(regmap, PLL_L_VAL(pll), &l)) ++ return 0; + l &= LUCID_EVO_PLL_L_VAL_MASK; +- regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac); ++ ++ if (regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac)) ++ return 0; + + return alpha_pll_calc_rate(parent_rate, l, frac, pll_alpha_width(pll)); + } +@@ -2416,7 +2435,8 @@ static unsigned long clk_rivian_evo_pll_recalc_rate(struct clk_hw *hw, + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l; + +- regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); ++ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) ++ return 0; + + return parent_rate * l; + } +diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c +index f95c3615ca7727..98f107e96317ec 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c ++++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c +@@ -412,19 +412,23 @@ static const struct clk_parent_data mmc0_mmc1_parents[] = { + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, + }; +-static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_mmc1_parents, 0x830, +- 0, 4, /* M */ +- 8, 2, /* P */ +- 24, 3, /* mux */ +- BIT(31), /* gate */ +- 0); +- +-static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc0_mmc1_parents, 0x834, +- 0, 4, /* M */ +- 8, 2, /* P */ +- 24, 3, /* mux */ +- BIT(31), /* gate */ +- 0); ++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", ++ mmc0_mmc1_parents, 0x830, ++ 0, 4, /* M */ ++ 8, 2, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 2, /* post-div */ ++ 0); ++ ++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", ++ mmc0_mmc1_parents, 0x834, ++ 0, 4, /* M */ ++ 8, 2, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 2, /* post-div */ ++ 0); + + static const struct clk_parent_data mmc2_parents[] = { + { .fw_name = "hosc" }, +@@ -433,12 +437,14 @@ static const struct clk_parent_data mmc2_parents[] = { + { .hw = &pll_periph0_800M_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, + }; +-static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x838, +- 0, 4, /* M */ +- 8, 2, /* P */ +- 24, 3, /* mux */ +- BIT(31), /* gate */ +- 0); ++static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc2_parents, ++ 0x838, ++ 0, 4, /* M */ ++ 8, 2, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 2, /* post-div */ ++ 0); + + static SUNXI_CCU_GATE_HWS(bus_mmc0_clk, "bus-mmc0", psi_ahb_hws, + 0x84c, BIT(0), 0); +diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h +index 6e50f3728fb5f1..7d836a9fb3db34 100644 +--- a/drivers/clk/sunxi-ng/ccu_mp.h ++++ b/drivers/clk/sunxi-ng/ccu_mp.h +@@ -52,6 +52,28 @@ struct ccu_mp { + } \ + } + ++#define SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, \ ++ _reg, \ ++ _mshift, _mwidth, \ ++ _pshift, _pwidth, \ ++ _muxshift, _muxwidth, \ ++ _gate, _postdiv, _flags)\ ++ struct ccu_mp _struct = { \ ++ .enable = _gate, \ ++ .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ ++ .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \ ++ .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ ++ .fixed_post_div = _postdiv, \ ++ .common = { \ ++ .reg = _reg, \ ++ .features = CCU_FEATURE_FIXED_POSTDIV, \ ++ .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ ++ _parents, \ ++ &ccu_mp_ops, \ ++ _flags), \ ++ } \ ++ } ++ + #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ +diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c +index b3ae38f3672052..39c70b5ac44c96 100644 +--- a/drivers/clocksource/mips-gic-timer.c ++++ b/drivers/clocksource/mips-gic-timer.c +@@ -114,6 +114,9 @@ static void gic_update_frequency(void *data) + + static int gic_starting_cpu(unsigned int cpu) + { ++ /* Ensure the GIC counter is running */ ++ clear_gic_config(GIC_CONFIG_COUNTSTOP); ++ + gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device)); + return 0; + } +@@ -248,9 +251,6 @@ static int __init gic_clocksource_of_init(struct device_node *node) + pr_warn("Unable to register clock notifier\n"); + } + +- /* And finally start the counter */ +- clear_gic_config(GIC_CONFIG_COUNTSTOP); +- + /* + * It's safe to use the MIPS GIC timer as a sched clock source only if + * its ticks are stable, which is true on either the platforms with +diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c +index 09becf14653b58..c58c1defd74588 100644 +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -165,6 +165,7 @@ static const struct of_device_id blocklist[] __initconst = { + { .compatible = "qcom,sm8350", }, + { .compatible = "qcom,sm8450", }, + { .compatible = "qcom,sm8550", }, ++ { .compatible = "qcom,sm8650", }, + + { .compatible = "st,stih407", }, + { .compatible = "st,stih410", }, +diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c +index 7b8fcfa55038bc..4e5b6f9a56d1b2 100644 +--- a/drivers/cpufreq/tegra186-cpufreq.c ++++ b/drivers/cpufreq/tegra186-cpufreq.c +@@ -73,11 +73,18 @@ static int tegra186_cpufreq_init(struct cpufreq_policy *policy) + { + struct tegra186_cpufreq_data *data = cpufreq_get_driver_data(); + unsigned int cluster = data->cpus[policy->cpu].bpmp_cluster_id; ++ u32 cpu; + + policy->freq_table = data->clusters[cluster].table; + policy->cpuinfo.transition_latency = 300 * 1000; + policy->driver_data = NULL; + ++ /* set same policy for all cpus in a cluster */ ++ for (cpu = 0; cpu < ARRAY_SIZE(tegra186_cpus); cpu++) { ++ if (data->cpus[cpu].bpmp_cluster_id == cluster) ++ cpumask_set_cpu(cpu, policy->cpus); ++ } ++ + return 0; + } + +diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c +index b96e3da0fedd01..edd9a8fb9878d6 100644 +--- a/drivers/cpuidle/governors/menu.c ++++ b/drivers/cpuidle/governors/menu.c +@@ -246,8 +246,19 @@ static unsigned int get_typical_interval(struct menu_device *data) + * This can deal with workloads that have long pauses interspersed + * with sporadic activity with a bunch of short pauses. + */ +- if ((divisor * 4) <= INTERVALS * 3) ++ if (divisor * 4 <= INTERVALS * 3) { ++ /* ++ * If there are sufficiently many data points still under ++ * consideration after the outliers have been eliminated, ++ * returning without a prediction would be a mistake because it ++ * is likely that the next interval will not exceed the current ++ * maximum, so return the latter in that case. ++ */ ++ if (divisor >= INTERVALS / 2) ++ return max; ++ + return UINT_MAX; ++ } + + thresh = max - 1; + goto again; +diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c +index 811ded72ce5fbd..798bb40fed68df 100644 +--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c ++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c +@@ -410,9 +410,10 @@ static int cpt_process_ccode(struct otx2_cptlfs_info *lfs, + break; + } + +- dev_err(&pdev->dev, +- "Request failed with software error code 0x%x\n", +- cpt_status->s.uc_compcode); ++ pr_debug("Request failed with software error code 0x%x: algo = %s driver = %s\n", ++ cpt_status->s.uc_compcode, ++ info->req->areq->tfm->__crt_alg->cra_name, ++ info->req->areq->tfm->__crt_alg->cra_driver_name); + otx2_cpt_dump_sg_list(pdev, info->req); + break; + } +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index cc9923ab686dcd..eccbcf67951fbe 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -58,7 +58,7 @@ static irqreturn_t fsl_edma3_tx_handler(int irq, void *dev_id) + + intr = edma_readl_chreg(fsl_chan, ch_int); + if (!intr) +- return IRQ_HANDLED; ++ return IRQ_NONE; + + edma_writel_chreg(fsl_chan, 1, ch_int); + +diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c +index c18633ad8455fa..7e3a67f9f0a654 100644 +--- a/drivers/dma/idxd/cdev.c ++++ b/drivers/dma/idxd/cdev.c +@@ -225,7 +225,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp) + struct idxd_wq *wq; + struct device *dev, *fdev; + int rc = 0; +- struct iommu_sva *sva; ++ struct iommu_sva *sva = NULL; + unsigned int pasid; + struct idxd_cdev *idxd_cdev; + +@@ -322,7 +322,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp) + if (device_user_pasid_enabled(idxd)) + idxd_xa_pasid_remove(ctx); + failed_get_pasid: +- if (device_user_pasid_enabled(idxd)) ++ if (device_user_pasid_enabled(idxd) && !IS_ERR_OR_NULL(sva)) + iommu_sva_unbind_device(sva); + failed: + mutex_unlock(&wq->wq_lock); +@@ -412,6 +412,9 @@ static int idxd_cdev_mmap(struct file *filp, struct vm_area_struct *vma) + if (!idxd->user_submission_safe && !capable(CAP_SYS_RAWIO)) + return -EPERM; + ++ if (current->mm != ctx->mm) ++ return -EPERM; ++ + rc = check_vma(wq, vma, __func__); + if (rc < 0) + return rc; +@@ -478,6 +481,9 @@ static ssize_t idxd_cdev_write(struct file *filp, const char __user *buf, size_t + ssize_t written = 0; + int i; + ++ if (current->mm != ctx->mm) ++ return -EPERM; ++ + for (i = 0; i < len/sizeof(struct dsa_hw_desc); i++) { + int rc = idxd_submit_user_descriptor(ctx, udesc + i); + +@@ -498,6 +504,9 @@ static __poll_t idxd_cdev_poll(struct file *filp, + struct idxd_device *idxd = wq->idxd; + __poll_t out = 0; + ++ if (current->mm != ctx->mm) ++ return POLLNVAL; ++ + poll_wait(filp, &wq->err_queue, wait); + spin_lock(&idxd->dev_lock); + if (idxd->sw_err.valid) +@@ -584,6 +593,7 @@ void idxd_wq_del_cdev(struct idxd_wq *wq) + + static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) + { ++ struct device *dev = &idxd_dev->conf_dev; + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + struct idxd_device *idxd = wq->idxd; + int rc; +@@ -611,6 +621,12 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) + + mutex_lock(&wq->wq_lock); + ++ if (!idxd_wq_driver_name_match(wq, dev)) { ++ idxd->cmd_status = IDXD_SCMD_WQ_NO_DRV_NAME; ++ rc = -ENODEV; ++ goto wq_err; ++ } ++ + wq->wq = create_workqueue(dev_name(wq_confdev(wq))); + if (!wq->wq) { + rc = -ENOMEM; +diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c +index 07623fb0f52fc2..47a01893cfdbf9 100644 +--- a/drivers/dma/idxd/dma.c ++++ b/drivers/dma/idxd/dma.c +@@ -306,6 +306,12 @@ static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev) + return -ENXIO; + + mutex_lock(&wq->wq_lock); ++ if (!idxd_wq_driver_name_match(wq, dev)) { ++ idxd->cmd_status = IDXD_SCMD_WQ_NO_DRV_NAME; ++ rc = -ENODEV; ++ goto err; ++ } ++ + wq->type = IDXD_WQT_KERNEL; + + rc = drv_enable_wq(wq); +diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h +index bea10c5cdb76bb..fcbb8caea89952 100644 +--- a/drivers/dma/idxd/idxd.h ++++ b/drivers/dma/idxd/idxd.h +@@ -159,6 +159,8 @@ struct idxd_cdev { + int minor; + }; + ++#define DRIVER_NAME_SIZE 128 ++ + #define IDXD_ALLOCATED_BATCH_SIZE 128U + #define WQ_NAME_SIZE 1024 + #define WQ_TYPE_SIZE 10 +@@ -227,6 +229,8 @@ struct idxd_wq { + /* Lock to protect upasid_xa access. */ + struct mutex uc_lock; + struct xarray upasid_xa; ++ ++ char driver_name[DRIVER_NAME_SIZE + 1]; + }; + + struct idxd_engine { +@@ -648,6 +652,11 @@ static inline void idxd_wqcfg_set_max_batch_shift(int idxd_type, union wqcfg *wq + wqcfg->max_batch_shift = max_batch_shift; + } + ++static inline int idxd_wq_driver_name_match(struct idxd_wq *wq, struct device *dev) ++{ ++ return (strncmp(wq->driver_name, dev->driver->name, strlen(dev->driver->name)) == 0); ++} ++ + int __must_check __idxd_driver_register(struct idxd_device_driver *idxd_drv, + struct module *module, const char *mod_name); + #define idxd_driver_register(driver) \ +diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c +index 1fd5a93045f79e..3a5ce477a81ad6 100644 +--- a/drivers/dma/idxd/sysfs.c ++++ b/drivers/dma/idxd/sysfs.c +@@ -1282,6 +1282,39 @@ static ssize_t wq_op_config_store(struct device *dev, struct device_attribute *a + static struct device_attribute dev_attr_wq_op_config = + __ATTR(op_config, 0644, wq_op_config_show, wq_op_config_store); + ++static ssize_t wq_driver_name_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct idxd_wq *wq = confdev_to_wq(dev); ++ ++ return sysfs_emit(buf, "%s\n", wq->driver_name); ++} ++ ++static ssize_t wq_driver_name_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct idxd_wq *wq = confdev_to_wq(dev); ++ char *input, *pos; ++ ++ if (wq->state != IDXD_WQ_DISABLED) ++ return -EPERM; ++ ++ if (strlen(buf) > DRIVER_NAME_SIZE || strlen(buf) == 0) ++ return -EINVAL; ++ ++ input = kstrndup(buf, count, GFP_KERNEL); ++ if (!input) ++ return -ENOMEM; ++ ++ pos = strim(input); ++ memset(wq->driver_name, 0, DRIVER_NAME_SIZE + 1); ++ sprintf(wq->driver_name, "%s", pos); ++ kfree(input); ++ return count; ++} ++ ++static struct device_attribute dev_attr_wq_driver_name = ++ __ATTR(driver_name, 0644, wq_driver_name_show, wq_driver_name_store); ++ + static struct attribute *idxd_wq_attributes[] = { + &dev_attr_wq_clients.attr, + &dev_attr_wq_state.attr, +@@ -1301,6 +1334,7 @@ static struct attribute *idxd_wq_attributes[] = { + &dev_attr_wq_occupancy.attr, + &dev_attr_wq_enqcmds_retries.attr, + &dev_attr_wq_op_config.attr, ++ &dev_attr_wq_driver_name.attr, + NULL, + }; + +diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c +index 56be8ef40f376b..e3635fba63b493 100644 +--- a/drivers/edac/ie31200_edac.c ++++ b/drivers/edac/ie31200_edac.c +@@ -405,10 +405,9 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) + int i, j, ret; + struct mem_ctl_info *mci = NULL; + struct edac_mc_layer layers[2]; +- struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL]; + void __iomem *window; + struct ie31200_priv *priv; +- u32 addr_decode, mad_offset; ++ u32 addr_decode[IE31200_CHANNELS], mad_offset; + + /* + * Kaby Lake, Coffee Lake seem to work like Skylake. Please re-visit +@@ -466,19 +465,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) + mad_offset = IE31200_MAD_DIMM_0_OFFSET; + } + +- /* populate DIMM info */ + for (i = 0; i < IE31200_CHANNELS; i++) { +- addr_decode = readl(window + mad_offset + ++ addr_decode[i] = readl(window + mad_offset + + (i * 4)); +- edac_dbg(0, "addr_decode: 0x%x\n", addr_decode); +- for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) { +- populate_dimm_info(&dimm_info[i][j], addr_decode, j, +- skl); +- edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n", +- dimm_info[i][j].size, +- dimm_info[i][j].dual_rank, +- dimm_info[i][j].x16_width); +- } ++ edac_dbg(0, "addr_decode: 0x%x\n", addr_decode[i]); + } + + /* +@@ -489,14 +479,22 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) + */ + for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) { + for (j = 0; j < IE31200_CHANNELS; j++) { ++ struct dimm_data dimm_info; + struct dimm_info *dimm; + unsigned long nr_pages; + +- nr_pages = IE31200_PAGES(dimm_info[j][i].size, skl); ++ populate_dimm_info(&dimm_info, addr_decode[j], i, ++ skl); ++ edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n", ++ dimm_info.size, ++ dimm_info.dual_rank, ++ dimm_info.x16_width); ++ ++ nr_pages = IE31200_PAGES(dimm_info.size, skl); + if (nr_pages == 0) + continue; + +- if (dimm_info[j][i].dual_rank) { ++ if (dimm_info.dual_rank) { + nr_pages = nr_pages / 2; + dimm = edac_get_dimm(mci, (i * 2) + 1, j, 0); + dimm->nr_pages = nr_pages; +diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c +index 7865438b36960d..d885e1381072ac 100644 +--- a/drivers/firmware/arm_ffa/bus.c ++++ b/drivers/firmware/arm_ffa/bus.c +@@ -191,6 +191,7 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, + dev = &ffa_dev->dev; + dev->bus = &ffa_bus_type; + dev->release = ffa_release_device; ++ dev->dma_mask = &dev->coherent_dma_mask; + dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); + + ffa_dev->id = id; +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 7c2db3f017651b..488f8345dd1b63 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -121,6 +121,14 @@ static int ffa_version_check(u32 *version) + return -EOPNOTSUPP; + } + ++ if (FFA_MAJOR_VERSION(ver.a0) > FFA_MAJOR_VERSION(FFA_DRIVER_VERSION)) { ++ pr_err("Incompatible v%d.%d! Latest supported v%d.%d\n", ++ FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0), ++ FFA_MAJOR_VERSION(FFA_DRIVER_VERSION), ++ FFA_MINOR_VERSION(FFA_DRIVER_VERSION)); ++ return -EINVAL; ++ } ++ + if (ver.a0 < FFA_MIN_VERSION) { + pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n", + FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0), +diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c +index 51eeaf14367dac..e1b949aedf9e08 100644 +--- a/drivers/firmware/arm_scmi/bus.c ++++ b/drivers/firmware/arm_scmi/bus.c +@@ -42,7 +42,7 @@ static atomic_t scmi_syspower_registered = ATOMIC_INIT(0); + * This helper let an SCMI driver request specific devices identified by the + * @id_table to be created for each active SCMI instance. + * +- * The requested device name MUST NOT be already existent for any protocol; ++ * The requested device name MUST NOT be already existent for this protocol; + * at first the freshly requested @id_table is annotated in the IDR table + * @scmi_requested_devices and then the requested device is advertised to any + * registered party via the @scmi_requested_devices_nh notification chain. +@@ -52,7 +52,6 @@ static atomic_t scmi_syspower_registered = ATOMIC_INIT(0); + static int scmi_protocol_device_request(const struct scmi_device_id *id_table) + { + int ret = 0; +- unsigned int id = 0; + struct list_head *head, *phead = NULL; + struct scmi_requested_dev *rdev; + +@@ -67,19 +66,13 @@ static int scmi_protocol_device_request(const struct scmi_device_id *id_table) + } + + /* +- * Search for the matching protocol rdev list and then search +- * of any existent equally named device...fails if any duplicate found. ++ * Find the matching protocol rdev list and then search of any ++ * existent equally named device...fails if any duplicate found. + */ + mutex_lock(&scmi_requested_devices_mtx); +- idr_for_each_entry(&scmi_requested_devices, head, id) { +- if (!phead) { +- /* A list found registered in the IDR is never empty */ +- rdev = list_first_entry(head, struct scmi_requested_dev, +- node); +- if (rdev->id_table->protocol_id == +- id_table->protocol_id) +- phead = head; +- } ++ phead = idr_find(&scmi_requested_devices, id_table->protocol_id); ++ if (phead) { ++ head = phead; + list_for_each_entry(rdev, head, node) { + if (!strcmp(rdev->id_table->name, id_table->name)) { + pr_err("Ignoring duplicate request [%d] %s\n", +diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c +index 4ffb9da537d82c..5295ff90482bc6 100644 +--- a/drivers/fpga/altera-cvp.c ++++ b/drivers/fpga/altera-cvp.c +@@ -52,7 +52,7 @@ + /* V2 Defines */ + #define VSE_CVP_TX_CREDITS 0x49 /* 8bit */ + +-#define V2_CREDIT_TIMEOUT_US 20000 ++#define V2_CREDIT_TIMEOUT_US 40000 + #define V2_CHECK_CREDIT_US 10 + #define V2_POLL_TIMEOUT_US 1000000 + #define V2_USER_TIMEOUT_US 500000 +diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c +index b882b26ab5007b..faadbe66b23e71 100644 +--- a/drivers/gpio/gpio-pca953x.c ++++ b/drivers/gpio/gpio-pca953x.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -519,12 +520,10 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) + struct pca953x_chip *chip = gpiochip_get_data(gc); + u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); + u8 bit = BIT(off % BANK_SZ); +- int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = regmap_write_bits(chip->regmap, dirreg, bit, bit); +- mutex_unlock(&chip->i2c_lock); +- return ret; ++ guard(mutex)(&chip->i2c_lock); ++ ++ return regmap_write_bits(chip->regmap, dirreg, bit, bit); + } + + static int pca953x_gpio_direction_output(struct gpio_chip *gc, +@@ -536,17 +535,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, + u8 bit = BIT(off % BANK_SZ); + int ret; + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); ++ + /* set output level */ + ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); + if (ret) +- goto exit; ++ return ret; + + /* then direction */ +- ret = regmap_write_bits(chip->regmap, dirreg, bit, 0); +-exit: +- mutex_unlock(&chip->i2c_lock); +- return ret; ++ return regmap_write_bits(chip->regmap, dirreg, bit, 0); + } + + static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) +@@ -557,9 +554,8 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) + u32 reg_val; + int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = regmap_read(chip->regmap, inreg, ®_val); +- mutex_unlock(&chip->i2c_lock); ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = regmap_read(chip->regmap, inreg, ®_val); + if (ret < 0) + return ret; + +@@ -572,9 +568,9 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) + u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); + u8 bit = BIT(off % BANK_SZ); + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); ++ + regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); +- mutex_unlock(&chip->i2c_lock); + } + + static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) +@@ -585,9 +581,8 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) + u32 reg_val; + int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = regmap_read(chip->regmap, dirreg, ®_val); +- mutex_unlock(&chip->i2c_lock); ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = regmap_read(chip->regmap, dirreg, ®_val); + if (ret < 0) + return ret; + +@@ -604,9 +599,8 @@ static int pca953x_gpio_get_multiple(struct gpio_chip *gc, + DECLARE_BITMAP(reg_val, MAX_LINE); + int ret; + +- mutex_lock(&chip->i2c_lock); +- ret = pca953x_read_regs(chip, chip->regs->input, reg_val); +- mutex_unlock(&chip->i2c_lock); ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = pca953x_read_regs(chip, chip->regs->input, reg_val); + if (ret) + return ret; + +@@ -621,16 +615,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, + DECLARE_BITMAP(reg_val, MAX_LINE); + int ret; + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); ++ + ret = pca953x_read_regs(chip, chip->regs->output, reg_val); + if (ret) +- goto exit; ++ return; + + bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio); + + pca953x_write_regs(chip, chip->regs->output, reg_val); +-exit: +- mutex_unlock(&chip->i2c_lock); + } + + static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, +@@ -638,7 +631,6 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, + unsigned long config) + { + enum pin_config_param param = pinconf_to_config_param(config); +- + u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset); + u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset); + u8 bit = BIT(offset % BANK_SZ); +@@ -651,7 +643,7 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, + if (!(chip->driver_data & PCA_PCAL)) + return -ENOTSUPP; + +- mutex_lock(&chip->i2c_lock); ++ guard(mutex)(&chip->i2c_lock); + + /* Configure pull-up/pull-down */ + if (param == PIN_CONFIG_BIAS_PULL_UP) +@@ -661,17 +653,13 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, + else + ret = 0; + if (ret) +- goto exit; ++ return ret; + + /* Disable/Enable pull-up/pull-down */ + if (param == PIN_CONFIG_BIAS_DISABLE) +- ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0); ++ return regmap_write_bits(chip->regmap, pull_en_reg, bit, 0); + else +- ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit); +- +-exit: +- mutex_unlock(&chip->i2c_lock); +- return ret; ++ return regmap_write_bits(chip->regmap, pull_en_reg, bit, bit); + } + + static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset, +@@ -883,10 +871,8 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) + + bitmap_zero(pending, MAX_LINE); + +- mutex_lock(&chip->i2c_lock); +- ret = pca953x_irq_pending(chip, pending); +- mutex_unlock(&chip->i2c_lock); +- ++ scoped_guard(mutex, &chip->i2c_lock) ++ ret = pca953x_irq_pending(chip, pending); + if (ret) { + ret = 0; + +@@ -1168,9 +1154,9 @@ static int pca953x_probe(struct i2c_client *client) + } + + #ifdef CONFIG_PM_SLEEP +-static int pca953x_regcache_sync(struct device *dev) ++static int pca953x_regcache_sync(struct pca953x_chip *chip) + { +- struct pca953x_chip *chip = dev_get_drvdata(dev); ++ struct device *dev = &chip->client->dev; + int ret; + u8 regaddr; + +@@ -1217,13 +1203,38 @@ static int pca953x_regcache_sync(struct device *dev) + return 0; + } + ++static int pca953x_restore_context(struct pca953x_chip *chip) ++{ ++ int ret; ++ ++ guard(mutex)(&chip->i2c_lock); ++ ++ if (chip->client->irq > 0) ++ enable_irq(chip->client->irq); ++ regcache_cache_only(chip->regmap, false); ++ regcache_mark_dirty(chip->regmap); ++ ret = pca953x_regcache_sync(chip); ++ if (ret) ++ return ret; ++ ++ return regcache_sync(chip->regmap); ++} ++ ++static void pca953x_save_context(struct pca953x_chip *chip) ++{ ++ guard(mutex)(&chip->i2c_lock); ++ ++ /* Disable IRQ to prevent early triggering while regmap "cache only" is on */ ++ if (chip->client->irq > 0) ++ disable_irq(chip->client->irq); ++ regcache_cache_only(chip->regmap, true); ++} ++ + static int pca953x_suspend(struct device *dev) + { + struct pca953x_chip *chip = dev_get_drvdata(dev); + +- mutex_lock(&chip->i2c_lock); +- regcache_cache_only(chip->regmap, true); +- mutex_unlock(&chip->i2c_lock); ++ pca953x_save_context(chip); + + if (atomic_read(&chip->wakeup_path)) + device_set_wakeup_path(dev); +@@ -1246,17 +1257,7 @@ static int pca953x_resume(struct device *dev) + } + } + +- mutex_lock(&chip->i2c_lock); +- regcache_cache_only(chip->regmap, false); +- regcache_mark_dirty(chip->regmap); +- ret = pca953x_regcache_sync(dev); +- if (ret) { +- mutex_unlock(&chip->i2c_lock); +- return ret; +- } +- +- ret = regcache_sync(chip->regmap); +- mutex_unlock(&chip->i2c_lock); ++ ret = pca953x_restore_context(chip); + if (ret) { + dev_err(dev, "Failed to restore register map: %d\n", ret); + return ret; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +index be4cc4868a748e..493e18bcea069e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +@@ -43,6 +43,29 @@ + #include + #include + ++static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops; ++ ++/** ++ * dma_buf_attach_adev - Helper to get adev of an attachment ++ * ++ * @attach: attachment ++ * ++ * Returns: ++ * A struct amdgpu_device * if the attaching device is an amdgpu device or ++ * partition, NULL otherwise. ++ */ ++static struct amdgpu_device *dma_buf_attach_adev(struct dma_buf_attachment *attach) ++{ ++ if (attach->importer_ops == &amdgpu_dma_buf_attach_ops) { ++ struct drm_gem_object *obj = attach->importer_priv; ++ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); ++ ++ return amdgpu_ttm_adev(bo->tbo.bdev); ++ } ++ ++ return NULL; ++} ++ + /** + * amdgpu_dma_buf_attach - &dma_buf_ops.attach implementation + * +@@ -54,12 +77,14 @@ + static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attach) + { ++ struct amdgpu_device *attach_adev = dma_buf_attach_adev(attach); + struct drm_gem_object *obj = dmabuf->priv; + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + int r; + +- if (pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) ++ if (!amdgpu_dmabuf_is_xgmi_accessible(attach_adev, bo) && ++ pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) + attach->peer2peer = false; + + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); +@@ -482,6 +507,9 @@ bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev, + struct drm_gem_object *obj = &bo->tbo.base; + struct drm_gem_object *gobj; + ++ if (!adev) ++ return false; ++ + if (obj->import_attach) { + struct dma_buf *dma_buf = obj->import_attach->dmabuf; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +index 6a24e8ceb94493..ffa5e72a84ebcb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +@@ -43,7 +43,7 @@ + #include "amdgpu_securedisplay.h" + #include "amdgpu_atomfirmware.h" + +-#define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*3) ++#define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*16) + + static int psp_load_smu_fw(struct psp_context *psp); + static int psp_rap_terminate(struct psp_context *psp); +@@ -506,7 +506,6 @@ static int psp_sw_fini(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct psp_context *psp = &adev->psp; +- struct psp_gfx_cmd_resp *cmd = psp->cmd; + + psp_memory_training_fini(psp); + +@@ -516,8 +515,8 @@ static int psp_sw_fini(void *handle) + amdgpu_ucode_release(&psp->cap_fw); + amdgpu_ucode_release(&psp->toc_fw); + +- kfree(cmd); +- cmd = NULL; ++ kfree(psp->cmd); ++ psp->cmd = NULL; + + psp_free_shared_bufs(psp); + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +index 66c6bab75f8a58..0d3d00681edac5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +@@ -92,12 +92,12 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) + { + uint64_t value; + +- /* Program the AGP BAR */ +- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BASE, 0); +- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 24); +- WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 24); +- + if (!amdgpu_sriov_vf(adev) || adev->asic_type <= CHIP_VEGA10) { ++ /* Program the AGP BAR */ ++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BASE, 0); ++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 24); ++ WREG32_SOC15_RLC(GC, 0, mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 24); ++ + /* Program the system aperture low logical page number. */ + WREG32_SOC15_RLC(GC, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, + min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c +index 9086f2fdfaf422..553f4f24f5adeb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c +@@ -172,6 +172,30 @@ static void mmhub_v1_7_init_tlb_regs(struct amdgpu_device *adev) + WREG32_SOC15(MMHUB, 0, regMC_VM_MX_L1_TLB_CNTL, tmp); + } + ++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */ ++static void mmhub_v1_7_init_snoop_override_regs(struct amdgpu_device *adev) ++{ ++ uint32_t tmp; ++ int i; ++ uint32_t distance = regDAGB1_WRCLI_GPU_SNOOP_OVERRIDE - ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE; ++ ++ for (i = 0; i < 5; i++) { /* DAGB instances */ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, i * distance); ++ tmp |= (1 << 15); /* SDMA client is BIT15 */ ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, i * distance, tmp); ++ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, i * distance); ++ tmp |= (1 << 15); ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, i * distance, tmp); ++ } ++ ++} ++ + static void mmhub_v1_7_init_cache_regs(struct amdgpu_device *adev) + { + uint32_t tmp; +@@ -337,6 +361,7 @@ static int mmhub_v1_7_gart_enable(struct amdgpu_device *adev) + mmhub_v1_7_init_system_aperture_regs(adev); + mmhub_v1_7_init_tlb_regs(adev); + mmhub_v1_7_init_cache_regs(adev); ++ mmhub_v1_7_init_snoop_override_regs(adev); + + mmhub_v1_7_enable_system_domain(adev); + mmhub_v1_7_disable_identity_aperture(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +index 3d8e579d5c4e8a..c7bdccff785b71 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +@@ -213,6 +213,32 @@ static void mmhub_v1_8_init_tlb_regs(struct amdgpu_device *adev) + } + } + ++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */ ++static void mmhub_v1_8_init_snoop_override_regs(struct amdgpu_device *adev) ++{ ++ uint32_t tmp, inst_mask; ++ int i, j; ++ uint32_t distance = regDAGB1_WRCLI_GPU_SNOOP_OVERRIDE - ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE; ++ ++ inst_mask = adev->aid_mask; ++ for_each_inst(i, inst_mask) { ++ for (j = 0; j < 5; j++) { /* DAGB instances */ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, j * distance); ++ tmp |= (1 << 15); /* SDMA client is BIT15 */ ++ WREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, j * distance, tmp); ++ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, j * distance); ++ tmp |= (1 << 15); ++ WREG32_SOC15_OFFSET(MMHUB, i, ++ regDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, j * distance, tmp); ++ } ++ } ++} ++ + static void mmhub_v1_8_init_cache_regs(struct amdgpu_device *adev) + { + uint32_t tmp, inst_mask; +@@ -418,6 +444,7 @@ static int mmhub_v1_8_gart_enable(struct amdgpu_device *adev) + mmhub_v1_8_init_system_aperture_regs(adev); + mmhub_v1_8_init_tlb_regs(adev); + mmhub_v1_8_init_cache_regs(adev); ++ mmhub_v1_8_init_snoop_override_regs(adev); + + mmhub_v1_8_enable_system_domain(adev); + mmhub_v1_8_disable_identity_aperture(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c +index 5718e4d40e6665..9713cb59d1c14f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c +@@ -198,6 +198,36 @@ static void mmhub_v9_4_init_tlb_regs(struct amdgpu_device *adev, int hubid) + hubid * MMHUB_INSTANCE_REGISTER_OFFSET, tmp); + } + ++/* Set snoop bit for SDMA so that SDMA writes probe-invalidates RW lines */ ++static void mmhub_v9_4_init_snoop_override_regs(struct amdgpu_device *adev, int hubid) ++{ ++ uint32_t tmp; ++ int i; ++ uint32_t distance = mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE - ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE; ++ uint32_t huboffset = hubid * MMHUB_INSTANCE_REGISTER_OFFSET; ++ ++ for (i = 0; i < 5 - (2 * hubid); i++) { ++ /* DAGB instances 0 to 4 are in hub0 and 5 to 7 are in hub1 */ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, ++ huboffset + i * distance); ++ tmp |= (1 << 15); /* SDMA client is BIT15 */ ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE, ++ huboffset + i * distance, tmp); ++ ++ tmp = RREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, ++ huboffset + i * distance); ++ tmp |= (1 << 15); ++ WREG32_SOC15_OFFSET(MMHUB, 0, ++ mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE, ++ huboffset + i * distance, tmp); ++ } ++ ++} ++ + static void mmhub_v9_4_init_cache_regs(struct amdgpu_device *adev, int hubid) + { + uint32_t tmp; +@@ -392,6 +422,7 @@ static int mmhub_v9_4_gart_enable(struct amdgpu_device *adev) + if (!amdgpu_sriov_vf(adev)) + mmhub_v9_4_init_cache_regs(adev, i); + ++ mmhub_v9_4_init_snoop_override_regs(adev, i); + mmhub_v9_4_enable_system_domain(adev, i); + if (!amdgpu_sriov_vf(adev)) + mmhub_v9_4_disable_identity_aperture(adev, i); +diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c +index 7910c463ae3855..82709e692f4cc0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/nv.c ++++ b/drivers/gpu/drm/amd/amdgpu/nv.c +@@ -142,23 +142,23 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] = { + }; + + static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn0[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 1920, 1088, 3)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 1920, 1088, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 1920, 1088, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, + }; + + static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn1[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 1920, 1088, 3)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 1920, 1088, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 1920, 1088, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + }; + +diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c +index 4712ffc0a482c8..7819f5d584f597 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc21.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc21.c +@@ -117,23 +117,17 @@ static struct amdgpu_video_codecs sriov_vcn_4_0_0_video_codecs_encode_vcn1 = { + }; + + static struct amdgpu_video_codec_info sriov_vcn_4_0_0_video_codecs_decode_array_vcn0[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, + }; + + static struct amdgpu_video_codec_info sriov_vcn_4_0_0_video_codecs_decode_array_vcn1[] = { +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 16384, 16384, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, + }; + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index 4d9a406925e189..fd4a75073364c7 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -2147,14 +2147,6 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, + return retval; + } + +-/* +- * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to +- * stay in user mode. +- */ +-#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL +-/* APE1 limit is inclusive and 64K aligned. */ +-#define APE1_LIMIT_ALIGNMENT 0xFFFF +- + static bool set_cache_memory_policy(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, +@@ -2169,34 +2161,6 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, + + dqm_lock(dqm); + +- if (alternate_aperture_size == 0) { +- /* base > limit disables APE1 */ +- qpd->sh_mem_ape1_base = 1; +- qpd->sh_mem_ape1_limit = 0; +- } else { +- /* +- * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]}, +- * SH_MEM_APE1_BASE[31:0], 0x0000 } +- * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]}, +- * SH_MEM_APE1_LIMIT[31:0], 0xFFFF } +- * Verify that the base and size parameters can be +- * represented in this format and convert them. +- * Additionally restrict APE1 to user-mode addresses. +- */ +- +- uint64_t base = (uintptr_t)alternate_aperture_base; +- uint64_t limit = base + alternate_aperture_size - 1; +- +- if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 || +- (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) { +- retval = false; +- goto out; +- } +- +- qpd->sh_mem_ape1_base = base >> 16; +- qpd->sh_mem_ape1_limit = limit >> 16; +- } +- + retval = dqm->asic_ops.set_cache_memory_policy( + dqm, + qpd, +@@ -2205,6 +2169,9 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, + alternate_aperture_base, + alternate_aperture_size); + ++ if (retval) ++ goto out; ++ + if ((dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0)) + program_sh_mem_settings(dqm, qpd); + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +index d4d95c7f2e5d40..32bedef912b3b2 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +@@ -27,6 +27,14 @@ + #include "oss/oss_2_4_sh_mask.h" + #include "gca/gfx_7_2_sh_mask.h" + ++/* ++ * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to ++ * stay in user mode. ++ */ ++#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL ++/* APE1 limit is inclusive and 64K aligned. */ ++#define APE1_LIMIT_ALIGNMENT 0xFFFF ++ + static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, +@@ -84,6 +92,36 @@ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + { + uint32_t default_mtype; + uint32_t ape1_mtype; ++ unsigned int temp; ++ bool retval = true; ++ ++ if (alternate_aperture_size == 0) { ++ /* base > limit disables APE1 */ ++ qpd->sh_mem_ape1_base = 1; ++ qpd->sh_mem_ape1_limit = 0; ++ } else { ++ /* ++ * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]}, ++ * SH_MEM_APE1_BASE[31:0], 0x0000 } ++ * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]}, ++ * SH_MEM_APE1_LIMIT[31:0], 0xFFFF } ++ * Verify that the base and size parameters can be ++ * represented in this format and convert them. ++ * Additionally restrict APE1 to user-mode addresses. ++ */ ++ ++ uint64_t base = (uintptr_t)alternate_aperture_base; ++ uint64_t limit = base + alternate_aperture_size - 1; ++ ++ if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 || ++ (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) { ++ retval = false; ++ goto out; ++ } ++ ++ qpd->sh_mem_ape1_base = base >> 16; ++ qpd->sh_mem_ape1_limit = limit >> 16; ++ } + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_NONCACHED : +@@ -97,37 +135,22 @@ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, + | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) + | DEFAULT_MTYPE(default_mtype) + | APE1_MTYPE(ape1_mtype); +- +- return true; +-} +- +-static int update_qpd_cik(struct device_queue_manager *dqm, +- struct qcm_process_device *qpd) +-{ +- struct kfd_process_device *pdd; +- unsigned int temp; +- +- pdd = qpd_to_pdd(qpd); +- +- /* check if sh_mem_config register already configured */ +- if (qpd->sh_mem_config == 0) { +- qpd->sh_mem_config = +- ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) | +- DEFAULT_MTYPE(MTYPE_NONCACHED) | +- APE1_MTYPE(MTYPE_NONCACHED); +- qpd->sh_mem_ape1_limit = 0; +- qpd->sh_mem_ape1_base = 0; +- } +- + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ +- temp = get_sh_mem_bases_nybble_64(pdd); ++ temp = get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd)); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + + pr_debug("is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n", + qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases); + ++out: ++ return retval; ++} ++ ++static int update_qpd_cik(struct device_queue_manager *dqm, ++ struct qcm_process_device *qpd) ++{ + return 0; + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +index b291ee0fab9439..320518f418903d 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +@@ -27,6 +27,14 @@ + #include "gca/gfx_8_0_sh_mask.h" + #include "oss/oss_3_0_sh_mask.h" + ++/* ++ * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to ++ * stay in user mode. ++ */ ++#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL ++/* APE1 limit is inclusive and 64K aligned. */ ++#define APE1_LIMIT_ALIGNMENT 0xFFFF ++ + static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, +@@ -85,6 +93,36 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + { + uint32_t default_mtype; + uint32_t ape1_mtype; ++ unsigned int temp; ++ bool retval = true; ++ ++ if (alternate_aperture_size == 0) { ++ /* base > limit disables APE1 */ ++ qpd->sh_mem_ape1_base = 1; ++ qpd->sh_mem_ape1_limit = 0; ++ } else { ++ /* ++ * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]}, ++ * SH_MEM_APE1_BASE[31:0], 0x0000 } ++ * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]}, ++ * SH_MEM_APE1_LIMIT[31:0], 0xFFFF } ++ * Verify that the base and size parameters can be ++ * represented in this format and convert them. ++ * Additionally restrict APE1 to user-mode addresses. ++ */ ++ ++ uint64_t base = (uintptr_t)alternate_aperture_base; ++ uint64_t limit = base + alternate_aperture_size - 1; ++ ++ if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 || ++ (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) { ++ retval = false; ++ goto out; ++ } ++ ++ qpd->sh_mem_ape1_base = base >> 16; ++ qpd->sh_mem_ape1_limit = limit >> 16; ++ } + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_UC : +@@ -100,40 +138,21 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, + default_mtype << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + ape1_mtype << SH_MEM_CONFIG__APE1_MTYPE__SHIFT; + +- return true; +-} +- +-static int update_qpd_vi(struct device_queue_manager *dqm, +- struct qcm_process_device *qpd) +-{ +- struct kfd_process_device *pdd; +- unsigned int temp; +- +- pdd = qpd_to_pdd(qpd); +- +- /* check if sh_mem_config register already configured */ +- if (qpd->sh_mem_config == 0) { +- qpd->sh_mem_config = +- SH_MEM_ALIGNMENT_MODE_UNALIGNED << +- SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | +- MTYPE_UC << +- SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | +- MTYPE_UC << +- SH_MEM_CONFIG__APE1_MTYPE__SHIFT; +- +- qpd->sh_mem_ape1_limit = 0; +- qpd->sh_mem_ape1_base = 0; +- } +- + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ +- temp = get_sh_mem_bases_nybble_64(pdd); ++ temp = get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd)); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + + pr_debug("sh_mem_bases nybble: 0x%X and register 0x%X\n", + temp, qpd->sh_mem_bases); ++out: ++ return retval; ++} + ++static int update_qpd_vi(struct device_queue_manager *dqm, ++ struct qcm_process_device *qpd) ++{ + return 0; + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index a6d08dee74f6ea..93740b8fc3f44b 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -812,6 +812,14 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) + return ERR_PTR(-EINVAL); + } + ++ /* If the process just called exec(3), it is possible that the ++ * cleanup of the kfd_process (following the release of the mm ++ * of the old process image) is still in the cleanup work queue. ++ * Make sure to drain any job before trying to recreate any ++ * resource for this process. ++ */ ++ flush_workqueue(kfd_process_wq); ++ + /* + * take kfd processes mutex before starting of process creation + * so there won't be a case where two threads of the same process +@@ -830,14 +838,6 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) + if (process) { + pr_debug("Process already found\n"); + } else { +- /* If the process just called exec(3), it is possible that the +- * cleanup of the kfd_process (following the release of the mm +- * of the old process image) is still in the cleanup work queue. +- * Make sure to drain any job before trying to recreate any +- * resource for this process. +- */ +- flush_workqueue(kfd_process_wq); +- + process = create_process(thread); + if (IS_ERR(process)) + goto out; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index bcf0dc05c76765..9189864c236a7e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -2896,11 +2896,6 @@ static int dm_resume(void *handle) + + return 0; + } +- +- /* leave display off for S4 sequence */ +- if (adev->in_s4) +- return 0; +- + /* Recreate dc_state - DC invalidates it when setting power state to S3. */ + dc_release_state(dm_state->context); + dm_state->context = dc_create_state(dm->dc); +@@ -7474,7 +7469,7 @@ static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap, + int i; + int result = -EIO; + +- if (!ddc_service->ddc_pin || !ddc_service->ddc_pin->hw_info.hw_supported) ++ if (!ddc_service->ddc_pin) + return result; + + cmd.payloads = kcalloc(num, sizeof(struct i2c_payload), GFP_KERNEL); +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +index d4d3f58a613f7a..327776eeb9f3ec 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +@@ -130,7 +130,7 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; + struct dc *dc = clk_mgr_base->ctx->dc; +- int display_count; ++ int display_count = 0; + bool update_dppclk = false; + bool update_dispclk = false; + bool dpp_clock_lowered = false; +@@ -194,8 +194,6 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. + if (new_clocks->dppclk_khz < MIN_DPP_DISP_CLK) + new_clocks->dppclk_khz = MIN_DPP_DISP_CLK; +- if (new_clocks->dispclk_khz < MIN_DPP_DISP_CLK) +- new_clocks->dispclk_khz = MIN_DPP_DISP_CLK; + + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { + if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) +@@ -204,15 +202,19 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + update_dppclk = true; + } + +- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { +- /* No need to apply the w/a if we haven't taken over from bios yet */ +- if (clk_mgr_base->clks.dispclk_khz) +- dcn315_disable_otg_wa(clk_mgr_base, context, true); ++ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) && ++ (new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) { ++ int requested_dispclk_khz = new_clocks->dispclk_khz; + ++ dcn315_disable_otg_wa(clk_mgr_base, context, true); ++ ++ /* Clamp the requested clock to PMFW based on their limit. */ ++ if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz) ++ requested_dispclk_khz = dc->debug.min_disp_clk_khz; ++ ++ dcn315_smu_set_dispclk(clk_mgr, requested_dispclk_khz); + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; +- dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); +- if (clk_mgr_base->clks.dispclk_khz) +- dcn315_disable_otg_wa(clk_mgr_base, context, false); ++ dcn315_disable_otg_wa(clk_mgr_base, context, false); + + update_dispclk = true; + } +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +index a13ead3d21e310..f95e5e767eb1a6 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +@@ -140,7 +140,7 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; + struct dc *dc = clk_mgr_base->ctx->dc; +- int display_count; ++ int display_count = 0; + bool update_dppclk = false; + bool update_dispclk = false; + bool dpp_clock_lowered = false; +@@ -201,8 +201,6 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, + // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. + if (new_clocks->dppclk_khz < 100000) + new_clocks->dppclk_khz = 100000; +- if (new_clocks->dispclk_khz < 100000) +- new_clocks->dispclk_khz = 100000; + + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { + if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) +@@ -211,11 +209,18 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, + update_dppclk = true; + } + +- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { ++ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) && ++ (new_clocks->dispclk_khz > 0 || (safe_to_lower && display_count == 0))) { ++ int requested_dispclk_khz = new_clocks->dispclk_khz; ++ + dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); + ++ /* Clamp the requested clock to PMFW based on their limit. */ ++ if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz) ++ requested_dispclk_khz = dc->debug.min_disp_clk_khz; ++ ++ dcn316_smu_set_dispclk(clk_mgr, requested_dispclk_khz); + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; +- dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); + dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); + + update_dispclk = true; +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index c2efe18ceacd07..640d010b52bec3 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -266,6 +266,7 @@ static bool create_links( + link->link_id.type = OBJECT_TYPE_CONNECTOR; + link->link_id.id = CONNECTOR_ID_VIRTUAL; + link->link_id.enum_id = ENUM_ID_1; ++ link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; + link->link_enc = kzalloc(sizeof(*link->link_enc), GFP_KERNEL); + + if (!link->link_enc) { +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +index 7b5c1498941dd6..d389eeb264a79e 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +@@ -1066,7 +1066,8 @@ void dce110_edp_backlight_control( + DC_LOG_DC("edp_receiver_ready_T9 skipped\n"); + } + +- if (!enable && link->dpcd_sink_ext_caps.bits.oled) { ++ if (!enable) { ++ /*follow oem panel config's requirement*/ + pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms; + msleep(pre_T11_delay); + } +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +index 50dc834046446a..4ce45f1bdac0fe 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +@@ -392,11 +392,6 @@ bool dpp3_get_optimal_number_of_taps( + int min_taps_y, min_taps_c; + enum lb_memory_config lb_config; + +- if (scl_data->viewport.width > scl_data->h_active && +- dpp->ctx->dc->debug.max_downscale_src_width != 0 && +- scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width) +- return false; +- + /* + * Set default taps if none are provided + * From programming guide: taps = min{ ceil(2*H_RATIO,1), 8} for downscaling +@@ -434,6 +429,12 @@ bool dpp3_get_optimal_number_of_taps( + else + scl_data->taps.h_taps_c = in_taps->h_taps_c; + ++ // Avoid null data in the scl data with this early return, proceed non-adaptive calcualtion first ++ if (scl_data->viewport.width > scl_data->h_active && ++ dpp->ctx->dc->debug.max_downscale_src_width != 0 && ++ scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width) ++ return false; ++ + /*Ensure we can support the requested number of vtaps*/ + min_taps_y = dc_fixpt_ceil(scl_data->ratios.vert); + min_taps_c = dc_fixpt_ceil(scl_data->ratios.vert_c); +diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +index 597fa0364a3a9b..d1601d61f05adc 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +@@ -1692,7 +1692,7 @@ static int dcn315_populate_dml_pipes_from_context( + pipes[pipe_cnt].dout.dsc_input_bpc = 0; + DC_FP_START(); + dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); +- if (pixel_rate_crb && !pipe->top_pipe && !pipe->prev_odm_pipe) { ++ if (pixel_rate_crb) { + int bpp = source_format_to_bpp(pipes[pipe_cnt].pipe.src.source_format); + /* Ceil to crb segment size */ + int approx_det_segs_required_for_pstate = dcn_get_approx_det_segs_required_for_pstate( +@@ -1749,28 +1749,26 @@ static int dcn315_populate_dml_pipes_from_context( + continue; + } + +- if (!pipe->top_pipe && !pipe->prev_odm_pipe) { +- bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc) +- || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); +- +- if (remaining_det_segs > MIN_RESERVED_DET_SEGS && crb_pipes != 0) +- pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes + +- (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0); +- if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) { +- /* Clamp to 2 pipe split max det segments */ +- remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS); +- pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS; +- } +- if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) { +- /* If we are splitting we must have an even number of segments */ +- remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2; +- pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2; +- } +- /* Convert segments into size for DML use */ +- pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB; +- +- crb_idx++; ++ bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc) ++ || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); ++ ++ if (remaining_det_segs > MIN_RESERVED_DET_SEGS && crb_pipes != 0) ++ pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes + ++ (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0); ++ if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) { ++ /* Clamp to 2 pipe split max det segments */ ++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS); ++ pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS; ++ } ++ if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) { ++ /* If we are splitting we must have an even number of segments */ ++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2; ++ pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2; + } ++ /* Convert segments into size for DML use */ ++ pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB; ++ ++ crb_idx++; + pipe_cnt++; + } + } +diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h +index eaad1260bfd180..4b284ce669ae52 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h +@@ -532,7 +532,7 @@ struct dc_state { + */ + struct bw_context bw_ctx; + +- struct block_sequence block_sequence[50]; ++ struct block_sequence block_sequence[100]; + unsigned int block_sequence_steps; + struct dc_dmub_cmd dc_dmub_cmd[10]; + unsigned int dmub_cmd_count; +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +index 4901e27f678bcf..9b470812d96a5f 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +@@ -145,6 +145,7 @@ void link_blank_dp_stream(struct dc_link *link, bool hw_init) + void link_set_all_streams_dpms_off_for_link(struct dc_link *link) + { + struct pipe_ctx *pipes[MAX_PIPES]; ++ struct dc_stream_state *streams[MAX_PIPES]; + struct dc_state *state = link->dc->current_state; + uint8_t count; + int i; +@@ -157,10 +158,18 @@ void link_set_all_streams_dpms_off_for_link(struct dc_link *link) + + link_get_master_pipes_with_dpms_on(link, state, &count, pipes); + ++ /* The subsequent call to dc_commit_updates_for_stream for a full update ++ * will release the current state and swap to a new state. Releasing the ++ * current state results in the stream pointers in the pipe_ctx structs ++ * to be zero'd. Hence, cache all streams prior to dc_commit_updates_for_stream. ++ */ ++ for (i = 0; i < count; i++) ++ streams[i] = pipes[i]->stream; ++ + for (i = 0; i < count; i++) { +- stream_update.stream = pipes[i]->stream; ++ stream_update.stream = streams[i]; + dc_commit_updates_for_stream(link->ctx->dc, NULL, 0, +- pipes[i]->stream, &stream_update, ++ streams[i], &stream_update, + state); + } + +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +index 3d589072fe307e..adf0ef8b70e4b1 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +@@ -239,21 +239,21 @@ static uint32_t intersect_frl_link_bw_support( + { + uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps; + +- // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode) +- if (hdmi_encoded_link_bw.bits.FRL_MODE) { +- if (hdmi_encoded_link_bw.bits.BW_48Gbps) +- supported_bw_in_kbps = 48000000; +- else if (hdmi_encoded_link_bw.bits.BW_40Gbps) +- supported_bw_in_kbps = 40000000; +- else if (hdmi_encoded_link_bw.bits.BW_32Gbps) +- supported_bw_in_kbps = 32000000; +- else if (hdmi_encoded_link_bw.bits.BW_24Gbps) +- supported_bw_in_kbps = 24000000; +- else if (hdmi_encoded_link_bw.bits.BW_18Gbps) +- supported_bw_in_kbps = 18000000; +- else if (hdmi_encoded_link_bw.bits.BW_9Gbps) +- supported_bw_in_kbps = 9000000; +- } ++ /* Skip checking FRL_MODE bit, as certain PCON will clear ++ * it despite supporting the link BW indicated in the other bits. ++ */ ++ if (hdmi_encoded_link_bw.bits.BW_48Gbps) ++ supported_bw_in_kbps = 48000000; ++ else if (hdmi_encoded_link_bw.bits.BW_40Gbps) ++ supported_bw_in_kbps = 40000000; ++ else if (hdmi_encoded_link_bw.bits.BW_32Gbps) ++ supported_bw_in_kbps = 32000000; ++ else if (hdmi_encoded_link_bw.bits.BW_24Gbps) ++ supported_bw_in_kbps = 24000000; ++ else if (hdmi_encoded_link_bw.bits.BW_18Gbps) ++ supported_bw_in_kbps = 18000000; ++ else if (hdmi_encoded_link_bw.bits.BW_9Gbps) ++ supported_bw_in_kbps = 9000000; + + return supported_bw_in_kbps; + } +@@ -920,6 +920,9 @@ bool link_decide_link_settings(struct dc_stream_state *stream, + * TODO: add MST specific link training routine + */ + decide_mst_link_settings(link, link_setting); ++ } else if (stream->signal == SIGNAL_TYPE_VIRTUAL) { ++ link_setting->lane_count = LANE_COUNT_FOUR; ++ link_setting->link_rate = LINK_RATE_HIGH3; + } else if (link->connector_signal == SIGNAL_TYPE_EDP) { + /* enable edp link optimization for DSC eDP case */ + if (stream->timing.flags.DSC) { +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c +index 9bde0c8bf914a6..f01a3df584552f 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c +@@ -74,7 +74,8 @@ void dp_disable_link_phy(struct dc_link *link, + struct dc *dc = link->ctx->dc; + + if (!link->wa_flags.dp_keep_receiver_powered && +- !link->skip_implict_edp_power_control) ++ !link->skip_implict_edp_power_control && ++ link->type != dc_connection_none) + dpcd_write_rx_power_ctrl(link, false); + + dc->hwss.disable_link_output(link, link_res, signal); +@@ -159,8 +160,9 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource + } else { + if (link->fec_state == dc_link_fec_ready) { + fec_config = 0; +- core_link_write_dpcd(link, DP_FEC_CONFIGURATION, +- &fec_config, sizeof(fec_config)); ++ if (link->type != dc_connection_none) ++ core_link_write_dpcd(link, DP_FEC_CONFIGURATION, ++ &fec_config, sizeof(fec_config)); + + link_enc->funcs->fec_set_ready(link_enc, false); + link->fec_state = dc_link_fec_not_ready; +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c +index 2b4c15b0b40708..52261e7c11c0b4 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c +@@ -36,7 +36,8 @@ + link->ctx->logger + + static int32_t get_cr_training_aux_rd_interval(struct dc_link *link, +- const struct dc_link_settings *link_settings) ++ const struct dc_link_settings *link_settings, ++ enum lttpr_mode lttpr_mode) + { + union training_aux_rd_interval training_rd_interval; + uint32_t wait_in_micro_secs = 100; +@@ -49,6 +50,8 @@ static int32_t get_cr_training_aux_rd_interval(struct dc_link *link, + DP_TRAINING_AUX_RD_INTERVAL, + (uint8_t *)&training_rd_interval, + sizeof(training_rd_interval)); ++ if (lttpr_mode != LTTPR_MODE_NON_TRANSPARENT) ++ wait_in_micro_secs = 400; + if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) + wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000; + } +@@ -110,7 +113,6 @@ void decide_8b_10b_training_settings( + */ + lt_settings->link_settings.link_spread = link->dp_ss_off ? + LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ; +- lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting); + lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting); + lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting); + lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting); +@@ -119,6 +121,7 @@ void decide_8b_10b_training_settings( + lt_settings->disallow_per_lane_settings = true; + lt_settings->always_match_dpcd_with_hw_lane_settings = true; + lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link); ++ lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting, lt_settings->lttpr_mode); + dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + } + +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +index 13104d000b9e09..d4d92da153ece2 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +@@ -662,6 +662,18 @@ bool edp_setup_psr(struct dc_link *link, + if (!link) + return false; + ++ //Clear PSR cfg ++ memset(&psr_configuration, 0, sizeof(psr_configuration)); ++ dm_helpers_dp_write_dpcd( ++ link->ctx, ++ link, ++ DP_PSR_EN_CFG, ++ &psr_configuration.raw, ++ sizeof(psr_configuration.raw)); ++ ++ if (link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED) ++ return false; ++ + dc = link->ctx->dc; + dmcu = dc->res_pool->dmcu; + psr = dc->res_pool->psr; +@@ -672,9 +684,6 @@ bool edp_setup_psr(struct dc_link *link, + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + +- +- memset(&psr_configuration, 0, sizeof(psr_configuration)); +- + psr_configuration.bits.ENABLE = 1; + psr_configuration.bits.CRC_VERIFICATION = 1; + psr_configuration.bits.FRAME_CAPTURE_INDICATION = +@@ -938,6 +947,16 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream + if (!link) + return false; + ++ //Clear Replay config ++ dm_helpers_dp_write_dpcd(link->ctx, link, ++ DP_SINK_PR_ENABLE_AND_CONFIGURATION, ++ (uint8_t *)&(replay_config.raw), sizeof(uint8_t)); ++ ++ if (!(link->replay_settings.config.replay_supported)) ++ return false; ++ ++ link->replay_settings.config.replay_error_status.raw = 0; ++ + dc = link->ctx->dc; + + replay = dc->res_pool->replay; +diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h +index c488d4a50cf46a..b2252deabc17a4 100644 +--- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h ++++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_offset.h +@@ -203,6 +203,10 @@ + #define mmDAGB0_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB0_WR_MISC_CREDIT 0x0058 + #define mmDAGB0_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE 0x005b ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x005c ++#define mmDAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB0_WRCLI_ASK_PENDING 0x005d + #define mmDAGB0_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB0_WRCLI_GO_PENDING 0x005e +@@ -455,6 +459,10 @@ + #define mmDAGB1_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB1_WR_MISC_CREDIT 0x00d8 + #define mmDAGB1_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE 0x00db ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x00dc ++#define mmDAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB1_WRCLI_ASK_PENDING 0x00dd + #define mmDAGB1_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB1_WRCLI_GO_PENDING 0x00de +@@ -707,6 +715,10 @@ + #define mmDAGB2_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB2_WR_MISC_CREDIT 0x0158 + #define mmDAGB2_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE 0x015b ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x015c ++#define mmDAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB2_WRCLI_ASK_PENDING 0x015d + #define mmDAGB2_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB2_WRCLI_GO_PENDING 0x015e +@@ -959,6 +971,10 @@ + #define mmDAGB3_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB3_WR_MISC_CREDIT 0x01d8 + #define mmDAGB3_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE 0x01db ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x01dc ++#define mmDAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB3_WRCLI_ASK_PENDING 0x01dd + #define mmDAGB3_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB3_WRCLI_GO_PENDING 0x01de +@@ -1211,6 +1227,10 @@ + #define mmDAGB4_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB4_WR_MISC_CREDIT 0x0258 + #define mmDAGB4_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE 0x025b ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x025c ++#define mmDAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB4_WRCLI_ASK_PENDING 0x025d + #define mmDAGB4_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB4_WRCLI_GO_PENDING 0x025e +@@ -4793,6 +4813,10 @@ + #define mmDAGB5_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB5_WR_MISC_CREDIT 0x3058 + #define mmDAGB5_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE 0x305b ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x305c ++#define mmDAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB5_WRCLI_ASK_PENDING 0x305d + #define mmDAGB5_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB5_WRCLI_GO_PENDING 0x305e +@@ -5045,6 +5069,10 @@ + #define mmDAGB6_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB6_WR_MISC_CREDIT 0x30d8 + #define mmDAGB6_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE 0x30db ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x30dc ++#define mmDAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB6_WRCLI_ASK_PENDING 0x30dd + #define mmDAGB6_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB6_WRCLI_GO_PENDING 0x30de +@@ -5297,6 +5325,10 @@ + #define mmDAGB7_WR_DATA_CREDIT_BASE_IDX 1 + #define mmDAGB7_WR_MISC_CREDIT 0x3158 + #define mmDAGB7_WR_MISC_CREDIT_BASE_IDX 1 ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE 0x315b ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_BASE_IDX 1 ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE 0x315c ++#define mmDAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE_BASE_IDX 1 + #define mmDAGB7_WRCLI_ASK_PENDING 0x315d + #define mmDAGB7_WRCLI_ASK_PENDING_BASE_IDX 1 + #define mmDAGB7_WRCLI_GO_PENDING 0x315e +diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h +index 2969fbf282b7d0..5069d2fd467f2b 100644 +--- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h ++++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_1_sh_mask.h +@@ -1532,6 +1532,12 @@ + //DAGB0_WRCLI_DBUS_GO_PENDING + #define DAGB0_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB0_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB0_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB0_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB0_DAGB_DLY + #define DAGB0_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB0_DAGB_DLY__CLI__SHIFT 0x8 +@@ -3207,6 +3213,12 @@ + //DAGB1_WRCLI_DBUS_GO_PENDING + #define DAGB1_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB1_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB1_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB1_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB1_DAGB_DLY + #define DAGB1_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB1_DAGB_DLY__CLI__SHIFT 0x8 +@@ -4882,6 +4894,12 @@ + //DAGB2_WRCLI_DBUS_GO_PENDING + #define DAGB2_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB2_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB2_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB2_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB2_DAGB_DLY + #define DAGB2_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB2_DAGB_DLY__CLI__SHIFT 0x8 +@@ -6557,6 +6575,12 @@ + //DAGB3_WRCLI_DBUS_GO_PENDING + #define DAGB3_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB3_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB3_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB3_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB3_DAGB_DLY + #define DAGB3_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB3_DAGB_DLY__CLI__SHIFT 0x8 +@@ -8232,6 +8256,12 @@ + //DAGB4_WRCLI_DBUS_GO_PENDING + #define DAGB4_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB4_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB4_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB4_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB4_DAGB_DLY + #define DAGB4_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB4_DAGB_DLY__CLI__SHIFT 0x8 +@@ -28737,6 +28767,12 @@ + //DAGB5_WRCLI_DBUS_GO_PENDING + #define DAGB5_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB5_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB5_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB5_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB5_DAGB_DLY + #define DAGB5_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB5_DAGB_DLY__CLI__SHIFT 0x8 +@@ -30412,6 +30448,12 @@ + //DAGB6_WRCLI_DBUS_GO_PENDING + #define DAGB6_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB6_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB6_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB6_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB6_DAGB_DLY + #define DAGB6_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB6_DAGB_DLY__CLI__SHIFT 0x8 +@@ -32087,6 +32129,12 @@ + //DAGB7_WRCLI_DBUS_GO_PENDING + #define DAGB7_WRCLI_DBUS_GO_PENDING__BUSY__SHIFT 0x0 + #define DAGB7_WRCLI_DBUS_GO_PENDING__BUSY_MASK 0xFFFFFFFFL ++//DAGB7_WRCLI_GPU_SNOOP_OVERRIDE ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE__SHIFT 0x0 ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE__ENABLE_MASK 0xFFFFFFFFL ++//DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE__SHIFT 0x0 ++#define DAGB7_WRCLI_GPU_SNOOP_OVERRIDE_VALUE__ENABLE_MASK 0xFFFFFFFFL + //DAGB7_DAGB_DLY + #define DAGB7_DAGB_DLY__DLY__SHIFT 0x0 + #define DAGB7_DAGB_DLY__CLI__SHIFT 0x8 +diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c +index 3de0f457fff6ab..5f58da6ebaadb4 100644 +--- a/drivers/gpu/drm/ast/ast_mode.c ++++ b/drivers/gpu/drm/ast/ast_mode.c +@@ -132,7 +132,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + return false; + } + +- switch (mode->crtc_hdisplay) { ++ switch (mode->hdisplay) { + case 640: + vbios_mode->enh_table = &res_640x480[refresh_rate_index]; + break; +@@ -146,7 +146,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table = &res_1152x864[refresh_rate_index]; + break; + case 1280: +- if (mode->crtc_vdisplay == 800) ++ if (mode->vdisplay == 800) + vbios_mode->enh_table = &res_1280x800[refresh_rate_index]; + else + vbios_mode->enh_table = &res_1280x1024[refresh_rate_index]; +@@ -158,7 +158,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table = &res_1440x900[refresh_rate_index]; + break; + case 1600: +- if (mode->crtc_vdisplay == 900) ++ if (mode->vdisplay == 900) + vbios_mode->enh_table = &res_1600x900[refresh_rate_index]; + else + vbios_mode->enh_table = &res_1600x1200[refresh_rate_index]; +@@ -167,7 +167,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table = &res_1680x1050[refresh_rate_index]; + break; + case 1920: +- if (mode->crtc_vdisplay == 1080) ++ if (mode->vdisplay == 1080) + vbios_mode->enh_table = &res_1920x1080[refresh_rate_index]; + else + vbios_mode->enh_table = &res_1920x1200[refresh_rate_index]; +@@ -211,6 +211,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0; + vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0; + ++ adjusted_mode->crtc_hdisplay = vbios_mode->enh_table->hde; + adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht; + adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder; + adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder; +@@ -220,6 +221,7 @@ static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + vbios_mode->enh_table->hfp + + vbios_mode->enh_table->hsync); + ++ adjusted_mode->crtc_vdisplay = vbios_mode->enh_table->vde; + adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt; + adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder; + adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder; +diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +index 8f786592143b6c..24e1e11acf6978 100644 +--- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c ++++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +@@ -244,7 +244,9 @@ static const struct hdmi_codec_pdata codec_data = { + .ops = &adv7511_codec_ops, + .max_i2s_channels = 2, + .i2s = 1, ++ .no_i2s_capture = 1, + .spdif = 1, ++ .no_spdif_capture = 1, + }; + + int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511) +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index f3681970887cc8..1aa59586c8f81a 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -573,6 +573,30 @@ mode_valid(struct drm_atomic_state *state) + return 0; + } + ++static int drm_atomic_check_valid_clones(struct drm_atomic_state *state, ++ struct drm_crtc *crtc) ++{ ++ struct drm_encoder *drm_enc; ++ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, ++ crtc); ++ ++ drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) { ++ if (!drm_enc->possible_clones) { ++ DRM_DEBUG("enc%d possible_clones is 0\n", drm_enc->base.id); ++ continue; ++ } ++ ++ if ((crtc_state->encoder_mask & drm_enc->possible_clones) != ++ crtc_state->encoder_mask) { ++ DRM_DEBUG("crtc%d failed valid clone check for mask 0x%x\n", ++ crtc->base.id, crtc_state->encoder_mask); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ + /** + * drm_atomic_helper_check_modeset - validate state object for modeset changes + * @dev: DRM device +@@ -744,6 +768,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret != 0) + return ret; ++ ++ ret = drm_atomic_check_valid_clones(state, crtc); ++ if (ret != 0) ++ return ret; + } + + /* +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index ad872c61aac0e3..c6e6e4766c8bf6 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -6471,6 +6471,7 @@ static void drm_reset_display_info(struct drm_connector *connector) + info->has_hdmi_infoframe = false; + info->rgb_quant_range_selectable = false; + memset(&info->hdmi, 0, sizeof(info->hdmi)); ++ memset(&connector->hdr_sink_metadata, 0, sizeof(connector->hdr_sink_metadata)); + + info->edid_hdmi_rgb444_dc_modes = 0; + info->edid_hdmi_ycbcr444_dc_modes = 0; +diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c +index 44a948b80ee14e..deb93f78ce3442 100644 +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -322,7 +322,7 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + return -ENOENT; + + /* Don't allow imported objects to be mapped */ +- if (obj->import_attach) { ++ if (drm_gem_is_imported(obj)) { + ret = -EINVAL; + goto out; + } +@@ -1155,7 +1155,7 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent, + drm_vma_node_start(&obj->vma_node)); + drm_printf_indent(p, indent, "size=%zu\n", obj->size); + drm_printf_indent(p, indent, "imported=%s\n", +- str_yes_no(obj->import_attach)); ++ str_yes_no(drm_gem_is_imported(obj))); + + if (obj->funcs->print_info) + obj->funcs->print_info(p, indent, obj); +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 54fc3f819577e3..6391afdf202e27 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -410,12 +410,13 @@ static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable) + + static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) + { +- mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); ++ if (dpi->conf->reg_h_fre_con) ++ mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, H_FRE_2N, H_FRE_2N); + } + + static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi) + { +- if (dpi->conf->edge_sel_en) ++ if (dpi->conf->edge_sel_en && dpi->conf->reg_h_fre_con) + mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN); + } + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index 94fe2f3836a9a3..53b3b24d7d7c05 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -1923,6 +1923,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, "LQ140M1JW46"), + EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), + ++ EDP_PANEL_ENTRY('S', 'T', 'A', 0x0004, &delay_200_500_e200, "116KHD024006"), + EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"), + + { /* sentinal */ } +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +index d8f8c37c326c43..0193d10867dd2f 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +@@ -1290,10 +1290,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, + + rb_swap = vop2_win_rb_swap(fb->format->format); + vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap); +- if (!vop2_cluster_window(win)) { +- uv_swap = vop2_win_uv_swap(fb->format->format); +- vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); +- } ++ uv_swap = vop2_win_uv_swap(fb->format->format); ++ vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); + + if (fb->format->is_yuv) { + vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4)); +diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c +index ffbbe9d527d324..0e8ea990118844 100644 +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -226,11 +226,21 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ v3d->clk = devm_clk_get_optional(dev, NULL); ++ if (IS_ERR(v3d->clk)) ++ return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n"); ++ ++ ret = clk_prepare_enable(v3d->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't enable the V3D clock\n"); ++ return ret; ++ } ++ + mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); + mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); + ret = dma_set_mask_and_coherent(dev, mask); + if (ret) +- return ret; ++ goto clk_disable; + + v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); + +@@ -245,28 +255,29 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + ret = PTR_ERR(v3d->reset); + + if (ret == -EPROBE_DEFER) +- return ret; ++ goto clk_disable; + + v3d->reset = NULL; + ret = map_regs(v3d, &v3d->bridge_regs, "bridge"); + if (ret) { + dev_err(dev, + "Failed to get reset control or bridge regs\n"); +- return ret; ++ goto clk_disable; + } + } + + if (v3d->ver < 41) { + ret = map_regs(v3d, &v3d->gca_regs, "gca"); + if (ret) +- return ret; ++ goto clk_disable; + } + + v3d->mmu_scratch = dma_alloc_wc(dev, 4096, &v3d->mmu_scratch_paddr, + GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); + if (!v3d->mmu_scratch) { + dev_err(dev, "Failed to allocate MMU scratch page\n"); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto clk_disable; + } + + ret = v3d_gem_init(drm); +@@ -289,6 +300,8 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) + v3d_gem_destroy(drm); + dma_free: + dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr); ++clk_disable: ++ clk_disable_unprepare(v3d->clk); + return ret; + } + +@@ -303,6 +316,8 @@ static void v3d_platform_drm_remove(struct platform_device *pdev) + + dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch, + v3d->mmu_scratch_paddr); ++ ++ clk_disable_unprepare(v3d->clk); + } + + static struct platform_driver v3d_platform_driver = { +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 8e721ec3faaff3..a8665d57094b22 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -41,6 +41,10 @@ + #define USB_VENDOR_ID_ACTIONSTAR 0x2101 + #define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011 + ++#define USB_VENDOR_ID_ADATA_XPG 0x125f ++#define USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE 0x7505 ++#define USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE 0x7506 ++ + #define USB_VENDOR_ID_ADS_TECH 0x06e1 + #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 5d7a418ccdbecf..73979643315bfd 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -27,6 +27,8 @@ + static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD), HID_QUIRK_BADPAD }, + { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR), HID_QUIRK_BADPAD }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016), HID_QUIRK_FULLSPEED_INTERVAL }, + { HID_USB_DEVICE(USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS), HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX), HID_QUIRK_NO_INIT_REPORTS }, +diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c +index c439ed2f16dbca..af6bc76dbf6493 100644 +--- a/drivers/hid/usbhid/usbkbd.c ++++ b/drivers/hid/usbhid/usbkbd.c +@@ -160,7 +160,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type, + return -1; + + spin_lock_irqsave(&kbd->leds_lock, flags); +- kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | ++ kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 4) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | + (!!test_bit(LED_NUML, dev->led)); + +diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c +index 44aaf9b9191d41..8d94ecc3cc468c 100644 +--- a/drivers/hwmon/dell-smm-hwmon.c ++++ b/drivers/hwmon/dell-smm-hwmon.c +@@ -67,7 +67,7 @@ + #define I8K_POWER_BATTERY 0x01 + + #define DELL_SMM_NO_TEMP 10 +-#define DELL_SMM_NO_FANS 3 ++#define DELL_SMM_NO_FANS 4 + + struct dell_smm_data { + struct mutex i8k_mutex; /* lock for sensors writes */ +@@ -940,11 +940,14 @@ static const struct hwmon_channel_info * const dell_smm_info[] = { + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | ++ HWMON_F_TARGET, ++ HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET + ), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, + HWMON_PWM_INPUT, ++ HWMON_PWM_INPUT, + HWMON_PWM_INPUT + ), + NULL +diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c +index d92c536be9af78..b779240328d59f 100644 +--- a/drivers/hwmon/gpio-fan.c ++++ b/drivers/hwmon/gpio-fan.c +@@ -393,7 +393,12 @@ static int gpio_fan_set_cur_state(struct thermal_cooling_device *cdev, + if (state >= fan_data->num_speed) + return -EINVAL; + ++ mutex_lock(&fan_data->lock); ++ + set_fan_speed(fan_data, state); ++ ++ mutex_unlock(&fan_data->lock); ++ + return 0; + } + +@@ -489,7 +494,11 @@ MODULE_DEVICE_TABLE(of, of_gpio_fan_match); + + static void gpio_fan_stop(void *data) + { ++ struct gpio_fan_data *fan_data = data; ++ ++ mutex_lock(&fan_data->lock); + set_fan_speed(data, 0); ++ mutex_unlock(&fan_data->lock); + } + + static int gpio_fan_probe(struct platform_device *pdev) +@@ -562,7 +571,9 @@ static int gpio_fan_suspend(struct device *dev) + + if (fan_data->gpios) { + fan_data->resume_speed = fan_data->speed_index; ++ mutex_lock(&fan_data->lock); + set_fan_speed(fan_data, 0); ++ mutex_unlock(&fan_data->lock); + } + + return 0; +@@ -572,8 +583,11 @@ static int gpio_fan_resume(struct device *dev) + { + struct gpio_fan_data *fan_data = dev_get_drvdata(dev); + +- if (fan_data->gpios) ++ if (fan_data->gpios) { ++ mutex_lock(&fan_data->lock); + set_fan_speed(fan_data, fan_data->resume_speed); ++ mutex_unlock(&fan_data->lock); ++ } + + return 0; + } +diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c +index 207084d55044a1..6768dbf3903906 100644 +--- a/drivers/hwmon/xgene-hwmon.c ++++ b/drivers/hwmon/xgene-hwmon.c +@@ -111,7 +111,7 @@ struct xgene_hwmon_dev { + + phys_addr_t comm_base_addr; + void *pcc_comm_addr; +- u64 usecs_lat; ++ unsigned int usecs_lat; + }; + + /* +diff --git a/drivers/hwtracing/intel_th/Kconfig b/drivers/hwtracing/intel_th/Kconfig +index 4b6359326ede99..4f7d2b6d79e294 100644 +--- a/drivers/hwtracing/intel_th/Kconfig ++++ b/drivers/hwtracing/intel_th/Kconfig +@@ -60,6 +60,7 @@ config INTEL_TH_STH + + config INTEL_TH_MSU + tristate "Intel(R) Trace Hub Memory Storage Unit" ++ depends on MMU + help + Memory Storage Unit (MSU) trace output device enables + storing STP traces to system memory. It supports single +diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c +index 9621efe0e95c4d..54629458fb710c 100644 +--- a/drivers/hwtracing/intel_th/msu.c ++++ b/drivers/hwtracing/intel_th/msu.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_X86 + #include +@@ -965,7 +966,6 @@ static void msc_buffer_contig_free(struct msc *msc) + for (off = 0; off < msc->nr_pages << PAGE_SHIFT; off += PAGE_SIZE) { + struct page *page = virt_to_page(msc->base + off); + +- page->mapping = NULL; + __free_page(page); + } + +@@ -1147,9 +1147,6 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win) + int i; + + for_each_sg(win->sgt->sgl, sg, win->nr_segs, i) { +- struct page *page = msc_sg_page(sg); +- +- page->mapping = NULL; + dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE, + sg_virt(sg), sg_dma_address(sg)); + } +@@ -1584,22 +1581,10 @@ static void msc_mmap_close(struct vm_area_struct *vma) + { + struct msc_iter *iter = vma->vm_file->private_data; + struct msc *msc = iter->msc; +- unsigned long pg; + + if (!atomic_dec_and_mutex_lock(&msc->mmap_count, &msc->buf_mutex)) + return; + +- /* drop page _refcounts */ +- for (pg = 0; pg < msc->nr_pages; pg++) { +- struct page *page = msc_buffer_get_page(msc, pg); +- +- if (WARN_ON_ONCE(!page)) +- continue; +- +- if (page->mapping) +- page->mapping = NULL; +- } +- + /* last mapping -- drop user_count */ + atomic_dec(&msc->user_count); + mutex_unlock(&msc->buf_mutex); +@@ -1609,16 +1594,14 @@ static vm_fault_t msc_mmap_fault(struct vm_fault *vmf) + { + struct msc_iter *iter = vmf->vma->vm_file->private_data; + struct msc *msc = iter->msc; ++ struct page *page; + +- vmf->page = msc_buffer_get_page(msc, vmf->pgoff); +- if (!vmf->page) ++ page = msc_buffer_get_page(msc, vmf->pgoff); ++ if (!page) + return VM_FAULT_SIGBUS; + +- get_page(vmf->page); +- vmf->page->mapping = vmf->vma->vm_file->f_mapping; +- vmf->page->index = vmf->pgoff; +- +- return 0; ++ get_page(page); ++ return vmf_insert_mixed(vmf->vma, vmf->address, page_to_pfn_t(page)); + } + + static const struct vm_operations_struct msc_mmap_ops = { +@@ -1659,7 +1642,7 @@ static int intel_th_msc_mmap(struct file *file, struct vm_area_struct *vma) + atomic_dec(&msc->user_count); + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +- vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY); ++ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY | VM_MIXEDMAP); + vma->vm_ops = &msc_mmap_ops; + return ret; + } +diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c +index ced2fb4aeda8d3..79e083aab08e0c 100644 +--- a/drivers/i2c/busses/i2c-designware-common.c ++++ b/drivers/i2c/busses/i2c-designware-common.c +@@ -669,6 +669,7 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) + + i2c_dw_release_lock(dev); + } ++EXPORT_SYMBOL_GPL(i2c_dw_disable); + + MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h +index 5eb130c1d67195..e93870a0f9a459 100644 +--- a/drivers/i2c/busses/i2c-designware-core.h ++++ b/drivers/i2c/busses/i2c-designware-core.h +@@ -238,7 +238,6 @@ struct reset_control; + * @semaphore_idx: Index of table with semaphore type attached to the bus. It's + * -1 if there is no semaphore. + * @shared_with_punit: true if this bus is shared with the SoCs PUNIT +- * @disable: function to disable the controller + * @init: function to initialize the I2C hardware + * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing + * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE +@@ -295,7 +294,6 @@ struct dw_i2c_dev { + void (*release_lock)(void); + int semaphore_idx; + bool shared_with_punit; +- void (*disable)(struct dw_i2c_dev *dev); + int (*init)(struct dw_i2c_dev *dev); + int (*set_sda_hold_time)(struct dw_i2c_dev *dev); + int mode; +@@ -305,6 +303,7 @@ struct dw_i2c_dev { + #define ACCESS_INTR_MASK BIT(0) + #define ACCESS_NO_IRQ_SUSPEND BIT(1) + #define ARBITRATION_SEMAPHORE BIT(2) ++#define ACCESS_POLLING BIT(3) + + #define MODEL_MSCC_OCELOT BIT(8) + #define MODEL_BAIKAL_BT1 BIT(9) +@@ -339,7 +338,6 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); + int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev); + int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev); + u32 i2c_dw_func(struct i2c_adapter *adap); +-void i2c_dw_disable(struct dw_i2c_dev *dev); + + static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) + { +@@ -354,6 +352,7 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) + } + + void __i2c_dw_disable(struct dw_i2c_dev *dev); ++void i2c_dw_disable(struct dw_i2c_dev *dev); + + extern void i2c_dw_configure_master(struct dw_i2c_dev *dev); + extern int i2c_dw_probe_master(struct dw_i2c_dev *dev); +diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c +index 579c668cb78a6d..51f5491648c077 100644 +--- a/drivers/i2c/busses/i2c-designware-master.c ++++ b/drivers/i2c/busses/i2c-designware-master.c +@@ -991,31 +991,6 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) + return 0; + } + +-static int i2c_dw_poll_adap_quirk(struct dw_i2c_dev *dev) +-{ +- struct i2c_adapter *adap = &dev->adapter; +- int ret; +- +- pm_runtime_get_noresume(dev->dev); +- ret = i2c_add_numbered_adapter(adap); +- if (ret) +- dev_err(dev->dev, "Failed to add adapter: %d\n", ret); +- pm_runtime_put_noidle(dev->dev); +- +- return ret; +-} +- +-static bool i2c_dw_is_model_poll(struct dw_i2c_dev *dev) +-{ +- switch (dev->flags & MODEL_MASK) { +- case MODEL_AMD_NAVI_GPU: +- case MODEL_WANGXUN_SP: +- return true; +- default: +- return false; +- } +-} +- + int i2c_dw_probe_master(struct dw_i2c_dev *dev) + { + struct i2c_adapter *adap = &dev->adapter; +@@ -1026,7 +1001,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + init_completion(&dev->cmd_complete); + + dev->init = i2c_dw_init_master; +- dev->disable = i2c_dw_disable; + + ret = i2c_dw_init_regmap(dev); + if (ret) +@@ -1071,9 +1045,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + adap->dev.parent = dev->dev; + i2c_set_adapdata(adap, dev); + +- if (i2c_dw_is_model_poll(dev)) +- return i2c_dw_poll_adap_quirk(dev); +- + if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { + irq_flags = IRQF_NO_SUSPEND; + } else { +@@ -1087,12 +1058,14 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) + regmap_write(dev->map, DW_IC_INTR_MASK, 0); + i2c_dw_release_lock(dev); + +- ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags, +- dev_name(dev->dev), dev); +- if (ret) { +- dev_err(dev->dev, "failure requesting irq %i: %d\n", +- dev->irq, ret); +- return ret; ++ if (!(dev->flags & ACCESS_POLLING)) { ++ ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, ++ irq_flags, dev_name(dev->dev), dev); ++ if (ret) { ++ dev_err(dev->dev, "failure requesting irq %i: %d\n", ++ dev->irq, ret); ++ return ret; ++ } + } + + ret = i2c_dw_init_recovery_info(dev); +diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c +index 61d7a27aa07018..b85f1e4ed13bc8 100644 +--- a/drivers/i2c/busses/i2c-designware-pcidrv.c ++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c +@@ -154,7 +154,7 @@ static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c) + { + struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev); + +- dev->flags |= MODEL_AMD_NAVI_GPU; ++ dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING; + dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; + return 0; + } +@@ -198,7 +198,7 @@ static int __maybe_unused i2c_dw_pci_runtime_suspend(struct device *dev) + { + struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + +- i_dev->disable(i_dev); ++ i2c_dw_disable(i_dev); + return 0; + } + +@@ -248,6 +248,7 @@ static const struct software_node dgpu_node = { + static int i2c_dw_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { ++ struct device *device = &pdev->dev; + struct dw_i2c_dev *dev; + struct i2c_adapter *adap; + int r; +@@ -256,25 +257,22 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + struct i2c_timings *t; + + if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) +- return dev_err_probe(&pdev->dev, -EINVAL, +- "Invalid driver data %ld\n", ++ return dev_err_probe(device, -EINVAL, "Invalid driver data %ld\n", + id->driver_data); + + controller = &dw_pci_controllers[id->driver_data]; + + r = pcim_enable_device(pdev); + if (r) +- return dev_err_probe(&pdev->dev, r, +- "Failed to enable I2C PCI device\n"); ++ return dev_err_probe(device, r, "Failed to enable I2C PCI device\n"); + + pci_set_master(pdev); + + r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); + if (r) +- return dev_err_probe(&pdev->dev, r, +- "I/O memory remapping failed\n"); ++ return dev_err_probe(device, r, "I/O memory remapping failed\n"); + +- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + +@@ -284,7 +282,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + + dev->get_clk_rate_khz = controller->get_clk_rate_khz; + dev->base = pcim_iomap_table(pdev)[0]; +- dev->dev = &pdev->dev; ++ dev->dev = device; + dev->irq = pci_irq_vector(pdev, 0); + dev->flags |= controller->flags; + +@@ -337,15 +335,17 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + + if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) { + dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, &dgpu_node); +- if (IS_ERR(dev->slave)) +- return dev_err_probe(dev->dev, PTR_ERR(dev->slave), ++ if (IS_ERR(dev->slave)) { ++ i2c_del_adapter(&dev->adapter); ++ return dev_err_probe(device, PTR_ERR(dev->slave), + "register UCSI failed\n"); ++ } + } + +- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); +- pm_runtime_use_autosuspend(&pdev->dev); +- pm_runtime_put_autosuspend(&pdev->dev); +- pm_runtime_allow(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(device, 1000); ++ pm_runtime_use_autosuspend(device); ++ pm_runtime_put_autosuspend(device); ++ pm_runtime_allow(device); + + return 0; + } +@@ -353,10 +353,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, + static void i2c_dw_pci_remove(struct pci_dev *pdev) + { + struct dw_i2c_dev *dev = pci_get_drvdata(pdev); ++ struct device *device = &pdev->dev; ++ ++ i2c_dw_disable(dev); + +- dev->disable(dev); +- pm_runtime_forbid(&pdev->dev); +- pm_runtime_get_noresume(&pdev->dev); ++ pm_runtime_forbid(device); ++ pm_runtime_get_noresume(device); + + i2c_del_adapter(&dev->adapter); + devm_free_irq(&pdev->dev, dev->irq, dev); +diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c +index 855b698e99c080..f3245a68563095 100644 +--- a/drivers/i2c/busses/i2c-designware-platdrv.c ++++ b/drivers/i2c/busses/i2c-designware-platdrv.c +@@ -275,6 +275,7 @@ static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) + + static int dw_i2c_plat_probe(struct platform_device *pdev) + { ++ struct device *device = &pdev->dev; + struct i2c_adapter *adap; + struct dw_i2c_dev *dev; + struct i2c_timings *t; +@@ -284,15 +285,15 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); ++ dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + +- dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); +- if (device_property_present(&pdev->dev, "wx,i2c-snps-model")) +- dev->flags = MODEL_WANGXUN_SP; ++ dev->flags = (uintptr_t)device_get_match_data(device); ++ if (device_property_present(device, "wx,i2c-snps-model")) ++ dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING; + +- dev->dev = &pdev->dev; ++ dev->dev = device; + dev->irq = irq; + platform_set_drvdata(pdev, dev); + +@@ -300,7 +301,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + if (ret) + return ret; + +- dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ dev->rst = devm_reset_control_get_optional_exclusive(device, NULL); + if (IS_ERR(dev->rst)) + return PTR_ERR(dev->rst); + +@@ -328,13 +329,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + i2c_dw_configure(dev); + + /* Optional interface clock */ +- dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk"); ++ dev->pclk = devm_clk_get_optional(device, "pclk"); + if (IS_ERR(dev->pclk)) { + ret = PTR_ERR(dev->pclk); + goto exit_reset; + } + +- dev->clk = devm_clk_get_optional(&pdev->dev, NULL); ++ dev->clk = devm_clk_get_optional(device, NULL); + if (IS_ERR(dev->clk)) { + ret = PTR_ERR(dev->clk); + goto exit_reset; +@@ -363,28 +364,24 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + adap->dev.of_node = pdev->dev.of_node; + adap->nr = -1; + +- if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { +- dev_pm_set_driver_flags(&pdev->dev, +- DPM_FLAG_SMART_PREPARE); +- } else { +- dev_pm_set_driver_flags(&pdev->dev, +- DPM_FLAG_SMART_PREPARE | +- DPM_FLAG_SMART_SUSPEND); +- } ++ if (dev->flags & ACCESS_NO_IRQ_SUSPEND) ++ dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE); ++ else ++ dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE | DPM_FLAG_SMART_SUSPEND); + +- device_enable_async_suspend(&pdev->dev); ++ device_enable_async_suspend(device); + + /* The code below assumes runtime PM to be disabled. */ +- WARN_ON(pm_runtime_enabled(&pdev->dev)); ++ WARN_ON(pm_runtime_enabled(device)); + +- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); +- pm_runtime_use_autosuspend(&pdev->dev); +- pm_runtime_set_active(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(device, 1000); ++ pm_runtime_use_autosuspend(device); ++ pm_runtime_set_active(device); + + if (dev->shared_with_punit) +- pm_runtime_get_noresume(&pdev->dev); ++ pm_runtime_get_noresume(device); + +- pm_runtime_enable(&pdev->dev); ++ pm_runtime_enable(device); + + ret = i2c_dw_probe(dev); + if (ret) +@@ -402,15 +399,16 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) + static void dw_i2c_plat_remove(struct platform_device *pdev) + { + struct dw_i2c_dev *dev = platform_get_drvdata(pdev); ++ struct device *device = &pdev->dev; + +- pm_runtime_get_sync(&pdev->dev); ++ pm_runtime_get_sync(device); + + i2c_del_adapter(&dev->adapter); + +- dev->disable(dev); ++ i2c_dw_disable(dev); + +- pm_runtime_dont_use_autosuspend(&pdev->dev); +- pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(device); ++ pm_runtime_put_sync(device); + dw_i2c_plat_pm_cleanup(dev); + + i2c_dw_remove_lock_support(dev); +@@ -436,7 +434,7 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev) + if (i_dev->shared_with_punit) + return 0; + +- i_dev->disable(i_dev); ++ i2c_dw_disable(i_dev); + i2c_dw_prepare_clk(i_dev, false); + + return 0; +diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c +index 78e2c47e3d7da7..345b532a2b455d 100644 +--- a/drivers/i2c/busses/i2c-designware-slave.c ++++ b/drivers/i2c/busses/i2c-designware-slave.c +@@ -88,7 +88,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave) + struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter); + + regmap_write(dev->map, DW_IC_INTR_MASK, 0); +- dev->disable(dev); ++ i2c_dw_disable(dev); + synchronize_irq(dev->irq); + dev->slave = NULL; + pm_runtime_put(dev->dev); +@@ -235,7 +235,6 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) + int ret; + + dev->init = i2c_dw_init_slave; +- dev->disable = i2c_dw_disable; + + ret = i2c_dw_init_regmap(dev); + if (ret) +diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c +index 3bd406470940fb..affdd94f06aaf0 100644 +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -1504,7 +1504,10 @@ static int i2c_pxa_probe(struct platform_device *dev) + i2c->adap.name); + } + +- clk_prepare_enable(i2c->clk); ++ ret = clk_prepare_enable(i2c->clk); ++ if (ret) ++ return dev_err_probe(&dev->dev, ret, ++ "failed to enable clock\n"); + + if (i2c->use_pio) { + i2c->adap.algo = &i2c_pxa_pio_algorithm; +diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c +index 598102d16677a1..ee92a315f074fe 100644 +--- a/drivers/i2c/busses/i2c-qup.c ++++ b/drivers/i2c/busses/i2c-qup.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -150,6 +151,8 @@ + /* TAG length for DATA READ in RX FIFO */ + #define READ_RX_TAGS_LEN 2 + ++#define QUP_BUS_WIDTH 8 ++ + static unsigned int scl_freq; + module_param_named(scl_freq, scl_freq, uint, 0444); + MODULE_PARM_DESC(scl_freq, "SCL frequency override"); +@@ -227,6 +230,7 @@ struct qup_i2c_dev { + int irq; + struct clk *clk; + struct clk *pclk; ++ struct icc_path *icc_path; + struct i2c_adapter adap; + + int clk_ctl; +@@ -255,6 +259,10 @@ struct qup_i2c_dev { + /* To configure when bus is in run state */ + u32 config_run; + ++ /* bandwidth votes */ ++ u32 src_clk_freq; ++ u32 cur_bw_clk_freq; ++ + /* dma parameters */ + bool is_dma; + /* To check if the current transfer is using DMA */ +@@ -453,6 +461,23 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) + return ret; + } + ++static int qup_i2c_vote_bw(struct qup_i2c_dev *qup, u32 clk_freq) ++{ ++ u32 needed_peak_bw; ++ int ret; ++ ++ if (qup->cur_bw_clk_freq == clk_freq) ++ return 0; ++ ++ needed_peak_bw = Bps_to_icc(clk_freq * QUP_BUS_WIDTH); ++ ret = icc_set_bw(qup->icc_path, 0, needed_peak_bw); ++ if (ret) ++ return ret; ++ ++ qup->cur_bw_clk_freq = clk_freq; ++ return 0; ++} ++ + static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) + { + struct qup_i2c_block *blk = &qup->blk; +@@ -840,6 +865,10 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int ret = 0; + int idx = 0; + ++ ret = qup_i2c_vote_bw(qup, qup->src_clk_freq); ++ if (ret) ++ return ret; ++ + enable_irq(qup->irq); + ret = qup_i2c_req_dma(qup); + +@@ -1645,6 +1674,7 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) + config = readl(qup->base + QUP_CONFIG); + config |= QUP_CLOCK_AUTO_GATE; + writel(config, qup->base + QUP_CONFIG); ++ qup_i2c_vote_bw(qup, 0); + clk_disable_unprepare(qup->pclk); + } + +@@ -1745,6 +1775,11 @@ static int qup_i2c_probe(struct platform_device *pdev) + goto fail_dma; + } + qup->is_dma = true; ++ ++ qup->icc_path = devm_of_icc_get(&pdev->dev, NULL); ++ if (IS_ERR(qup->icc_path)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(qup->icc_path), ++ "failed to get interconnect path\n"); + } + + nodma: +@@ -1793,6 +1828,7 @@ static int qup_i2c_probe(struct platform_device *pdev) + qup_i2c_enable_clocks(qup); + src_clk_freq = clk_get_rate(qup->clk); + } ++ qup->src_clk_freq = src_clk_freq; + + /* + * Bootloaders might leave a pending interrupt on certain QUP's, +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index fa1f12a89158cf..d1630d47ef6fcf 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -503,6 +503,8 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) + queue_work(master->base.wq, &master->hj_work); + break; + case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: ++ svc_i3c_master_emit_stop(master); ++ break; + default: + break; + } +@@ -840,6 +842,8 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, + u32 reg; + int ret, i; + ++ svc_i3c_master_flush_fifo(master); ++ + while (true) { + /* Enter/proceed with DAA */ + writel(SVC_I3C_MCTRL_REQUEST_PROC_DAA | +diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c +index 07c571c7b69992..c5b68639476058 100644 +--- a/drivers/infiniband/core/umem.c ++++ b/drivers/infiniband/core/umem.c +@@ -80,9 +80,12 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem, + unsigned long pgsz_bitmap, + unsigned long virt) + { +- struct scatterlist *sg; ++ unsigned long curr_len = 0; ++ dma_addr_t curr_base = ~0; + unsigned long va, pgoff; ++ struct scatterlist *sg; + dma_addr_t mask; ++ dma_addr_t end; + int i; + + umem->iova = va = virt; +@@ -107,17 +110,30 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem, + pgoff = umem->address & ~PAGE_MASK; + + for_each_sgtable_dma_sg(&umem->sgt_append.sgt, sg, i) { +- /* Walk SGL and reduce max page size if VA/PA bits differ +- * for any address. ++ /* If the current entry is physically contiguous with the previous ++ * one, no need to take its start addresses into consideration. + */ +- mask |= (sg_dma_address(sg) + pgoff) ^ va; ++ if (check_add_overflow(curr_base, curr_len, &end) || ++ end != sg_dma_address(sg)) { ++ ++ curr_base = sg_dma_address(sg); ++ curr_len = 0; ++ ++ /* Reduce max page size if VA/PA bits differ */ ++ mask |= (curr_base + pgoff) ^ va; ++ ++ /* The alignment of any VA matching a discontinuity point ++ * in the physical memory sets the maximum possible page ++ * size as this must be a starting point of a new page that ++ * needs to be aligned. ++ */ ++ if (i != 0) ++ mask |= va; ++ } ++ ++ curr_len += sg_dma_len(sg); + va += sg_dma_len(sg) - pgoff; +- /* Except for the last entry, the ending iova alignment sets +- * the maximum possible page size as the low bits of the iova +- * must be zero when starting the next chunk. +- */ +- if (i != (umem->sgt_append.sgt.nents - 1)) +- mask |= va; ++ + pgoff = 0; + } + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index c6053e82ecf6f3..33e2fe0facd529 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -718,8 +718,8 @@ static int ib_uverbs_reg_mr(struct uverbs_attr_bundle *attrs) + goto err_free; + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_free; + } + +@@ -809,8 +809,8 @@ static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs) + if (cmd.flags & IB_MR_REREG_PD) { + new_pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, + attrs); +- if (!new_pd) { +- ret = -EINVAL; ++ if (IS_ERR(new_pd)) { ++ ret = PTR_ERR(new_pd); + goto put_uobjs; + } + } else { +@@ -919,8 +919,8 @@ static int ib_uverbs_alloc_mw(struct uverbs_attr_bundle *attrs) + return PTR_ERR(uobj); + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_free; + } + +@@ -1127,8 +1127,8 @@ static int ib_uverbs_resize_cq(struct uverbs_attr_bundle *attrs) + return ret; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + ret = cq->device->ops.resize_cq(cq, cmd.cqe, &attrs->driver_udata); + if (ret) +@@ -1189,8 +1189,8 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs) + return ret; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + /* we copy a struct ib_uverbs_poll_cq_resp to user space */ + header_ptr = attrs->ucore.outbuf; +@@ -1238,8 +1238,8 @@ static int ib_uverbs_req_notify_cq(struct uverbs_attr_bundle *attrs) + return ret; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + ib_req_notify_cq(cq, cmd.solicited_only ? + IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); +@@ -1321,8 +1321,8 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + ind_tbl = uobj_get_obj_read(rwq_ind_table, + UVERBS_OBJECT_RWQ_IND_TBL, + cmd->rwq_ind_tbl_handle, attrs); +- if (!ind_tbl) { +- ret = -EINVAL; ++ if (IS_ERR(ind_tbl)) { ++ ret = PTR_ERR(ind_tbl); + goto err_put; + } + +@@ -1360,8 +1360,10 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + if (cmd->is_srq) { + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, + cmd->srq_handle, attrs); +- if (!srq || srq->srq_type == IB_SRQT_XRC) { +- ret = -EINVAL; ++ if (IS_ERR(srq) || ++ srq->srq_type == IB_SRQT_XRC) { ++ ret = IS_ERR(srq) ? PTR_ERR(srq) : ++ -EINVAL; + goto err_put; + } + } +@@ -1371,23 +1373,29 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + rcq = uobj_get_obj_read( + cq, UVERBS_OBJECT_CQ, + cmd->recv_cq_handle, attrs); +- if (!rcq) { +- ret = -EINVAL; ++ if (IS_ERR(rcq)) { ++ ret = PTR_ERR(rcq); + goto err_put; + } + } + } + } + +- if (has_sq) ++ if (has_sq) { + scq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, + cmd->send_cq_handle, attrs); ++ if (IS_ERR(scq)) { ++ ret = PTR_ERR(scq); ++ goto err_put; ++ } ++ } ++ + if (!ind_tbl && cmd->qp_type != IB_QPT_XRC_INI) + rcq = rcq ?: scq; + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, + attrs); +- if (!pd || (!scq && has_sq)) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_put; + } + +@@ -1482,18 +1490,18 @@ static int create_qp(struct uverbs_attr_bundle *attrs, + err_put: + if (!IS_ERR(xrcd_uobj)) + uobj_put_read(xrcd_uobj); +- if (pd) ++ if (!IS_ERR_OR_NULL(pd)) + uobj_put_obj_read(pd); +- if (scq) ++ if (!IS_ERR_OR_NULL(scq)) + rdma_lookup_put_uobject(&scq->uobject->uevent.uobject, + UVERBS_LOOKUP_READ); +- if (rcq && rcq != scq) ++ if (!IS_ERR_OR_NULL(rcq) && rcq != scq) + rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject, + UVERBS_LOOKUP_READ); +- if (srq) ++ if (!IS_ERR_OR_NULL(srq)) + rdma_lookup_put_uobject(&srq->uobject->uevent.uobject, + UVERBS_LOOKUP_READ); +- if (ind_tbl) ++ if (!IS_ERR_OR_NULL(ind_tbl)) + uobj_put_obj_read(ind_tbl); + + uobj_alloc_abort(&obj->uevent.uobject, attrs); +@@ -1655,8 +1663,8 @@ static int ib_uverbs_query_qp(struct uverbs_attr_bundle *attrs) + } + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -1761,8 +1769,8 @@ static int modify_qp(struct uverbs_attr_bundle *attrs, + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle, + attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -2027,8 +2035,8 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + return -ENOMEM; + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -2065,9 +2073,9 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) + + ud->ah = uobj_get_obj_read(ah, UVERBS_OBJECT_AH, + user_wr->wr.ud.ah, attrs); +- if (!ud->ah) { ++ if (IS_ERR(ud->ah)) { ++ ret = PTR_ERR(ud->ah); + kfree(ud); +- ret = -EINVAL; + goto out_put; + } + ud->remote_qpn = user_wr->wr.ud.remote_qpn; +@@ -2304,8 +2312,8 @@ static int ib_uverbs_post_recv(struct uverbs_attr_bundle *attrs) + return PTR_ERR(wr); + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- ret = -EINVAL; ++ if (IS_ERR(qp)) { ++ ret = PTR_ERR(qp); + goto out; + } + +@@ -2355,8 +2363,8 @@ static int ib_uverbs_post_srq_recv(struct uverbs_attr_bundle *attrs) + return PTR_ERR(wr); + + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs); +- if (!srq) { +- ret = -EINVAL; ++ if (IS_ERR(srq)) { ++ ret = PTR_ERR(srq); + goto out; + } + +@@ -2412,8 +2420,8 @@ static int ib_uverbs_create_ah(struct uverbs_attr_bundle *attrs) + } + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err; + } + +@@ -2482,8 +2490,8 @@ static int ib_uverbs_attach_mcast(struct uverbs_attr_bundle *attrs) + return ret; + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) +- return -EINVAL; ++ if (IS_ERR(qp)) ++ return PTR_ERR(qp); + + obj = qp->uobject; + +@@ -2532,8 +2540,8 @@ static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs) + return ret; + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) +- return -EINVAL; ++ if (IS_ERR(qp)) ++ return PTR_ERR(qp); + + obj = qp->uobject; + mutex_lock(&obj->mcast_lock); +@@ -2667,8 +2675,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs, + UVERBS_OBJECT_FLOW_ACTION, + kern_spec->action.handle, + attrs); +- if (!ib_spec->action.act) +- return -EINVAL; ++ if (IS_ERR(ib_spec->action.act)) ++ return PTR_ERR(ib_spec->action.act); + ib_spec->action.size = + sizeof(struct ib_flow_spec_action_handle); + flow_resources_add(uflow_res, +@@ -2685,8 +2693,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs, + UVERBS_OBJECT_COUNTERS, + kern_spec->flow_count.handle, + attrs); +- if (!ib_spec->flow_count.counters) +- return -EINVAL; ++ if (IS_ERR(ib_spec->flow_count.counters)) ++ return PTR_ERR(ib_spec->flow_count.counters); + ib_spec->flow_count.size = + sizeof(struct ib_flow_spec_action_count); + flow_resources_add(uflow_res, +@@ -2904,14 +2912,14 @@ static int ib_uverbs_ex_create_wq(struct uverbs_attr_bundle *attrs) + return PTR_ERR(obj); + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs); +- if (!pd) { +- err = -EINVAL; ++ if (IS_ERR(pd)) { ++ err = PTR_ERR(pd); + goto err_uobj; + } + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) { +- err = -EINVAL; ++ if (IS_ERR(cq)) { ++ err = PTR_ERR(cq); + goto err_put_pd; + } + +@@ -3012,8 +3020,8 @@ static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs) + return -EINVAL; + + wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, attrs); +- if (!wq) +- return -EINVAL; ++ if (IS_ERR(wq)) ++ return PTR_ERR(wq); + + if (cmd.attr_mask & IB_WQ_FLAGS) { + wq_attr.flags = cmd.flags; +@@ -3096,8 +3104,8 @@ static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs) + num_read_wqs++) { + wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, + wqs_handles[num_read_wqs], attrs); +- if (!wq) { +- err = -EINVAL; ++ if (IS_ERR(wq)) { ++ err = PTR_ERR(wq); + goto put_wqs; + } + +@@ -3252,8 +3260,8 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs) + } + + qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); +- if (!qp) { +- err = -EINVAL; ++ if (IS_ERR(qp)) { ++ err = PTR_ERR(qp); + goto err_uobj; + } + +@@ -3399,15 +3407,15 @@ static int __uverbs_create_xsrq(struct uverbs_attr_bundle *attrs, + if (ib_srq_has_cq(cmd->srq_type)) { + attr.ext.cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, + cmd->cq_handle, attrs); +- if (!attr.ext.cq) { +- ret = -EINVAL; ++ if (IS_ERR(attr.ext.cq)) { ++ ret = PTR_ERR(attr.ext.cq); + goto err_put_xrcd; + } + } + + pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, attrs); +- if (!pd) { +- ret = -EINVAL; ++ if (IS_ERR(pd)) { ++ ret = PTR_ERR(pd); + goto err_put_cq; + } + +@@ -3514,8 +3522,8 @@ static int ib_uverbs_modify_srq(struct uverbs_attr_bundle *attrs) + return ret; + + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs); +- if (!srq) +- return -EINVAL; ++ if (IS_ERR(srq)) ++ return PTR_ERR(srq); + + attr.max_wr = cmd.max_wr; + attr.srq_limit = cmd.srq_limit; +@@ -3542,8 +3550,8 @@ static int ib_uverbs_query_srq(struct uverbs_attr_bundle *attrs) + return ret; + + srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs); +- if (!srq) +- return -EINVAL; ++ if (IS_ERR(srq)) ++ return PTR_ERR(srq); + + ret = ib_query_srq(srq, &attr); + +@@ -3668,8 +3676,8 @@ static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs) + return -EOPNOTSUPP; + + cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs); +- if (!cq) +- return -EINVAL; ++ if (IS_ERR(cq)) ++ return PTR_ERR(cq); + + ret = rdma_set_cq_moderation(cq, cmd.attr.cq_count, cmd.attr.cq_period); + +diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c +index ba05de0380e96e..6567d437512808 100644 +--- a/drivers/infiniband/core/verbs.c ++++ b/drivers/infiniband/core/verbs.c +@@ -3029,22 +3029,23 @@ EXPORT_SYMBOL(__rdma_block_iter_start); + bool __rdma_block_iter_next(struct ib_block_iter *biter) + { + unsigned int block_offset; +- unsigned int sg_delta; ++ unsigned int delta; + + if (!biter->__sg_nents || !biter->__sg) + return false; + + biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; + block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); +- sg_delta = BIT_ULL(biter->__pg_bit) - block_offset; ++ delta = BIT_ULL(biter->__pg_bit) - block_offset; + +- if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) { +- biter->__sg_advance += sg_delta; +- } else { ++ while (biter->__sg_nents && biter->__sg && ++ sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) { ++ delta -= sg_dma_len(biter->__sg) - biter->__sg_advance; + biter->__sg_advance = 0; + biter->__sg = sg_next(biter->__sg); + biter->__sg_nents--; + } ++ biter->__sg_advance += delta; + + return true; + } +diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c +index c65321964131cf..e6fed973ea7411 100644 +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -289,6 +289,8 @@ static const struct xpad_device { + { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, + { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, + { 0x10f5, 0x7005, "Turtle Beach Recon Controller", 0, XTYPE_XBOXONE }, ++ { 0x10f5, 0x7008, "Turtle Beach Recon Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, ++ { 0x10f5, 0x7073, "Turtle Beach Stealth Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 }, + { 0x11ff, 0x0511, "PXN V900", 0, XTYPE_XBOX360 }, + { 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 }, +@@ -353,6 +355,7 @@ static const struct xpad_device { + { 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 }, + { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, + { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE }, ++ { 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, +diff --git a/drivers/iommu/amd/io_pgtable_v2.c b/drivers/iommu/amd/io_pgtable_v2.c +index cbf0c46015125a..6c0777a3c57b79 100644 +--- a/drivers/iommu/amd/io_pgtable_v2.c ++++ b/drivers/iommu/amd/io_pgtable_v2.c +@@ -259,7 +259,7 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova, + pte = v2_alloc_pte(pdom->nid, pdom->iop.pgd, + iova, map_size, gfp, &updated); + if (!pte) { +- ret = -EINVAL; ++ ret = -ENOMEM; + goto out; + } + +diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c +index 2da969fc899004..3f7fcf1801a97a 100644 +--- a/drivers/iommu/dma-iommu.c ++++ b/drivers/iommu/dma-iommu.c +@@ -1716,7 +1716,7 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr) + static DEFINE_MUTEX(msi_prepare_lock); /* see below */ + + if (!domain || !domain->iova_cookie) { +- desc->iommu_cookie = NULL; ++ msi_desc_set_iommu_msi_iova(desc, 0, 0); + return 0; + } + +@@ -1728,11 +1728,12 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr) + mutex_lock(&msi_prepare_lock); + msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain); + mutex_unlock(&msi_prepare_lock); +- +- msi_desc_set_iommu_cookie(desc, msi_page); +- + if (!msi_page) + return -ENOMEM; ++ ++ msi_desc_set_iommu_msi_iova( ++ desc, msi_page->iova, ++ ilog2(cookie_msi_granule(domain->iova_cookie))); + return 0; + } + +@@ -1743,18 +1744,15 @@ int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr) + */ + void iommu_dma_compose_msi_msg(struct msi_desc *desc, struct msi_msg *msg) + { +- struct device *dev = msi_desc_to_dev(desc); +- const struct iommu_domain *domain = iommu_get_domain_for_dev(dev); +- const struct iommu_dma_msi_page *msi_page; ++#ifdef CONFIG_IRQ_MSI_IOMMU ++ if (desc->iommu_msi_shift) { ++ u64 msi_iova = desc->iommu_msi_iova << desc->iommu_msi_shift; + +- msi_page = msi_desc_get_iommu_cookie(desc); +- +- if (!domain || !domain->iova_cookie || WARN_ON(!msi_page)) +- return; +- +- msg->address_hi = upper_32_bits(msi_page->iova); +- msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1; +- msg->address_lo += lower_32_bits(msi_page->iova); ++ msg->address_hi = upper_32_bits(msi_iova); ++ msg->address_lo = lower_32_bits(msi_iova) | ++ (msg->address_lo & ((1 << desc->iommu_msi_shift) - 1)); ++ } ++#endif + } + + static int iommu_dma_init(void) +diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c +index e1a81e0109e8a5..c0aa34b1d0e2dc 100644 +--- a/drivers/leds/rgb/leds-pwm-multicolor.c ++++ b/drivers/leds/rgb/leds-pwm-multicolor.c +@@ -135,8 +135,11 @@ static int led_pwm_mc_probe(struct platform_device *pdev) + + /* init the multicolor's LED class device */ + cdev = &priv->mc_cdev.led_cdev; +- fwnode_property_read_u32(mcnode, "max-brightness", ++ ret = fwnode_property_read_u32(mcnode, "max-brightness", + &cdev->max_brightness); ++ if (ret) ++ goto release_mcnode; ++ + cdev->flags = LED_CORE_SUSPENDRESUME; + cdev->brightness_set_blocking = led_pwm_mc_set; + +diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c +index 79719fc8a08fb4..f8912fa60c4988 100644 +--- a/drivers/leds/trigger/ledtrig-netdev.c ++++ b/drivers/leds/trigger/ledtrig-netdev.c +@@ -54,6 +54,7 @@ struct led_netdev_data { + unsigned int last_activity; + + unsigned long mode; ++ unsigned long blink_delay; + int link_speed; + u8 duplex; + +@@ -69,6 +70,10 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) + /* Already validated, hw control is possible with the requested mode */ + if (trigger_data->hw_control) { + led_cdev->hw_control_set(led_cdev, trigger_data->mode); ++ if (led_cdev->blink_set) { ++ led_cdev->blink_set(led_cdev, &trigger_data->blink_delay, ++ &trigger_data->blink_delay); ++ } + + return; + } +@@ -386,10 +391,11 @@ static ssize_t interval_store(struct device *dev, + size_t size) + { + struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); ++ struct led_classdev *led_cdev = trigger_data->led_cdev; + unsigned long value; + int ret; + +- if (trigger_data->hw_control) ++ if (trigger_data->hw_control && !led_cdev->blink_set) + return -EINVAL; + + ret = kstrtoul(buf, 0, &value); +@@ -398,9 +404,13 @@ static ssize_t interval_store(struct device *dev, + + /* impose some basic bounds on the timer interval */ + if (value >= 5 && value <= 10000) { +- cancel_delayed_work_sync(&trigger_data->work); ++ if (trigger_data->hw_control) { ++ trigger_data->blink_delay = value; ++ } else { ++ cancel_delayed_work_sync(&trigger_data->work); + +- atomic_set(&trigger_data->interval, msecs_to_jiffies(value)); ++ atomic_set(&trigger_data->interval, msecs_to_jiffies(value)); ++ } + set_baseline_state(trigger_data); /* resets timer */ + } + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index ebff3baf304515..f13d705f7861af 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -415,11 +415,12 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) + + mutex_lock(&con_mutex); + +- if (of_parse_phandle_with_args(dev->of_node, "mboxes", +- "#mbox-cells", index, &spec)) { ++ ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", ++ index, &spec); ++ if (ret) { + dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__); + mutex_unlock(&con_mutex); +- return ERR_PTR(-ENODEV); ++ return ERR_PTR(ret); + } + + chan = ERR_PTR(-EPROBE_DEFER); +diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c +index f8215a8f656a46..49254d99a8ad68 100644 +--- a/drivers/mailbox/pcc.c ++++ b/drivers/mailbox/pcc.c +@@ -419,8 +419,12 @@ int pcc_mbox_ioremap(struct mbox_chan *chan) + return -1; + pchan_info = chan->con_priv; + pcc_mbox_chan = &pchan_info->chan; +- pcc_mbox_chan->shmem = ioremap(pcc_mbox_chan->shmem_base_addr, +- pcc_mbox_chan->shmem_size); ++ ++ pcc_mbox_chan->shmem = acpi_os_ioremap(pcc_mbox_chan->shmem_base_addr, ++ pcc_mbox_chan->shmem_size); ++ if (!pcc_mbox_chan->shmem) ++ return -ENXIO; ++ + return 0; + } + EXPORT_SYMBOL_GPL(pcc_mbox_ioremap); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index c5851c9f7ec041..0d002d50329da9 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2903,6 +2903,27 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + return to_cblock(size); + } + ++static bool can_resume(struct cache *cache) ++{ ++ /* ++ * Disallow retrying the resume operation for devices that failed the ++ * first resume attempt, as the failure leaves the policy object partially ++ * initialized. Retrying could trigger BUG_ON when loading cache mappings ++ * into the incomplete policy object. ++ */ ++ if (cache->sized && !cache->loaded_mappings) { ++ if (get_cache_mode(cache) != CM_WRITE) ++ DMERR("%s: unable to resume a failed-loaded cache, please check metadata.", ++ cache_device_name(cache)); ++ else ++ DMERR("%s: unable to resume cache due to missing proper cache table reload", ++ cache_device_name(cache)); ++ return false; ++ } ++ ++ return true; ++} ++ + static bool can_resize(struct cache *cache, dm_cblock_t new_size) + { + if (from_cblock(new_size) > from_cblock(cache->cache_size)) { +@@ -2951,6 +2972,9 @@ static int cache_preresume(struct dm_target *ti) + struct cache *cache = ti->private; + dm_cblock_t csize = get_cache_dev_size(cache); + ++ if (!can_resume(cache)) ++ return -EINVAL; ++ + /* + * Check to see if the cache has resized. + */ +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 7a33da2dd64b12..bf2ade89c8c2dc 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -669,6 +669,10 @@ int dm_table_add_target(struct dm_table *t, const char *type, + DMERR("%s: zero-length target", dm_device_name(t->md)); + return -EINVAL; + } ++ if (start + len < start || start + len > LLONG_MAX >> SECTOR_SHIFT) { ++ DMERR("%s: too large device", dm_device_name(t->md)); ++ return -EINVAL; ++ } + + ti->type = dm_get_target_type(type); + if (!ti->type) { +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index 5dd0a42463a2b8..9ea868bd0d1293 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1536,14 +1536,18 @@ static void __send_empty_flush(struct clone_info *ci) + { + struct dm_table *t = ci->map; + struct bio flush_bio; ++ blk_opf_t opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC; ++ ++ if ((ci->io->orig_bio->bi_opf & (REQ_IDLE | REQ_SYNC)) == ++ (REQ_IDLE | REQ_SYNC)) ++ opf |= REQ_IDLE; + + /* + * Use an on-stack bio for this, it's safe since we don't + * need to reference it after submit. It's just used as + * the basis for the clone(s). + */ +- bio_init(&flush_bio, ci->io->md->disk->part0, NULL, 0, +- REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC); ++ bio_init(&flush_bio, ci->io->md->disk->part0, NULL, 0, opf); + + ci->bio = &flush_bio; + ci->sector_count = 0; +diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c +index 99ba925e8ec8e6..114ac0c263fb2b 100644 +--- a/drivers/media/i2c/adv7180.c ++++ b/drivers/media/i2c/adv7180.c +@@ -194,6 +194,7 @@ struct adv7180_state; + #define ADV7180_FLAG_V2 BIT(1) + #define ADV7180_FLAG_MIPI_CSI2 BIT(2) + #define ADV7180_FLAG_I2P BIT(3) ++#define ADV7180_FLAG_TEST_PATTERN BIT(4) + + struct adv7180_chip_info { + unsigned int flags; +@@ -673,11 +674,15 @@ static int adv7180_init_controls(struct adv7180_state *state) + ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); + v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); + +- v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops, +- V4L2_CID_TEST_PATTERN, +- ARRAY_SIZE(test_pattern_menu) - 1, +- 0, ARRAY_SIZE(test_pattern_menu) - 1, +- test_pattern_menu); ++ if (state->chip_info->flags & ADV7180_FLAG_TEST_PATTERN) { ++ v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, ++ &adv7180_ctrl_ops, ++ V4L2_CID_TEST_PATTERN, ++ ARRAY_SIZE(test_pattern_menu) - 1, ++ 0, ++ ARRAY_SIZE(test_pattern_menu) - 1, ++ test_pattern_menu); ++ } + + state->sd.ctrl_handler = &state->ctrl_hdl; + if (state->ctrl_hdl.error) { +@@ -1209,7 +1214,7 @@ static const struct adv7180_chip_info adv7182_info = { + }; + + static const struct adv7180_chip_info adv7280_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1223,7 +1228,8 @@ static const struct adv7180_chip_info adv7280_info = { + }; + + static const struct adv7180_chip_info adv7280_m_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1244,7 +1250,8 @@ static const struct adv7180_chip_info adv7280_m_info = { + }; + + static const struct adv7180_chip_info adv7281_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN7) | +@@ -1259,7 +1266,8 @@ static const struct adv7180_chip_info adv7281_info = { + }; + + static const struct adv7180_chip_info adv7281_m_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1279,7 +1287,8 @@ static const struct adv7180_chip_info adv7281_m_info = { + }; + + static const struct adv7180_chip_info adv7281_ma_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +@@ -1304,7 +1313,7 @@ static const struct adv7180_chip_info adv7281_ma_info = { + }; + + static const struct adv7180_chip_info adv7282_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN7) | +@@ -1319,7 +1328,8 @@ static const struct adv7180_chip_info adv7282_info = { + }; + + static const struct adv7180_chip_info adv7282_m_info = { +- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, ++ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P | ++ ADV7180_FLAG_TEST_PATTERN, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | +diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c +index a14e571dc62bc5..a3d5a8a7c660b0 100644 +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -77,7 +77,7 @@ + #define IMX219_VTS_30FPS_640x480 0x06e3 + #define IMX219_VTS_MAX 0xffff + +-#define IMX219_VBLANK_MIN 4 ++#define IMX219_VBLANK_MIN 32 + + /*Frame Length Line*/ + #define IMX219_FLL_MIN 0x08a6 +diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c +index 566f5eaddd572e..b12a6bd42102e9 100644 +--- a/drivers/media/i2c/tc358746.c ++++ b/drivers/media/i2c/tc358746.c +@@ -460,24 +460,20 @@ static int tc358746_apply_misc_config(struct tc358746 *tc358746) + return err; + } + +-/* Use MHz as base so the div needs no u64 */ +-static u32 tc358746_cfg_to_cnt(unsigned int cfg_val, +- unsigned int clk_mhz, +- unsigned int time_base) ++static u32 tc358746_cfg_to_cnt(unsigned long cfg_val, unsigned long clk_hz, ++ unsigned long long time_base) + { +- return DIV_ROUND_UP(cfg_val * clk_mhz, time_base); ++ return div64_u64((u64)cfg_val * clk_hz + time_base - 1, time_base); + } + +-static u32 tc358746_ps_to_cnt(unsigned int cfg_val, +- unsigned int clk_mhz) ++static u32 tc358746_ps_to_cnt(unsigned long cfg_val, unsigned long clk_hz) + { +- return tc358746_cfg_to_cnt(cfg_val, clk_mhz, USEC_PER_SEC); ++ return tc358746_cfg_to_cnt(cfg_val, clk_hz, PSEC_PER_SEC); + } + +-static u32 tc358746_us_to_cnt(unsigned int cfg_val, +- unsigned int clk_mhz) ++static u32 tc358746_us_to_cnt(unsigned long cfg_val, unsigned long clk_hz) + { +- return tc358746_cfg_to_cnt(cfg_val, clk_mhz, 1); ++ return tc358746_cfg_to_cnt(cfg_val, clk_hz, USEC_PER_SEC); + } + + static int tc358746_apply_dphy_config(struct tc358746 *tc358746) +@@ -492,7 +488,6 @@ static int tc358746_apply_dphy_config(struct tc358746 *tc358746) + + /* The hs_byte_clk is also called SYSCLK in the excel sheet */ + hs_byte_clk = cfg->hs_clk_rate / 8; +- hs_byte_clk /= HZ_PER_MHZ; + hf_clk = hs_byte_clk / 2; + + val = tc358746_us_to_cnt(cfg->init, hf_clk) - 1; +diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c +index 6360314f04a636..b90e2e690f3aa1 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid.c ++++ b/drivers/media/platform/qcom/camss/camss-csid.c +@@ -239,11 +239,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) + int ret; + + if (enable) { +- ret = v4l2_ctrl_handler_setup(&csid->ctrls); +- if (ret < 0) { +- dev_err(csid->camss->dev, +- "could not sync v4l2 controls: %d\n", ret); +- return ret; ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) { ++ ret = v4l2_ctrl_handler_setup(&csid->ctrls); ++ if (ret < 0) { ++ dev_err(csid->camss->dev, ++ "could not sync v4l2 controls: %d\n", ret); ++ return ret; ++ } + } + + if (!csid->testgen.enabled && +@@ -318,7 +320,8 @@ static void csid_try_format(struct csid_device *csid, + break; + + case MSM_CSID_PAD_SRC: +- if (csid->testgen_mode->cur.val == 0) { ++ if (csid->testgen.nmodes == CSID_PAYLOAD_MODE_DISABLED || ++ csid->testgen_mode->cur.val == 0) { + /* Test generator is disabled, */ + /* keep pad formats in sync */ + u32 code = fmt->code; +@@ -368,7 +371,8 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, + + code->code = csid->formats[code->index].code; + } else { +- if (csid->testgen_mode->cur.val == 0) { ++ if (csid->testgen.nmodes == CSID_PAYLOAD_MODE_DISABLED || ++ csid->testgen_mode->cur.val == 0) { + struct v4l2_mbus_framefmt *sink_fmt; + + sink_fmt = __csid_get_format(csid, sd_state, +@@ -750,7 +754,8 @@ static int csid_link_setup(struct media_entity *entity, + + /* If test generator is enabled */ + /* do not allow a link from CSIPHY to CSID */ +- if (csid->testgen_mode->cur.val != 0) ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED && ++ csid->testgen_mode->cur.val != 0) + return -EBUSY; + + sd = media_entity_to_v4l2_subdev(remote->entity); +@@ -843,24 +848,27 @@ int msm_csid_register_entity(struct csid_device *csid, + MSM_CSID_NAME, csid->id); + v4l2_set_subdevdata(sd, csid); + +- ret = v4l2_ctrl_handler_init(&csid->ctrls, 1); +- if (ret < 0) { +- dev_err(dev, "Failed to init ctrl handler: %d\n", ret); +- return ret; +- } ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) { ++ ret = v4l2_ctrl_handler_init(&csid->ctrls, 1); ++ if (ret < 0) { ++ dev_err(dev, "Failed to init ctrl handler: %d\n", ret); ++ return ret; ++ } + +- csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls, +- &csid_ctrl_ops, V4L2_CID_TEST_PATTERN, +- csid->testgen.nmodes, 0, 0, +- csid->testgen.modes); ++ csid->testgen_mode = ++ v4l2_ctrl_new_std_menu_items(&csid->ctrls, ++ &csid_ctrl_ops, V4L2_CID_TEST_PATTERN, ++ csid->testgen.nmodes, 0, 0, ++ csid->testgen.modes); + +- if (csid->ctrls.error) { +- dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error); +- ret = csid->ctrls.error; +- goto free_ctrl; +- } ++ if (csid->ctrls.error) { ++ dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error); ++ ret = csid->ctrls.error; ++ goto free_ctrl; ++ } + +- csid->subdev.ctrl_handler = &csid->ctrls; ++ csid->subdev.ctrl_handler = &csid->ctrls; ++ } + + ret = csid_init_formats(sd, NULL); + if (ret < 0) { +@@ -891,7 +899,8 @@ int msm_csid_register_entity(struct csid_device *csid, + media_cleanup: + media_entity_cleanup(&sd->entity); + free_ctrl: +- v4l2_ctrl_handler_free(&csid->ctrls); ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) ++ v4l2_ctrl_handler_free(&csid->ctrls); + + return ret; + } +@@ -904,5 +913,6 @@ void msm_csid_unregister_entity(struct csid_device *csid) + { + v4l2_device_unregister_subdev(&csid->subdev); + media_entity_cleanup(&csid->subdev.entity); +- v4l2_ctrl_handler_free(&csid->ctrls); ++ if (csid->testgen.nmodes != CSID_PAYLOAD_MODE_DISABLED) ++ v4l2_ctrl_handler_free(&csid->ctrls); + } +diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +index 5dc1f908b49bd6..9aa484126a0dd6 100644 +--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c ++++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +@@ -806,13 +806,12 @@ static int c8sectpfe_probe(struct platform_device *pdev) + } + tsin->i2c_adapter = + of_find_i2c_adapter_by_node(i2c_bus); ++ of_node_put(i2c_bus); + if (!tsin->i2c_adapter) { + dev_err(&pdev->dev, "No i2c adapter found\n"); +- of_node_put(i2c_bus); + ret = -ENODEV; + goto err_node_put; + } +- of_node_put(i2c_bus); + + /* Acquire reset GPIO and activate it */ + tsin->rst_gpio = devm_fwnode_gpiod_get(dev, +diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c +index 42048727d7ff35..b8cdffc9a1e9e9 100644 +--- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c +@@ -765,9 +765,14 @@ static int vivid_thread_vid_cap(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "Video Capture Thread End\n"); + return 0; +diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-out.c b/drivers/media/test-drivers/vivid/vivid-kthread-out.c +index fac6208b51da84..015a7b166a1e61 100644 +--- a/drivers/media/test-drivers/vivid/vivid-kthread-out.c ++++ b/drivers/media/test-drivers/vivid/vivid-kthread-out.c +@@ -235,9 +235,14 @@ static int vivid_thread_vid_out(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "Video Output Thread End\n"); + return 0; +diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c +index fa711ee36a3fbc..c862689786b69c 100644 +--- a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c ++++ b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c +@@ -135,9 +135,14 @@ static int vivid_thread_touch_cap(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "Touch Capture Thread End\n"); + return 0; +diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +index a81f26b769883f..1dd59c710dae74 100644 +--- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +@@ -206,9 +206,14 @@ static int vivid_thread_sdr_cap(void *data) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; +- while (time_is_after_jiffies(cur_jiffies + wait_jiffies) && +- !kthread_should_stop()) +- schedule(); ++ if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) ++ continue; ++ ++ wait_queue_head_t wait; ++ ++ init_waitqueue_head(&wait); ++ wait_event_interruptible_timeout(wait, kthread_should_stop(), ++ cur_jiffies + wait_jiffies - jiffies); + } + dprintk(dev, 1, "SDR Capture Thread End\n"); + return 0; +diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c +index c5e21785fafe28..02343e88cc618c 100644 +--- a/drivers/media/usb/cx231xx/cx231xx-417.c ++++ b/drivers/media/usb/cx231xx/cx231xx-417.c +@@ -1722,6 +1722,8 @@ static void cx231xx_video_dev_init( + vfd->lock = &dev->lock; + vfd->release = video_device_release_empty; + vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl; ++ vfd->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_CAPTURE; + video_set_drvdata(vfd, dev); + if (dev->tuner_type == TUNER_ABSENT) { + v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); +diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c +index 028c4a5049af97..5926a9dfb0b1f8 100644 +--- a/drivers/media/usb/uvc/uvc_ctrl.c ++++ b/drivers/media/usb/uvc/uvc_ctrl.c +@@ -815,6 +815,25 @@ static inline void uvc_clear_bit(u8 *data, int bit) + data[bit >> 3] &= ~(1 << (bit & 7)); + } + ++static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val) ++{ ++ unsigned int i; ++ ++ for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { ++ u32 menu_value; ++ ++ if (!test_bit(i, &mapping->menu_mask)) ++ continue; ++ ++ menu_value = uvc_mapping_get_menu_value(mapping, i); ++ ++ if (menu_value == val) ++ return i; ++ } ++ ++ return val; ++} ++ + /* + * Extract the bit string specified by mapping->offset and mapping->size + * from the little-endian data stored at 'data' and return the result as +@@ -849,6 +868,16 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, + if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) + value |= -(value & (1 << (mapping->size - 1))); + ++ /* If it is a menu, convert from uvc to v4l2. */ ++ if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) ++ return value; ++ ++ switch (query) { ++ case UVC_GET_CUR: ++ case UVC_GET_DEF: ++ return uvc_menu_to_v4l2_menu(mapping, value); ++ } ++ + return value; + } + +@@ -1013,32 +1042,6 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, + return 0; + } + +-static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, +- const u8 *data) +-{ +- s32 value = mapping->get(mapping, UVC_GET_CUR, data); +- +- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { +- unsigned int i; +- +- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { +- u32 menu_value; +- +- if (!test_bit(i, &mapping->menu_mask)) +- continue; +- +- menu_value = uvc_mapping_get_menu_value(mapping, i); +- +- if (menu_value == value) { +- value = i; +- break; +- } +- } +- } +- +- return value; +-} +- + static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain, + struct uvc_control *ctrl) + { +@@ -1089,8 +1092,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, + if (ret < 0) + return ret; + +- *value = __uvc_ctrl_get_value(mapping, +- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); ++ *value = mapping->get(mapping, UVC_GET_CUR, ++ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + + return 0; + } +@@ -1240,7 +1243,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, + { + struct uvc_control_mapping *master_map = NULL; + struct uvc_control *master_ctrl = NULL; +- unsigned int i; + + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); + v4l2_ctrl->id = mapping->id; +@@ -1283,21 +1285,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, + v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1; + v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1; + v4l2_ctrl->step = 1; +- +- for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { +- u32 menu_value; +- +- if (!test_bit(i, &mapping->menu_mask)) +- continue; +- +- menu_value = uvc_mapping_get_menu_value(mapping, i); +- +- if (menu_value == v4l2_ctrl->default_value) { +- v4l2_ctrl->default_value = i; +- break; +- } +- } +- + return 0; + + case V4L2_CTRL_TYPE_BOOLEAN: +@@ -1580,7 +1567,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain, + uvc_ctrl_set_handle(handle, ctrl, NULL); + + list_for_each_entry(mapping, &ctrl->info.mappings, list) { +- s32 value = __uvc_ctrl_get_value(mapping, data); ++ s32 value = mapping->get(mapping, UVC_GET_CUR, data); + + /* + * handle may be NULL here if the device sends auto-update +diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c +index 7bcd706281daf3..cb7d9fb589fca9 100644 +--- a/drivers/media/usb/uvc/uvc_v4l2.c ++++ b/drivers/media/usb/uvc/uvc_v4l2.c +@@ -106,6 +106,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain, + struct uvc_control_mapping *map; + int ret; + ++ if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) { ++ uvc_dbg(chain->dev, CONTROL, ++ "Unsupported UVC data type %u\n", xmap->data_type); ++ return -EINVAL; ++ } ++ + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (map == NULL) + return -ENOMEM; +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index 5f115438d07228..cb3ad72a3e54a6 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -351,6 +351,8 @@ static int call_enum_dv_timings(struct v4l2_subdev *sd, + static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_config *config) + { ++ memset(config, 0, sizeof(*config)); ++ + return check_pad(sd, pad) ? : + sd->ops->pad->get_mbus_config(sd, pad, config); + } +diff --git a/drivers/mfd/tps65219.c b/drivers/mfd/tps65219.c +index 0e0c42e4fdfc75..72a5f51fe32a52 100644 +--- a/drivers/mfd/tps65219.c ++++ b/drivers/mfd/tps65219.c +@@ -228,7 +228,6 @@ static struct regmap_irq_chip tps65219_irq_chip = { + static int tps65219_probe(struct i2c_client *client) + { + struct tps65219 *tps; +- unsigned int chipid; + bool pwr_button; + int ret; + +@@ -253,12 +252,6 @@ static int tps65219_probe(struct i2c_client *client) + if (ret) + return ret; + +- ret = regmap_read(tps->regmap, TPS65219_REG_TI_DEV_ID, &chipid); +- if (ret) { +- dev_err(tps->dev, "Failed to read device ID: %d\n", ret); +- return ret; +- } +- + ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, + tps65219_cells, ARRAY_SIZE(tps65219_cells), + NULL, 0, regmap_irq_get_domain(tps->irq_data)); +diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c +index 698408e8bad035..381a61adf06eee 100644 +--- a/drivers/mmc/host/dw_mmc-exynos.c ++++ b/drivers/mmc/host/dw_mmc-exynos.c +@@ -28,6 +28,8 @@ enum dw_mci_exynos_type { + DW_MCI_TYPE_EXYNOS5420_SMU, + DW_MCI_TYPE_EXYNOS7, + DW_MCI_TYPE_EXYNOS7_SMU, ++ DW_MCI_TYPE_EXYNOS7870, ++ DW_MCI_TYPE_EXYNOS7870_SMU, + DW_MCI_TYPE_ARTPEC8, + }; + +@@ -70,6 +72,12 @@ static struct dw_mci_exynos_compatible { + }, { + .compatible = "samsung,exynos7-dw-mshc-smu", + .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, ++ }, { ++ .compatible = "samsung,exynos7870-dw-mshc", ++ .ctrl_type = DW_MCI_TYPE_EXYNOS7870, ++ }, { ++ .compatible = "samsung,exynos7870-dw-mshc-smu", ++ .ctrl_type = DW_MCI_TYPE_EXYNOS7870_SMU, + }, { + .compatible = "axis,artpec8-dw-mshc", + .ctrl_type = DW_MCI_TYPE_ARTPEC8, +@@ -86,6 +94,8 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) + return EXYNOS4210_FIXED_CIU_CLK_DIV; + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; + else +@@ -101,7 +111,8 @@ static void dw_mci_exynos_config_smu(struct dw_mci *host) + * set for non-ecryption mode at this time. + */ + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || +- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) { + mci_writel(host, MPSBEGIN0, 0); + mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX); + mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT | +@@ -127,6 +138,12 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); + } + ++ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) { ++ /* Quirk needed for certain Exynos SoCs */ ++ host->quirks |= DW_MMC_QUIRK_FIFO64_32; ++ } ++ + if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) { + /* Quirk needed for the ARTPEC-8 SoC */ + host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT; +@@ -144,6 +161,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -153,6 +172,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -223,6 +244,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -231,6 +254,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) + if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -410,6 +435,8 @@ static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); + else +@@ -423,6 +450,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -430,6 +459,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -444,6 +475,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + clksel = mci_readl(host, CLKSEL64); + else +@@ -454,6 +487,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || ++ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) + mci_writel(host, CLKSEL64, clksel); + else +@@ -633,6 +668,10 @@ static const struct of_device_id dw_mci_exynos_match[] = { + .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc-smu", + .data = &exynos_drv_data, }, ++ { .compatible = "samsung,exynos7870-dw-mshc", ++ .data = &exynos_drv_data, }, ++ { .compatible = "samsung,exynos7870-dw-mshc-smu", ++ .data = &exynos_drv_data, }, + { .compatible = "axis,artpec8-dw-mshc", + .data = &artpec_drv_data, }, + {}, +diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c +index 6b351810a301c9..dbfe0a5324eaf0 100644 +--- a/drivers/mmc/host/sdhci-pci-core.c ++++ b/drivers/mmc/host/sdhci-pci-core.c +@@ -608,8 +608,12 @@ static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, + + sdhci_set_power(host, mode, vdd); + +- if (mode == MMC_POWER_OFF) ++ if (mode == MMC_POWER_OFF) { ++ if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD || ++ slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BYT_SD) ++ usleep_range(15000, 17500); + return; ++ } + + /* + * Bus power might not enable after D3 -> D0 transition due to the +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index 9796a3cb3ca62c..f32429ff905ff6 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -2035,10 +2035,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) + + host->mmc->actual_clock = 0; + +- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); ++ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); ++ if (clk & SDHCI_CLOCK_CARD_EN) ++ sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, ++ SDHCI_CLOCK_CONTROL); + +- if (clock == 0) ++ if (clock == 0) { ++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + return; ++ } + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + sdhci_enable_clk(host, clk); +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 7eb62fe55947fe..56c241246d1af4 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -2469,7 +2469,7 @@ static int __bond_release_one(struct net_device *bond_dev, + + RCU_INIT_POINTER(bond->current_arp_slave, NULL); + +- if (!all && (!bond->params.fail_over_mac || ++ if (!all && (bond->params.fail_over_mac != BOND_FOM_ACTIVE || + BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) { + if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) && + bond_has_slaves(bond)) +diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c +index 7f405bcf11c23e..603680792f1ff6 100644 +--- a/drivers/net/can/c_can/c_can_platform.c ++++ b/drivers/net/can/c_can/c_can_platform.c +@@ -333,7 +333,7 @@ static int c_can_plat_probe(struct platform_device *pdev) + /* Check if we need custom RAMINIT via syscon. Mostly for TI + * platforms. Only supported with DT boot. + */ +- if (np && of_property_read_bool(np, "syscon-raminit")) { ++ if (np && of_property_present(np, "syscon-raminit")) { + u32 id; + struct c_can_raminit *raminit = &priv->raminit_sys; + +diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c +index c490b4ba065ba4..73b448cd00f29f 100644 +--- a/drivers/net/can/kvaser_pciefd.c ++++ b/drivers/net/can/kvaser_pciefd.c +@@ -1137,7 +1137,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, + skb = alloc_canfd_skb(priv->dev, &cf); + if (!skb) { + priv->dev->stats.rx_dropped++; +- return -ENOMEM; ++ return 0; + } + + cf->len = can_fd_dlc2len(dlc); +@@ -1149,7 +1149,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, + skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf); + if (!skb) { + priv->dev->stats.rx_dropped++; +- return -ENOMEM; ++ return 0; + } + can_frame_set_cc_len((struct can_frame *)cf, dlc, priv->ctrlmode); + } +@@ -1167,7 +1167,9 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, + priv->dev->stats.rx_packets++; + kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp); + +- return netif_rx(skb); ++ netif_rx(skb); ++ ++ return 0; + } + + static void kvaser_pciefd_change_state(struct kvaser_pciefd_can *can, +@@ -1580,24 +1582,28 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf) + return res; + } + +-static u32 kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) ++static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) + { ++ void __iomem *srb_cmd_reg = KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG; + u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG); + +- if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) ++ iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG); ++ ++ if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) { + kvaser_pciefd_read_buffer(pcie, 0); ++ iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, srb_cmd_reg); /* Rearm buffer */ ++ } + +- if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) ++ if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) { + kvaser_pciefd_read_buffer(pcie, 1); ++ iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1, srb_cmd_reg); /* Rearm buffer */ ++ } + + if (irq & KVASER_PCIEFD_SRB_IRQ_DOF0 || + irq & KVASER_PCIEFD_SRB_IRQ_DOF1 || + irq & KVASER_PCIEFD_SRB_IRQ_DUF0 || + irq & KVASER_PCIEFD_SRB_IRQ_DUF1) + dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq); +- +- iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG); +- return irq; + } + + static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) +@@ -1625,29 +1631,22 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) + struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev; + const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask; + u32 pci_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie)); +- u32 srb_irq = 0; +- u32 srb_release = 0; + int i; + + if (!(pci_irq & irq_mask->all)) + return IRQ_NONE; + ++ iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); ++ + if (pci_irq & irq_mask->kcan_rx0) +- srb_irq = kvaser_pciefd_receive_irq(pcie); ++ kvaser_pciefd_receive_irq(pcie); + + for (i = 0; i < pcie->nr_channels; i++) { + if (pci_irq & irq_mask->kcan_tx[i]) + kvaser_pciefd_transmit_irq(pcie->can[i]); + } + +- if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD0) +- srb_release |= KVASER_PCIEFD_SRB_CMD_RDB0; +- +- if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD1) +- srb_release |= KVASER_PCIEFD_SRB_CMD_RDB1; +- +- if (srb_release) +- iowrite32(srb_release, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG); ++ iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); + + return IRQ_HANDLED; + } +@@ -1667,13 +1666,22 @@ static void kvaser_pciefd_teardown_can_ctrls(struct kvaser_pciefd *pcie) + } + } + ++static void kvaser_pciefd_disable_irq_srcs(struct kvaser_pciefd *pcie) ++{ ++ unsigned int i; ++ ++ /* Masking PCI_IRQ is insufficient as running ISR will unmask it */ ++ iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG); ++ for (i = 0; i < pcie->nr_channels; ++i) ++ iowrite32(0, pcie->can[i]->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); ++} ++ + static int kvaser_pciefd_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { + int err; + struct kvaser_pciefd *pcie; + const struct kvaser_pciefd_irq_mask *irq_mask; +- void __iomem *irq_en_base; + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) +@@ -1726,8 +1734,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, + KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG); + + /* Enable PCI interrupts */ +- irq_en_base = KVASER_PCIEFD_PCI_IEN_ADDR(pcie); +- iowrite32(irq_mask->all, irq_en_base); ++ iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); + /* Ready the DMA buffers */ + iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, + KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG); +@@ -1741,8 +1748,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, + return 0; + + err_free_irq: +- /* Disable PCI interrupts */ +- iowrite32(0, irq_en_base); ++ kvaser_pciefd_disable_irq_srcs(pcie); + free_irq(pcie->pci->irq, pcie); + + err_teardown_can_ctrls: +@@ -1762,35 +1768,25 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, + return err; + } + +-static void kvaser_pciefd_remove_all_ctrls(struct kvaser_pciefd *pcie) +-{ +- int i; +- +- for (i = 0; i < pcie->nr_channels; i++) { +- struct kvaser_pciefd_can *can = pcie->can[i]; +- +- if (can) { +- iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); +- unregister_candev(can->can.dev); +- del_timer(&can->bec_poll_timer); +- kvaser_pciefd_pwm_stop(can); +- free_candev(can->can.dev); +- } +- } +-} +- + static void kvaser_pciefd_remove(struct pci_dev *pdev) + { + struct kvaser_pciefd *pcie = pci_get_drvdata(pdev); ++ unsigned int i; + +- kvaser_pciefd_remove_all_ctrls(pcie); ++ for (i = 0; i < pcie->nr_channels; ++i) { ++ struct kvaser_pciefd_can *can = pcie->can[i]; + +- /* Disable interrupts */ +- iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG); +- iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie)); ++ unregister_candev(can->can.dev); ++ del_timer(&can->bec_poll_timer); ++ kvaser_pciefd_pwm_stop(can); ++ } + ++ kvaser_pciefd_disable_irq_srcs(pcie); + free_irq(pcie->pci->irq, pcie); + ++ for (i = 0; i < pcie->nr_channels; ++i) ++ free_candev(pcie->can[i]->can.dev); ++ + pci_iounmap(pdev, pcie->reg_base); + pci_release_regions(pdev); + pci_disable_device(pdev); +diff --git a/drivers/net/can/slcan/slcan-core.c b/drivers/net/can/slcan/slcan-core.c +index 24c6622d36bd85..58ff2ec1d9757e 100644 +--- a/drivers/net/can/slcan/slcan-core.c ++++ b/drivers/net/can/slcan/slcan-core.c +@@ -71,12 +71,21 @@ MODULE_AUTHOR("Dario Binacchi "); + #define SLCAN_CMD_LEN 1 + #define SLCAN_SFF_ID_LEN 3 + #define SLCAN_EFF_ID_LEN 8 ++#define SLCAN_DATA_LENGTH_LEN 1 ++#define SLCAN_ERROR_LEN 1 + #define SLCAN_STATE_LEN 1 + #define SLCAN_STATE_BE_RXCNT_LEN 3 + #define SLCAN_STATE_BE_TXCNT_LEN 3 +-#define SLCAN_STATE_FRAME_LEN (1 + SLCAN_CMD_LEN + \ +- SLCAN_STATE_BE_RXCNT_LEN + \ +- SLCAN_STATE_BE_TXCNT_LEN) ++#define SLCAN_STATE_MSG_LEN (SLCAN_CMD_LEN + \ ++ SLCAN_STATE_LEN + \ ++ SLCAN_STATE_BE_RXCNT_LEN + \ ++ SLCAN_STATE_BE_TXCNT_LEN) ++#define SLCAN_ERROR_MSG_LEN_MIN (SLCAN_CMD_LEN + \ ++ SLCAN_ERROR_LEN + \ ++ SLCAN_DATA_LENGTH_LEN) ++#define SLCAN_FRAME_MSG_LEN_MIN (SLCAN_CMD_LEN + \ ++ SLCAN_SFF_ID_LEN + \ ++ SLCAN_DATA_LENGTH_LEN) + struct slcan { + struct can_priv can; + +@@ -176,6 +185,9 @@ static void slcan_bump_frame(struct slcan *sl) + u32 tmpid; + char *cmd = sl->rbuff; + ++ if (sl->rcount < SLCAN_FRAME_MSG_LEN_MIN) ++ return; ++ + skb = alloc_can_skb(sl->dev, &cf); + if (unlikely(!skb)) { + sl->dev->stats.rx_dropped++; +@@ -281,7 +293,7 @@ static void slcan_bump_state(struct slcan *sl) + return; + } + +- if (state == sl->can.state || sl->rcount < SLCAN_STATE_FRAME_LEN) ++ if (state == sl->can.state || sl->rcount != SLCAN_STATE_MSG_LEN) + return; + + cmd += SLCAN_STATE_BE_RXCNT_LEN + SLCAN_CMD_LEN + 1; +@@ -328,6 +340,9 @@ static void slcan_bump_err(struct slcan *sl) + bool rx_errors = false, tx_errors = false, rx_over_errors = false; + int i, len; + ++ if (sl->rcount < SLCAN_ERROR_MSG_LEN_MIN) ++ return; ++ + /* get len from sanitized ASCII value */ + len = cmd[1]; + if (len >= '0' && len < '9') +@@ -456,8 +471,7 @@ static void slcan_bump(struct slcan *sl) + static void slcan_unesc(struct slcan *sl, unsigned char s) + { + if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */ +- if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && +- sl->rcount > 4) ++ if (!test_and_clear_bit(SLF_ERROR, &sl->flags)) + slcan_bump(sl); + + sl->rcount = 0; +diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c +index b3fa867c8ccd91..c2ef55cff6b3ec 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.c ++++ b/drivers/net/ethernet/amd/pds_core/core.c +@@ -413,10 +413,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init) + if (err) + return err; + +- /* Scale the descriptor ring length based on number of CPUs and VFs */ +- numdescs = max_t(int, PDSC_ADMINQ_MIN_LENGTH, num_online_cpus()); +- numdescs += 2 * pci_sriov_get_totalvfs(pdsc->pdev); +- numdescs = roundup_pow_of_two(numdescs); ++ numdescs = PDSC_ADMINQ_MAX_LENGTH; + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_ADMINQ, 0, "adminq", + PDS_CORE_QCQ_F_CORE | PDS_CORE_QCQ_F_INTR, + numdescs, +diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h +index 61ee607ee48ace..42137140850314 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.h ++++ b/drivers/net/ethernet/amd/pds_core/core.h +@@ -16,7 +16,7 @@ + + #define PDSC_WATCHDOG_SECS 5 + #define PDSC_QUEUE_NAME_MAX_SZ 16 +-#define PDSC_ADMINQ_MIN_LENGTH 16 /* must be a power of two */ ++#define PDSC_ADMINQ_MAX_LENGTH 16 /* must be a power of two */ + #define PDSC_NOTIFYQ_LENGTH 64 /* must be a power of two */ + #define PDSC_TEARDOWN_RECOVERY false + #define PDSC_TEARDOWN_REMOVING true +diff --git a/drivers/net/ethernet/apm/xgene-v2/main.c b/drivers/net/ethernet/apm/xgene-v2/main.c +index 379d19d18dbed0..5808e3c73a8f43 100644 +--- a/drivers/net/ethernet/apm/xgene-v2/main.c ++++ b/drivers/net/ethernet/apm/xgene-v2/main.c +@@ -9,8 +9,6 @@ + + #include "main.h" + +-static const struct acpi_device_id xge_acpi_match[]; +- + static int xge_get_resources(struct xge_pdata *pdata) + { + struct platform_device *pdev; +@@ -733,7 +731,7 @@ MODULE_DEVICE_TABLE(acpi, xge_acpi_match); + static struct platform_driver xge_driver = { + .driver = { + .name = "xgene-enet-v2", +- .acpi_match_table = ACPI_PTR(xge_acpi_match), ++ .acpi_match_table = xge_acpi_match, + }, + .probe = xge_probe, + .remove = xge_remove, +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c +index 8feb7d4226bb58..0c09d82dbf00d4 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc.c +@@ -1572,6 +1572,16 @@ static void enetc_xdp_drop(struct enetc_bdr *rx_ring, int rx_ring_first, + } + } + ++static void enetc_bulk_flip_buff(struct enetc_bdr *rx_ring, int rx_ring_first, ++ int rx_ring_last) ++{ ++ while (rx_ring_first != rx_ring_last) { ++ enetc_flip_rx_buff(rx_ring, ++ &rx_ring->rx_swbd[rx_ring_first]); ++ enetc_bdr_idx_inc(rx_ring, &rx_ring_first); ++ } ++} ++ + static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring, + struct napi_struct *napi, int work_limit, + struct bpf_prog *prog) +@@ -1687,11 +1697,7 @@ static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring, + enetc_xdp_drop(rx_ring, orig_i, i); + rx_ring->stats.xdp_redirect_failures++; + } else { +- while (orig_i != i) { +- enetc_flip_rx_buff(rx_ring, +- &rx_ring->rx_swbd[orig_i]); +- enetc_bdr_idx_inc(rx_ring, &orig_i); +- } ++ enetc_bulk_flip_buff(rx_ring, orig_i, i); + xdp_redirect_frm_cnt++; + rx_ring->stats.xdp_redirect++; + } +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index 7261838a09db63..291c88a76a27f4 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -1079,6 +1079,29 @@ static void fec_enet_enable_ring(struct net_device *ndev) + } + } + ++/* 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. ++ */ ++static void fec_ctrl_reset(struct fec_enet_private *fep, bool allow_wol) ++{ ++ u32 val; ++ ++ if (!allow_wol || !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { ++ 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(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL); ++ udelay(10); ++ } ++ } else { ++ val = readl(fep->hwp + FEC_ECNTRL); ++ val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); ++ writel(val, fep->hwp + FEC_ECNTRL); ++ } ++} ++ + /* + * This function is called to start or restart the FEC during a link + * change, transmit timeout, or to reconfigure the FEC. The network +@@ -1095,17 +1118,7 @@ fec_restart(struct net_device *ndev) + if (fep->bufdesc_ex) + fec_ptp_save_state(fep); + +- /* 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->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); +- } ++ fec_ctrl_reset(fep, false); + + /* + * enet-mac reset will reset mac address registers too, +@@ -1359,22 +1372,7 @@ fec_stop(struct net_device *ndev) + if (fep->bufdesc_ex) + fec_ptp_save_state(fep); + +- /* 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(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL); +- udelay(10); +- } +- } else { +- val = readl(fep->hwp + FEC_ECNTRL); +- val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); +- writel(val, fep->hwp + FEC_ECNTRL); +- } ++ fec_ctrl_reset(fep, true); + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + +diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c +index 39b5f24be7e4fc..dd58b2372dc0c7 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c ++++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c +@@ -3329,8 +3329,7 @@ static u32 ice_get_combined_cnt(struct ice_vsi *vsi) + ice_for_each_q_vector(vsi, q_idx) { + struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; + +- if (q_vector->rx.rx_ring && q_vector->tx.tx_ring) +- combined++; ++ combined += min(q_vector->num_ring_tx, q_vector->num_ring_rx); + } + + return combined; +diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c +index ad82ff7d199570..09f9c7ba52795b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_irq.c ++++ b/drivers/net/ethernet/intel/ice/ice_irq.c +@@ -45,7 +45,7 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index) + /** + * ice_get_irq_res - get an interrupt resource + * @pf: board private structure +- * @dyn_only: force entry to be dynamically allocated ++ * @dyn_allowed: allow entry to be dynamically allocated + * + * Allocate new irq entry in the free slot of the tracker. Since xarray + * is used, always allocate new entry at the lowest possible index. Set +@@ -53,11 +53,12 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index) + * + * Returns allocated irq entry or NULL on failure. + */ +-static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only) ++static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, ++ bool dyn_allowed) + { +- struct xa_limit limit = { .max = pf->irq_tracker.num_entries, ++ struct xa_limit limit = { .max = pf->irq_tracker.num_entries - 1, + .min = 0 }; +- unsigned int num_static = pf->irq_tracker.num_static; ++ unsigned int num_static = pf->irq_tracker.num_static - 1; + struct ice_irq_entry *entry; + unsigned int index; + int ret; +@@ -66,9 +67,9 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only) + if (!entry) + return NULL; + +- /* skip preallocated entries if the caller says so */ +- if (dyn_only) +- limit.min = num_static; ++ /* only already allocated if the caller says so */ ++ if (!dyn_allowed) ++ limit.max = num_static; + + ret = xa_alloc(&pf->irq_tracker.entries, &index, entry, limit, + GFP_KERNEL); +@@ -78,7 +79,7 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only) + entry = NULL; + } else { + entry->index = index; +- entry->dynamic = index >= num_static; ++ entry->dynamic = index > num_static; + } + + return entry; +@@ -272,7 +273,7 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) + /** + * ice_alloc_irq - Allocate new interrupt vector + * @pf: board private structure +- * @dyn_only: force dynamic allocation of the interrupt ++ * @dyn_allowed: allow dynamic allocation of the interrupt + * + * Allocate new interrupt vector for a given owner id. + * return struct msi_map with interrupt details and track +@@ -285,20 +286,20 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) + * interrupt will be allocated with pci_msix_alloc_irq_at. + * + * Some callers may only support dynamically allocated interrupts. +- * This is indicated with dyn_only flag. ++ * This is indicated with dyn_allowed flag. + * + * On failure, return map with negative .index. The caller + * is expected to check returned map index. + * + */ +-struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_only) ++struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_allowed) + { + int sriov_base_vector = pf->sriov_base_vector; + struct msi_map map = { .index = -ENOENT }; + struct device *dev = ice_pf_to_dev(pf); + struct ice_irq_entry *entry; + +- entry = ice_get_irq_res(pf, dyn_only); ++ entry = ice_get_irq_res(pf, dyn_allowed); + if (!entry) + return map; + +diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c +index 4e675c7c199fa1..4db0b770420e65 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lag.c ++++ b/drivers/net/ethernet/intel/ice/ice_lag.c +@@ -1229,12 +1229,18 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) + */ + if (!primary_lag) { + lag->primary = true; ++ if (!ice_is_switchdev_running(lag->pf)) ++ return; ++ + /* Configure primary's SWID to be shared */ + ice_lag_primary_swid(lag, true); + primary_lag = lag; + } else { + u16 swid; + ++ if (!ice_is_switchdev_running(primary_lag->pf)) ++ return; ++ + swid = primary_lag->pf->hw.port_info->sw_id; + ice_lag_set_swid(swid, lag, true); + ice_lag_add_prune_list(primary_lag, lag->pf); +diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c +index 1fc4805353eb58..a6a290514e5484 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_lib.c +@@ -587,6 +587,8 @@ ice_vsi_alloc_def(struct ice_vsi *vsi, struct ice_channel *ch) + return -ENOMEM; + } + ++ vsi->irq_dyn_alloc = pci_msix_can_alloc_dyn(vsi->back->pdev); ++ + switch (vsi->type) { + case ICE_VSI_SWITCHDEV_CTRL: + /* Setup eswitch MSIX irq handler for VSI */ +diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c +index e709b10a29761b..1edcf930318315 100644 +--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c ++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c +@@ -3769,7 +3769,6 @@ static int ice_vc_repr_add_mac(struct ice_vf *vf, u8 *msg) + } + + ice_vfhw_mac_add(vf, &al->list[i]); +- vf->num_mac++; + break; + } + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +index 339be6950c0395..6302990e9a5ff8 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +@@ -66,8 +66,18 @@ static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool en); + /* Supported devices */ + static const struct pci_device_id cgx_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, +- { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM) }, +- { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN10K_A) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF10K_A) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF10K_B) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN10K_B) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CN20KA) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_RPM, ++ PCI_ANY_ID, PCI_SUBSYS_DEVID_CNF20KA) }, + { 0, } /* end of table */ + }; + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index a607c7294b0c59..9fbc071ef29b0c 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -30,6 +30,8 @@ + #define PCI_SUBSYS_DEVID_CNF10K_A 0xBA00 + #define PCI_SUBSYS_DEVID_CNF10K_B 0xBC00 + #define PCI_SUBSYS_DEVID_CN10K_B 0xBD00 ++#define PCI_SUBSYS_DEVID_CN20KA 0xC220 ++#define PCI_SUBSYS_DEVID_CNF20KA 0xC320 + + /* PCI BAR nos */ + #define PCI_AF_REG_BAR_NUM 0 +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +index 0e74c5a2231e63..1e4cd4f7d0cfd4 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +@@ -13,19 +13,26 @@ + /* RVU LMTST */ + #define LMT_TBL_OP_READ 0 + #define LMT_TBL_OP_WRITE 1 +-#define LMT_MAP_TABLE_SIZE (128 * 1024) + #define LMT_MAPTBL_ENTRY_SIZE 16 ++#define LMT_MAX_VFS 256 ++ ++#define LMT_MAP_ENTRY_ENA BIT_ULL(20) ++#define LMT_MAP_ENTRY_LINES GENMASK_ULL(18, 16) + + /* Function to perform operations (read/write) on lmtst map table */ + static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val, + int lmt_tbl_op) + { + void __iomem *lmt_map_base; +- u64 tbl_base; ++ u64 tbl_base, cfg; ++ int pfs, vfs; + + tbl_base = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_MAP_BASE); ++ cfg = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CFG); ++ vfs = 1 << (cfg & 0xF); ++ pfs = 1 << ((cfg >> 4) & 0x7); + +- lmt_map_base = ioremap_wc(tbl_base, LMT_MAP_TABLE_SIZE); ++ lmt_map_base = ioremap_wc(tbl_base, pfs * vfs * LMT_MAPTBL_ENTRY_SIZE); + if (!lmt_map_base) { + dev_err(rvu->dev, "Failed to setup lmt map table mapping!!\n"); + return -ENOMEM; +@@ -35,6 +42,13 @@ static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val, + *val = readq(lmt_map_base + index); + } else { + writeq((*val), (lmt_map_base + index)); ++ ++ cfg = FIELD_PREP(LMT_MAP_ENTRY_ENA, 0x1); ++ /* 2048 LMTLINES */ ++ cfg |= FIELD_PREP(LMT_MAP_ENTRY_LINES, 0x6); ++ ++ writeq(cfg, (lmt_map_base + (index + 8))); ++ + /* Flushing the AP interceptor cache to make APR_LMT_MAP_ENTRY_S + * changes effective. Write 1 for flush and read is being used as a + * barrier and sets up a data dependency. Write to 0 after a write +@@ -52,7 +66,7 @@ static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val, + #define LMT_MAP_TBL_W1_OFF 8 + static u32 rvu_get_lmtst_tbl_index(struct rvu *rvu, u16 pcifunc) + { +- return ((rvu_get_pf(pcifunc) * rvu->hw->total_vfs) + ++ return ((rvu_get_pf(pcifunc) * LMT_MAX_VFS) + + (pcifunc & RVU_PFVF_FUNC_MASK)) * LMT_MAPTBL_ENTRY_SIZE; + } + +@@ -69,7 +83,7 @@ static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc, + + mutex_lock(&rvu->rsrc_lock); + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_REQ, iova); +- pf = rvu_get_pf(pcifunc) & 0x1F; ++ pf = rvu_get_pf(pcifunc) & RVU_PFVF_PF_MASK; + val = BIT_ULL(63) | BIT_ULL(14) | BIT_ULL(13) | pf << 8 | + ((pcifunc & RVU_PFVF_FUNC_MASK) & 0xFF); + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TXN_REQ, val); +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +index feca86e429df20..56dab11833b533 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +@@ -580,6 +580,7 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + u64 lmt_addr, val, tbl_base; + int pf, vf, num_vfs, hw_vfs; + void __iomem *lmt_map_base; ++ int apr_pfs, apr_vfs; + int buf_size = 10240; + size_t off = 0; + int index = 0; +@@ -595,8 +596,12 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + return -ENOMEM; + + tbl_base = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_MAP_BASE); ++ val = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CFG); ++ apr_vfs = 1 << (val & 0xF); ++ apr_pfs = 1 << ((val >> 4) & 0x7); + +- lmt_map_base = ioremap_wc(tbl_base, 128 * 1024); ++ lmt_map_base = ioremap_wc(tbl_base, apr_pfs * apr_vfs * ++ LMT_MAPTBL_ENTRY_SIZE); + if (!lmt_map_base) { + dev_err(rvu->dev, "Failed to setup lmt map table mapping!!\n"); + kfree(buf); +@@ -618,7 +623,7 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + off += scnprintf(&buf[off], buf_size - 1 - off, "PF%d \t\t\t", + pf); + +- index = pf * rvu->hw->total_vfs * LMT_MAPTBL_ENTRY_SIZE; ++ index = pf * apr_vfs * LMT_MAPTBL_ENTRY_SIZE; + off += scnprintf(&buf[off], buf_size - 1 - off, " 0x%llx\t\t", + (tbl_base + index)); + lmt_addr = readq(lmt_map_base + index); +@@ -631,7 +636,7 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, + /* Reading num of VFs per PF */ + rvu_get_pf_numvfs(rvu, pf, &num_vfs, &hw_vfs); + for (vf = 0; vf < num_vfs; vf++) { +- index = (pf * rvu->hw->total_vfs * 16) + ++ index = (pf * apr_vfs * LMT_MAPTBL_ENTRY_SIZE) + + ((vf + 1) * LMT_MAPTBL_ENTRY_SIZE); + off += scnprintf(&buf[off], buf_size - 1 - off, + "PF%d:VF%d \t\t", pf, vf); +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +index 47adccf7a77765..1999918ca500fa 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +@@ -988,6 +988,7 @@ static int otx2_cq_init(struct otx2_nic *pfvf, u16 qidx) + int err, pool_id, non_xdp_queues; + struct nix_aq_enq_req *aq; + struct otx2_cq_queue *cq; ++ struct otx2_pool *pool; + + cq = &qset->cq[qidx]; + cq->cq_idx = qidx; +@@ -996,8 +997,13 @@ static int otx2_cq_init(struct otx2_nic *pfvf, u16 qidx) + cq->cq_type = CQ_RX; + cq->cint_idx = qidx; + cq->cqe_cnt = qset->rqe_cnt; +- if (pfvf->xdp_prog) ++ if (pfvf->xdp_prog) { ++ pool = &qset->pool[qidx]; + xdp_rxq_info_reg(&cq->xdp_rxq, pfvf->netdev, qidx, 0); ++ xdp_rxq_info_reg_mem_model(&cq->xdp_rxq, ++ MEM_TYPE_PAGE_POOL, ++ pool->page_pool); ++ } + } else if (qidx < non_xdp_queues) { + cq->cq_type = CQ_TX; + cq->cint_idx = qidx - pfvf->hw.rx_queues; +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +index a4efbeb1620841..889fd26843e608 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -34,8 +34,10 @@ struct mtk_flow_data { + u16 vlan_in; + + struct { +- u16 id; +- __be16 proto; ++ struct { ++ u16 id; ++ __be16 proto; ++ } vlans[2]; + u8 num; + } vlan; + struct { +@@ -330,18 +332,19 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f, + case FLOW_ACTION_CSUM: + break; + case FLOW_ACTION_VLAN_PUSH: +- if (data.vlan.num == 1 || ++ if (data.vlan.num + data.pppoe.num == 2 || + act->vlan.proto != htons(ETH_P_8021Q)) + return -EOPNOTSUPP; + +- data.vlan.id = act->vlan.vid; +- data.vlan.proto = act->vlan.proto; ++ data.vlan.vlans[data.vlan.num].id = act->vlan.vid; ++ data.vlan.vlans[data.vlan.num].proto = act->vlan.proto; + data.vlan.num++; + break; + case FLOW_ACTION_VLAN_POP: + break; + case FLOW_ACTION_PPPOE_PUSH: +- if (data.pppoe.num == 1) ++ if (data.pppoe.num == 1 || ++ data.vlan.num == 2) + return -EOPNOTSUPP; + + data.pppoe.sid = act->pppoe.sid; +@@ -431,12 +434,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f, + if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) + foe.bridge.vlan = data.vlan_in; + +- if (data.vlan.num == 1) { +- if (data.vlan.proto != htons(ETH_P_8021Q)) +- return -EOPNOTSUPP; ++ for (i = 0; i < data.vlan.num; i++) ++ mtk_foe_entry_set_vlan(eth, &foe, data.vlan.vlans[i].id); + +- mtk_foe_entry_set_vlan(eth, &foe, data.vlan.id); +- } + if (data.pppoe.num == 1) + mtk_foe_entry_set_pppoe(eth, &foe, data.pppoe.sid); + +diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c +index b330020dc0d674..f2bded847e61d1 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/alloc.c ++++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c +@@ -682,9 +682,9 @@ static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device) + } + + static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, +- struct mlx4_db *db, int order) ++ struct mlx4_db *db, unsigned int order) + { +- int o; ++ unsigned int o; + int i; + + for (o = order; o <= 1; ++o) { +@@ -712,7 +712,7 @@ static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, + return 0; + } + +-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order) ++int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, unsigned int order) + { + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_db_pgdir *pgdir; +diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c +index 65cb63f6c46587..61a0fd8424a2c5 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c +@@ -450,6 +450,8 @@ int mlx4_en_process_tx_cq(struct net_device *dev, + + if (unlikely(!priv->port_up)) + return 0; ++ if (unlikely(!napi_budget) && cq->type == TX_XDP) ++ return 0; + + netdev_txq_bql_complete_prefetchw(ring->tx_queue); + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h +index 20a6bc1a234f4e..9cf33ae48c216f 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h +@@ -93,8 +93,6 @@ struct page_pool; + #define MLX5_MPWRQ_DEF_LOG_STRIDE_SZ(mdev) \ + MLX5_MPWRQ_LOG_STRIDE_SZ(mdev, order_base_2(MLX5E_RX_MAX_HEAD)) + +-#define MLX5_MPWRQ_MAX_LOG_WQE_SZ 18 +- + /* Keep in sync with mlx5e_mpwrq_log_wqe_sz. + * These are theoretical maximums, which can be further restricted by + * capabilities. These values are used for static resource allocations and +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +index 775010e94cb7c6..dcd5db907f1028 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +@@ -9,6 +9,9 @@ + #include + #include + ++#define MLX5_MPWRQ_MAX_LOG_WQE_SZ 18 ++#define MLX5_REP_MPWRQ_MAX_LOG_WQE_SZ 17 ++ + static u8 mlx5e_mpwrq_min_page_shift(struct mlx5_core_dev *mdev) + { + u8 min_page_shift = MLX5_CAP_GEN_2(mdev, log_min_mkey_entity_size); +@@ -102,18 +105,22 @@ u8 mlx5e_mpwrq_log_wqe_sz(struct mlx5_core_dev *mdev, u8 page_shift, + enum mlx5e_mpwrq_umr_mode umr_mode) + { + u8 umr_entry_size = mlx5e_mpwrq_umr_entry_size(umr_mode); +- u8 max_pages_per_wqe, max_log_mpwqe_size; ++ u8 max_pages_per_wqe, max_log_wqe_size_calc; ++ u8 max_log_wqe_size_cap; + u16 max_wqe_size; + + /* Keep in sync with MLX5_MPWRQ_MAX_PAGES_PER_WQE. */ + max_wqe_size = mlx5e_get_max_sq_aligned_wqebbs(mdev) * MLX5_SEND_WQE_BB; + max_pages_per_wqe = ALIGN_DOWN(max_wqe_size - sizeof(struct mlx5e_umr_wqe), + MLX5_UMR_FLEX_ALIGNMENT) / umr_entry_size; +- max_log_mpwqe_size = ilog2(max_pages_per_wqe) + page_shift; ++ max_log_wqe_size_calc = ilog2(max_pages_per_wqe) + page_shift; ++ ++ WARN_ON_ONCE(max_log_wqe_size_calc < MLX5E_ORDER2_MAX_PACKET_MTU); + +- WARN_ON_ONCE(max_log_mpwqe_size < MLX5E_ORDER2_MAX_PACKET_MTU); ++ max_log_wqe_size_cap = mlx5_core_is_ecpf(mdev) ? ++ MLX5_REP_MPWRQ_MAX_LOG_WQE_SZ : MLX5_MPWRQ_MAX_LOG_WQE_SZ; + +- return min_t(u8, max_log_mpwqe_size, MLX5_MPWRQ_MAX_LOG_WQE_SZ); ++ return min_t(u8, max_log_wqe_size_calc, max_log_wqe_size_cap); + } + + u8 mlx5e_mpwrq_pages_per_wqe(struct mlx5_core_dev *mdev, u8 page_shift, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index d9dc7280302eb7..5c6f01abdcb91d 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -3627,8 +3627,11 @@ static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv, + /* MQPRIO is another toplevel qdisc that can't be attached + * simultaneously with the offloaded HTB. + */ +- if (WARN_ON(mlx5e_selq_is_htb_enabled(&priv->selq))) +- return -EINVAL; ++ if (mlx5e_selq_is_htb_enabled(&priv->selq)) { ++ NL_SET_ERR_MSG_MOD(mqprio->extack, ++ "MQPRIO cannot be configured when HTB offload is enabled."); ++ return -EOPNOTSUPP; ++ } + + switch (mqprio->mode) { + case TC_MQPRIO_MODE_DCB: +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +index 751d3ffcd2f6ce..851c499faa7954 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +@@ -63,6 +63,7 @@ + #define MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE \ + max(0x7, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE) + #define MLX5E_REP_PARAMS_DEF_NUM_CHANNELS 1 ++#define MLX5E_REP_PARAMS_DEF_LOG_RQ_SIZE 0x8 + + static const char mlx5e_rep_driver_name[] = "mlx5e_rep"; + +@@ -798,6 +799,8 @@ static void mlx5e_build_rep_params(struct net_device *netdev) + + /* RQ */ + mlx5e_build_rq_params(mdev, params); ++ if (!mlx5e_is_uplink_rep(priv) && mlx5_core_is_ecpf(mdev)) ++ params->log_rq_mtu_frames = MLX5E_REP_PARAMS_DEF_LOG_RQ_SIZE; + + /* If netdev is already registered (e.g. move from nic profile to uplink, + * RTNL lock must be held before triggering netdev notifiers. +@@ -829,6 +832,8 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev, + netdev->ethtool_ops = &mlx5e_rep_ethtool_ops; + + netdev->watchdog_timeo = 15 * HZ; ++ if (mlx5_core_is_ecpf(mdev)) ++ netdev->tx_queue_len = 1 << MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE; + + #if IS_ENABLED(CONFIG_MLX5_CLS_ACT) + netdev->hw_features |= NETIF_F_HW_TC; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +index 08a75654f5f188..c170503b3aace1 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +@@ -165,6 +165,9 @@ mlx5e_test_loopback_validate(struct sk_buff *skb, + struct udphdr *udph; + struct iphdr *iph; + ++ if (skb_linearize(skb)) ++ goto out; ++ + /* We are only going to peek, no need to clone the SKB */ + if (MLX5E_TEST_PKT_SIZE - ETH_HLEN > skb_headlen(skb)) + goto out; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c +index 8587cd572da536..bdb825aa872688 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c +@@ -96,7 +96,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw) + if (!flow_group_in) + return -ENOMEM; + +- ft_attr.max_fte = POOL_NEXT_SIZE; ++ ft_attr.max_fte = MLX5_FS_MAX_POOL_SIZE; + ft_attr.prio = LEGACY_FDB_PRIO; + fdb = mlx5_create_flow_table(root_ns, &ft_attr); + if (IS_ERR(fdb)) { +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c +index 3ec892d51f57d2..e7143d32b22119 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/events.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c +@@ -163,11 +163,16 @@ static int temp_warn(struct notifier_block *nb, unsigned long type, void *data) + u64 value_msb; + + value_lsb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_lsb); ++ /* bit 1-63 are not supported for NICs, ++ * hence read only bit 0 (asic) from lsb. ++ */ ++ value_lsb &= 0x1; + value_msb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_msb); + +- mlx5_core_warn(events->dev, +- "High temperature on sensors with bit set %llx %llx", +- value_msb, value_lsb); ++ if (net_ratelimit()) ++ mlx5_core_warn(events->dev, ++ "High temperature on sensors with bit set %llx %llx", ++ value_msb, value_lsb); + + return NOTIFY_OK; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c +index c14590acc77260..f6abfd00d7e68c 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c +@@ -50,10 +50,12 @@ mlx5_ft_pool_get_avail_sz(struct mlx5_core_dev *dev, enum fs_flow_table_type tab + int i, found_i = -1; + + for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--) { +- if (dev->priv.ft_pool->ft_left[i] && FT_POOLS[i] >= desired_size && ++ if (dev->priv.ft_pool->ft_left[i] && ++ (FT_POOLS[i] >= desired_size || ++ desired_size == MLX5_FS_MAX_POOL_SIZE) && + FT_POOLS[i] <= max_ft_size) { + found_i = i; +- if (desired_size != POOL_NEXT_SIZE) ++ if (desired_size != MLX5_FS_MAX_POOL_SIZE) + break; + } + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h +index 25f4274b372b56..173e312db7204f 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h +@@ -7,8 +7,6 @@ + #include + #include "fs_core.h" + +-#define POOL_NEXT_SIZE 0 +- + int mlx5_ft_pool_init(struct mlx5_core_dev *dev); + void mlx5_ft_pool_destroy(struct mlx5_core_dev *dev); + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c +index d798834c4e755d..3ac8043f76dacc 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c +@@ -833,6 +833,7 @@ static void poll_health(struct timer_list *t) + health->prev = count; + if (health->miss_counter == MAX_MISSES) { + mlx5_core_err(dev, "device's health compromised - reached miss count\n"); ++ health->synd = ioread8(&h->synd); + print_health_info(dev); + queue_work(health->wq, &health->report_work); + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c +index 711d14dea2485f..d313cb7f0ed88c 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c +@@ -161,7 +161,8 @@ mlx5_chains_create_table(struct mlx5_fs_chains *chains, + ft_attr.flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | + MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); + +- sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? FT_TBL_SZ : POOL_NEXT_SIZE; ++ sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? ++ FT_TBL_SZ : MLX5_FS_MAX_POOL_SIZE; + ft_attr.max_fte = sz; + + /* We use chains_default_ft(chains) as the table's next_ft till +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 5d2ceff72784f2..f971d60484f065 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -3259,6 +3259,7 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, + struct pci_dev *pdev) + { + struct lan743x_tx *tx; ++ u32 sgmii_ctl; + int index; + int ret; + +@@ -3271,6 +3272,15 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, + spin_lock_init(&adapter->eth_syslock_spinlock); + mutex_init(&adapter->sgmii_rw_lock); + pci11x1x_set_rfe_rd_fifo_threshold(adapter); ++ sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); ++ if (adapter->is_sgmii_en) { ++ sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_; ++ sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_; ++ } else { ++ sgmii_ctl &= ~SGMII_CTL_SGMII_ENABLE_; ++ sgmii_ctl |= SGMII_CTL_SGMII_POWER_DN_; ++ } ++ lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + } else { + adapter->max_tx_channels = LAN743X_MAX_TX_CHANNELS; + adapter->used_tx_channels = LAN743X_USED_TX_CHANNELS; +@@ -3319,7 +3329,6 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, + + static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) + { +- u32 sgmii_ctl; + int ret; + + adapter->mdiobus = devm_mdiobus_alloc(&adapter->pdev->dev); +@@ -3331,10 +3340,6 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) + adapter->mdiobus->priv = (void *)adapter; + if (adapter->is_pci11x1x) { + if (adapter->is_sgmii_en) { +- sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); +- sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_; +- sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_; +- lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + netif_dbg(adapter, drv, adapter->netdev, + "SGMII operation\n"); + adapter->mdiobus->read = lan743x_mdiobus_read_c22; +@@ -3345,10 +3350,6 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter) + netif_dbg(adapter, drv, adapter->netdev, + "lan743x-mdiobus-c45\n"); + } else { +- sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); +- sgmii_ctl &= ~SGMII_CTL_SGMII_ENABLE_; +- sgmii_ctl |= SGMII_CTL_SGMII_POWER_DN_; +- lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + netif_dbg(adapter, drv, adapter->netdev, + "RGMII operation\n"); + // Only C22 support when RGMII I/F +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index ae014e21eb6056..9ed965d61e3554 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -1036,7 +1036,7 @@ static u32 mana_gd_write_client_oob(const struct gdma_wqe_request *wqe_req, + header->inline_oob_size_div4 = client_oob_size / sizeof(u32); + + if (oob_in_sgl) { +- WARN_ON_ONCE(!pad_data || wqe_req->num_sge < 2); ++ WARN_ON_ONCE(wqe_req->num_sge < 2); + + header->client_oob_in_sgl = 1; + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index 7e5258b2c4290b..5af932a5e70c44 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5125,6 +5125,7 @@ static int r8169_mdio_register(struct rtl8169_private *tp) + new_bus->priv = tp; + new_bus->parent = &pdev->dev; + new_bus->irq[0] = PHY_MAC_INTERRUPT; ++ new_bus->phy_mask = GENMASK(31, 1); + snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x-%x", + pci_domain_nr(pdev->bus), pci_dev_id(pdev)); + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +index 63998d65fef8eb..9377b05bfc71e1 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +@@ -966,7 +966,7 @@ static int sun8i_dwmac_set_syscon(struct device *dev, + /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY + * address. No need to mask it again. + */ +- reg |= 1 << H3_EPHY_ADDR_SHIFT; ++ reg |= ret << H3_EPHY_ADDR_SHIFT; + } else { + /* For SoCs without internal PHY the PHY selection bit should be + * set to 0 (external PHY). +diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +index 9c8376b2718916..c379a958380ce0 100644 +--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c ++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +@@ -2095,7 +2095,7 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) + port->slave.mac_addr); + if (!is_valid_ether_addr(port->slave.mac_addr)) { + eth_random_addr(port->slave.mac_addr); +- dev_err(dev, "Use random MAC address\n"); ++ dev_info(dev, "Use random MAC address\n"); + } + } + } +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index 9061dca97fcbfd..1c1d4806c119b8 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -1416,6 +1416,7 @@ static int cpsw_create_ports(struct cpsw_common *cpsw) + ndev->netdev_ops = &cpsw_netdev_ops; + ndev->ethtool_ops = &cpsw_ethtool_ops; + SET_NETDEV_DEV(ndev, dev); ++ ndev->dev.of_node = slave_data->slave_node; + + if (!napi_ndev) { + /* CPSW Host port CPDMA interface is shared between +diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c +index 0a0ad3d77557f9..587643a371de3c 100644 +--- a/drivers/net/ieee802154/ca8210.c ++++ b/drivers/net/ieee802154/ca8210.c +@@ -1446,8 +1446,7 @@ static u8 mcps_data_request( + command.pdata.data_req.src_addr_mode = src_addr_mode; + command.pdata.data_req.dst.mode = dst_address_mode; + if (dst_address_mode != MAC_MODE_NO_ADDR) { +- command.pdata.data_req.dst.pan_id[0] = LS_BYTE(dst_pan_id); +- command.pdata.data_req.dst.pan_id[1] = MS_BYTE(dst_pan_id); ++ put_unaligned_le16(dst_pan_id, command.pdata.data_req.dst.pan_id); + if (dst_address_mode == MAC_MODE_SHORT_ADDR) { + command.pdata.data_req.dst.address[0] = LS_BYTE( + dst_addr->short_address +@@ -1795,12 +1794,12 @@ static int ca8210_skb_rx( + } + hdr.source.mode = data_ind[0]; + dev_dbg(&priv->spi->dev, "srcAddrMode: %#03x\n", hdr.source.mode); +- hdr.source.pan_id = *(u16 *)&data_ind[1]; ++ hdr.source.pan_id = cpu_to_le16(get_unaligned_le16(&data_ind[1])); + dev_dbg(&priv->spi->dev, "srcPanId: %#06x\n", hdr.source.pan_id); + memcpy(&hdr.source.extended_addr, &data_ind[3], 8); + hdr.dest.mode = data_ind[11]; + dev_dbg(&priv->spi->dev, "dstAddrMode: %#03x\n", hdr.dest.mode); +- hdr.dest.pan_id = *(u16 *)&data_ind[12]; ++ hdr.dest.pan_id = cpu_to_le16(get_unaligned_le16(&data_ind[12])); + dev_dbg(&priv->spi->dev, "dstPanId: %#06x\n", hdr.dest.pan_id); + memcpy(&hdr.dest.extended_addr, &data_ind[14], 8); + +@@ -1927,7 +1926,7 @@ static int ca8210_skb_tx( + status = mcps_data_request( + header.source.mode, + header.dest.mode, +- header.dest.pan_id, ++ le16_to_cpu(header.dest.pan_id), + (union macaddr *)&header.dest.extended_addr, + skb->len - mac_len, + &skb->data[mac_len], +diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c +index b5f012619e42da..800e8b9eb4532b 100644 +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1718,7 +1718,7 @@ bool phylink_expects_phy(struct phylink *pl) + { + if (pl->cfg_link_an_mode == MLO_AN_FIXED || + (pl->cfg_link_an_mode == MLO_AN_INBAND && +- phy_interface_mode_is_8023z(pl->link_config.interface))) ++ phy_interface_mode_is_8023z(pl->link_interface))) + return false; + return true; + } +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index bbcefcc7ef8f06..1e85cfe524e875 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -10032,6 +10032,7 @@ static const struct usb_device_id rtl8152_table[] = { + { USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) }, + { USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) }, + { USB_DEVICE(VENDOR_ID_DLINK, 0xb301) }, ++ { USB_DEVICE(VENDOR_ID_DELL, 0xb097) }, + { USB_DEVICE(VENDOR_ID_ASUS, 0x1976) }, + {} + }; +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index 64db3e98a1b664..2ed879a0abc6ce 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -227,9 +227,9 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, + be32_to_cpu(fdb->vni))) + goto nla_put_failure; + +- ci.ndm_used = jiffies_to_clock_t(now - fdb->used); ++ ci.ndm_used = jiffies_to_clock_t(now - READ_ONCE(fdb->used)); + ci.ndm_confirmed = 0; +- ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated); ++ ci.ndm_updated = jiffies_to_clock_t(now - READ_ONCE(fdb->updated)); + ci.ndm_refcnt = 0; + + if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) +@@ -435,8 +435,8 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, + struct vxlan_fdb *f; + + f = __vxlan_find_mac(vxlan, mac, vni); +- if (f && f->used != jiffies) +- f->used = jiffies; ++ if (f && READ_ONCE(f->used) != jiffies) ++ WRITE_ONCE(f->used, jiffies); + + return f; + } +@@ -1010,12 +1010,12 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, + !(f->flags & NTF_VXLAN_ADDED_BY_USER)) { + if (f->state != state) { + f->state = state; +- f->updated = jiffies; ++ WRITE_ONCE(f->updated, jiffies); + notify = 1; + } + if (f->flags != fdb_flags) { + f->flags = fdb_flags; +- f->updated = jiffies; ++ WRITE_ONCE(f->updated, jiffies); + notify = 1; + } + } +@@ -1049,7 +1049,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, + } + + if (ndm_flags & NTF_USE) +- f->used = jiffies; ++ WRITE_ONCE(f->used, jiffies); + + if (notify) { + if (rd == NULL) +@@ -1478,7 +1478,7 @@ static bool vxlan_snoop(struct net_device *dev, + src_mac, &rdst->remote_ip.sa, &src_ip->sa); + + rdst->remote_ip = *src_ip; +- f->updated = jiffies; ++ WRITE_ONCE(f->updated, jiffies); + vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL); + } else { + u32 hash_index = fdb_head_index(vxlan, src_mac, vni); +@@ -2920,7 +2920,7 @@ static void vxlan_cleanup(struct timer_list *t) + if (f->flags & NTF_EXT_LEARNED) + continue; + +- timeout = f->used + vxlan->cfg.age_interval * HZ; ++ timeout = READ_ONCE(f->used) + vxlan->cfg.age_interval * HZ; + if (time_before_eq(timeout, jiffies)) { + netdev_dbg(vxlan->dev, + "garbage collect %pM\n", +@@ -4240,6 +4240,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + struct netlink_ext_ack *extack) + { + struct vxlan_dev *vxlan = netdev_priv(dev); ++ bool rem_ip_changed, change_igmp; + struct net_device *lowerdev; + struct vxlan_config conf; + struct vxlan_rdst *dst; +@@ -4263,8 +4264,13 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + if (err) + return err; + ++ rem_ip_changed = !vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip); ++ change_igmp = vxlan->dev->flags & IFF_UP && ++ (rem_ip_changed || ++ dst->remote_ifindex != conf.remote_ifindex); ++ + /* handle default dst entry */ +- if (!vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip)) { ++ if (rem_ip_changed) { + u32 hash_index = fdb_head_index(vxlan, all_zeros_mac, conf.vni); + + spin_lock_bh(&vxlan->hash_lock[hash_index]); +@@ -4308,6 +4314,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + } + } + ++ if (change_igmp && vxlan_addr_multicast(&dst->remote_ip)) ++ err = vxlan_multicast_leave(vxlan); ++ + if (conf.age_interval != vxlan->cfg.age_interval) + mod_timer(&vxlan->age_timer, jiffies); + +@@ -4315,7 +4324,12 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + if (lowerdev && lowerdev != dst->remote_dev) + dst->remote_dev = lowerdev; + vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true); +- return 0; ++ ++ if (!err && change_igmp && ++ vxlan_addr_multicast(&dst->remote_ip)) ++ err = vxlan_multicast_join(vxlan); ++ ++ return err; + } + + static void vxlan_dellink(struct net_device *dev, struct list_head *head) +diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h +index 33f4706af880d1..18dfd7aab610c9 100644 +--- a/drivers/net/wireless/ath/ath12k/core.h ++++ b/drivers/net/wireless/ath/ath12k/core.h +@@ -125,6 +125,7 @@ struct ath12k_ext_irq_grp { + u32 num_irq; + u32 grp_id; + u64 timestamp; ++ bool napi_enabled; + struct napi_struct napi; + struct net_device napi_ndev; + }; +diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c +index e025e4d0e7678f..474e0d4d406ea1 100644 +--- a/drivers/net/wireless/ath/ath12k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath12k/dp_tx.c +@@ -118,7 +118,7 @@ static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab, void *cmd, + le32_encode_bits(ti->data_len, + HAL_TX_MSDU_EXT_INFO1_BUF_LEN); + +- tcl_ext_cmd->info1 = le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) | ++ tcl_ext_cmd->info1 |= le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) | + le32_encode_bits(ti->encap_type, + HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) | + le32_encode_bits(ti->encrypt_type, +@@ -422,13 +422,13 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, + + switch (wbm_status) { + case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK: +- case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: +- case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: + ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK); + ts.ack_rssi = le32_get_bits(status_desc->info2, + HTT_TX_WBM_COMP_INFO2_ACK_RSSI); + ath12k_dp_tx_htt_tx_complete_buf(ab, msdu, tx_ring, &ts); + break; ++ case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: ++ case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: + case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ: + case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT: + ath12k_dp_tx_free_txbuf(ab, msdu, mac_id, tx_ring); +diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h +index 6c17adc6d60b56..1bb840c2bef577 100644 +--- a/drivers/net/wireless/ath/ath12k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath12k/hal_desc.h +@@ -2918,7 +2918,7 @@ struct hal_mon_buf_ring { + + #define HAL_MON_DEST_COOKIE_BUF_ID GENMASK(17, 0) + +-#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(15, 0) ++#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(11, 0) + #define HAL_MON_DEST_INFO0_FLUSH_DETECTED BIT(16) + #define HAL_MON_DEST_INFO0_END_OF_PPDU BIT(17) + #define HAL_MON_DEST_INFO0_INITIATOR BIT(18) +diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c +index 041a9602f0e15f..5fd80f90ecafed 100644 +--- a/drivers/net/wireless/ath/ath12k/pci.c ++++ b/drivers/net/wireless/ath/ath12k/pci.c +@@ -442,8 +442,11 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab) + + ath12k_pci_ext_grp_disable(irq_grp); + +- napi_synchronize(&irq_grp->napi); +- napi_disable(&irq_grp->napi); ++ if (irq_grp->napi_enabled) { ++ napi_synchronize(&irq_grp->napi); ++ napi_disable(&irq_grp->napi); ++ irq_grp->napi_enabled = false; ++ } + } + } + +@@ -976,7 +979,11 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab) + for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + +- napi_enable(&irq_grp->napi); ++ if (!irq_grp->napi_enabled) { ++ napi_enable(&irq_grp->napi); ++ irq_grp->napi_enabled = true; ++ } ++ + ath12k_pci_ext_grp_enable(irq_grp); + } + } +diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c +index c977dfbae0a464..d87d5980325e8f 100644 +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -2115,8 +2115,8 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar, + arg->dwell_time_active = 50; + arg->dwell_time_active_2g = 0; + arg->dwell_time_passive = 150; +- arg->dwell_time_active_6g = 40; +- arg->dwell_time_passive_6g = 30; ++ arg->dwell_time_active_6g = 70; ++ arg->dwell_time_passive_6g = 70; + arg->min_rest_time = 50; + arg->max_rest_time = 500; + arg->repeat_probe_time = 0; +diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c +index 4f00400c7ffb83..58386906598a73 100644 +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -691,7 +691,9 @@ static int ath9k_of_init(struct ath_softc *sc) + ah->ah_flags |= AH_NO_EEP_SWAP; + } + +- of_get_mac_address(np, common->macaddr); ++ ret = of_get_mac_address(np, common->macaddr); ++ if (ret == -EPROBE_DEFER) ++ return ret; + + return 0; + } +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +index a97ed7cbe4d140..d588e4cd808d8e 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + /* +- * Copyright (C) 2018-2024 Intel Corporation ++ * Copyright (C) 2018-2025 Intel Corporation + */ + #include + #include "iwl-drv.h" +@@ -1382,15 +1382,15 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + switch (tp_id) { + case IWL_FW_INI_TIME_POINT_EARLY: + iwl_dbg_tlv_init_cfg(fwrt); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_update_drams(fwrt); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + case IWL_FW_INI_TIME_POINT_AFTER_ALIVE: + iwl_dbg_tlv_apply_buffers(fwrt); + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + case IWL_FW_INI_TIME_POINT_PERIODIC: + iwl_dbg_tlv_set_periodic_trigs(fwrt); +@@ -1400,14 +1400,14 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, + case IWL_FW_INI_TIME_POINT_MISSED_BEACONS: + case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, + iwl_dbg_tlv_check_fw_pkt); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + default: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); +- iwl_dbg_tlv_apply_config(fwrt, conf_list); + iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL); ++ iwl_dbg_tlv_apply_config(fwrt, conf_list); + break; + } + } +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +index 4a2de79f2e864b..c01a9a6f06a4d0 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +@@ -580,6 +580,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { + IWL_DEV_INFO(0x7A70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), + IWL_DEV_INFO(0x7AF0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), + IWL_DEV_INFO(0x7AF0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), ++ IWL_DEV_INFO(0x7F70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), ++ IWL_DEV_INFO(0x7F70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), + + IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name), + IWL_DEV_INFO(0x7E40, 0x1691, iwl_cfg_ma, iwl_ax411_killer_1690s_name), +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index 8b620d4fed4390..df0ea638370b56 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -439,6 +439,7 @@ struct mt76_hw_cap { + #define MT_DRV_RX_DMA_HDR BIT(3) + #define MT_DRV_HW_MGMT_TXQ BIT(4) + #define MT_DRV_AMSDU_OFFLOAD BIT(5) ++#define MT_DRV_IGNORE_TXS_FAILED BIT(6) + + struct mt76_driver_ops { + u32 drv_flags; +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +index 87bfa441a93743..4979012d5abfa0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +@@ -280,6 +280,9 @@ enum tx_mgnt_type { + #define MT_TXFREE_INFO_COUNT GENMASK(27, 24) + #define MT_TXFREE_INFO_STAT GENMASK(29, 28) + ++#define MT_TXS_HDR_SIZE 4 /* Unit: DW */ ++#define MT_TXS_SIZE 12 /* Unit: DW */ ++ + #define MT_TXS0_BW GENMASK(31, 29) + #define MT_TXS0_TID GENMASK(28, 26) + #define MT_TXS0_AMPDU BIT(25) +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +index 9277ff38b7a228..57ae362dad50b7 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +@@ -152,7 +152,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x02_txwi), + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | +- MT_DRV_SW_RX_AIRTIME, ++ MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +index 0422c332354a13..520fd46227a7b8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +@@ -210,7 +210,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) + { + static const struct mt76_driver_ops drv_ops = { +- .drv_flags = MT_DRV_SW_RX_AIRTIME, ++ .drv_flags = MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02u_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +index df85ebc6e1df07..7e2475b3c278e0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +@@ -22,7 +22,8 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x02_txwi), + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | +- MT_DRV_SW_RX_AIRTIME, ++ MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +index d8043099921966..70d3895762b4cd 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +@@ -29,7 +29,8 @@ static int mt76x2u_probe(struct usb_interface *intf, + const struct usb_device_id *id) + { + static const struct mt76_driver_ops drv_ops = { +- .drv_flags = MT_DRV_SW_RX_AIRTIME, ++ .drv_flags = MT_DRV_SW_RX_AIRTIME | ++ MT_DRV_IGNORE_TXS_FAILED, + .survey_flags = SURVEY_INFO_TIME_TX, + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02u_tx_prepare_skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 73d46ec1181ae8..35d9673ec0d8fc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1354,7 +1354,7 @@ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len) + mt7996_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: +- for (rxd += 4; rxd + 8 <= end; rxd += 8) ++ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE) + mt7996_mac_add_txs(dev, rxd); + return false; + case PKT_TYPE_RX_FW_MONITOR: +@@ -1391,7 +1391,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + mt7996_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_TXS: +- for (rxd += 4; rxd + 8 <= end; rxd += 8) ++ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE) + mt7996_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; +diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c +index 1809b03292c3d9..47cdccdbed6aaf 100644 +--- a/drivers/net/wireless/mediatek/mt76/tx.c ++++ b/drivers/net/wireless/mediatek/mt76/tx.c +@@ -100,7 +100,8 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, + return; + + /* Tx status can be unreliable. if it fails, mark the frame as ACKed */ +- if (flags & MT_TX_CB_TXS_FAILED) { ++ if (flags & MT_TX_CB_TXS_FAILED && ++ (dev->drv->drv_flags & MT_DRV_IGNORE_TXS_FAILED)) { + info->status.rates[0].count = 0; + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; +diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +index 6e47dde9389092..05e77d2bda3738 100644 +--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c ++++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +@@ -900,9 +900,10 @@ rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len) + return len; + + write_error: +- dev_info(&udev->dev, +- "%s: Failed to write block at addr: %04x size: %04x\n", +- __func__, addr, blocksize); ++ if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE) ++ dev_info(&udev->dev, ++ "%s: Failed to write block at addr: %04x size: %04x\n", ++ __func__, addr, blocksize); + return -EAGAIN; + } + +@@ -4073,8 +4074,14 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) + */ + rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, fops->trxff_boundary); + +- ret = rtl8xxxu_download_firmware(priv); +- dev_dbg(dev, "%s: download_firmware %i\n", __func__, ret); ++ for (int retry = 5; retry >= 0 ; retry--) { ++ ret = rtl8xxxu_download_firmware(priv); ++ dev_dbg(dev, "%s: download_firmware %i\n", __func__, ret); ++ if (ret != -EAGAIN) ++ break; ++ if (retry) ++ dev_dbg(dev, "%s: retry firmware download\n", __func__); ++ } + if (ret) + goto exit; + ret = rtl8xxxu_start_firmware(priv); +diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c +index 0c1c1ff31085cf..929182424b8b87 100644 +--- a/drivers/net/wireless/realtek/rtw88/mac.c ++++ b/drivers/net/wireless/realtek/rtw88/mac.c +@@ -783,7 +783,8 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev, + if (!check_firmware_size(data, size)) + return -EINVAL; + +- if (!ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp)) ++ if (rtwdev->chip->ltecoex_addr && ++ !ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp)) + return -EBUSY; + + wlan_cpu_enable(rtwdev, false); +@@ -801,7 +802,8 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev, + + wlan_cpu_enable(rtwdev, true); + +- if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) { ++ if (rtwdev->chip->ltecoex_addr && ++ !ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) { + ret = -EBUSY; + goto dlfw_fail; + } +diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c +index b90ea6c88b15d9..0d0b5123b5fe28 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.c ++++ b/drivers/net/wireless/realtek/rtw88/main.c +@@ -1544,6 +1544,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, + { + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; ++ int i; + + ht_cap->ht_supported = true; + ht_cap->cap = 0; +@@ -1563,25 +1564,20 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ampdu_density = chip->ampdu_density; + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +- if (efuse->hw_cap.nss > 1) { +- ht_cap->mcs.rx_mask[0] = 0xFF; +- ht_cap->mcs.rx_mask[1] = 0xFF; +- ht_cap->mcs.rx_mask[4] = 0x01; +- ht_cap->mcs.rx_highest = cpu_to_le16(300); +- } else { +- ht_cap->mcs.rx_mask[0] = 0xFF; +- ht_cap->mcs.rx_mask[1] = 0x00; +- ht_cap->mcs.rx_mask[4] = 0x01; +- ht_cap->mcs.rx_highest = cpu_to_le16(150); +- } ++ ++ for (i = 0; i < efuse->hw_cap.nss; i++) ++ ht_cap->mcs.rx_mask[i] = 0xFF; ++ ht_cap->mcs.rx_mask[4] = 0x01; ++ ht_cap->mcs.rx_highest = cpu_to_le16(150 * efuse->hw_cap.nss); + } + + static void rtw_init_vht_cap(struct rtw_dev *rtwdev, + struct ieee80211_sta_vht_cap *vht_cap) + { + struct rtw_efuse *efuse = &rtwdev->efuse; +- u16 mcs_map; ++ u16 mcs_map = 0; + __le16 highest; ++ int i; + + if (efuse->hw_cap.ptcl != EFUSE_HW_CAP_IGNORE && + efuse->hw_cap.ptcl != EFUSE_HW_CAP_PTCL_VHT) +@@ -1604,21 +1600,15 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev, + if (rtw_chip_has_rx_ldpc(rtwdev)) + vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; + +- mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | +- IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; +- if (efuse->hw_cap.nss > 1) { +- highest = cpu_to_le16(780); +- mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2; +- } else { +- highest = cpu_to_le16(390); +- mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << 2; ++ for (i = 0; i < 8; i++) { ++ if (i < efuse->hw_cap.nss) ++ mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2); ++ else ++ mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2); + } + ++ highest = cpu_to_le16(390 * efuse->hw_cap.nss); ++ + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.rx_highest = highest; +diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h +index 7c6c11d50ff30f..0e76bc07bddef3 100644 +--- a/drivers/net/wireless/realtek/rtw88/reg.h ++++ b/drivers/net/wireless/realtek/rtw88/reg.h +@@ -108,6 +108,7 @@ + #define BIT_SHIFT_ROM_PGE 16 + #define BIT_FW_INIT_RDY BIT(15) + #define BIT_FW_DW_RDY BIT(14) ++#define BIT_CPU_CLK_SEL (BIT(12) | BIT(13)) + #define BIT_RPWM_TOGGLE BIT(7) + #define BIT_RAM_DL_SEL BIT(7) /* legacy only */ + #define BIT_DMEM_CHKSUM_OK BIT(6) +@@ -125,7 +126,7 @@ + BIT_CHECK_SUM_OK) + #define FW_READY_LEGACY (BIT_MCUFWDL_RDY | BIT_FWDL_CHK_RPT | \ + BIT_WINTINI_RDY | BIT_RAM_DL_SEL) +-#define FW_READY_MASK 0xffff ++#define FW_READY_MASK (0xffff & ~BIT_CPU_CLK_SEL) + + #define REG_MCU_TST_CFG 0x84 + #define VAL_FW_TRIGGER 0x1 +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c +index 3017a9760da8dc..99318a82b43f4b 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c +@@ -975,11 +975,11 @@ static void rtw8822b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, + } + + static void +-rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) ++rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, ++ u8 rs, u32 *phy_pwr_idx) + { + struct rtw_hal *hal = &rtwdev->hal; + static const u32 offset_txagc[2] = {0x1d00, 0x1d80}; +- static u32 phy_pwr_idx; + u8 rate, rate_idx, pwr_index, shift; + int j; + +@@ -987,12 +987,12 @@ rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) + rate = rtw_rate_section[rs][j]; + pwr_index = hal->tx_pwr_tbl[path][rate]; + shift = rate & 0x3; +- phy_pwr_idx |= ((u32)pwr_index << (shift * 8)); ++ *phy_pwr_idx |= ((u32)pwr_index << (shift * 8)); + if (shift == 0x3) { + rate_idx = rate & 0xfc; + rtw_write32(rtwdev, offset_txagc[path] + rate_idx, +- phy_pwr_idx); +- phy_pwr_idx = 0; ++ *phy_pwr_idx); ++ *phy_pwr_idx = 0; + } + } + } +@@ -1000,11 +1000,13 @@ rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) + static void rtw8822b_set_tx_power_index(struct rtw_dev *rtwdev) + { + struct rtw_hal *hal = &rtwdev->hal; ++ u32 phy_pwr_idx = 0; + int rs, path; + + for (path = 0; path < hal->rf_path_num; path++) { + for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) +- rtw8822b_set_tx_power_index_by_rate(rtwdev, path, rs); ++ rtw8822b_set_tx_power_index_by_rate(rtwdev, path, rs, ++ &phy_pwr_idx); + } + } + +diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c +index e222d3c01a77ec..66819f69440550 100644 +--- a/drivers/net/wireless/realtek/rtw88/util.c ++++ b/drivers/net/wireless/realtek/rtw88/util.c +@@ -101,7 +101,8 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss) + *nss = 4; + *mcs = rate - DESC_RATEVHT4SS_MCS0; + } else if (rate >= DESC_RATEMCS0 && +- rate <= DESC_RATEMCS15) { ++ rate <= DESC_RATEMCS31) { ++ *nss = 0; + *mcs = rate - DESC_RATEMCS0; + } + } +diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c +index a8e2efae6e5260..89b0a7970508e2 100644 +--- a/drivers/net/wireless/realtek/rtw89/fw.c ++++ b/drivers/net/wireless/realtek/rtw89/fw.c +@@ -755,7 +755,6 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); +- ret = -1; + goto fail; + } + +@@ -816,7 +815,6 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev, + ret = rtw89_h2c_tx(rtwdev, skb, true); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); +- ret = -1; + goto fail; + } + +diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c +index 9e2328db186560..91f0895d9f5404 100644 +--- a/drivers/net/wireless/realtek/rtw89/regd.c ++++ b/drivers/net/wireless/realtek/rtw89/regd.c +@@ -451,6 +451,7 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct rtw89_dev *rtwdev = hw->priv; + ++ wiphy_lock(wiphy); + mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); + +@@ -468,6 +469,7 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request + + exit: + mutex_unlock(&rtwdev->mutex); ++ wiphy_unlock(wiphy); + } + + static void __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) +diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c +index 01b17b8f4ff9dc..45165cf3e824e6 100644 +--- a/drivers/net/wireless/realtek/rtw89/ser.c ++++ b/drivers/net/wireless/realtek/rtw89/ser.c +@@ -156,9 +156,11 @@ static void ser_state_run(struct rtw89_ser *ser, u8 evt) + rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s receive %s\n", + ser_st_name(ser), ser_ev_name(ser, evt)); + ++ wiphy_lock(rtwdev->hw->wiphy); + mutex_lock(&rtwdev->mutex); + rtw89_leave_lps(rtwdev); + mutex_unlock(&rtwdev->mutex); ++ wiphy_unlock(rtwdev->hw->wiphy); + + ser->st_tbl[ser->state].st_func(ser, evt); + } +@@ -676,9 +678,11 @@ static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt) + + switch (evt) { + case SER_EV_STATE_IN: ++ wiphy_lock(rtwdev->hw->wiphy); + mutex_lock(&rtwdev->mutex); + ser_l2_reset_st_pre_hdl(ser); + mutex_unlock(&rtwdev->mutex); ++ wiphy_unlock(rtwdev->hw->wiphy); + + ieee80211_restart_hw(rtwdev->hw); + ser_set_alarm(ser, SER_RECFG_TIMEOUT, SER_EV_L2_RECFG_TIMEOUT); +diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c +index 082253a3a95607..04f4a049599a1a 100644 +--- a/drivers/nvdimm/label.c ++++ b/drivers/nvdimm/label.c +@@ -442,7 +442,8 @@ int nd_label_data_init(struct nvdimm_drvdata *ndd) + if (ndd->data) + return 0; + +- if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0) { ++ if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0 || ++ ndd->nsarea.config_size == 0) { + dev_dbg(ndd->dev, "failed to init config data area: (%u:%u)\n", + ndd->nsarea.max_xfer, ndd->nsarea.config_size); + return -ENXIO; +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 1e5c8220e365ca..97ab91a479d112 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3429,6 +3429,9 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1217, 0x8760), /* O2 Micro 64GB Steam Deck */ + .driver_data = NVME_QUIRK_DMAPOOL_ALIGN_512, }, ++ { PCI_DEVICE(0x126f, 0x1001), /* Silicon Motion generic */ ++ .driver_data = NVME_QUIRK_NO_DEEPEST_PS | ++ NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x126f, 0x2262), /* Silicon Motion generic */ + .driver_data = NVME_QUIRK_NO_DEEPEST_PS | + NVME_QUIRK_BOGUS_NID, }, +@@ -3452,6 +3455,9 @@ static const struct pci_device_id nvme_id_table[] = { + NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x15b7, 0x5008), /* Sandisk SN530 */ + .driver_data = NVME_QUIRK_BROKEN_MSI }, ++ { PCI_DEVICE(0x15b7, 0x5009), /* Sandisk SN550 */ ++ .driver_data = NVME_QUIRK_BROKEN_MSI | ++ NVME_QUIRK_NO_DEEPEST_PS }, + { PCI_DEVICE(0x1987, 0x5012), /* Phison E12 */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1987, 0x5016), /* Phison E16 */ +@@ -3535,6 +3541,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(0x1e49, 0x0041), /* ZHITAI TiPro7000 NVMe SSD */ + .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, ++ { PCI_DEVICE(0x025e, 0xf1ac), /* SOLIDIGM P44 pro SSDPFKKW020X7 */ ++ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(0xc0a9, 0x540a), /* Crucial P2 */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1d97, 0x2263), /* Lexar NM610 */ +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index a0af659a4c4a21..6a539c3b8b530e 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -1456,6 +1456,9 @@ static void nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue) + { + struct socket *sock = queue->sock; + ++ if (!queue->state_change) ++ return; ++ + write_lock_bh(&sock->sk->sk_callback_lock); + sock->sk->sk_data_ready = queue->data_ready; + sock->sk->sk_state_change = queue->state_change; +diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c +index 3ea94bc26e8003..dd00cc09ae5ec5 100644 +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -456,9 +456,11 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, + cell->nbits = info->nbits; + cell->np = info->np; + +- if (cell->nbits) ++ if (cell->nbits) { + cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, + BITS_PER_BYTE); ++ cell->raw_len = ALIGN(cell->bytes, nvmem->word_size); ++ } + + if (!IS_ALIGNED(cell->offset, nvmem->stride)) { + dev_err(&nvmem->dev, +@@ -467,6 +469,18 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, + return -EINVAL; + } + ++ if (!IS_ALIGNED(cell->raw_len, nvmem->word_size)) { ++ dev_err(&nvmem->dev, ++ "cell %s raw len %zd unaligned to nvmem word size %d\n", ++ cell->name ?: "", cell->raw_len, ++ nvmem->word_size); ++ ++ if (info->raw_len) ++ return -EINVAL; ++ ++ cell->raw_len = ALIGN(cell->raw_len, nvmem->word_size); ++ } ++ + return 0; + } + +diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c +index 6c554040c6e67d..7b0621fdbc82e2 100644 +--- a/drivers/nvmem/qfprom.c ++++ b/drivers/nvmem/qfprom.c +@@ -321,19 +321,32 @@ static int qfprom_reg_read(void *context, + unsigned int reg, void *_val, size_t bytes) + { + struct qfprom_priv *priv = context; +- u8 *val = _val; +- int i = 0, words = bytes; ++ u32 *val = _val; + void __iomem *base = priv->qfpcorrected; ++ int words = DIV_ROUND_UP(bytes, sizeof(u32)); ++ int i; + + if (read_raw_data && priv->qfpraw) + base = priv->qfpraw; + +- while (words--) +- *val++ = readb(base + reg + i++); ++ for (i = 0; i < words; i++) ++ *val++ = readl(base + reg + i * sizeof(u32)); + + return 0; + } + ++/* Align reads to word boundary */ ++static void qfprom_fixup_dt_cell_info(struct nvmem_device *nvmem, ++ struct nvmem_cell_info *cell) ++{ ++ unsigned int byte_offset = cell->offset % sizeof(u32); ++ ++ cell->bit_offset += byte_offset * BITS_PER_BYTE; ++ cell->offset -= byte_offset; ++ if (byte_offset && !cell->nbits) ++ cell->nbits = cell->bytes * BITS_PER_BYTE; ++} ++ + static void qfprom_runtime_disable(void *data) + { + pm_runtime_disable(data); +@@ -358,10 +371,11 @@ static int qfprom_probe(struct platform_device *pdev) + struct nvmem_config econfig = { + .name = "qfprom", + .add_legacy_fixed_of_cells = true, +- .stride = 1, +- .word_size = 1, ++ .stride = 4, ++ .word_size = 4, + .id = NVMEM_DEVID_AUTO, + .reg_read = qfprom_reg_read, ++ .fixup_dt_cell_info = qfprom_fixup_dt_cell_info, + }; + struct device *dev = &pdev->dev; + struct resource *res; +diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c +index 7107d68a2f8c75..c6684ab14e742e 100644 +--- a/drivers/nvmem/rockchip-otp.c ++++ b/drivers/nvmem/rockchip-otp.c +@@ -59,7 +59,6 @@ + #define RK3588_OTPC_AUTO_EN 0x08 + #define RK3588_OTPC_INT_ST 0x84 + #define RK3588_OTPC_DOUT0 0x20 +-#define RK3588_NO_SECURE_OFFSET 0x300 + #define RK3588_NBYTES 4 + #define RK3588_BURST_NUM 1 + #define RK3588_BURST_SHIFT 8 +@@ -69,6 +68,7 @@ + + struct rockchip_data { + int size; ++ int read_offset; + const char * const *clks; + int num_clks; + nvmem_reg_read_t reg_read; +@@ -196,7 +196,7 @@ static int rk3588_otp_read(void *context, unsigned int offset, + addr_start = round_down(offset, RK3588_NBYTES) / RK3588_NBYTES; + addr_end = round_up(offset + bytes, RK3588_NBYTES) / RK3588_NBYTES; + addr_len = addr_end - addr_start; +- addr_start += RK3588_NO_SECURE_OFFSET; ++ addr_start += otp->data->read_offset / RK3588_NBYTES; + + buf = kzalloc(array_size(addr_len, RK3588_NBYTES), GFP_KERNEL); + if (!buf) +@@ -273,12 +273,21 @@ static const struct rockchip_data px30_data = { + .reg_read = px30_otp_read, + }; + ++static const struct rockchip_data rk3576_data = { ++ .size = 0x100, ++ .read_offset = 0x700, ++ .clks = px30_otp_clocks, ++ .num_clks = ARRAY_SIZE(px30_otp_clocks), ++ .reg_read = rk3588_otp_read, ++}; ++ + static const char * const rk3588_otp_clocks[] = { + "otp", "apb_pclk", "phy", "arb", + }; + + static const struct rockchip_data rk3588_data = { + .size = 0x400, ++ .read_offset = 0xc00, + .clks = rk3588_otp_clocks, + .num_clks = ARRAY_SIZE(rk3588_otp_clocks), + .reg_read = rk3588_otp_read, +@@ -293,6 +302,10 @@ static const struct of_device_id rockchip_otp_match[] = { + .compatible = "rockchip,rk3308-otp", + .data = &px30_data, + }, ++ { ++ .compatible = "rockchip,rk3576-otp", ++ .data = &rk3576_data, ++ }, + { + .compatible = "rockchip,rk3588-otp", + .data = &rk3588_data, +diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig +index e9ae66cc4189b1..a3927daebeb024 100644 +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -180,6 +180,12 @@ config PCI_P2PDMA + P2P DMA transactions must be between devices behind the same root + port. + ++ Enabling this option will reduce the entropy of x86 KASLR memory ++ regions. For example - on a 46 bit system, the entropy goes down ++ from 16 bits to 15 bits. The actual reduction in entropy depends ++ on the physical address bits, on processor features, kernel config ++ (5 level page table) and physical memory present on the system. ++ + If unsure, say N. + + config PCI_LABEL +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index f2e5feba552678..26ad643fb42484 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -281,7 +281,7 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr, + u32 index; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + +- for (index = 0; index < pci->num_ob_windows; index++) { ++ for_each_set_bit(index, ep->ob_window_map, pci->num_ob_windows) { + if (ep->outbound_addr[index] != addr) + continue; + *atu_index = index; +diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c +index 940af934ce1bb8..9bcf4c68058eb3 100644 +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -284,8 +284,8 @@ static int brcm_pcie_encode_ibar_size(u64 size) + if (log2_in >= 12 && log2_in <= 15) + /* Covers 4KB to 32KB (inclusive) */ + return (log2_in - 12) + 0x1c; +- else if (log2_in >= 16 && log2_in <= 35) +- /* Covers 64KB to 32GB, (inclusive) */ ++ else if (log2_in >= 16 && log2_in <= 36) ++ /* Covers 64KB to 64GB, (inclusive) */ + return log2_in - 15; + /* Something is awry so disable */ + return 0; +@@ -1632,3 +1632,4 @@ module_platform_driver(brcm_pcie_driver); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Broadcom STB PCIe RC driver"); + MODULE_AUTHOR("Broadcom"); ++MODULE_SOFTDEP("pre: irq_bcm2712_mip"); +diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c +index dfa222e02c4da9..ad82feff0405ee 100644 +--- a/drivers/pci/controller/vmd.c ++++ b/drivers/pci/controller/vmd.c +@@ -17,6 +17,8 @@ + #include + #include + ++#include ++ + #include + + #define VMD_CFGBAR 0 +@@ -981,6 +983,24 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) + struct vmd_dev *vmd; + int err; + ++ if (xen_domain()) { ++ /* ++ * Xen doesn't have knowledge about devices in the VMD bus ++ * because the config space of devices behind the VMD bridge is ++ * not known to Xen, and hence Xen cannot discover or configure ++ * them in any way. ++ * ++ * Bypass of MSI remapping won't work in that case as direct ++ * write by Linux to the MSI entries won't result in functional ++ * interrupts, as Xen is the entity that manages the host ++ * interrupt controller and must configure interrupts. However ++ * multiplexing of interrupts by the VMD bridge will work under ++ * Xen, so force the usage of that mode which must always be ++ * supported by VMD bridges. ++ */ ++ features &= ~VMD_FEAT_CAN_BYPASS_MSI_REMAP; ++ } ++ + if (resource_size(&dev->resource[VMD_CFGBAR]) < (1 << 20)) + return -ENOMEM; + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index fba402f4f6330d..3f40be417856e0 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -802,11 +802,9 @@ static resource_size_t calculate_iosize(resource_size_t size, + size = (size & 0xff) + ((size & ~0xffUL) << 2); + #endif + size = size + size1; +- if (size < old_size) +- size = old_size; + +- size = ALIGN(max(size, add_size) + children_add_size, align); +- return size; ++ size = max(size, add_size) + children_add_size; ++ return ALIGN(max(size, old_size), align); + } + + static resource_size_t calculate_memsize(resource_size_t size, +diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c +index 7bd1733d797703..77aa37de59880f 100644 +--- a/drivers/perf/arm-cmn.c ++++ b/drivers/perf/arm-cmn.c +@@ -684,8 +684,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj, + + if ((chan == 5 && cmn->rsp_vc_num < 2) || + (chan == 6 && cmn->dat_vc_num < 2) || +- (chan == 7 && cmn->snp_vc_num < 2) || +- (chan == 8 && cmn->req_vc_num < 2)) ++ (chan == 7 && cmn->req_vc_num < 2) || ++ (chan == 8 && cmn->snp_vc_num < 2)) + return 0; + } + +@@ -841,8 +841,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj, + _CMN_EVENT_XP(pub_##_name, (_event) | (4 << 5)), \ + _CMN_EVENT_XP(rsp2_##_name, (_event) | (5 << 5)), \ + _CMN_EVENT_XP(dat2_##_name, (_event) | (6 << 5)), \ +- _CMN_EVENT_XP(snp2_##_name, (_event) | (7 << 5)), \ +- _CMN_EVENT_XP(req2_##_name, (_event) | (8 << 5)) ++ _CMN_EVENT_XP(req2_##_name, (_event) | (7 << 5)), \ ++ _CMN_EVENT_XP(snp2_##_name, (_event) | (8 << 5)) + + #define CMN_EVENT_XP_DAT(_name, _event) \ + _CMN_EVENT_XP_PORT(dat_##_name, (_event) | (3 << 5)), \ +@@ -2443,6 +2443,7 @@ static int arm_cmn_probe(struct platform_device *pdev) + + cmn->dev = &pdev->dev; + cmn->part = (unsigned long)device_get_match_data(cmn->dev); ++ cmn->cpu = cpumask_local_spread(0, dev_to_node(cmn->dev)); + platform_set_drvdata(pdev, cmn); + + if (cmn->part == PART_CMN600 && has_acpi_companion(cmn->dev)) { +@@ -2470,7 +2471,6 @@ static int arm_cmn_probe(struct platform_device *pdev) + if (err) + return err; + +- cmn->cpu = cpumask_local_spread(0, dev_to_node(cmn->dev)); + cmn->pmu = (struct pmu) { + .module = THIS_MODULE, + .attr_groups = arm_cmn_attr_groups, +diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c +index 0e8f54168cb641..0858e6096453ef 100644 +--- a/drivers/perf/arm_pmuv3.c ++++ b/drivers/perf/arm_pmuv3.c +@@ -751,10 +751,10 @@ static void armv8pmu_start(struct arm_pmu *cpu_pmu) + else + armv8pmu_disable_user_access(); + ++ kvm_vcpu_pmu_resync_el0(); ++ + /* Enable all counters */ + armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E); +- +- kvm_vcpu_pmu_resync_el0(); + } + + static void armv8pmu_stop(struct arm_pmu *cpu_pmu) +diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c +index a892e1d7e2d024..9417372a015547 100644 +--- a/drivers/phy/phy-core.c ++++ b/drivers/phy/phy-core.c +@@ -400,13 +400,14 @@ EXPORT_SYMBOL_GPL(phy_power_off); + + int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode) + { +- int ret; ++ int ret = 0; + +- if (!phy || !phy->ops->set_mode) ++ if (!phy) + return 0; + + mutex_lock(&phy->mutex); +- ret = phy->ops->set_mode(phy, mode, submode); ++ if (phy->ops->set_mode) ++ ret = phy->ops->set_mode(phy, mode, submode); + if (!ret) + phy->attrs.mode = mode; + mutex_unlock(&phy->mutex); +diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +index aa578be2bcb6df..9a6391361a0bed 100644 +--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c ++++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c +@@ -9,6 +9,7 @@ + * Copyright (C) 2014 Cogent Embedded, Inc. + */ + ++#include + #include + #include + #include +@@ -19,12 +20,14 @@ + #include + #include + #include ++#include + #include + #include + #include + + /******* USB2.0 Host registers (original offset is +0x200) *******/ + #define USB2_INT_ENABLE 0x000 ++#define USB2_AHB_BUS_CTR 0x008 + #define USB2_USBCTR 0x00c + #define USB2_SPD_RSM_TIMSET 0x10c + #define USB2_OC_TIMSET 0x110 +@@ -40,6 +43,10 @@ + #define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) /* For EHCI */ + #define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) /* For OHCI */ + ++/* AHB_BUS_CTR */ ++#define USB2_AHB_BUS_CTR_MBL_MASK GENMASK(1, 0) ++#define USB2_AHB_BUS_CTR_MBL_INCR4 2 ++ + /* USBCTR */ + #define USB2_USBCTR_DIRPD BIT(2) + #define USB2_USBCTR_PLL_RST BIT(1) +@@ -110,10 +117,10 @@ struct rcar_gen3_chan { + struct extcon_dev *extcon; + struct rcar_gen3_phy rphys[NUM_OF_PHYS]; + struct regulator *vbus; ++ struct reset_control *rstc; + struct work_struct work; +- struct mutex lock; /* protects rphys[...].powered */ ++ spinlock_t lock; /* protects access to hardware and driver data structure. */ + enum usb_dr_mode dr_mode; +- int irq; + u32 obint_enable_bits; + bool extcon_host; + bool is_otg_channel; +@@ -124,6 +131,7 @@ struct rcar_gen3_chan { + struct rcar_gen3_phy_drv_data { + const struct phy_ops *phy_usb2_ops; + bool no_adp_ctrl; ++ bool init_bus; + }; + + /* +@@ -338,6 +346,8 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, + bool is_b_device; + enum phy_mode cur_mode, new_mode; + ++ guard(spinlock_irqsave)(&ch->lock); ++ + if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) + return -EIO; + +@@ -405,7 +415,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + } +- msleep(20); ++ mdelay(20); + + writel(0xffffffff, usb2_base + USB2_OBINTSTA); + writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN); +@@ -417,16 +427,27 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) + { + struct rcar_gen3_chan *ch = _ch; + void __iomem *usb2_base = ch->base; +- u32 status = readl(usb2_base + USB2_OBINTSTA); ++ struct device *dev = ch->dev; + irqreturn_t ret = IRQ_NONE; ++ u32 status; ++ ++ pm_runtime_get_noresume(dev); ++ ++ if (pm_runtime_suspended(dev)) ++ goto rpm_put; + +- if (status & ch->obint_enable_bits) { +- dev_vdbg(ch->dev, "%s: %08x\n", __func__, status); +- writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); +- rcar_gen3_device_recognition(ch); +- ret = IRQ_HANDLED; ++ scoped_guard(spinlock, &ch->lock) { ++ status = readl(usb2_base + USB2_OBINTSTA); ++ if (status & ch->obint_enable_bits) { ++ dev_vdbg(dev, "%s: %08x\n", __func__, status); ++ writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); ++ rcar_gen3_device_recognition(ch); ++ ret = IRQ_HANDLED; ++ } + } + ++rpm_put: ++ pm_runtime_put_noidle(dev); + return ret; + } + +@@ -436,17 +457,8 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) + struct rcar_gen3_chan *channel = rphy->ch; + void __iomem *usb2_base = channel->base; + u32 val; +- int ret; + +- if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) { +- INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); +- ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq, +- IRQF_SHARED, dev_name(channel->dev), channel); +- if (ret < 0) { +- dev_err(channel->dev, "No irq handler (%d)\n", channel->irq); +- return ret; +- } +- } ++ guard(spinlock_irqsave)(&channel->lock); + + /* Initialize USB2 part */ + val = readl(usb2_base + USB2_INT_ENABLE); +@@ -474,6 +486,8 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) + void __iomem *usb2_base = channel->base; + u32 val; + ++ guard(spinlock_irqsave)(&channel->lock); ++ + rphy->initialized = false; + + val = readl(usb2_base + USB2_INT_ENABLE); +@@ -482,9 +496,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) + val &= ~USB2_INT_ENABLE_UCOM_INTEN; + writel(val, usb2_base + USB2_INT_ENABLE); + +- if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel)) +- free_irq(channel->irq, channel); +- + return 0; + } + +@@ -496,16 +507,17 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) + u32 val; + int ret = 0; + +- mutex_lock(&channel->lock); +- if (!rcar_gen3_are_all_rphys_power_off(channel)) +- goto out; +- + if (channel->vbus) { + ret = regulator_enable(channel->vbus); + if (ret) +- goto out; ++ return ret; + } + ++ guard(spinlock_irqsave)(&channel->lock); ++ ++ if (!rcar_gen3_are_all_rphys_power_off(channel)) ++ goto out; ++ + val = readl(usb2_base + USB2_USBCTR); + val |= USB2_USBCTR_PLL_RST; + writel(val, usb2_base + USB2_USBCTR); +@@ -515,7 +527,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) + out: + /* The powered flag should be set for any other phys anyway */ + rphy->powered = true; +- mutex_unlock(&channel->lock); + + return 0; + } +@@ -526,18 +537,20 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p) + struct rcar_gen3_chan *channel = rphy->ch; + int ret = 0; + +- mutex_lock(&channel->lock); +- rphy->powered = false; ++ scoped_guard(spinlock_irqsave, &channel->lock) { ++ rphy->powered = false; + +- if (!rcar_gen3_are_all_rphys_power_off(channel)) +- goto out; ++ if (rcar_gen3_are_all_rphys_power_off(channel)) { ++ u32 val = readl(channel->base + USB2_USBCTR); ++ ++ val |= USB2_USBCTR_PLL_RST; ++ writel(val, channel->base + USB2_USBCTR); ++ } ++ } + + if (channel->vbus) + ret = regulator_disable(channel->vbus); + +-out: +- mutex_unlock(&channel->lock); +- + return ret; + } + +@@ -645,13 +658,42 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) + return candidate; + } + ++static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) ++{ ++ struct device *dev = channel->dev; ++ int ret; ++ u32 val; ++ ++ channel->rstc = devm_reset_control_array_get_shared(dev); ++ if (IS_ERR(channel->rstc)) ++ return PTR_ERR(channel->rstc); ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret) ++ return ret; ++ ++ ret = reset_control_deassert(channel->rstc); ++ if (ret) ++ goto rpm_put; ++ ++ val = readl(channel->base + USB2_AHB_BUS_CTR); ++ val &= ~USB2_AHB_BUS_CTR_MBL_MASK; ++ val |= USB2_AHB_BUS_CTR_MBL_INCR4; ++ writel(val, channel->base + USB2_AHB_BUS_CTR); ++ ++rpm_put: ++ pm_runtime_put(dev); ++ ++ return ret; ++} ++ + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + { + const struct rcar_gen3_phy_drv_data *phy_data; + struct device *dev = &pdev->dev; + struct rcar_gen3_chan *channel; + struct phy_provider *provider; +- int ret = 0, i; ++ int ret = 0, i, irq; + + if (!dev->of_node) { + dev_err(dev, "This driver needs device tree\n"); +@@ -667,8 +709,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + return PTR_ERR(channel->base); + + channel->obint_enable_bits = USB2_OBINT_BITS; +- /* get irq number here and request_irq for OTG in phy_init */ +- channel->irq = platform_get_irq_optional(pdev, 0); + channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); + if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { + channel->is_otg_channel = true; +@@ -698,11 +738,20 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + goto error; + } + ++ platform_set_drvdata(pdev, channel); ++ channel->dev = dev; ++ ++ if (phy_data->init_bus) { ++ ret = rcar_gen3_phy_usb2_init_bus(channel); ++ if (ret) ++ goto error; ++ } ++ + channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl; + if (phy_data->no_adp_ctrl) + channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; + +- mutex_init(&channel->lock); ++ spin_lock_init(&channel->lock); + for (i = 0; i < NUM_OF_PHYS; i++) { + channel->rphys[i].phy = devm_phy_create(dev, NULL, + phy_data->phy_usb2_ops); +@@ -725,8 +774,19 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) + channel->vbus = NULL; + } + +- platform_set_drvdata(pdev, channel); +- channel->dev = dev; ++ irq = platform_get_irq_optional(pdev, 0); ++ if (irq < 0 && irq != -ENXIO) { ++ ret = irq; ++ goto error; ++ } else if (irq > 0) { ++ INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); ++ ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, ++ IRQF_SHARED, dev_name(dev), channel); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request irq (%d)\n", irq); ++ goto error; ++ } ++ } + + provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate); + if (IS_ERR(provider)) { +@@ -754,6 +814,7 @@ static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev) + if (channel->is_otg_channel) + device_remove_file(&pdev->dev, &dev_attr_role); + ++ reset_control_assert(channel->rstc); + pm_runtime_disable(&pdev->dev); + }; + +diff --git a/drivers/phy/starfive/phy-jh7110-usb.c b/drivers/phy/starfive/phy-jh7110-usb.c +index 633912f8a05d04..bf52b41110db8e 100644 +--- a/drivers/phy/starfive/phy-jh7110-usb.c ++++ b/drivers/phy/starfive/phy-jh7110-usb.c +@@ -16,6 +16,8 @@ + #include + + #define USB_125M_CLK_RATE 125000000 ++#define USB_CLK_MODE_OFF 0x0 ++#define USB_CLK_MODE_RX_NORMAL_PWR BIT(1) + #define USB_LS_KEEPALIVE_OFF 0x4 + #define USB_LS_KEEPALIVE_ENABLE BIT(4) + +@@ -68,6 +70,7 @@ static int jh7110_usb2_phy_init(struct phy *_phy) + { + struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); + int ret; ++ unsigned int val; + + ret = clk_set_rate(phy->usb_125m_clk, USB_125M_CLK_RATE); + if (ret) +@@ -77,6 +80,10 @@ static int jh7110_usb2_phy_init(struct phy *_phy) + if (ret) + return ret; + ++ val = readl(phy->regs + USB_CLK_MODE_OFF); ++ val |= USB_CLK_MODE_RX_NORMAL_PWR; ++ writel(val, phy->regs + USB_CLK_MODE_OFF); ++ + return 0; + } + +diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +index cf6efa9c0364a1..a039b490cdb8e6 100644 +--- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +@@ -72,7 +72,7 @@ static enum bcm281xx_pin_type hdmi_pin = BCM281XX_PIN_TYPE_HDMI; + struct bcm281xx_pin_function { + const char *name; + const char * const *groups; +- const unsigned ngroups; ++ const unsigned int ngroups; + }; + + /* +@@ -84,10 +84,10 @@ struct bcm281xx_pinctrl_data { + + /* List of all pins */ + const struct pinctrl_pin_desc *pins; +- const unsigned npins; ++ const unsigned int npins; + + const struct bcm281xx_pin_function *functions; +- const unsigned nfunctions; ++ const unsigned int nfunctions; + + struct regmap *regmap; + }; +@@ -941,7 +941,7 @@ static struct bcm281xx_pinctrl_data bcm281xx_pinctrl = { + }; + + static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, +- unsigned pin) ++ unsigned int pin) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -985,7 +985,7 @@ static int bcm281xx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) + } + + static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, +- unsigned group) ++ unsigned int group) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -993,9 +993,9 @@ static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, +- unsigned group, ++ unsigned int group, + const unsigned **pins, +- unsigned *num_pins) ++ unsigned int *num_pins) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -1007,7 +1007,7 @@ static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + + static void bcm281xx_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, +- unsigned offset) ++ unsigned int offset) + { + seq_printf(s, " %s", dev_name(pctldev->dev)); + } +@@ -1029,7 +1029,7 @@ static int bcm281xx_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev) + } + + static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, +- unsigned function) ++ unsigned int function) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -1037,9 +1037,9 @@ static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, +- unsigned function, ++ unsigned int function, + const char * const **groups, +- unsigned * const num_groups) ++ unsigned int * const num_groups) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + +@@ -1050,8 +1050,8 @@ static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev, +- unsigned function, +- unsigned group) ++ unsigned int function, ++ unsigned int group) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + const struct bcm281xx_pin_function *f = &pdata->functions[function]; +@@ -1082,7 +1082,7 @@ static const struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = { + }; + + static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *config) + { + return -ENOTSUPP; +@@ -1091,9 +1091,9 @@ static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, + + /* Goes through the configs and update register val/mask */ + static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs, ++ unsigned int num_configs, + u32 *val, + u32 *mask) + { +@@ -1207,9 +1207,9 @@ static const u16 bcm281xx_pullup_map[] = { + + /* Goes through the configs and update register val/mask */ + static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs, ++ unsigned int num_configs, + u32 *val, + u32 *mask) + { +@@ -1277,9 +1277,9 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, + + /* Goes through the configs and update register val/mask */ + static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs, ++ unsigned int num_configs, + u32 *val, + u32 *mask) + { +@@ -1321,9 +1321,9 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, + } + + static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, +- unsigned pin, ++ unsigned int pin, + unsigned long *configs, +- unsigned num_configs) ++ unsigned int num_configs) + { + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + enum bcm281xx_pin_type pin_type; +diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c +index 5ee746cb81f591..6520b88db1105b 100644 +--- a/drivers/pinctrl/devicetree.c ++++ b/drivers/pinctrl/devicetree.c +@@ -143,10 +143,14 @@ static int dt_to_map_one_config(struct pinctrl *p, + pctldev = get_pinctrl_dev_from_of_node(np_pctldev); + if (pctldev) + break; +- /* Do not defer probing of hogs (circular loop) */ ++ /* ++ * Do not defer probing of hogs (circular loop) ++ * ++ * Return 1 to let the caller catch the case. ++ */ + if (np_pctldev == p->dev->of_node) { + of_node_put(np_pctldev); +- return -ENODEV; ++ return 1; + } + } + of_node_put(np_pctldev); +@@ -265,6 +269,8 @@ int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev) + ret = dt_to_map_one_config(p, pctldev, statename, + np_config); + of_node_put(np_config); ++ if (ret == 1) ++ continue; + if (ret < 0) + goto err; + } +diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c +index 524424ee6c4e71..5cc00fdc48d840 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson.c ++++ b/drivers/pinctrl/meson/pinctrl-meson.c +@@ -486,7 +486,7 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + if (meson_pinconf_get_pull(pc, pin) == param) +- arg = 1; ++ arg = 60000; + else + return -EINVAL; + break; +diff --git a/drivers/pinctrl/qcom/pinctrl-apq8064.c b/drivers/pinctrl/qcom/pinctrl-apq8064.c +index 20c3b902504451..a18df416229993 100644 +--- a/drivers/pinctrl/qcom/pinctrl-apq8064.c ++++ b/drivers/pinctrl/qcom/pinctrl-apq8064.c +@@ -629,7 +629,7 @@ static struct platform_driver apq8064_pinctrl_driver = { + .of_match_table = apq8064_pinctrl_of_match, + }, + .probe = apq8064_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init apq8064_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-apq8084.c b/drivers/pinctrl/qcom/pinctrl-apq8084.c +index 3fc0a40762b631..afada80e52a235 100644 +--- a/drivers/pinctrl/qcom/pinctrl-apq8084.c ++++ b/drivers/pinctrl/qcom/pinctrl-apq8084.c +@@ -1207,7 +1207,7 @@ static struct platform_driver apq8084_pinctrl_driver = { + .of_match_table = apq8084_pinctrl_of_match, + }, + .probe = apq8084_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init apq8084_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c +index 1f7944dd829d1b..cb13576ad6cfb4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c +@@ -710,7 +710,7 @@ static struct platform_driver ipq4019_pinctrl_driver = { + .of_match_table = ipq4019_pinctrl_of_match, + }, + .probe = ipq4019_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq4019_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c +index e2951f81c3eeb3..68f65b57003e91 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c +@@ -754,7 +754,7 @@ static struct platform_driver ipq5018_pinctrl_driver = { + .of_match_table = ipq5018_pinctrl_of_match, + }, + .probe = ipq5018_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq5018_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5332.c b/drivers/pinctrl/qcom/pinctrl-ipq5332.c +index 625f8014051f6a..88217511897088 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq5332.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq5332.c +@@ -834,7 +834,7 @@ static struct platform_driver ipq5332_pinctrl_driver = { + .of_match_table = ipq5332_pinctrl_of_match, + }, + .probe = ipq5332_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq5332_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq6018.c b/drivers/pinctrl/qcom/pinctrl-ipq6018.c +index 0ad08647dbcdf0..ac330d8712b5cb 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq6018.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq6018.c +@@ -1080,7 +1080,7 @@ static struct platform_driver ipq6018_pinctrl_driver = { + .of_match_table = ipq6018_pinctrl_of_match, + }, + .probe = ipq6018_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq6018_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c +index e2bb94e86aef6e..e10e1bc4c91131 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c +@@ -631,7 +631,7 @@ static struct platform_driver ipq8064_pinctrl_driver = { + .of_match_table = ipq8064_pinctrl_of_match, + }, + .probe = ipq8064_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq8064_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8074.c b/drivers/pinctrl/qcom/pinctrl-ipq8074.c +index 337f3a1c92c192..fee32c1d1d3e9a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq8074.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq8074.c +@@ -1041,7 +1041,7 @@ static struct platform_driver ipq8074_pinctrl_driver = { + .of_match_table = ipq8074_pinctrl_of_match, + }, + .probe = ipq8074_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq8074_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-ipq9574.c b/drivers/pinctrl/qcom/pinctrl-ipq9574.c +index e2491617b2364a..20ab59cb621bc3 100644 +--- a/drivers/pinctrl/qcom/pinctrl-ipq9574.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq9574.c +@@ -799,7 +799,7 @@ static struct platform_driver ipq9574_pinctrl_driver = { + .of_match_table = ipq9574_pinctrl_of_match, + }, + .probe = ipq9574_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init ipq9574_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9607.c b/drivers/pinctrl/qcom/pinctrl-mdm9607.c +index e7cd3ef1cf3e81..415d24e16267d0 100644 +--- a/drivers/pinctrl/qcom/pinctrl-mdm9607.c ++++ b/drivers/pinctrl/qcom/pinctrl-mdm9607.c +@@ -1059,7 +1059,7 @@ static struct platform_driver mdm9607_pinctrl_driver = { + .of_match_table = mdm9607_pinctrl_of_match, + }, + .probe = mdm9607_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init mdm9607_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9615.c b/drivers/pinctrl/qcom/pinctrl-mdm9615.c +index 0a2ae383d3d57b..3f2eafea0b2467 100644 +--- a/drivers/pinctrl/qcom/pinctrl-mdm9615.c ++++ b/drivers/pinctrl/qcom/pinctrl-mdm9615.c +@@ -446,7 +446,7 @@ static struct platform_driver mdm9615_pinctrl_driver = { + .of_match_table = mdm9615_pinctrl_of_match, + }, + .probe = mdm9615_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init mdm9615_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c +index b252fc22f64e6b..ed70767ca0f0c9 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -43,7 +43,6 @@ + * @pctrl: pinctrl handle. + * @chip: gpiochip handle. + * @desc: pin controller descriptor +- * @restart_nb: restart notifier block. + * @irq: parent irq for the TLMM irq_chip. + * @intr_target_use_scm: route irq to application cpu using scm calls + * @lock: Spinlock to protect register resources as well +@@ -63,7 +62,6 @@ struct msm_pinctrl { + struct pinctrl_dev *pctrl; + struct gpio_chip chip; + struct pinctrl_desc desc; +- struct notifier_block restart_nb; + + int irq; + +@@ -1424,10 +1422,9 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) + return 0; + } + +-static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, +- void *data) ++static int msm_ps_hold_restart(struct sys_off_data *data) + { +- struct msm_pinctrl *pctrl = container_of(nb, struct msm_pinctrl, restart_nb); ++ struct msm_pinctrl *pctrl = data->cb_data; + + writel(0, pctrl->regs[0] + PS_HOLD_OFFSET); + mdelay(1000); +@@ -1438,7 +1435,11 @@ static struct msm_pinctrl *poweroff_pctrl; + + static void msm_ps_hold_poweroff(void) + { +- msm_ps_hold_restart(&poweroff_pctrl->restart_nb, 0, NULL); ++ struct sys_off_data data = { ++ .cb_data = poweroff_pctrl, ++ }; ++ ++ msm_ps_hold_restart(&data); + } + + static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) +@@ -1448,9 +1449,11 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) + + for (i = 0; i < pctrl->soc->nfunctions; i++) + if (!strcmp(func[i].name, "ps_hold")) { +- pctrl->restart_nb.notifier_call = msm_ps_hold_restart; +- pctrl->restart_nb.priority = 128; +- if (register_restart_handler(&pctrl->restart_nb)) ++ if (devm_register_sys_off_handler(pctrl->dev, ++ SYS_OFF_MODE_RESTART, ++ 128, ++ msm_ps_hold_restart, ++ pctrl)) + dev_err(pctrl->dev, + "failed to setup restart handler.\n"); + poweroff_pctrl = pctrl; +@@ -1547,15 +1550,11 @@ int msm_pinctrl_probe(struct platform_device *pdev, + } + EXPORT_SYMBOL(msm_pinctrl_probe); + +-int msm_pinctrl_remove(struct platform_device *pdev) ++void msm_pinctrl_remove(struct platform_device *pdev) + { + struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); + + gpiochip_remove(&pctrl->chip); +- +- unregister_restart_handler(&pctrl->restart_nb); +- +- return 0; + } + EXPORT_SYMBOL(msm_pinctrl_remove); + +diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h +index 1d2f2e904da190..4968d08a384da9 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm.h ++++ b/drivers/pinctrl/qcom/pinctrl-msm.h +@@ -166,6 +166,6 @@ extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops; + + int msm_pinctrl_probe(struct platform_device *pdev, + const struct msm_pinctrl_soc_data *soc_data); +-int msm_pinctrl_remove(struct platform_device *pdev); ++void msm_pinctrl_remove(struct platform_device *pdev); + + #endif +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8226.c b/drivers/pinctrl/qcom/pinctrl-msm8226.c +index 994619840a706c..90b4004e7faf18 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8226.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8226.c +@@ -638,7 +638,7 @@ static struct platform_driver msm8226_pinctrl_driver = { + .of_match_table = msm8226_pinctrl_of_match, + }, + .probe = msm8226_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8226_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8660.c b/drivers/pinctrl/qcom/pinctrl-msm8660.c +index 999a5f867eb508..dba6d531b4a146 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8660.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8660.c +@@ -981,7 +981,7 @@ static struct platform_driver msm8660_pinctrl_driver = { + .of_match_table = msm8660_pinctrl_of_match, + }, + .probe = msm8660_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8660_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8909.c b/drivers/pinctrl/qcom/pinctrl-msm8909.c +index 756856d20d6b5f..14b17ba9f9061a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8909.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8909.c +@@ -929,7 +929,7 @@ static struct platform_driver msm8909_pinctrl_driver = { + .of_match_table = msm8909_pinctrl_of_match, + }, + .probe = msm8909_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8909_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8916.c b/drivers/pinctrl/qcom/pinctrl-msm8916.c +index cea5c54f92fec1..184dcf8422735b 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8916.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8916.c +@@ -969,7 +969,7 @@ static struct platform_driver msm8916_pinctrl_driver = { + .of_match_table = msm8916_pinctrl_of_match, + }, + .probe = msm8916_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8916_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8953.c b/drivers/pinctrl/qcom/pinctrl-msm8953.c +index 998351bdfee136..c2253821ae8d36 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8953.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8953.c +@@ -1816,7 +1816,7 @@ static struct platform_driver msm8953_pinctrl_driver = { + .of_match_table = msm8953_pinctrl_of_match, + }, + .probe = msm8953_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8953_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8960.c b/drivers/pinctrl/qcom/pinctrl-msm8960.c +index ebe230b3b437cc..6b9148d226e9b8 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8960.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8960.c +@@ -1246,7 +1246,7 @@ static struct platform_driver msm8960_pinctrl_driver = { + .of_match_table = msm8960_pinctrl_of_match, + }, + .probe = msm8960_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8960_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8976.c b/drivers/pinctrl/qcom/pinctrl-msm8976.c +index c30d80e4e98ca6..9a951888e8a1b1 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8976.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8976.c +@@ -1096,7 +1096,7 @@ static struct platform_driver msm8976_pinctrl_driver = { + .of_match_table = msm8976_pinctrl_of_match, + }, + .probe = msm8976_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8976_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8994.c b/drivers/pinctrl/qcom/pinctrl-msm8994.c +index b1a6759ab4a5e7..1ed1dd32d6c795 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8994.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8994.c +@@ -1343,7 +1343,7 @@ static struct platform_driver msm8994_pinctrl_driver = { + .of_match_table = msm8994_pinctrl_of_match, + }, + .probe = msm8994_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8994_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8996.c b/drivers/pinctrl/qcom/pinctrl-msm8996.c +index 46cc0b49dbab52..5f0e7f78fd5178 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8996.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8996.c +@@ -1906,7 +1906,7 @@ static struct platform_driver msm8996_pinctrl_driver = { + .of_match_table = msm8996_pinctrl_of_match, + }, + .probe = msm8996_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8996_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c +index b7cbf32b3125a9..4aaf45e54f3a79 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8998.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c +@@ -1535,7 +1535,7 @@ static struct platform_driver msm8998_pinctrl_driver = { + .of_match_table = msm8998_pinctrl_of_match, + }, + .probe = msm8998_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8998_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-msm8x74.c b/drivers/pinctrl/qcom/pinctrl-msm8x74.c +index d5fe62992849c9..58b4f6f31ae6ae 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm8x74.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm8x74.c +@@ -1071,7 +1071,7 @@ static struct platform_driver msm8x74_pinctrl_driver = { + .of_match_table = msm8x74_pinctrl_of_match, + }, + .probe = msm8x74_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init msm8x74_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qcm2290.c b/drivers/pinctrl/qcom/pinctrl-qcm2290.c +index ba699eac9ee8b2..f5c1c427b44e91 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qcm2290.c ++++ b/drivers/pinctrl/qcom/pinctrl-qcm2290.c +@@ -1113,7 +1113,7 @@ static struct platform_driver qcm2290_pinctrl_driver = { + .of_match_table = qcm2290_pinctrl_of_match, + }, + .probe = qcm2290_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qcm2290_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c +index ae7224012f8aa0..9a875b7dc9989c 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qcs404.c ++++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c +@@ -1644,7 +1644,7 @@ static struct platform_driver qcs404_pinctrl_driver = { + .of_match_table = qcs404_pinctrl_of_match, + }, + .probe = qcs404_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qcs404_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c +index b5808fcfb13cde..4d2f6f495163bc 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c ++++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c +@@ -145,7 +145,7 @@ static struct platform_driver qdf2xxx_pinctrl_driver = { + .acpi_match_table = qdf2xxx_acpi_ids, + }, + .probe = qdf2xxx_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qdf2xxx_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-qdu1000.c b/drivers/pinctrl/qcom/pinctrl-qdu1000.c +index 47bc529ef550d2..da4f940bc8d4e8 100644 +--- a/drivers/pinctrl/qcom/pinctrl-qdu1000.c ++++ b/drivers/pinctrl/qcom/pinctrl-qdu1000.c +@@ -1248,7 +1248,7 @@ static struct platform_driver qdu1000_tlmm_driver = { + .of_match_table = qdu1000_tlmm_of_match, + }, + .probe = qdu1000_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init qdu1000_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c +index 8fdea25d8d67e1..5459c0c681a23f 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sa8775p.c ++++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c +@@ -1530,7 +1530,7 @@ static struct platform_driver sa8775p_pinctrl_driver = { + .of_match_table = sa8775p_pinctrl_of_match, + }, + .probe = sa8775p_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sa8775p_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc7180.c b/drivers/pinctrl/qcom/pinctrl-sc7180.c +index 6eb0c73791c0bc..c27aaa599b917a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc7180.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc7180.c +@@ -1159,7 +1159,7 @@ static struct platform_driver sc7180_pinctrl_driver = { + .of_match_table = sc7180_pinctrl_of_match, + }, + .probe = sc7180_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc7180_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c +index 0c10eeb60b55e7..c2db663e396eb4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc7280.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c +@@ -1505,7 +1505,7 @@ static struct platform_driver sc7280_pinctrl_driver = { + .of_match_table = sc7280_pinctrl_of_match, + }, + .probe = sc7280_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc7280_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc8180x.c b/drivers/pinctrl/qcom/pinctrl-sc8180x.c +index d6a79ad41a40a8..cfa7c8be9770c9 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc8180x.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc8180x.c +@@ -1720,7 +1720,7 @@ static struct platform_driver sc8180x_pinctrl_driver = { + .acpi_match_table = sc8180x_pinctrl_acpi_match, + }, + .probe = sc8180x_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc8180x_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c +index 96f4fb5a5d297f..4b1c49697698de 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c ++++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c +@@ -1926,7 +1926,7 @@ static struct platform_driver sc8280xp_pinctrl_driver = { + .of_match_table = sc8280xp_pinctrl_of_match, + }, + .probe = sc8280xp_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sc8280xp_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c +index c2e0d5c034acf6..b0c29a24b09b5a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdm660.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c +@@ -1428,7 +1428,7 @@ static struct platform_driver sdm660_pinctrl_driver = { + .of_match_table = sdm660_pinctrl_of_match, + }, + .probe = sdm660_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdm660_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c +index cc3cce077de4e6..1e694a966953ac 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdm670.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c +@@ -1318,7 +1318,7 @@ static struct platform_driver sdm670_pinctrl_driver = { + .of_match_table = sdm670_pinctrl_of_match, + }, + .probe = sdm670_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdm670_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c +index cc05c415ed1551..3f3265e0018d66 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c +@@ -1351,7 +1351,7 @@ static struct platform_driver sdm845_pinctrl_driver = { + .acpi_match_table = ACPI_PTR(sdm845_pinctrl_acpi_match), + }, + .probe = sdm845_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdm845_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdx55.c b/drivers/pinctrl/qcom/pinctrl-sdx55.c +index 8826db9d21d04c..c88b8bfcacb6a7 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdx55.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdx55.c +@@ -990,7 +990,7 @@ static struct platform_driver sdx55_pinctrl_driver = { + .of_match_table = sdx55_pinctrl_of_match, + }, + .probe = sdx55_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdx55_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdx65.c b/drivers/pinctrl/qcom/pinctrl-sdx65.c +index f6f319c997fc7a..bd44ec0fcab43c 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdx65.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdx65.c +@@ -939,7 +939,7 @@ static struct platform_driver sdx65_pinctrl_driver = { + .of_match_table = sdx65_pinctrl_of_match, + }, + .probe = sdx65_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdx65_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sdx75.c b/drivers/pinctrl/qcom/pinctrl-sdx75.c +index 3cfe8c7f04df81..396f6fc779a2e5 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sdx75.c ++++ b/drivers/pinctrl/qcom/pinctrl-sdx75.c +@@ -1124,7 +1124,7 @@ static struct platform_driver sdx75_pinctrl_driver = { + .of_match_table = sdx75_pinctrl_of_match, + }, + .probe = sdx75_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sdx75_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115.c b/drivers/pinctrl/qcom/pinctrl-sm6115.c +index 2a06025f488584..87057089b2b649 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6115.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6115.c +@@ -895,7 +895,7 @@ static struct platform_driver sm6115_tlmm_driver = { + .of_match_table = sm6115_tlmm_of_match, + }, + .probe = sm6115_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6115_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6125.c b/drivers/pinctrl/qcom/pinctrl-sm6125.c +index d5e2b896954c22..e07339ba72bcac 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6125.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6125.c +@@ -1249,7 +1249,7 @@ static struct platform_driver sm6125_tlmm_driver = { + .of_match_table = sm6125_tlmm_of_match, + }, + .probe = sm6125_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6125_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350.c b/drivers/pinctrl/qcom/pinctrl-sm6350.c +index f3828c07b13450..4aeb1ba43ee3d4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6350.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6350.c +@@ -1373,7 +1373,7 @@ static struct platform_driver sm6350_tlmm_driver = { + .of_match_table = sm6350_tlmm_of_match, + }, + .probe = sm6350_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6350_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm6375.c b/drivers/pinctrl/qcom/pinctrl-sm6375.c +index c82c8516932ea2..d86630d7125c2a 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm6375.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm6375.c +@@ -1516,7 +1516,7 @@ static struct platform_driver sm6375_tlmm_driver = { + .of_match_table = sm6375_tlmm_of_match, + }, + .probe = sm6375_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm6375_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c +index edb5984cd35190..b9f067de8ef0e4 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm7150.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c +@@ -1254,7 +1254,7 @@ static struct platform_driver sm7150_tlmm_driver = { + .of_match_table = sm7150_tlmm_of_match, + }, + .probe = sm7150_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm7150_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c +index 01aea9c70b7a78..f8f5bee74f1dc0 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8150.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c +@@ -1542,7 +1542,7 @@ static struct platform_driver sm8150_pinctrl_driver = { + .of_match_table = sm8150_pinctrl_of_match, + }, + .probe = sm8150_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8150_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c +index e9961a49ff9811..54fda77bf2968c 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8250.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c +@@ -1351,7 +1351,7 @@ static struct platform_driver sm8250_pinctrl_driver = { + .of_match_table = sm8250_pinctrl_of_match, + }, + .probe = sm8250_pinctrl_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8250_pinctrl_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8350.c b/drivers/pinctrl/qcom/pinctrl-sm8350.c +index 9c69458bd91091..ac7f2820f2cbfb 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8350.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8350.c +@@ -1642,7 +1642,7 @@ static struct platform_driver sm8350_tlmm_driver = { + .of_match_table = sm8350_tlmm_of_match, + }, + .probe = sm8350_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8350_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450.c b/drivers/pinctrl/qcom/pinctrl-sm8450.c +index d11bb1ee9e3d8d..61728671169527 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8450.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8450.c +@@ -1677,7 +1677,7 @@ static struct platform_driver sm8450_tlmm_driver = { + .of_match_table = sm8450_tlmm_of_match, + }, + .probe = sm8450_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8450_tlmm_init(void) +diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c +index 3c847d9cb5d93b..9184e0183755da 100644 +--- a/drivers/pinctrl/qcom/pinctrl-sm8550.c ++++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c +@@ -1762,7 +1762,7 @@ static struct platform_driver sm8550_tlmm_driver = { + .of_match_table = sm8550_tlmm_of_match, + }, + .probe = sm8550_tlmm_probe, +- .remove = msm_pinctrl_remove, ++ .remove_new = msm_pinctrl_remove, + }; + + static int __init sm8550_tlmm_init(void) +diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c +index 7c12a3470642c3..637b89ebe0e455 100644 +--- a/drivers/pinctrl/tegra/pinctrl-tegra.c ++++ b/drivers/pinctrl/tegra/pinctrl-tegra.c +@@ -280,8 +280,8 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev, + return 0; + } + +-static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, +- unsigned int offset) ++static int tegra_pinctrl_get_group_index(struct pinctrl_dev *pctldev, ++ unsigned int offset) + { + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + unsigned int group, num_pins, j; +@@ -294,12 +294,35 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev * + continue; + for (j = 0; j < num_pins; j++) { + if (offset == pins[j]) +- return &pmx->soc->groups[group]; ++ return group; + } + } + +- dev_err(pctldev->dev, "Pingroup not found for pin %u\n", offset); +- return NULL; ++ return -EINVAL; ++} ++ ++static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev, ++ unsigned int offset, ++ int group_index) ++{ ++ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); ++ ++ if (group_index < 0 || group_index >= pmx->soc->ngroups) ++ return NULL; ++ ++ return &pmx->soc->groups[group_index]; ++} ++ ++static struct tegra_pingroup_config *tegra_pinctrl_get_group_config(struct pinctrl_dev *pctldev, ++ unsigned int offset, ++ int group_index) ++{ ++ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); ++ ++ if (group_index < 0) ++ return NULL; ++ ++ return &pmx->pingroup_configs[group_index]; + } + + static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, +@@ -308,12 +331,15 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + { + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tegra_pingroup *group; ++ struct tegra_pingroup_config *config; ++ int group_index; + u32 value; + + if (!pmx->soc->sfsel_in_mux) + return 0; + +- group = tegra_pinctrl_get_group(pctldev, offset); ++ group_index = tegra_pinctrl_get_group_index(pctldev, offset); ++ group = tegra_pinctrl_get_group(pctldev, offset, group_index); + + if (!group) + return -EINVAL; +@@ -321,7 +347,11 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + if (group->mux_reg < 0 || group->sfsel_bit < 0) + return -EINVAL; + ++ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); ++ if (!config) ++ return -EINVAL; + value = pmx_readl(pmx, group->mux_bank, group->mux_reg); ++ config->is_sfsel = (value & BIT(group->sfsel_bit)) != 0; + value &= ~BIT(group->sfsel_bit); + pmx_writel(pmx, value, group->mux_bank, group->mux_reg); + +@@ -334,12 +364,15 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, + { + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tegra_pingroup *group; ++ struct tegra_pingroup_config *config; ++ int group_index; + u32 value; + + if (!pmx->soc->sfsel_in_mux) + return; + +- group = tegra_pinctrl_get_group(pctldev, offset); ++ group_index = tegra_pinctrl_get_group_index(pctldev, offset); ++ group = tegra_pinctrl_get_group(pctldev, offset, group_index); + + if (!group) + return; +@@ -347,8 +380,12 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, + if (group->mux_reg < 0 || group->sfsel_bit < 0) + return; + ++ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index); ++ if (!config) ++ return; + value = pmx_readl(pmx, group->mux_bank, group->mux_reg); +- value |= BIT(group->sfsel_bit); ++ if (config->is_sfsel) ++ value |= BIT(group->sfsel_bit); + pmx_writel(pmx, value, group->mux_bank, group->mux_reg); + } + +@@ -785,6 +822,12 @@ int tegra_pinctrl_probe(struct platform_device *pdev, + pmx->dev = &pdev->dev; + pmx->soc = soc_data; + ++ pmx->pingroup_configs = devm_kcalloc(&pdev->dev, ++ pmx->soc->ngroups, sizeof(*pmx->pingroup_configs), ++ GFP_KERNEL); ++ if (!pmx->pingroup_configs) ++ return -ENOMEM; ++ + /* + * Each mux group will appear in 4 functions' list of groups. + * This over-allocates slightly, since not all groups are mux groups. +diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h +index b3289bdf727d82..b97136685f7a88 100644 +--- a/drivers/pinctrl/tegra/pinctrl-tegra.h ++++ b/drivers/pinctrl/tegra/pinctrl-tegra.h +@@ -8,6 +8,10 @@ + #ifndef __PINMUX_TEGRA_H__ + #define __PINMUX_TEGRA_H__ + ++struct tegra_pingroup_config { ++ bool is_sfsel; ++}; ++ + struct tegra_pmx { + struct device *dev; + struct pinctrl_dev *pctl; +@@ -21,6 +25,8 @@ struct tegra_pmx { + int nbanks; + void __iomem **regs; + u32 *backup_regs; ++ /* Array of size soc->ngroups */ ++ struct tegra_pingroup_config *pingroup_configs; + }; + + enum tegra_pinconf_param { +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c +index 230e6ee966366a..d8f1bf5e58a0f4 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c +@@ -45,7 +45,7 @@ static ssize_t current_password_store(struct kobject *kobj, + int length; + + length = strlen(buf); +- if (buf[length-1] == '\n') ++ if (length && buf[length - 1] == '\n') + length--; + + /* firmware does verifiation of min/max password length, +diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c +index 085e044e888e4e..d7ef4f046d99b5 100644 +--- a/drivers/platform/x86/fujitsu-laptop.c ++++ b/drivers/platform/x86/fujitsu-laptop.c +@@ -17,13 +17,13 @@ + /* + * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional + * features made available on a range of Fujitsu laptops including the +- * P2xxx/P5xxx/S6xxx/S7xxx series. ++ * P2xxx/P5xxx/S2xxx/S6xxx/S7xxx series. + * + * This driver implements a vendor-specific backlight control interface for + * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu + * laptops. + * +- * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and ++ * This driver has been tested on a Fujitsu Lifebook S2110, S6410, S7020 and + * P8010. It should work on most P-series and S-series Lifebooks, but + * YMMV. + * +@@ -102,7 +102,11 @@ + #define KEY2_CODE 0x411 + #define KEY3_CODE 0x412 + #define KEY4_CODE 0x413 +-#define KEY5_CODE 0x420 ++#define KEY5_CODE 0x414 ++#define KEY6_CODE 0x415 ++#define KEY7_CODE 0x416 ++#define KEY8_CODE 0x417 ++#define KEY9_CODE 0x420 + + /* Hotkey ringbuffer limits */ + #define MAX_HOTKEY_RINGBUFFER_SIZE 100 +@@ -450,7 +454,7 @@ static const struct key_entry keymap_default[] = { + { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, + { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, + { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, +- { KE_KEY, KEY5_CODE, { KEY_RFKILL } }, ++ { KE_KEY, KEY9_CODE, { KEY_RFKILL } }, + /* Soft keys read from status flags */ + { KE_KEY, FLAG_RFKILL, { KEY_RFKILL } }, + { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } }, +@@ -474,6 +478,18 @@ static const struct key_entry keymap_p8010[] = { + { KE_END, 0 } + }; + ++static const struct key_entry keymap_s2110[] = { ++ { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, /* "A" */ ++ { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, /* "B" */ ++ { KE_KEY, KEY3_CODE, { KEY_WWW } }, /* "Internet" */ ++ { KE_KEY, KEY4_CODE, { KEY_EMAIL } }, /* "E-mail" */ ++ { KE_KEY, KEY5_CODE, { KEY_STOPCD } }, ++ { KE_KEY, KEY6_CODE, { KEY_PLAYPAUSE } }, ++ { KE_KEY, KEY7_CODE, { KEY_PREVIOUSSONG } }, ++ { KE_KEY, KEY8_CODE, { KEY_NEXTSONG } }, ++ { KE_END, 0 } ++}; ++ + static const struct key_entry *keymap = keymap_default; + + static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id) +@@ -511,6 +527,15 @@ static const struct dmi_system_id fujitsu_laptop_dmi_table[] = { + }, + .driver_data = (void *)keymap_p8010 + }, ++ { ++ .callback = fujitsu_laptop_dmi_keymap_override, ++ .ident = "Fujitsu LifeBook S2110", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S2110"), ++ }, ++ .driver_data = (void *)keymap_s2110 ++ }, + {} + }; + +diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c +index cde5f845cf2557..8de0d3232e48c5 100644 +--- a/drivers/platform/x86/thinkpad_acpi.c ++++ b/drivers/platform/x86/thinkpad_acpi.c +@@ -212,6 +212,7 @@ enum tpacpi_hkey_event_t { + /* Thermal events */ + TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */ + TP_HKEY_EV_ALARM_BAT_XHOT = 0x6012, /* battery critically hot */ ++ TP_HKEY_EV_ALARM_BAT_LIM_CHANGE = 0x6013, /* battery charge limit changed*/ + TP_HKEY_EV_ALARM_SENSOR_HOT = 0x6021, /* sensor too hot */ + TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ + TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* windows; thermal table changed */ +@@ -3942,6 +3943,10 @@ static bool hotkey_notify_6xxx(const u32 hkey, + pr_alert("THERMAL EMERGENCY: battery is extremely hot!\n"); + /* recommended action: immediate sleep/hibernate */ + break; ++ case TP_HKEY_EV_ALARM_BAT_LIM_CHANGE: ++ pr_debug("Battery Info: battery charge threshold changed\n"); ++ /* User changed charging threshold. No action needed */ ++ return true; + case TP_HKEY_EV_ALARM_SENSOR_HOT: + pr_crit("THERMAL ALARM: a sensor reports something is too hot!\n"); + /* recommended action: warn user through gui, that */ +@@ -11315,6 +11320,8 @@ static int __must_check __init get_thinkpad_model_data( + tp->vendor = PCI_VENDOR_ID_IBM; + else if (dmi_name_in_vendors("LENOVO")) + tp->vendor = PCI_VENDOR_ID_LENOVO; ++ else if (dmi_name_in_vendors("NEC")) ++ tp->vendor = PCI_VENDOR_ID_LENOVO; + else + return 0; + +diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c +index 13fce2b134f60a..84d68c805cac85 100644 +--- a/drivers/pmdomain/imx/gpcv2.c ++++ b/drivers/pmdomain/imx/gpcv2.c +@@ -1350,7 +1350,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) + } + + if (IS_ENABLED(CONFIG_LOCKDEP) && +- of_property_read_bool(domain->dev->of_node, "power-domains")) ++ of_property_present(domain->dev->of_node, "power-domains")) + lockdep_set_subclass(&domain->genpd.mlock, 1); + + ret = of_genpd_add_provider_simple(domain->dev->of_node, +diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c +index 40f7dba42b5ad7..404cbe32711e73 100644 +--- a/drivers/regulator/ad5398.c ++++ b/drivers/regulator/ad5398.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #define AD5398_CURRENT_EN_MASK 0x8000 + +@@ -221,15 +222,20 @@ static int ad5398_probe(struct i2c_client *client) + const struct ad5398_current_data_format *df = + (struct ad5398_current_data_format *)id->driver_data; + +- if (!init_data) +- return -EINVAL; +- + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + config.dev = &client->dev; ++ if (client->dev.of_node) ++ init_data = of_get_regulator_init_data(&client->dev, ++ client->dev.of_node, ++ &ad5398_reg); ++ if (!init_data) ++ return -EINVAL; ++ + config.init_data = init_data; ++ config.of_node = client->dev.of_node; + config.driver_data = chip; + + chip->client = client; +diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c +index 90de22c81da976..37174b544113f8 100644 +--- a/drivers/remoteproc/qcom_wcnss.c ++++ b/drivers/remoteproc/qcom_wcnss.c +@@ -117,10 +117,10 @@ static const struct wcnss_data pronto_v1_data = { + .pmu_offset = 0x1004, + .spare_offset = 0x1088, + +- .pd_names = { "mx", "cx" }, ++ .pd_names = { "cx", "mx" }, + .vregs = (struct wcnss_vreg_info[]) { +- { "vddmx", 950000, 1150000, 0 }, + { "vddcx", .super_turbo = true}, ++ { "vddmx", 950000, 1150000, 0 }, + { "vddpx", 1800000, 1800000, 0 }, + }, + .num_pd_vregs = 2, +@@ -131,10 +131,10 @@ static const struct wcnss_data pronto_v2_data = { + .pmu_offset = 0x1004, + .spare_offset = 0x1088, + +- .pd_names = { "mx", "cx" }, ++ .pd_names = { "cx", "mx" }, + .vregs = (struct wcnss_vreg_info[]) { +- { "vddmx", 1287500, 1287500, 0 }, + { "vddcx", .super_turbo = true }, ++ { "vddmx", 1287500, 1287500, 0 }, + { "vddpx", 1800000, 1800000, 0 }, + }, + .num_pd_vregs = 2, +@@ -397,8 +397,17 @@ static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev) + static int wcnss_init_pds(struct qcom_wcnss *wcnss, + const char * const pd_names[WCNSS_MAX_PDS]) + { ++ struct device *dev = wcnss->dev; + int i, ret; + ++ /* Handle single power domain */ ++ if (dev->pm_domain) { ++ wcnss->pds[0] = dev; ++ wcnss->num_pds = 1; ++ pm_runtime_enable(dev); ++ return 0; ++ } ++ + for (i = 0; i < WCNSS_MAX_PDS; i++) { + if (!pd_names[i]) + break; +@@ -418,8 +427,15 @@ static int wcnss_init_pds(struct qcom_wcnss *wcnss, + + static void wcnss_release_pds(struct qcom_wcnss *wcnss) + { ++ struct device *dev = wcnss->dev; + int i; + ++ /* Handle single power domain */ ++ if (wcnss->num_pds == 1 && dev->pm_domain) { ++ pm_runtime_disable(dev); ++ return; ++ } ++ + for (i = 0; i < wcnss->num_pds; i++) + dev_pm_domain_detach(wcnss->pds[i], false); + } +@@ -437,10 +453,14 @@ static int wcnss_init_regulators(struct qcom_wcnss *wcnss, + * the regulators for the power domains. For old device trees we need to + * reserve extra space to manage them through the regulator interface. + */ +- if (wcnss->num_pds) +- info += num_pd_vregs; +- else ++ if (wcnss->num_pds) { ++ info += wcnss->num_pds; ++ /* Handle single power domain case */ ++ if (wcnss->num_pds < num_pd_vregs) ++ num_vregs += num_pd_vregs - wcnss->num_pds; ++ } else { + num_vregs += num_pd_vregs; ++ } + + bulk = devm_kcalloc(wcnss->dev, + num_vregs, sizeof(struct regulator_bulk_data), +diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c +index 506b7d1c239701..0c78451960926d 100644 +--- a/drivers/rtc/rtc-ds1307.c ++++ b/drivers/rtc/rtc-ds1307.c +@@ -1802,10 +1802,8 @@ static int ds1307_probe(struct i2c_client *client) + * For some variants, be sure alarms can trigger when we're + * running on Vbackup (BBSQI/BBSQW) + */ +- if (want_irq || ds1307_can_wakeup_device) { ++ if (want_irq || ds1307_can_wakeup_device) + regs[0] |= DS1337_BIT_INTCN | chip->bbsqi_bit; +- regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); +- } + + regmap_write(ds1307->regmap, DS1337_REG_CONTROL, + regs[0]); +diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c +index 35b2e36b426a0d..cb01038a2e27fe 100644 +--- a/drivers/rtc/rtc-rv3032.c ++++ b/drivers/rtc/rtc-rv3032.c +@@ -69,7 +69,7 @@ + #define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5) + #define RV3032_CLKOUT2_OS BIT(7) + +-#define RV3032_CTRL1_EERD BIT(3) ++#define RV3032_CTRL1_EERD BIT(2) + #define RV3032_CTRL1_WADA BIT(5) + + #define RV3032_CTRL2_STOP BIT(0) +diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c +index d6ea2fd4c2a02b..d4151f519e8b22 100644 +--- a/drivers/s390/crypto/vfio_ap_ops.c ++++ b/drivers/s390/crypto/vfio_ap_ops.c +@@ -834,48 +834,66 @@ static void vfio_ap_mdev_remove(struct mdev_device *mdev) + vfio_put_device(&matrix_mdev->vdev); + } + +-#define MDEV_SHARING_ERR "Userspace may not re-assign queue %02lx.%04lx " \ +- "already assigned to %s" ++#define MDEV_SHARING_ERR "Userspace may not assign queue %02lx.%04lx to mdev: already assigned to %s" + +-static void vfio_ap_mdev_log_sharing_err(struct ap_matrix_mdev *matrix_mdev, +- unsigned long *apm, +- unsigned long *aqm) ++#define MDEV_IN_USE_ERR "Can not reserve queue %02lx.%04lx for host driver: in use by mdev" ++ ++static void vfio_ap_mdev_log_sharing_err(struct ap_matrix_mdev *assignee, ++ struct ap_matrix_mdev *assigned_to, ++ unsigned long *apm, unsigned long *aqm) + { + unsigned long apid, apqi; +- const struct device *dev = mdev_dev(matrix_mdev->mdev); +- const char *mdev_name = dev_name(dev); + +- for_each_set_bit_inv(apid, apm, AP_DEVICES) ++ for_each_set_bit_inv(apid, apm, AP_DEVICES) { ++ for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) { ++ dev_warn(mdev_dev(assignee->mdev), MDEV_SHARING_ERR, ++ apid, apqi, dev_name(mdev_dev(assigned_to->mdev))); ++ } ++ } ++} ++ ++static void vfio_ap_mdev_log_in_use_err(struct ap_matrix_mdev *assignee, ++ unsigned long *apm, unsigned long *aqm) ++{ ++ unsigned long apid, apqi; ++ ++ for_each_set_bit_inv(apid, apm, AP_DEVICES) { + for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) +- dev_warn(dev, MDEV_SHARING_ERR, apid, apqi, mdev_name); ++ dev_warn(mdev_dev(assignee->mdev), MDEV_IN_USE_ERR, apid, apqi); ++ } + } + + /** + * vfio_ap_mdev_verify_no_sharing - verify APQNs are not shared by matrix mdevs + * ++ * @assignee: the matrix mdev to which @mdev_apm and @mdev_aqm are being ++ * assigned; or, NULL if this function was called by the AP bus ++ * driver in_use callback to verify none of the APQNs being reserved ++ * for the host device driver are in use by a vfio_ap mediated device + * @mdev_apm: mask indicating the APIDs of the APQNs to be verified + * @mdev_aqm: mask indicating the APQIs of the APQNs to be verified + * +- * Verifies that each APQN derived from the Cartesian product of a bitmap of +- * AP adapter IDs and AP queue indexes is not configured for any matrix +- * mediated device. AP queue sharing is not allowed. ++ * Verifies that each APQN derived from the Cartesian product of APIDs ++ * represented by the bits set in @mdev_apm and the APQIs of the bits set in ++ * @mdev_aqm is not assigned to a mediated device other than the mdev to which ++ * the APQN is being assigned (@assignee). AP queue sharing is not allowed. + * + * Return: 0 if the APQNs are not shared; otherwise return -EADDRINUSE. + */ +-static int vfio_ap_mdev_verify_no_sharing(unsigned long *mdev_apm, ++static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *assignee, ++ unsigned long *mdev_apm, + unsigned long *mdev_aqm) + { +- struct ap_matrix_mdev *matrix_mdev; ++ struct ap_matrix_mdev *assigned_to; + DECLARE_BITMAP(apm, AP_DEVICES); + DECLARE_BITMAP(aqm, AP_DOMAINS); + +- list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) { ++ list_for_each_entry(assigned_to, &matrix_dev->mdev_list, node) { + /* +- * If the input apm and aqm are fields of the matrix_mdev +- * object, then move on to the next matrix_mdev. ++ * If the mdev to which the mdev_apm and mdev_aqm is being ++ * assigned is the same as the mdev being verified + */ +- if (mdev_apm == matrix_mdev->matrix.apm && +- mdev_aqm == matrix_mdev->matrix.aqm) ++ if (assignee == assigned_to) + continue; + + memset(apm, 0, sizeof(apm)); +@@ -885,15 +903,16 @@ static int vfio_ap_mdev_verify_no_sharing(unsigned long *mdev_apm, + * We work on full longs, as we can only exclude the leftover + * bits in non-inverse order. The leftover is all zeros. + */ +- if (!bitmap_and(apm, mdev_apm, matrix_mdev->matrix.apm, +- AP_DEVICES)) ++ if (!bitmap_and(apm, mdev_apm, assigned_to->matrix.apm, AP_DEVICES)) + continue; + +- if (!bitmap_and(aqm, mdev_aqm, matrix_mdev->matrix.aqm, +- AP_DOMAINS)) ++ if (!bitmap_and(aqm, mdev_aqm, assigned_to->matrix.aqm, AP_DOMAINS)) + continue; + +- vfio_ap_mdev_log_sharing_err(matrix_mdev, apm, aqm); ++ if (assignee) ++ vfio_ap_mdev_log_sharing_err(assignee, assigned_to, apm, aqm); ++ else ++ vfio_ap_mdev_log_in_use_err(assigned_to, apm, aqm); + + return -EADDRINUSE; + } +@@ -922,7 +941,8 @@ static int vfio_ap_mdev_validate_masks(struct ap_matrix_mdev *matrix_mdev) + matrix_mdev->matrix.aqm)) + return -EADDRNOTAVAIL; + +- return vfio_ap_mdev_verify_no_sharing(matrix_mdev->matrix.apm, ++ return vfio_ap_mdev_verify_no_sharing(matrix_mdev, ++ matrix_mdev->matrix.apm, + matrix_mdev->matrix.aqm); + } + +@@ -2271,7 +2291,7 @@ int vfio_ap_mdev_resource_in_use(unsigned long *apm, unsigned long *aqm) + + mutex_lock(&matrix_dev->guests_lock); + mutex_lock(&matrix_dev->mdevs_lock); +- ret = vfio_ap_mdev_verify_no_sharing(apm, aqm); ++ ret = vfio_ap_mdev_verify_no_sharing(NULL, apm, aqm); + mutex_unlock(&matrix_dev->mdevs_lock); + mutex_unlock(&matrix_dev->guests_lock); + +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 0ad8a10002ce36..5c9bc8af3c2df8 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -5646,6 +5646,7 @@ static struct lpfc_nodelist * + __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) + { + struct lpfc_nodelist *ndlp; ++ struct lpfc_nodelist *np = NULL; + uint32_t data1; + + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { +@@ -5660,14 +5661,20 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) + ndlp, ndlp->nlp_DID, + ndlp->nlp_flag, data1, ndlp->nlp_rpi, + ndlp->active_rrqs_xri_bitmap); +- return ndlp; ++ ++ /* Check for new or potentially stale node */ ++ if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) ++ return ndlp; ++ np = ndlp; + } + } + +- /* FIND node did NOT FOUND */ +- lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, +- "0932 FIND node did x%x NOT FOUND.\n", did); +- return NULL; ++ if (!np) ++ /* FIND node did NOT FOUND */ ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, ++ "0932 FIND node did x%x NOT FOUND.\n", did); ++ ++ return np; + } + + struct lpfc_nodelist * +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index 424b39a8155cb9..7c8e0e1d36da9b 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -13180,6 +13180,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) + eqhdl = lpfc_get_eq_hdl(0); + rc = pci_irq_vector(phba->pcidev, 0); + if (rc < 0) { ++ free_irq(phba->pcidev->irq, phba); + pci_free_irq_vectors(phba->pcidev); + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0496 MSI pci_irq_vec failed (%d)\n", rc); +@@ -13260,6 +13261,7 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) + eqhdl = lpfc_get_eq_hdl(0); + retval = pci_irq_vector(phba->pcidev, 0); + if (retval < 0) { ++ free_irq(phba->pcidev->irq, phba); + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0502 INTR pci_irq_vec failed (%d)\n", + retval); +diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c +index 0d148c39ebcc98..60714a6c26375e 100644 +--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c ++++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c +@@ -174,6 +174,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, + char *desc = NULL; + u16 event; + ++ if (!(mrioc->logging_level & MPI3_DEBUG_EVENT)) ++ return; ++ + event = event_reply->event; + + switch (event) { +diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c +index e289f18fc76437..daef90ee431f52 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c +@@ -679,6 +679,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, + size_t data_in_sz = 0; + long ret; + u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE; ++ int tm_ret; + + issue_reset = 0; + +@@ -1120,18 +1121,25 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device( + pcie_device->device_info)))) +- mpt3sas_scsih_issue_locked_tm(ioc, ++ tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, + le16_to_cpu(mpi_request->FunctionDependent1), + 0, 0, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, + 0, pcie_device->reset_timeout, + MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE); + else +- mpt3sas_scsih_issue_locked_tm(ioc, ++ tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, + le16_to_cpu(mpi_request->FunctionDependent1), + 0, 0, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, + 0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET); ++ ++ if (tm_ret != SUCCESS) { ++ ioc_info(ioc, ++ "target reset failed, issue hard reset: handle (0x%04x)\n", ++ le16_to_cpu(mpi_request->FunctionDependent1)); ++ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); ++ } + } else + mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); + } +diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c +index 900322bad4f3be..f9ab45c4bb40d5 100644 +--- a/drivers/scsi/st.c ++++ b/drivers/scsi/st.c +@@ -953,7 +953,6 @@ static void reset_state(struct scsi_tape *STp) + STp->partition = find_partition(STp); + if (STp->partition < 0) + STp->partition = 0; +- STp->new_partition = STp->partition; + } + } + +@@ -2895,7 +2894,6 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon + timeout = STp->long_timeout * 8; + + DEBC_printk(STp, "Erasing tape.\n"); +- fileno = blkno = at_sm = 0; + break; + case MTSETBLK: /* Set block length */ + case MTSETDENSITY: /* Set tape density */ +@@ -2928,14 +2926,17 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon + if (cmd_in == MTSETDENSITY) { + (STp->buffer)->b_data[4] = arg; + STp->density_changed = 1; /* At least we tried ;-) */ ++ STp->changed_density = arg; + } else if (cmd_in == SET_DENS_AND_BLK) + (STp->buffer)->b_data[4] = arg >> 24; + else + (STp->buffer)->b_data[4] = STp->density; + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { + ltmp = arg & MT_ST_BLKSIZE_MASK; +- if (cmd_in == MTSETBLK) ++ if (cmd_in == MTSETBLK) { + STp->blksize_changed = 1; /* At least we tried ;-) */ ++ STp->changed_blksize = arg; ++ } + } else + ltmp = STp->block_size; + (STp->buffer)->b_data[9] = (ltmp >> 16); +@@ -3082,7 +3083,9 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon + cmd_in == MTSETDRVBUFFER || + cmd_in == SET_DENS_AND_BLK) { + if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST && +- !(STp->use_pf & PF_TESTED)) { ++ cmdstatp->sense_hdr.asc == 0x24 && ++ (STp->device)->scsi_level <= SCSI_2 && ++ !(STp->use_pf & PF_TESTED)) { + /* Try the other possible state of Page Format if not + already tried */ + STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; +@@ -3634,9 +3637,25 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) + retval = (-EIO); + goto out; + } +- reset_state(STp); ++ reset_state(STp); /* Clears pos_unknown */ + /* remove this when the midlevel properly clears was_reset */ + STp->device->was_reset = 0; ++ ++ /* Fix the device settings after reset, ignore errors */ ++ if (mtc.mt_op == MTREW || mtc.mt_op == MTSEEK || ++ mtc.mt_op == MTEOM) { ++ if (STp->can_partitions) { ++ /* STp->new_partition contains the ++ * latest partition set ++ */ ++ STp->partition = 0; ++ switch_partition(STp); ++ } ++ if (STp->density_changed) ++ st_int_ioctl(STp, MTSETDENSITY, STp->changed_density); ++ if (STp->blksize_changed) ++ st_int_ioctl(STp, MTSETBLK, STp->changed_blksize); ++ } + } + + if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && +diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h +index 1aaaf5369a40fc..6d31b894ee84cc 100644 +--- a/drivers/scsi/st.h ++++ b/drivers/scsi/st.h +@@ -165,6 +165,7 @@ struct scsi_tape { + unsigned char compression_changed; + unsigned char drv_buffer; + unsigned char density; ++ unsigned char changed_density; + unsigned char door_locked; + unsigned char autorew_dev; /* auto-rewind device */ + unsigned char rew_at_close; /* rewind necessary at close */ +@@ -172,6 +173,7 @@ struct scsi_tape { + unsigned char cleaning_req; /* cleaning requested? */ + unsigned char first_tur; /* first TEST UNIT READY */ + int block_size; ++ int changed_blksize; + int min_block; + int max_block; + int recover_count; /* From tape opening */ +diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h +index 24bd619ec5e487..1da1dfd9cb199c 100644 +--- a/drivers/soc/apple/rtkit-internal.h ++++ b/drivers/soc/apple/rtkit-internal.h +@@ -48,6 +48,7 @@ struct apple_rtkit { + + struct apple_rtkit_shmem ioreport_buffer; + struct apple_rtkit_shmem crashlog_buffer; ++ struct apple_rtkit_shmem oslog_buffer; + + struct apple_rtkit_shmem syslog_buffer; + char *syslog_msg_buffer; +diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c +index d9f19dc99da5e8..2c37216f423d20 100644 +--- a/drivers/soc/apple/rtkit.c ++++ b/drivers/soc/apple/rtkit.c +@@ -66,8 +66,9 @@ enum { + #define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24) + + #define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56) +-#define APPLE_RTKIT_OSLOG_INIT 1 +-#define APPLE_RTKIT_OSLOG_ACK 3 ++#define APPLE_RTKIT_OSLOG_BUFFER_REQUEST 1 ++#define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36) ++#define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0) + + #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 + #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 +@@ -256,15 +257,21 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, + struct apple_rtkit_shmem *buffer, + u8 ep, u64 msg) + { +- size_t n_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg); + u64 reply; + int err; + ++ /* The different size vs. IOVA shifts look odd but are indeed correct this way */ ++ if (ep == APPLE_RTKIT_EP_OSLOG) { ++ buffer->size = FIELD_GET(APPLE_RTKIT_OSLOG_SIZE, msg); ++ buffer->iova = FIELD_GET(APPLE_RTKIT_OSLOG_IOVA, msg) << 12; ++ } else { ++ buffer->size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg) << 12; ++ buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); ++ } ++ + buffer->buffer = NULL; + buffer->iomem = NULL; + buffer->is_mapped = false; +- buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); +- buffer->size = n_4kpages << 12; + + dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n", + buffer->size, &buffer->iova); +@@ -289,11 +296,21 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, + } + + if (!buffer->is_mapped) { +- reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, +- APPLE_RTKIT_BUFFER_REQUEST); +- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, n_4kpages); +- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, +- buffer->iova); ++ /* oslog uses different fields and needs a shifted IOVA instead of size */ ++ if (ep == APPLE_RTKIT_EP_OSLOG) { ++ reply = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, ++ APPLE_RTKIT_OSLOG_BUFFER_REQUEST); ++ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_SIZE, buffer->size); ++ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_IOVA, ++ buffer->iova >> 12); ++ } else { ++ reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, ++ APPLE_RTKIT_BUFFER_REQUEST); ++ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, ++ buffer->size >> 12); ++ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, ++ buffer->iova); ++ } + apple_rtkit_send_message(rtk, ep, reply, NULL, false); + } + +@@ -487,25 +504,18 @@ static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg) + } + } + +-static void apple_rtkit_oslog_rx_init(struct apple_rtkit *rtk, u64 msg) +-{ +- u64 ack; +- +- dev_dbg(rtk->dev, "RTKit: oslog init: msg: 0x%llx\n", msg); +- ack = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_ACK); +- apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_OSLOG, ack, NULL, false); +-} +- + static void apple_rtkit_oslog_rx(struct apple_rtkit *rtk, u64 msg) + { + u8 type = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg); + + switch (type) { +- case APPLE_RTKIT_OSLOG_INIT: +- apple_rtkit_oslog_rx_init(rtk, msg); ++ case APPLE_RTKIT_OSLOG_BUFFER_REQUEST: ++ apple_rtkit_common_rx_get_buffer(rtk, &rtk->oslog_buffer, ++ APPLE_RTKIT_EP_OSLOG, msg); + break; + default: +- dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", msg); ++ dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", ++ msg); + } + } + +@@ -744,7 +754,7 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, + rtk->mbox_cl.rx_callback = &apple_rtkit_rx; + rtk->mbox_cl.tx_done = &apple_rtkit_tx_done; + +- rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM, ++ rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_HIGHPRI | WQ_MEM_RECLAIM, + dev_name(rtk->dev)); + if (!rtk->wq) { + ret = -ENOMEM; +@@ -787,6 +797,7 @@ int apple_rtkit_reinit(struct apple_rtkit *rtk) + + apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); + apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); ++ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer); + apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); + + kfree(rtk->syslog_msg_buffer); +@@ -967,6 +978,7 @@ void apple_rtkit_free(struct apple_rtkit *rtk) + + apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); + apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); ++ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer); + apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); + + kfree(rtk->syslog_msg_buffer); +diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c +index 6ea9b8c7d335c0..7a3bdef5a7c0da 100644 +--- a/drivers/soc/ti/k3-socinfo.c ++++ b/drivers/soc/ti/k3-socinfo.c +@@ -63,6 +63,12 @@ k3_chipinfo_partno_to_names(unsigned int partno, + return -EINVAL; + } + ++static const struct regmap_config k3_chipinfo_regmap_cfg = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++}; ++ + static int k3_chipinfo_probe(struct platform_device *pdev) + { + struct device_node *node = pdev->dev.of_node; +@@ -70,13 +76,18 @@ static int k3_chipinfo_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct soc_device *soc_dev; + struct regmap *regmap; ++ void __iomem *base; + u32 partno_id; + u32 variant; + u32 jtag_id; + u32 mfg; + int ret; + +- regmap = device_node_to_regmap(node); ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ regmap = regmap_init_mmio(dev, base, &k3_chipinfo_regmap_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + +diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c +index 79173ab540a6bf..31b203ebbae0ca 100644 +--- a/drivers/soundwire/amd_manager.c ++++ b/drivers/soundwire/amd_manager.c +@@ -1138,6 +1138,7 @@ static int __maybe_unused amd_suspend(struct device *dev) + amd_sdw_wake_enable(amd_manager, false); + return amd_sdw_clock_stop(amd_manager); + } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) { ++ amd_sdw_wake_enable(amd_manager, false); + /* + * As per hardware programming sequence on AMD platforms, + * clock stop should be invoked first before powering-off +@@ -1165,6 +1166,7 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev) + amd_sdw_wake_enable(amd_manager, true); + return amd_sdw_clock_stop(amd_manager); + } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) { ++ amd_sdw_wake_enable(amd_manager, true); + ret = amd_sdw_clock_stop(amd_manager); + if (ret) + return ret; +diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c +index e7553c38be59d6..767942f19adb6a 100644 +--- a/drivers/soundwire/bus.c ++++ b/drivers/soundwire/bus.c +@@ -121,6 +121,10 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, + set_bit(SDW_GROUP13_DEV_NUM, bus->assigned); + set_bit(SDW_MASTER_DEV_NUM, bus->assigned); + ++ ret = sdw_irq_create(bus, fwnode); ++ if (ret) ++ return ret; ++ + /* + * SDW is an enumerable bus, but devices can be powered off. So, + * they won't be able to report as present. +@@ -137,6 +141,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, + + if (ret < 0) { + dev_err(bus->dev, "Finding slaves failed:%d\n", ret); ++ sdw_irq_delete(bus); + return ret; + } + +@@ -155,10 +160,6 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, + bus->params.curr_bank = SDW_BANK0; + bus->params.next_bank = SDW_BANK1; + +- ret = sdw_irq_create(bus, fwnode); +- if (ret) +- return ret; +- + return 0; + } + EXPORT_SYMBOL(sdw_bus_master_add); +diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c +index bcb0de864d34db..7dd94369abb47c 100644 +--- a/drivers/spi/spi-fsl-dspi.c ++++ b/drivers/spi/spi-fsl-dspi.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0+ + // + // Copyright 2013 Freescale Semiconductor, Inc. +-// Copyright 2020 NXP ++// Copyright 2020-2025 NXP + // + // Freescale DSPI driver + // This file contains a driver for the Freescale DSPI +@@ -62,6 +62,7 @@ + #define SPI_SR_TFIWF BIT(18) + #define SPI_SR_RFDF BIT(17) + #define SPI_SR_CMDFFF BIT(16) ++#define SPI_SR_TXRXS BIT(30) + #define SPI_SR_CLEAR (SPI_SR_TCFQF | \ + SPI_SR_TFUF | SPI_SR_TFFF | \ + SPI_SR_CMDTCF | SPI_SR_SPEF | \ +@@ -926,9 +927,20 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + struct spi_transfer *transfer; + bool cs = false; + int status = 0; ++ u32 val = 0; ++ bool cs_change = false; + + message->actual_length = 0; + ++ /* Put DSPI in running mode if halted. */ ++ regmap_read(dspi->regmap, SPI_MCR, &val); ++ if (val & SPI_MCR_HALT) { ++ regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_HALT, 0); ++ while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 && ++ !(val & SPI_SR_TXRXS)) ++ ; ++ } ++ + list_for_each_entry(transfer, &message->transfers, transfer_list) { + dspi->cur_transfer = transfer; + dspi->cur_msg = message; +@@ -958,6 +970,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + dspi->tx_cmd |= SPI_PUSHR_CMD_CONT; + } + ++ cs_change = transfer->cs_change; + dspi->tx = transfer->tx_buf; + dspi->rx = transfer->rx_buf; + dspi->len = transfer->len; +@@ -967,6 +980,8 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); + ++ regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); ++ + spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, + dspi->progress, !dspi->irq); + +@@ -993,6 +1008,15 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, + dspi_deassert_cs(spi, &cs); + } + ++ if (status || !cs_change) { ++ /* Put DSPI in stop mode */ ++ regmap_update_bits(dspi->regmap, SPI_MCR, ++ SPI_MCR_HALT, SPI_MCR_HALT); ++ while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 && ++ val & SPI_SR_TXRXS) ++ ; ++ } ++ + message->status = status; + spi_finalize_current_message(ctlr); + +@@ -1163,6 +1187,20 @@ static int dspi_resume(struct device *dev) + + static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); + ++static const struct regmap_range dspi_yes_ranges[] = { ++ regmap_reg_range(SPI_MCR, SPI_MCR), ++ regmap_reg_range(SPI_TCR, SPI_CTAR(3)), ++ regmap_reg_range(SPI_SR, SPI_TXFR3), ++ regmap_reg_range(SPI_RXFR0, SPI_RXFR3), ++ regmap_reg_range(SPI_CTARE(0), SPI_CTARE(3)), ++ regmap_reg_range(SPI_SREX, SPI_SREX), ++}; ++ ++static const struct regmap_access_table dspi_access_table = { ++ .yes_ranges = dspi_yes_ranges, ++ .n_yes_ranges = ARRAY_SIZE(dspi_yes_ranges), ++}; ++ + static const struct regmap_range dspi_volatile_ranges[] = { + regmap_reg_range(SPI_MCR, SPI_TCR), + regmap_reg_range(SPI_SR, SPI_SR), +@@ -1180,6 +1218,8 @@ static const struct regmap_config dspi_regmap_config = { + .reg_stride = 4, + .max_register = 0x88, + .volatile_table = &dspi_volatile_table, ++ .rd_table = &dspi_access_table, ++ .wr_table = &dspi_access_table, + }; + + static const struct regmap_range dspi_xspi_volatile_ranges[] = { +@@ -1201,6 +1241,8 @@ static const struct regmap_config dspi_xspi_regmap_config[] = { + .reg_stride = 4, + .max_register = 0x13c, + .volatile_table = &dspi_xspi_volatile_table, ++ .rd_table = &dspi_access_table, ++ .wr_table = &dspi_access_table, + }, + { + .name = "pushr", +@@ -1223,6 +1265,8 @@ static int dspi_init(struct fsl_dspi *dspi) + if (!spi_controller_is_target(dspi->ctlr)) + mcr |= SPI_MCR_HOST; + ++ mcr |= SPI_MCR_HALT; ++ + regmap_write(dspi->regmap, SPI_MCR, mcr); + regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index 1f374cf4d6f65c..1615f935c8f03f 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -542,7 +542,7 @@ static int rockchip_spi_config(struct rockchip_spi *rs, + cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; + if (spi->mode & SPI_LSB_FIRST) + cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; +- if (spi->mode & SPI_CS_HIGH) ++ if ((spi->mode & SPI_CS_HIGH) && !(spi_get_csgpiod(spi, 0))) + cr0 |= BIT(spi_get_chipselect(spi, 0)) << CR0_SOI_OFFSET; + + if (xfer->rx_buf && xfer->tx_buf) +diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c +index b8947265d329e4..5b2cb225a41983 100644 +--- a/drivers/spi/spi-sun4i.c ++++ b/drivers/spi/spi-sun4i.c +@@ -263,6 +263,9 @@ static int sun4i_spi_transfer_one(struct spi_master *master, + else + reg |= SUN4I_CTL_DHB; + ++ /* Now that the settings are correct, enable the interface */ ++ reg |= SUN4I_CTL_ENABLE; ++ + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); + + /* Ensure that we have a parent clock fast enough */ +@@ -403,7 +406,7 @@ static int sun4i_spi_runtime_resume(struct device *dev) + } + + sun4i_spi_write(sspi, SUN4I_CTL_REG, +- SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP); ++ SUN4I_CTL_MASTER | SUN4I_CTL_TP); + + return 0; + +diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c +index 3503e6c0a5c983..b5deb4fe3b8324 100644 +--- a/drivers/spi/spi-zynqmp-gqspi.c ++++ b/drivers/spi/spi-zynqmp-gqspi.c +@@ -799,7 +799,6 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi) + static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) + { + struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_id; +- irqreturn_t ret = IRQ_NONE; + u32 status, mask, dma_status = 0; + + status = zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST); +@@ -814,27 +813,24 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) + dma_status); + } + +- if (mask & GQSPI_ISR_TXNOT_FULL_MASK) { ++ if (!mask && !dma_status) ++ return IRQ_NONE; ++ ++ if (mask & GQSPI_ISR_TXNOT_FULL_MASK) + zynqmp_qspi_filltxfifo(xqspi, GQSPI_TX_FIFO_FILL); +- ret = IRQ_HANDLED; +- } + +- if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK) { ++ if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK) + zynqmp_process_dma_irq(xqspi); +- ret = IRQ_HANDLED; +- } else if (!(mask & GQSPI_IER_RXEMPTY_MASK) && +- (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) { ++ else if (!(mask & GQSPI_IER_RXEMPTY_MASK) && ++ (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) + zynqmp_qspi_readrxfifo(xqspi, GQSPI_RX_FIFO_FILL); +- ret = IRQ_HANDLED; +- } + + if (xqspi->bytes_to_receive == 0 && xqspi->bytes_to_transfer == 0 && + ((status & GQSPI_IRQ_MASK) == GQSPI_IRQ_MASK)) { + zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK); + complete(&xqspi->data_completion); +- ret = IRQ_HANDLED; + } +- return ret; ++ return IRQ_HANDLED; + } + + /** +diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c +index b516c2893420bc..b756d4cfecfe93 100644 +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -4323,8 +4323,8 @@ int iscsit_close_connection( + spin_unlock(&iscsit_global->ts_bitmap_lock); + + iscsit_stop_timers_for_cmds(conn); +- iscsit_stop_nopin_response_timer(conn); + iscsit_stop_nopin_timer(conn); ++ iscsit_stop_nopin_response_timer(conn); + + if (conn->conn_transport->iscsit_wait_conn) + conn->conn_transport->iscsit_wait_conn(conn); +diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c +index f110f932ba0543..675f774be1d30e 100644 +--- a/drivers/target/target_core_spc.c ++++ b/drivers/target/target_core_spc.c +@@ -2151,8 +2151,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) + if (descr->serv_action_valid) + return TCM_INVALID_CDB_FIELD; + +- if (!descr->enabled || descr->enabled(descr, cmd)) ++ if (!descr->enabled || descr->enabled(descr, cmd)) { + *opcode = descr; ++ return TCM_NO_SENSE; ++ } + break; + case 0x2: + /* +@@ -2166,8 +2168,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) + if (descr->serv_action_valid && + descr->service_action == requested_sa) { + if (!descr->enabled || descr->enabled(descr, +- cmd)) ++ cmd)) { + *opcode = descr; ++ return TCM_NO_SENSE; ++ } + } else if (!descr->serv_action_valid) + return TCM_INVALID_CDB_FIELD; + break; +@@ -2180,13 +2184,15 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) + */ + if (descr->service_action == requested_sa) + if (!descr->enabled || descr->enabled(descr, +- cmd)) ++ cmd)) { + *opcode = descr; ++ return TCM_NO_SENSE; ++ } + break; + } + } + +- return 0; ++ return TCM_NO_SENSE; + } + + static sense_reason_t +diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c +index 61c3d450ee605a..2e06b26be4ef69 100644 +--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c ++++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c +@@ -331,6 +331,7 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) + tj_max = intel_tcc_get_tjmax(cpu); + if (tj_max < 0) + return tj_max; ++ tj_max *= 1000; + + zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL); + if (!zonedev) +diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c +index 404f01cca4dab5..ff8657afb31d3c 100644 +--- a/drivers/thermal/qoriq_thermal.c ++++ b/drivers/thermal/qoriq_thermal.c +@@ -18,6 +18,7 @@ + #define SITES_MAX 16 + #define TMR_DISABLE 0x0 + #define TMR_ME 0x80000000 ++#define TMR_CMD BIT(29) + #define TMR_ALPF 0x0c000000 + #define TMR_ALPF_V2 0x03000000 + #define TMTMIR_DEFAULT 0x0000000f +@@ -356,6 +357,12 @@ static int __maybe_unused qoriq_tmu_suspend(struct device *dev) + if (ret) + return ret; + ++ if (data->ver > TMU_VER1) { ++ ret = regmap_set_bits(data->regmap, REGS_TMR, TMR_CMD); ++ if (ret) ++ return ret; ++ } ++ + clk_disable_unprepare(data->clk); + + return 0; +@@ -370,6 +377,12 @@ static int __maybe_unused qoriq_tmu_resume(struct device *dev) + if (ret) + return ret; + ++ if (data->ver > TMU_VER1) { ++ ret = regmap_clear_bits(data->regmap, REGS_TMR, TMR_CMD); ++ if (ret) ++ return ret; ++ } ++ + /* Enable monitoring */ + return regmap_update_bits(data->regmap, REGS_TMR, TMR_ME, TMR_ME); + } +diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c +index 2ee8c5ebca7c3c..43146c0685dfa7 100644 +--- a/drivers/thunderbolt/retimer.c ++++ b/drivers/thunderbolt/retimer.c +@@ -89,9 +89,11 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt) + if (ret) + goto err_nvm; + +- ret = tb_nvm_add_non_active(nvm, nvm_write); +- if (ret) +- goto err_nvm; ++ if (!rt->no_nvm_upgrade) { ++ ret = tb_nvm_add_non_active(nvm, nvm_write); ++ if (ret) ++ goto err_nvm; ++ } + + rt->nvm = nvm; + return 0; +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index c2778300e15100..d5ad6cae6b652b 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -1676,7 +1676,7 @@ static void serial8250_disable_ms(struct uart_port *port) + if (up->bugs & UART_BUG_NOMSR) + return; + +- mctrl_gpio_disable_ms(up->gpios); ++ mctrl_gpio_disable_ms_no_sync(up->gpios); + + up->ier &= ~UART_IER_MSI; + serial_port_out(port, UART_IER, up->ier); +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index bcca5627afaca8..85559d9b35d830 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -698,7 +698,7 @@ static void atmel_disable_ms(struct uart_port *port) + + atmel_port->ms_irq_enabled = false; + +- mctrl_gpio_disable_ms(atmel_port->gpios); ++ mctrl_gpio_disable_ms_no_sync(atmel_port->gpios); + + if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) + idr |= ATMEL_US_CTSIC; +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index 349d4849ba5e3b..04809b781f45be 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1597,7 +1597,7 @@ static void imx_uart_shutdown(struct uart_port *port) + imx_uart_dma_exit(sport); + } + +- mctrl_gpio_disable_ms(sport->gpios); ++ mctrl_gpio_disable_ms_sync(sport->gpios); + + spin_lock_irqsave(&sport->port.lock, flags); + ucr2 = imx_uart_readl(sport, UCR2); +diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c +index 7d5aaa8d422b19..d5fb293dd5a93c 100644 +--- a/drivers/tty/serial/serial_mctrl_gpio.c ++++ b/drivers/tty/serial/serial_mctrl_gpio.c +@@ -322,11 +322,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) + } + EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms); + +-/** +- * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines +- * @gpios: gpios to disable +- */ +-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) ++static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync) + { + enum mctrl_gpio_idx i; + +@@ -342,10 +338,34 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) + if (!gpios->irq[i]) + continue; + +- disable_irq(gpios->irq[i]); ++ if (sync) ++ disable_irq(gpios->irq[i]); ++ else ++ disable_irq_nosync(gpios->irq[i]); + } + } +-EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); ++ ++/** ++ * mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms ++ * lines, and wait for any pending IRQ to be processed ++ * @gpios: gpios to disable ++ */ ++void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios) ++{ ++ mctrl_gpio_disable_ms(gpios, true); ++} ++EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync); ++ ++/** ++ * mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the ++ * ms lines, and return immediately ++ * @gpios: gpios to disable ++ */ ++void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios) ++{ ++ mctrl_gpio_disable_ms(gpios, false); ++} ++EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync); + + void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) + { +diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h +index fc76910fb105a3..79e97838ebe567 100644 +--- a/drivers/tty/serial/serial_mctrl_gpio.h ++++ b/drivers/tty/serial/serial_mctrl_gpio.h +@@ -87,9 +87,16 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios); + void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); + + /* +- * Disable gpio interrupts to report status line changes. ++ * Disable gpio interrupts to report status line changes, and block until ++ * any corresponding IRQ is processed + */ +-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios); ++void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios); ++ ++/* ++ * Disable gpio interrupts to report status line changes, and return ++ * immediately ++ */ ++void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios); + + /* + * Enable gpio wakeup interrupts to enable wake up source. +@@ -148,7 +155,11 @@ static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) + { + } + +-static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) ++static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios) ++{ ++} ++ ++static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios) + { + } + +diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c +index 4350a69d97d7ac..61d8f50676b1bd 100644 +--- a/drivers/tty/serial/sh-sci.c ++++ b/drivers/tty/serial/sh-sci.c +@@ -104,6 +104,20 @@ struct plat_sci_reg { + u8 offset, size; + }; + ++struct sci_suspend_regs { ++ u16 scdl; ++ u16 sccks; ++ u16 scsmr; ++ u16 scscr; ++ u16 scfcr; ++ u16 scsptr; ++ u16 hssrr; ++ u16 scpcr; ++ u16 scpdr; ++ u8 scbrr; ++ u8 semr; ++}; ++ + struct sci_port_params { + const struct plat_sci_reg regs[SCIx_NR_REGS]; + unsigned int fifosize; +@@ -134,6 +148,8 @@ struct sci_port { + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + ++ struct reset_control *rstc; ++ + #ifdef CONFIG_SERIAL_SH_SCI_DMA + struct dma_chan *chan_tx_saved; + struct dma_chan *chan_rx_saved; +@@ -153,6 +169,7 @@ struct sci_port { + int rx_trigger; + struct timer_list rx_fifo_timer; + int rx_fifo_timeout; ++ struct sci_suspend_regs suspend_regs; + u16 hscif_tot; + + bool has_rtscts; +@@ -2237,7 +2254,7 @@ static void sci_shutdown(struct uart_port *port) + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + s->autorts = false; +- mctrl_gpio_disable_ms(to_sci_port(port)->gpios); ++ mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios); + + spin_lock_irqsave(&port->lock, flags); + sci_stop_rx(port); +@@ -3325,6 +3342,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, + } + + sp = &sci_ports[id]; ++ sp->rstc = rstc; + *dev_id = id; + + p->type = SCI_OF_TYPE(data); +@@ -3473,13 +3491,77 @@ static int sci_probe(struct platform_device *dev) + return 0; + } + ++static void sci_console_save(struct sci_port *s) ++{ ++ struct sci_suspend_regs *regs = &s->suspend_regs; ++ struct uart_port *port = &s->port; ++ ++ if (sci_getreg(port, SCDL)->size) ++ regs->scdl = sci_serial_in(port, SCDL); ++ if (sci_getreg(port, SCCKS)->size) ++ regs->sccks = sci_serial_in(port, SCCKS); ++ if (sci_getreg(port, SCSMR)->size) ++ regs->scsmr = sci_serial_in(port, SCSMR); ++ if (sci_getreg(port, SCSCR)->size) ++ regs->scscr = sci_serial_in(port, SCSCR); ++ if (sci_getreg(port, SCFCR)->size) ++ regs->scfcr = sci_serial_in(port, SCFCR); ++ if (sci_getreg(port, SCSPTR)->size) ++ regs->scsptr = sci_serial_in(port, SCSPTR); ++ if (sci_getreg(port, SCBRR)->size) ++ regs->scbrr = sci_serial_in(port, SCBRR); ++ if (sci_getreg(port, HSSRR)->size) ++ regs->hssrr = sci_serial_in(port, HSSRR); ++ if (sci_getreg(port, SCPCR)->size) ++ regs->scpcr = sci_serial_in(port, SCPCR); ++ if (sci_getreg(port, SCPDR)->size) ++ regs->scpdr = sci_serial_in(port, SCPDR); ++ if (sci_getreg(port, SEMR)->size) ++ regs->semr = sci_serial_in(port, SEMR); ++} ++ ++static void sci_console_restore(struct sci_port *s) ++{ ++ struct sci_suspend_regs *regs = &s->suspend_regs; ++ struct uart_port *port = &s->port; ++ ++ if (sci_getreg(port, SCDL)->size) ++ sci_serial_out(port, SCDL, regs->scdl); ++ if (sci_getreg(port, SCCKS)->size) ++ sci_serial_out(port, SCCKS, regs->sccks); ++ if (sci_getreg(port, SCSMR)->size) ++ sci_serial_out(port, SCSMR, regs->scsmr); ++ if (sci_getreg(port, SCSCR)->size) ++ sci_serial_out(port, SCSCR, regs->scscr); ++ if (sci_getreg(port, SCFCR)->size) ++ sci_serial_out(port, SCFCR, regs->scfcr); ++ if (sci_getreg(port, SCSPTR)->size) ++ sci_serial_out(port, SCSPTR, regs->scsptr); ++ if (sci_getreg(port, SCBRR)->size) ++ sci_serial_out(port, SCBRR, regs->scbrr); ++ if (sci_getreg(port, HSSRR)->size) ++ sci_serial_out(port, HSSRR, regs->hssrr); ++ if (sci_getreg(port, SCPCR)->size) ++ sci_serial_out(port, SCPCR, regs->scpcr); ++ if (sci_getreg(port, SCPDR)->size) ++ sci_serial_out(port, SCPDR, regs->scpdr); ++ if (sci_getreg(port, SEMR)->size) ++ sci_serial_out(port, SEMR, regs->semr); ++} ++ + static __maybe_unused int sci_suspend(struct device *dev) + { + struct sci_port *sport = dev_get_drvdata(dev); + +- if (sport) ++ if (sport) { + uart_suspend_port(&sci_uart_driver, &sport->port); + ++ if (!console_suspend_enabled && uart_console(&sport->port)) ++ sci_console_save(sport); ++ else ++ return reset_control_assert(sport->rstc); ++ } ++ + return 0; + } + +@@ -3487,8 +3569,18 @@ static __maybe_unused int sci_resume(struct device *dev) + { + struct sci_port *sport = dev_get_drvdata(dev); + +- if (sport) ++ if (sport) { ++ if (!console_suspend_enabled && uart_console(&sport->port)) { ++ sci_console_restore(sport); ++ } else { ++ int ret = reset_control_deassert(sport->rstc); ++ ++ if (ret) ++ return ret; ++ } ++ + uart_resume_port(&sci_uart_driver, &sport->port); ++ } + + return 0; + } +diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c +index 9ef90bb30a47eb..b58422ae156c93 100644 +--- a/drivers/tty/serial/stm32-usart.c ++++ b/drivers/tty/serial/stm32-usart.c +@@ -952,7 +952,7 @@ static void stm32_usart_enable_ms(struct uart_port *port) + + static void stm32_usart_disable_ms(struct uart_port *port) + { +- mctrl_gpio_disable_ms(to_stm32_port(port)->gpios); ++ mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios); + } + + /* Transmit stop */ +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index cb5611cbf45474..2346a1fc72b56e 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -257,6 +257,7 @@ static const struct ufs_dev_quirk ufs_fixups[] = { + .model = UFS_ANY_MODEL, + .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM | + UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE | ++ UFS_DEVICE_QUIRK_PA_HIBER8TIME | + UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS }, + { .wmanufacturerid = UFS_VENDOR_SKHYNIX, + .model = UFS_ANY_MODEL, +@@ -8459,6 +8460,31 @@ static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba) + return ret; + } + ++/** ++ * ufshcd_quirk_override_pa_h8time - Ensures proper adjustment of PA_HIBERN8TIME. ++ * @hba: per-adapter instance ++ * ++ * Some UFS devices require specific adjustments to the PA_HIBERN8TIME parameter ++ * to ensure proper hibernation timing. This function retrieves the current ++ * PA_HIBERN8TIME value and increments it by 100us. ++ */ ++static void ufshcd_quirk_override_pa_h8time(struct ufs_hba *hba) ++{ ++ u32 pa_h8time; ++ int ret; ++ ++ ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_HIBERN8TIME), &pa_h8time); ++ if (ret) { ++ dev_err(hba->dev, "Failed to get PA_HIBERN8TIME: %d\n", ret); ++ return; ++ } ++ ++ /* Increment by 1 to increase hibernation time by 100 µs */ ++ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), pa_h8time + 1); ++ if (ret) ++ dev_err(hba->dev, "Failed updating PA_HIBERN8TIME: %d\n", ret); ++} ++ + static void ufshcd_tune_unipro_params(struct ufs_hba *hba) + { + if (ufshcd_is_unipro_pa_params_tuning_req(hba)) { +@@ -8474,6 +8500,9 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) + + if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) + ufshcd_quirk_tune_host_pa_tactivate(hba); ++ ++ if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_HIBER8TIME) ++ ufshcd_quirk_override_pa_h8time(hba); + } + + static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 5a53280fa2edfd..44352df58c9e4e 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1180,7 +1180,14 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, + */ + switch (GET_EP_CTX_STATE(ep_ctx)) { + case EP_STATE_HALTED: +- xhci_dbg(xhci, "Stop ep completion raced with stall, reset ep\n"); ++ xhci_dbg(xhci, "Stop ep completion raced with stall\n"); ++ /* ++ * If the halt happened before Stop Endpoint failed, its transfer event ++ * should have already been handled and Reset Endpoint should be pending. ++ */ ++ if (ep->ep_state & EP_HALTED) ++ goto reset_done; ++ + if (ep->ep_state & EP_HAS_STREAMS) { + reset_type = EP_SOFT_RESET; + } else { +@@ -1191,8 +1198,11 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, + } + /* reset ep, reset handler cleans up cancelled tds */ + err = xhci_handle_halted_endpoint(xhci, ep, td, reset_type); ++ xhci_dbg(xhci, "Stop ep completion resetting ep, status %d\n", err); + if (err) + break; ++reset_done: ++ /* Reset EP handler will clean up cancelled TDs */ + ep->ep_state &= ~EP_STOP_CMD_PENDING; + return; + case EP_STATE_STOPPED: +diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c +index b56aae3f7be378..9b8b70ffde5a0a 100644 +--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c ++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c +@@ -3420,6 +3420,9 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, + ndev->mvdev.max_vqs = max_vqs; + mvdev = &ndev->mvdev; + mvdev->mdev = mdev; ++ /* cpu_to_mlx5vdpa16() below depends on this flag */ ++ mvdev->actual_features = ++ (device_features & BIT_ULL(VIRTIO_F_VERSION_1)); + + ndev->vqs = kcalloc(max_vqs, sizeof(*ndev->vqs), GFP_KERNEL); + ndev->event_cbs = kcalloc(max_vqs + 1, sizeof(*ndev->event_cbs), GFP_KERNEL); +diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c +index a2ad4f7c716bf3..d9eb8733a324b7 100644 +--- a/drivers/vfio/pci/vfio_pci_config.c ++++ b/drivers/vfio/pci/vfio_pci_config.c +@@ -1813,7 +1813,8 @@ int vfio_config_init(struct vfio_pci_core_device *vdev) + cpu_to_le16(PCI_COMMAND_MEMORY); + } + +- if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx) ++ if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx || ++ vdev->pdev->irq == IRQ_NOTCONNECTED) + vconfig[PCI_INTERRUPT_PIN] = 0; + + ret = vfio_cap_init(vdev); +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index a8f259bc2f4d0c..fa168b43423954 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -731,15 +731,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_finish_enable); + static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_type) + { + if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) { +- u8 pin; +- +- if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || +- vdev->nointx || vdev->pdev->is_virtfn) +- return 0; +- +- pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin); +- +- return pin ? 1 : 0; ++ return vdev->vconfig[PCI_INTERRUPT_PIN] ? 1 : 0; + } else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) { + u8 pos; + u16 flags; +diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c +index 620134041b4881..c4322faca2bd5b 100644 +--- a/drivers/vfio/pci/vfio_pci_intrs.c ++++ b/drivers/vfio/pci/vfio_pci_intrs.c +@@ -269,7 +269,7 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev, + if (!is_irq_none(vdev)) + return -EINVAL; + +- if (!pdev->irq) ++ if (!pdev->irq || pdev->irq == IRQ_NOTCONNECTED) + return -ENODEV; + + name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-intx(%s)", pci_name(pdev)); +diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c +index 8d8a22504d71fc..66235151115740 100644 +--- a/drivers/vhost/scsi.c ++++ b/drivers/vhost/scsi.c +@@ -560,6 +560,9 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) + int ret; + + llnode = llist_del_all(&svq->completion_list); ++ ++ mutex_lock(&svq->vq.mutex); ++ + llist_for_each_entry_safe(cmd, t, llnode, tvc_completion_list) { + se_cmd = &cmd->tvc_se_cmd; + +@@ -593,6 +596,8 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) + vhost_scsi_release_cmd_res(se_cmd); + } + ++ mutex_unlock(&svq->vq.mutex); ++ + if (signal) + vhost_signal(&svq->vs->dev, &svq->vq); + } +@@ -746,7 +751,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + size_t len = iov_iter_count(iter); + unsigned int nbytes = 0; + struct page *page; +- int i; ++ int i, ret; + + if (cmd->tvc_data_direction == DMA_FROM_DEVICE) { + cmd->saved_iter_addr = dup_iter(&cmd->saved_iter, iter, +@@ -759,6 +764,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + page = alloc_page(GFP_KERNEL); + if (!page) { + i--; ++ ret = -ENOMEM; + goto err; + } + +@@ -766,8 +772,10 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + sg_set_page(&sg[i], page, nbytes, 0); + + if (cmd->tvc_data_direction == DMA_TO_DEVICE && +- copy_page_from_iter(page, 0, nbytes, iter) != nbytes) ++ copy_page_from_iter(page, 0, nbytes, iter) != nbytes) { ++ ret = -EFAULT; + goto err; ++ } + + len -= nbytes; + } +@@ -782,7 +790,7 @@ vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter, + for (; i >= 0; i--) + __free_page(sg_page(&sg[i])); + kfree(cmd->saved_iter_addr); +- return -ENOMEM; ++ return ret; + } + + static int +@@ -1221,9 +1229,9 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) + " %d\n", cmd, exp_data_len, prot_bytes, data_direction); + + if (data_direction != DMA_NONE) { +- if (unlikely(vhost_scsi_mapal(cmd, prot_bytes, +- &prot_iter, exp_data_len, +- &data_iter))) { ++ ret = vhost_scsi_mapal(cmd, prot_bytes, &prot_iter, ++ exp_data_len, &data_iter); ++ if (unlikely(ret)) { + vq_err(vq, "Failed to map iov to sgl\n"); + vhost_scsi_release_cmd_res(&cmd->tvc_se_cmd); + goto err; +@@ -1301,8 +1309,11 @@ static void vhost_scsi_tmf_resp_work(struct vhost_work *work) + resp_code = VIRTIO_SCSI_S_FUNCTION_REJECTED; + } + ++ mutex_lock(&tmf->svq->vq.mutex); + vhost_scsi_send_tmf_resp(tmf->vhost, &tmf->svq->vq, tmf->in_iovs, + tmf->vq_desc, &tmf->resp_iov, resp_code); ++ mutex_unlock(&tmf->svq->vq.mutex); ++ + vhost_scsi_release_tmf_res(tmf); + } + +diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c +index 8587c9da067003..42e681a78136ab 100644 +--- a/drivers/video/fbdev/core/bitblit.c ++++ b/drivers/video/fbdev/core/bitblit.c +@@ -59,12 +59,11 @@ static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + struct fb_fillrect region; + +- region.color = attr_bgcol_ec(bgshift, vc, info); ++ region.color = bg; + region.dx = sx * vc->vc_font.width; + region.dy = sy * vc->vc_font.height; + region.width = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 405d587450ef84..7a6f9a3cb3ba34 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -1240,7 +1240,7 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_ops *ops = info->fbcon_par; +- ++ int fg, bg; + struct fbcon_display *p = &fb_display[vc->vc_num]; + u_int y_break; + +@@ -1261,16 +1261,18 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + fbcon_clear_margins(vc, 0); + } + ++ fg = get_color(vc, info, vc->vc_video_erase_char, 1); ++ bg = get_color(vc, info, vc->vc_video_erase_char, 0); + /* Split blits that cross physical y_wrap boundary */ + + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; +- ops->clear(vc, info, real_y(p, sy), sx, b, width); ++ ops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg); + ops->clear(vc, info, real_y(p, sy + b), sx, height - b, +- width); ++ width, fg, bg); + } else +- ops->clear(vc, info, real_y(p, sy), sx, height, width); ++ ops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg); + } + + static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, +diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h +index 0eaf54a2115167..25691d4b027bfc 100644 +--- a/drivers/video/fbdev/core/fbcon.h ++++ b/drivers/video/fbdev/core/fbcon.h +@@ -55,7 +55,7 @@ struct fbcon_ops { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); + void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width); ++ int sx, int height, int width, int fb, int bg); + void (*putcs)(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg); +@@ -116,42 +116,6 @@ static inline int mono_col(const struct fb_info *info) + return (~(0xfff << max_len)) & 0xff; + } + +-static inline int attr_col_ec(int shift, struct vc_data *vc, +- struct fb_info *info, int is_fg) +-{ +- int is_mono01; +- int col; +- int fg; +- int bg; +- +- if (!vc) +- return 0; +- +- if (vc->vc_can_do_color) +- return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char) +- : attr_bgcol(shift,vc->vc_video_erase_char); +- +- if (!info) +- return 0; +- +- col = mono_col(info); +- is_mono01 = info->fix.visual == FB_VISUAL_MONO01; +- +- if (attr_reverse(vc->vc_video_erase_char)) { +- fg = is_mono01 ? col : 0; +- bg = is_mono01 ? 0 : col; +- } +- else { +- fg = is_mono01 ? 0 : col; +- bg = is_mono01 ? col : 0; +- } +- +- return is_fg ? fg : bg; +-} +- +-#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0) +-#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1) +- + /* + * Scroll Method + */ +diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c +index 2789ace7963427..9f4d65478554ad 100644 +--- a/drivers/video/fbdev/core/fbcon_ccw.c ++++ b/drivers/video/fbdev/core/fbcon_ccw.c +@@ -78,14 +78,13 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vyres = GETVYRES(ops->p, info); + +- region.color = attr_bgcol_ec(bgshift,vc,info); ++ region.color = bg; + region.dx = sy * vc->vc_font.height; + region.dy = vyres - ((sx + width) * vc->vc_font.width); + region.height = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c +index 86a254c1b2b7b6..b18e31886da102 100644 +--- a/drivers/video/fbdev/core/fbcon_cw.c ++++ b/drivers/video/fbdev/core/fbcon_cw.c +@@ -63,14 +63,13 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vxres = GETVXRES(ops->p, info); + +- region.color = attr_bgcol_ec(bgshift,vc,info); ++ region.color = bg; + region.dx = vxres - ((sy + height) * vc->vc_font.height); + region.dy = sx * vc->vc_font.width; + region.height = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c +index 23bc045769d088..b6b074cfd9dc08 100644 +--- a/drivers/video/fbdev/core/fbcon_ud.c ++++ b/drivers/video/fbdev/core/fbcon_ud.c +@@ -64,15 +64,14 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vyres = GETVYRES(ops->p, info); + u32 vxres = GETVXRES(ops->p, info); + +- region.color = attr_bgcol_ec(bgshift,vc,info); ++ region.color = bg; + region.dy = vyres - ((sy + height) * vc->vc_font.height); + region.dx = vxres - ((sx + width) * vc->vc_font.width); + region.width = width * vc->vc_font.width; +diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c +index 2768eff247ba46..b3aa0c6620c7d1 100644 +--- a/drivers/video/fbdev/core/tileblit.c ++++ b/drivers/video/fbdev/core/tileblit.c +@@ -32,16 +32,14 @@ static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy, + } + + static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, +- int sx, int height, int width) ++ int sx, int height, int width, int fg, int bg) + { + struct fb_tilerect rect; +- int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; +- int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; + + rect.index = vc->vc_video_erase_char & + ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); +- rect.fg = attr_fgcol_ec(fgshift, vc, info); +- rect.bg = attr_bgcol_ec(bgshift, vc, info); ++ rect.fg = fg; ++ rect.bg = bg; + rect.sx = sx; + rect.sy = sy; + rect.width = width; +@@ -76,7 +74,42 @@ static void tile_putcs(struct vc_data *vc, struct fb_info *info, + static void tile_clear_margins(struct vc_data *vc, struct fb_info *info, + int color, int bottom_only) + { +- return; ++ unsigned int cw = vc->vc_font.width; ++ unsigned int ch = vc->vc_font.height; ++ unsigned int rw = info->var.xres - (vc->vc_cols*cw); ++ unsigned int bh = info->var.yres - (vc->vc_rows*ch); ++ unsigned int rs = info->var.xres - rw; ++ unsigned int bs = info->var.yres - bh; ++ unsigned int vwt = info->var.xres_virtual / cw; ++ unsigned int vht = info->var.yres_virtual / ch; ++ struct fb_tilerect rect; ++ ++ rect.index = vc->vc_video_erase_char & ++ ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); ++ rect.fg = color; ++ rect.bg = color; ++ ++ if ((int) rw > 0 && !bottom_only) { ++ rect.sx = (info->var.xoffset + rs + cw - 1) / cw; ++ rect.sy = 0; ++ rect.width = (rw + cw - 1) / cw; ++ rect.height = vht; ++ if (rect.width + rect.sx > vwt) ++ rect.width = vwt - rect.sx; ++ if (rect.sx < vwt) ++ info->tileops->fb_tilefill(info, &rect); ++ } ++ ++ if ((int) bh > 0) { ++ rect.sx = info->var.xoffset / cw; ++ rect.sy = (info->var.yoffset + bs) / ch; ++ rect.width = rs / cw; ++ rect.height = (bh + ch - 1) / ch; ++ if (rect.height + rect.sy > vht) ++ rect.height = vht - rect.sy; ++ if (rect.sy < vht) ++ info->tileops->fb_tilefill(info, &rect); ++ } + } + + static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, +diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c +index 0bced82fa4940d..8cf1268a4e5545 100644 +--- a/drivers/video/fbdev/fsl-diu-fb.c ++++ b/drivers/video/fbdev/fsl-diu-fb.c +@@ -1827,6 +1827,7 @@ static void fsl_diu_remove(struct platform_device *pdev) + int i; + + data = dev_get_drvdata(&pdev->dev); ++ device_remove_file(&pdev->dev, &data->dev_attr); + disable_lcdc(&data->fsl_diu_info[0]); + + free_irq(data->irq, data->diu_reg); +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index 80669e05bf0ee4..c5f04234d9511a 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -2530,7 +2530,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq) + struct vring_virtqueue *vq = to_vvq(_vq); + + if (vq->event_triggered) +- vq->event_triggered = false; ++ data_race(vq->event_triggered = false); + + return vq->packed_ring ? virtqueue_enable_cb_delayed_packed(_vq) : + virtqueue_enable_cb_delayed_split(_vq); +diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c +index b72a858bbac702..001b2c9311254c 100644 +--- a/drivers/watchdog/aspeed_wdt.c ++++ b/drivers/watchdog/aspeed_wdt.c +@@ -11,21 +11,30 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + + static bool nowayout = WATCHDOG_NOWAYOUT; + module_param(nowayout, bool, 0); + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++struct aspeed_wdt_scu { ++ const char *compatible; ++ u32 reset_status_reg; ++ u32 wdt_reset_mask; ++ u32 wdt_reset_mask_shift; ++}; + + struct aspeed_wdt_config { + u32 ext_pulse_width_mask; + u32 irq_shift; + u32 irq_mask; ++ struct aspeed_wdt_scu scu; + }; + + struct aspeed_wdt { +@@ -39,18 +48,36 @@ static const struct aspeed_wdt_config ast2400_config = { + .ext_pulse_width_mask = 0xff, + .irq_shift = 0, + .irq_mask = 0, ++ .scu = { ++ .compatible = "aspeed,ast2400-scu", ++ .reset_status_reg = 0x3c, ++ .wdt_reset_mask = 0x1, ++ .wdt_reset_mask_shift = 1, ++ }, + }; + + static const struct aspeed_wdt_config ast2500_config = { + .ext_pulse_width_mask = 0xfffff, + .irq_shift = 12, + .irq_mask = GENMASK(31, 12), ++ .scu = { ++ .compatible = "aspeed,ast2500-scu", ++ .reset_status_reg = 0x3c, ++ .wdt_reset_mask = 0x1, ++ .wdt_reset_mask_shift = 2, ++ }, + }; + + static const struct aspeed_wdt_config ast2600_config = { + .ext_pulse_width_mask = 0xfffff, + .irq_shift = 0, + .irq_mask = GENMASK(31, 10), ++ .scu = { ++ .compatible = "aspeed,ast2600-scu", ++ .reset_status_reg = 0x74, ++ .wdt_reset_mask = 0xf, ++ .wdt_reset_mask_shift = 16, ++ }, + }; + + static const struct of_device_id aspeed_wdt_of_table[] = { +@@ -211,6 +238,56 @@ static int aspeed_wdt_restart(struct watchdog_device *wdd, + return 0; + } + ++static void aspeed_wdt_update_bootstatus(struct platform_device *pdev, ++ struct aspeed_wdt *wdt) ++{ ++ const struct resource *res; ++ struct aspeed_wdt_scu scu = wdt->cfg->scu; ++ struct regmap *scu_base; ++ u32 reset_mask_width; ++ u32 reset_mask_shift; ++ u32 idx = 0; ++ u32 status; ++ int ret; ++ ++ if (!of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt")) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ idx = ((intptr_t)wdt->base & 0x00000fff) / (uintptr_t)resource_size(res); ++ } ++ ++ scu_base = syscon_regmap_lookup_by_compatible(scu.compatible); ++ if (IS_ERR(scu_base)) { ++ wdt->wdd.bootstatus = WDIOS_UNKNOWN; ++ return; ++ } ++ ++ ret = regmap_read(scu_base, scu.reset_status_reg, &status); ++ if (ret) { ++ wdt->wdd.bootstatus = WDIOS_UNKNOWN; ++ return; ++ } ++ ++ reset_mask_width = hweight32(scu.wdt_reset_mask); ++ reset_mask_shift = scu.wdt_reset_mask_shift + ++ reset_mask_width * idx; ++ ++ if (status & (scu.wdt_reset_mask << reset_mask_shift)) ++ wdt->wdd.bootstatus = WDIOF_CARDRESET; ++ ++ /* clear wdt reset event flag */ ++ if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt") || ++ of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2500-wdt")) { ++ ret = regmap_read(scu_base, scu.reset_status_reg, &status); ++ if (!ret) { ++ status &= ~(scu.wdt_reset_mask << reset_mask_shift); ++ regmap_write(scu_base, scu.reset_status_reg, status); ++ } ++ } else { ++ regmap_write(scu_base, scu.reset_status_reg, ++ scu.wdt_reset_mask << reset_mask_shift); ++ } ++} ++ + /* access_cs0 shows if cs0 is accessible, hence the reverted bit */ + static ssize_t access_cs0_show(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -447,10 +524,10 @@ static int aspeed_wdt_probe(struct platform_device *pdev) + writel(duration - 1, wdt->base + WDT_RESET_WIDTH); + } + ++ aspeed_wdt_update_bootstatus(pdev, wdt); ++ + status = readl(wdt->base + WDT_TIMEOUT_STATUS); + if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) { +- wdt->wdd.bootstatus = WDIOF_CARDRESET; +- + if (of_device_is_compatible(np, "aspeed,ast2400-wdt") || + of_device_is_compatible(np, "aspeed,ast2500-wdt")) + wdt->wdd.groups = bswitch_groups; +diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c +index 544d3f9010b92a..1db82da56db62b 100644 +--- a/drivers/xen/platform-pci.c ++++ b/drivers/xen/platform-pci.c +@@ -26,6 +26,8 @@ + + #define DRV_NAME "xen-platform-pci" + ++#define PCI_DEVICE_ID_XEN_PLATFORM_XS61 0x0002 ++ + static unsigned long platform_mmio; + static unsigned long platform_mmio_alloc; + static unsigned long platform_mmiolen; +@@ -174,6 +176,8 @@ static int platform_pci_probe(struct pci_dev *pdev, + static const struct pci_device_id platform_pci_tbl[] = { + {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM_XS61, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} + }; + +diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c +index 25164d56c9d995..d3b6908110c6f0 100644 +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -966,9 +966,15 @@ static int __init xenbus_init(void) + if (xen_pv_domain()) + xen_store_domain_type = XS_PV; + if (xen_hvm_domain()) ++ { + xen_store_domain_type = XS_HVM; +- if (xen_hvm_domain() && xen_initial_domain()) +- xen_store_domain_type = XS_LOCAL; ++ err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); ++ if (err) ++ goto out_error; ++ xen_store_evtchn = (int)v; ++ if (!v && xen_initial_domain()) ++ xen_store_domain_type = XS_LOCAL; ++ } + if (xen_pv_domain() && !xen_start_info->store_evtchn) + xen_store_domain_type = XS_LOCAL; + if (xen_pv_domain() && xen_start_info->store_evtchn) +@@ -987,10 +993,6 @@ static int __init xenbus_init(void) + xen_store_interface = gfn_to_virt(xen_store_gfn); + break; + case XS_HVM: +- err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); +- if (err) +- goto out_error; +- xen_store_evtchn = (int)v; + err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); + if (err) + goto out_error; +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 434cf3d5f4cf18..226e6434a58a94 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -1885,6 +1885,17 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) + up_write(&space_info->groups_sem); + goto next; + } ++ ++ /* ++ * Cache the zone_unusable value before turning the block group ++ * to read only. As soon as the block group is read only it's ++ * zone_unusable value gets moved to the block group's read-only ++ * bytes and isn't available for calculations anymore. We also ++ * cache it before unlocking the block group, to prevent races ++ * (reports from KCSAN and such tools) with tasks updating it. ++ */ ++ zone_unusable = bg->zone_unusable; ++ + spin_unlock(&bg->lock); + + /* +@@ -1900,13 +1911,6 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) + goto next; + } + +- /* +- * Cache the zone_unusable value before turning the block group +- * to read only. As soon as the blog group is read only it's +- * zone_unusable value gets moved to the block group's read-only +- * bytes and isn't available for calculations anymore. +- */ +- zone_unusable = bg->zone_unusable; + ret = inc_block_group_ro(bg, 0); + up_write(&space_info->groups_sem); + if (ret < 0) +diff --git a/fs/btrfs/discard.c b/fs/btrfs/discard.c +index 944a7340f6a449..3981c941f5b556 100644 +--- a/fs/btrfs/discard.c ++++ b/fs/btrfs/discard.c +@@ -167,13 +167,7 @@ static bool remove_from_discard_list(struct btrfs_discard_ctl *discard_ctl, + block_group->discard_eligible_time = 0; + queued = !list_empty(&block_group->discard_list); + list_del_init(&block_group->discard_list); +- /* +- * If the block group is currently running in the discard workfn, we +- * don't want to deref it, since it's still being used by the workfn. +- * The workfn will notice this case and deref the block group when it is +- * finished. +- */ +- if (queued && !running) ++ if (queued) + btrfs_put_block_group(block_group); + + spin_unlock(&discard_ctl->lock); +@@ -260,9 +254,10 @@ static struct btrfs_block_group *peek_discard_list( + block_group->discard_cursor = block_group->start; + block_group->discard_state = BTRFS_DISCARD_EXTENTS; + } +- discard_ctl->block_group = block_group; + } + if (block_group) { ++ btrfs_get_block_group(block_group); ++ discard_ctl->block_group = block_group; + *discard_state = block_group->discard_state; + *discard_index = block_group->discard_index; + } +@@ -493,9 +488,20 @@ static void btrfs_discard_workfn(struct work_struct *work) + + block_group = peek_discard_list(discard_ctl, &discard_state, + &discard_index, now); +- if (!block_group || !btrfs_run_discard_work(discard_ctl)) ++ if (!block_group) + return; ++ if (!btrfs_run_discard_work(discard_ctl)) { ++ spin_lock(&discard_ctl->lock); ++ btrfs_put_block_group(block_group); ++ discard_ctl->block_group = NULL; ++ spin_unlock(&discard_ctl->lock); ++ return; ++ } + if (now < block_group->discard_eligible_time) { ++ spin_lock(&discard_ctl->lock); ++ btrfs_put_block_group(block_group); ++ discard_ctl->block_group = NULL; ++ spin_unlock(&discard_ctl->lock); + btrfs_discard_schedule_work(discard_ctl, false); + return; + } +@@ -547,15 +553,7 @@ static void btrfs_discard_workfn(struct work_struct *work) + spin_lock(&discard_ctl->lock); + discard_ctl->prev_discard = trimmed; + discard_ctl->prev_discard_time = now; +- /* +- * If the block group was removed from the discard list while it was +- * running in this workfn, then we didn't deref it, since this function +- * still owned that reference. But we set the discard_ctl->block_group +- * back to NULL, so we can use that condition to know that now we need +- * to deref the block_group. +- */ +- if (discard_ctl->block_group == NULL) +- btrfs_put_block_group(block_group); ++ btrfs_put_block_group(block_group); + discard_ctl->block_group = NULL; + __btrfs_discard_schedule_work(discard_ctl, now, false); + spin_unlock(&discard_ctl->lock); +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 2387210231f236..34a30d61b470c3 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -4313,6 +4313,14 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) + /* clear out the rbtree of defraggable inodes */ + btrfs_cleanup_defrag_inodes(fs_info); + ++ /* ++ * Handle the error fs first, as it will flush and wait for all ordered ++ * extents. This will generate delayed iputs, thus we want to handle ++ * it first. ++ */ ++ if (unlikely(BTRFS_FS_ERROR(fs_info))) ++ btrfs_error_commit_super(fs_info); ++ + /* + * Wait for any fixup workers to complete. + * If we don't wait for them here and they are still running by the time +@@ -4333,6 +4341,19 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) + */ + btrfs_flush_workqueue(fs_info->delalloc_workers); + ++ /* ++ * We can have ordered extents getting their last reference dropped from ++ * the fs_info->workers queue because for async writes for data bios we ++ * queue a work for that queue, at btrfs_wq_submit_bio(), that runs ++ * run_one_async_done() which calls btrfs_bio_end_io() in case the bio ++ * has an error, and that later function can do the final ++ * btrfs_put_ordered_extent() on the ordered extent attached to the bio, ++ * which adds a delayed iput for the inode. So we must flush the queue ++ * so that we don't have delayed iputs after committing the current ++ * transaction below and stopping the cleaner and transaction kthreads. ++ */ ++ btrfs_flush_workqueue(fs_info->workers); ++ + /* + * When finishing a compressed write bio we schedule a work queue item + * to finish an ordered extent - btrfs_finish_compressed_write_work() +@@ -4402,9 +4423,6 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) + btrfs_err(fs_info, "commit super ret %d", ret); + } + +- if (BTRFS_FS_ERROR(fs_info)) +- btrfs_error_commit_super(fs_info); +- + kthread_stop(fs_info->transaction_kthread); + kthread_stop(fs_info->cleaner_kthread); + +@@ -4541,10 +4559,6 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info) + /* cleanup FS via transaction */ + btrfs_cleanup_transaction(fs_info); + +- mutex_lock(&fs_info->cleaner_mutex); +- btrfs_run_delayed_iputs(fs_info); +- mutex_unlock(&fs_info->cleaner_mutex); +- + down_write(&fs_info->cleanup_work_sem); + up_write(&fs_info->cleanup_work_sem); + } +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index b2ae50dcca0fe0..ed08d8e5639f59 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -3565,10 +3565,10 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info, + return eb; + } + +-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS + struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, + u64 start) + { ++#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS + struct extent_buffer *eb, *exists = NULL; + int ret; + +@@ -3604,8 +3604,11 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, + free_eb: + btrfs_release_extent_buffer(eb); + return exists; +-} ++#else ++ /* Stub to avoid linker error when compiled with optimizations turned off. */ ++ return NULL; + #endif ++} + + static struct extent_buffer *grab_extent_buffer( + struct btrfs_fs_info *fs_info, struct page *page) +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 537e184b4b1dfc..474758c878fcab 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -2931,6 +2931,7 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra, + int ret; + + ASSERT(page_index <= last_index); ++again: + page = find_lock_page(inode->i_mapping, page_index); + if (!page) { + page_cache_sync_readahead(inode->i_mapping, ra, NULL, +@@ -2952,6 +2953,11 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra, + ret = -EIO; + goto release_page; + } ++ if (page->mapping != inode->i_mapping) { ++ unlock_page(page); ++ put_page(page); ++ goto again; ++ } + } + + /* +diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c +index 6be092bb814fdc..da49bdb70375b6 100644 +--- a/fs/btrfs/scrub.c ++++ b/fs/btrfs/scrub.c +@@ -1538,8 +1538,8 @@ static int scrub_find_fill_first_stripe(struct btrfs_block_group *bg, + u64 extent_gen; + int ret; + +- if (unlikely(!extent_root)) { +- btrfs_err(fs_info, "no valid extent root for scrub"); ++ if (unlikely(!extent_root || !csum_root)) { ++ btrfs_err(fs_info, "no valid extent or csum root for scrub"); + return -EUCLEAN; + } + memset(stripe->sectors, 0, sizeof(struct scrub_sector_verification) * +diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c +index aa1e6d88a72c7c..e2ead36e5be422 100644 +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -487,10 +487,8 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) + if (p->buf_len >= len) + return 0; + +- if (len > PATH_MAX) { +- WARN_ON(1); +- return -ENOMEM; +- } ++ if (WARN_ON(len > PATH_MAX)) ++ return -ENAMETOOLONG; + + path_len = p->end - p->start; + old_buf_len = p->buf_len; +diff --git a/fs/coredump.c b/fs/coredump.c +index 9d235fa14ab98f..d3a4f5dc2e362a 100644 +--- a/fs/coredump.c ++++ b/fs/coredump.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -56,6 +57,13 @@ + static bool dump_vma_snapshot(struct coredump_params *cprm); + static void free_vma_snapshot(struct coredump_params *cprm); + ++/* ++ * File descriptor number for the pidfd for the thread-group leader of ++ * the coredumping task installed into the usermode helper's file ++ * descriptor table. ++ */ ++#define COREDUMP_PIDFD_NUMBER 3 ++ + static int core_uses_pid; + static unsigned int core_pipe_limit; + static char core_pattern[CORENAME_MAX_SIZE] = "core"; +@@ -332,6 +340,27 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm, + case 'C': + err = cn_printf(cn, "%d", cprm->cpu); + break; ++ /* pidfd number */ ++ case 'F': { ++ /* ++ * Installing a pidfd only makes sense if ++ * we actually spawn a usermode helper. ++ */ ++ if (!ispipe) ++ break; ++ ++ /* ++ * Note that we'll install a pidfd for the ++ * thread-group leader. We know that task ++ * linkage hasn't been removed yet and even if ++ * this @current isn't the actual thread-group ++ * leader we know that the thread-group leader ++ * cannot be reaped until @current has exited. ++ */ ++ cprm->pid = task_tgid(current); ++ err = cn_printf(cn, "%d", COREDUMP_PIDFD_NUMBER); ++ break; ++ } + default: + break; + } +@@ -488,7 +517,7 @@ static void wait_for_dump_helpers(struct file *file) + } + + /* +- * umh_pipe_setup ++ * umh_coredump_setup + * helper function to customize the process used + * to collect the core in userspace. Specifically + * it sets up a pipe and installs it as fd 0 (stdin) +@@ -498,21 +527,61 @@ static void wait_for_dump_helpers(struct file *file) + * is a special value that we use to trap recursive + * core dumps + */ +-static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) ++static int umh_coredump_setup(struct subprocess_info *info, struct cred *new) + { + struct file *files[2]; ++ struct file *pidfs_file = NULL; + struct coredump_params *cp = (struct coredump_params *)info->data; +- int err = create_pipe_files(files, 0); ++ int err; ++ ++ if (cp->pid) { ++ int fd; ++ ++ fd = pidfd_prepare(cp->pid, 0, &pidfs_file); ++ if (fd < 0) ++ return fd; ++ ++ /* ++ * We don't care about the fd. We also cannot simply ++ * replace it below because dup2() will refuse to close ++ * this file descriptor if its in a larval state. So ++ * close it! ++ */ ++ put_unused_fd(fd); ++ ++ /* ++ * Usermode helpers are childen of either ++ * system_unbound_wq or of kthreadd. So we know that ++ * we're starting off with a clean file descriptor ++ * table. So we should always be able to use ++ * COREDUMP_PIDFD_NUMBER as our file descriptor value. ++ */ ++ err = replace_fd(COREDUMP_PIDFD_NUMBER, pidfs_file, 0); ++ if (err < 0) ++ goto out_fail; ++ ++ pidfs_file = NULL; ++ } ++ ++ err = create_pipe_files(files, 0); + if (err) +- return err; ++ goto out_fail; + + cp->file = files[1]; + + err = replace_fd(0, files[0], 0); + fput(files[0]); ++ if (err < 0) ++ goto out_fail; ++ + /* and disallow core files too */ + current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; + ++ err = 0; ++ ++out_fail: ++ if (pidfs_file) ++ fput(pidfs_file); + return err; + } + +@@ -589,7 +658,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) + } + + if (cprm.limit == 1) { +- /* See umh_pipe_setup() which sets RLIMIT_CORE = 1. ++ /* See umh_coredump_setup() which sets RLIMIT_CORE = 1. + * + * Normally core limits are irrelevant to pipes, since + * we're not writing to the file system, but we use +@@ -634,7 +703,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) + retval = -ENOMEM; + sub_info = call_usermodehelper_setup(helper_argv[0], + helper_argv, NULL, GFP_KERNEL, +- umh_pipe_setup, NULL, &cprm); ++ umh_coredump_setup, NULL, &cprm); + if (sub_info) + retval = call_usermodehelper_exec(sub_info, + UMH_WAIT_EXEC); +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 0618af36f5506b..3c9ab6461579c9 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -1826,8 +1826,8 @@ static int dlm_tcp_listen_validate(void) + { + /* We don't support multi-homed hosts */ + if (dlm_local_count > 1) { +- log_print("TCP protocol can't handle multi-homed hosts, try SCTP"); +- return -EINVAL; ++ log_print("Detect multi-homed hosts but use only the first IP address."); ++ log_print("Try SCTP, if you want to enable multi-link."); + } + + return 0; +diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c +index 396474e9e2bffe..3a2dfc59fb40fc 100644 +--- a/fs/ext4/balloc.c ++++ b/fs/ext4/balloc.c +@@ -641,8 +641,8 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi, + /* Hm, nope. Are (enough) root reserved clusters available? */ + if (uid_eq(sbi->s_resuid, current_fsuid()) || + (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) || +- capable(CAP_SYS_RESOURCE) || +- (flags & EXT4_MB_USE_ROOT_BLOCKS)) { ++ (flags & EXT4_MB_USE_ROOT_BLOCKS) || ++ capable(CAP_SYS_RESOURCE)) { + + if (free_clusters >= (nclusters + dirty_clusters + + resv_clusters)) +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 60455c84a93742..81fe87fcbfa068 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -273,7 +273,8 @@ struct ext4_system_blocks { + /* + * Flags for ext4_io_end->flags + */ +-#define EXT4_IO_END_UNWRITTEN 0x0001 ++#define EXT4_IO_END_UNWRITTEN 0x0001 ++#define EXT4_IO_END_FAILED 0x0002 + + struct ext4_io_end_vec { + struct list_head list; /* list of io_end_vec */ +@@ -2994,6 +2995,8 @@ extern int ext4_inode_attach_jinode(struct inode *inode); + extern int ext4_can_truncate(struct inode *inode); + extern int ext4_truncate(struct inode *); + extern int ext4_break_layouts(struct inode *); ++extern int ext4_truncate_page_cache_block_range(struct inode *inode, ++ loff_t start, loff_t end); + extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length); + extern void ext4_set_inode_flags(struct inode *, bool init); + extern int ext4_alloc_da_blocks(struct inode *inode); +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 32218ac7f50fe2..39e3661a80c433 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4660,22 +4660,13 @@ static long ext4_zero_range(struct file *file, loff_t offset, + goto out_mutex; + } + +- /* +- * For journalled data we need to write (and checkpoint) pages +- * before discarding page cache to avoid inconsitent data on +- * disk in case of crash before zeroing trans is committed. +- */ +- if (ext4_should_journal_data(inode)) { +- ret = filemap_write_and_wait_range(mapping, start, +- end - 1); +- if (ret) { +- filemap_invalidate_unlock(mapping); +- goto out_mutex; +- } ++ /* Now release the pages and zero block aligned part of pages */ ++ ret = ext4_truncate_page_cache_block_range(inode, start, end); ++ if (ret) { ++ filemap_invalidate_unlock(mapping); ++ goto out_mutex; + } + +- /* Now release the pages and zero block aligned part of pages */ +- truncate_pagecache_range(inode, start, end - 1); + inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); + + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index d3d28e65872027..86245e27be18db 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -3892,6 +3893,68 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, + return ret; + } + ++static inline void ext4_truncate_folio(struct inode *inode, ++ loff_t start, loff_t end) ++{ ++ unsigned long blocksize = i_blocksize(inode); ++ struct folio *folio; ++ ++ /* Nothing to be done if no complete block needs to be truncated. */ ++ if (round_up(start, blocksize) >= round_down(end, blocksize)) ++ return; ++ ++ folio = filemap_lock_folio(inode->i_mapping, start >> PAGE_SHIFT); ++ if (IS_ERR(folio)) ++ return; ++ ++ if (folio_mkclean(folio)) ++ folio_mark_dirty(folio); ++ folio_unlock(folio); ++ folio_put(folio); ++} ++ ++int ext4_truncate_page_cache_block_range(struct inode *inode, ++ loff_t start, loff_t end) ++{ ++ unsigned long blocksize = i_blocksize(inode); ++ int ret; ++ ++ /* ++ * For journalled data we need to write (and checkpoint) pages ++ * before discarding page cache to avoid inconsitent data on disk ++ * in case of crash before freeing or unwritten converting trans ++ * is committed. ++ */ ++ if (ext4_should_journal_data(inode)) { ++ ret = filemap_write_and_wait_range(inode->i_mapping, start, ++ end - 1); ++ if (ret) ++ return ret; ++ goto truncate_pagecache; ++ } ++ ++ /* ++ * If the block size is less than the page size, the file's mapped ++ * blocks within one page could be freed or converted to unwritten. ++ * So it's necessary to remove writable userspace mappings, and then ++ * ext4_page_mkwrite() can be called during subsequent write access ++ * to these partial folios. ++ */ ++ if (!IS_ALIGNED(start | end, PAGE_SIZE) && ++ blocksize < PAGE_SIZE && start < inode->i_size) { ++ loff_t page_boundary = round_up(start, PAGE_SIZE); ++ ++ ext4_truncate_folio(inode, start, min(page_boundary, end)); ++ if (end > page_boundary) ++ ext4_truncate_folio(inode, ++ round_down(end, PAGE_SIZE), end); ++ } ++ ++truncate_pagecache: ++ truncate_pagecache_range(inode, start, end - 1); ++ return 0; ++} ++ + static void ext4_wait_dax_page(struct inode *inode) + { + filemap_invalidate_unlock(inode->i_mapping); +@@ -3946,17 +4009,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) + + trace_ext4_punch_hole(inode, offset, length, 0); + +- /* +- * Write out all dirty pages to avoid race conditions +- * Then release them. +- */ +- if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { +- ret = filemap_write_and_wait_range(mapping, offset, +- offset + length - 1); +- if (ret) +- return ret; +- } +- + inode_lock(inode); + + /* No need to punch hole beyond i_size */ +@@ -4018,8 +4070,11 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) + ret = ext4_update_disksize_before_punch(inode, offset, length); + if (ret) + goto out_dio; +- truncate_pagecache_range(inode, first_block_offset, +- last_block_offset); ++ ++ ret = ext4_truncate_page_cache_block_range(inode, ++ first_block_offset, last_block_offset + 1); ++ if (ret) ++ goto out_dio; + } + + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index 7ab4f5a9bf5b87..7287dbfe13f120 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -181,14 +181,25 @@ static int ext4_end_io_end(ext4_io_end_t *io_end) + "list->prev 0x%p\n", + io_end, inode->i_ino, io_end->list.next, io_end->list.prev); + +- io_end->handle = NULL; /* Following call will use up the handle */ +- ret = ext4_convert_unwritten_io_end_vec(handle, io_end); ++ /* ++ * Do not convert the unwritten extents if data writeback fails, ++ * or stale data may be exposed. ++ */ ++ io_end->handle = NULL; /* Following call will use up the handle */ ++ if (unlikely(io_end->flag & EXT4_IO_END_FAILED)) { ++ ret = -EIO; ++ if (handle) ++ jbd2_journal_free_reserved(handle); ++ } else { ++ ret = ext4_convert_unwritten_io_end_vec(handle, io_end); ++ } + if (ret < 0 && !ext4_forced_shutdown(inode->i_sb)) { + ext4_msg(inode->i_sb, KERN_EMERG, + "failed to convert unwritten extents to written " + "extents -- potential data loss! " + "(inode %lu, error %d)", inode->i_ino, ret); + } ++ + ext4_clear_io_unwritten_flag(io_end); + ext4_release_io_end(io_end); + return ret; +@@ -344,6 +355,7 @@ static void ext4_end_bio(struct bio *bio) + bio->bi_status, inode->i_ino, + (unsigned long long) + bi_sector >> (inode->i_blkbits - 9)); ++ io_end->flag |= EXT4_IO_END_FAILED; + mapping_set_error(inode->i_mapping, + blk_status_to_errno(bio->bi_status)); + } +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 751c879271e05e..d2b58f940aab5e 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -2821,6 +2821,13 @@ static int ext4_check_opt_consistency(struct fs_context *fc, + } + + if (is_remount) { ++ if (!sbi->s_journal && ++ ctx_test_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT)) { ++ ext4_msg(NULL, KERN_WARNING, ++ "Remounting fs w/o journal so ignoring data_err option"); ++ ctx_clear_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT); ++ } ++ + if (ctx_test_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS) && + (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)) { + ext4_msg(NULL, KERN_ERR, "can't mount with " +@@ -5421,6 +5428,11 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) + "data=, fs mounted w/o journal"); + goto failed_mount3a; + } ++ if (test_opt(sb, DATA_ERR_ABORT)) { ++ ext4_msg(sb, KERN_ERR, ++ "can't mount with data_err=abort, fs mounted w/o journal"); ++ goto failed_mount3a; ++ } + sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM; + clear_opt(sb, JOURNAL_CHECKSUM); + clear_opt(sb, DATA_FLAGS); +@@ -6771,6 +6783,7 @@ static int ext4_reconfigure(struct fs_context *fc) + { + struct super_block *sb = fc->root->d_sb; + int ret; ++ bool old_ro = sb_rdonly(sb); + + fc->s_fs_info = EXT4_SB(sb); + +@@ -6782,9 +6795,9 @@ static int ext4_reconfigure(struct fs_context *fc) + if (ret < 0) + return ret; + +- ext4_msg(sb, KERN_INFO, "re-mounted %pU %s. Quota mode: %s.", +- &sb->s_uuid, sb_rdonly(sb) ? "ro" : "r/w", +- ext4_quota_mode(sb)); ++ ext4_msg(sb, KERN_INFO, "re-mounted %pU%s.", ++ &sb->s_uuid, ++ (old_ro != sb_rdonly(sb)) ? (sb_rdonly(sb) ? " ro" : " r/w") : ""); + + return 0; + } +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 180feefc4a9ceb..c4b0661888a159 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -61,6 +61,12 @@ struct f2fs_attr { + int id; + }; + ++struct f2fs_base_attr { ++ struct attribute attr; ++ ssize_t (*show)(struct f2fs_base_attr *a, char *buf); ++ ssize_t (*store)(struct f2fs_base_attr *a, const char *buf, size_t len); ++}; ++ + static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf); + +@@ -791,6 +797,25 @@ static void f2fs_sb_release(struct kobject *kobj) + complete(&sbi->s_kobj_unregister); + } + ++static ssize_t f2fs_base_attr_show(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ struct f2fs_base_attr *a = container_of(attr, ++ struct f2fs_base_attr, attr); ++ ++ return a->show ? a->show(a, buf) : 0; ++} ++ ++static ssize_t f2fs_base_attr_store(struct kobject *kobj, ++ struct attribute *attr, ++ const char *buf, size_t len) ++{ ++ struct f2fs_base_attr *a = container_of(attr, ++ struct f2fs_base_attr, attr); ++ ++ return a->store ? a->store(a, buf, len) : 0; ++} ++ + /* + * Note that there are three feature list entries: + * 1) /sys/fs/f2fs/features +@@ -809,14 +834,13 @@ static void f2fs_sb_release(struct kobject *kobj) + * please add new on-disk feature in this list only. + * - ref. F2FS_SB_FEATURE_RO_ATTR() + */ +-static ssize_t f2fs_feature_show(struct f2fs_attr *a, +- struct f2fs_sb_info *sbi, char *buf) ++static ssize_t f2fs_feature_show(struct f2fs_base_attr *a, char *buf) + { + return sysfs_emit(buf, "supported\n"); + } + + #define F2FS_FEATURE_RO_ATTR(_name) \ +-static struct f2fs_attr f2fs_attr_##_name = { \ ++static struct f2fs_base_attr f2fs_base_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = 0444 }, \ + .show = f2fs_feature_show, \ + } +@@ -1166,37 +1190,38 @@ static struct attribute *f2fs_attrs[] = { + }; + ATTRIBUTE_GROUPS(f2fs); + ++#define BASE_ATTR_LIST(name) (&f2fs_base_attr_##name.attr) + static struct attribute *f2fs_feat_attrs[] = { + #ifdef CONFIG_FS_ENCRYPTION +- ATTR_LIST(encryption), +- ATTR_LIST(test_dummy_encryption_v2), ++ BASE_ATTR_LIST(encryption), ++ BASE_ATTR_LIST(test_dummy_encryption_v2), + #if IS_ENABLED(CONFIG_UNICODE) +- ATTR_LIST(encrypted_casefold), ++ BASE_ATTR_LIST(encrypted_casefold), + #endif + #endif /* CONFIG_FS_ENCRYPTION */ + #ifdef CONFIG_BLK_DEV_ZONED +- ATTR_LIST(block_zoned), ++ BASE_ATTR_LIST(block_zoned), + #endif +- ATTR_LIST(atomic_write), +- ATTR_LIST(extra_attr), +- ATTR_LIST(project_quota), +- ATTR_LIST(inode_checksum), +- ATTR_LIST(flexible_inline_xattr), +- ATTR_LIST(quota_ino), +- ATTR_LIST(inode_crtime), +- ATTR_LIST(lost_found), ++ BASE_ATTR_LIST(atomic_write), ++ BASE_ATTR_LIST(extra_attr), ++ BASE_ATTR_LIST(project_quota), ++ BASE_ATTR_LIST(inode_checksum), ++ BASE_ATTR_LIST(flexible_inline_xattr), ++ BASE_ATTR_LIST(quota_ino), ++ BASE_ATTR_LIST(inode_crtime), ++ BASE_ATTR_LIST(lost_found), + #ifdef CONFIG_FS_VERITY +- ATTR_LIST(verity), ++ BASE_ATTR_LIST(verity), + #endif +- ATTR_LIST(sb_checksum), ++ BASE_ATTR_LIST(sb_checksum), + #if IS_ENABLED(CONFIG_UNICODE) +- ATTR_LIST(casefold), ++ BASE_ATTR_LIST(casefold), + #endif +- ATTR_LIST(readonly), ++ BASE_ATTR_LIST(readonly), + #ifdef CONFIG_F2FS_FS_COMPRESSION +- ATTR_LIST(compression), ++ BASE_ATTR_LIST(compression), + #endif +- ATTR_LIST(pin_file), ++ BASE_ATTR_LIST(pin_file), + NULL, + }; + ATTRIBUTE_GROUPS(f2fs_feat); +@@ -1263,9 +1288,14 @@ static struct kset f2fs_kset = { + .kobj = {.ktype = &f2fs_ktype}, + }; + ++static const struct sysfs_ops f2fs_feat_attr_ops = { ++ .show = f2fs_base_attr_show, ++ .store = f2fs_base_attr_store, ++}; ++ + static const struct kobj_type f2fs_feat_ktype = { + .default_groups = f2fs_feat_groups, +- .sysfs_ops = &f2fs_attr_ops, ++ .sysfs_ops = &f2fs_feat_attr_ops, + }; + + static struct kobject f2fs_feat = { +diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c +index e4d6cc0d2332a4..82951a535d2d4d 100644 +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -1121,6 +1121,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, + else if (err == -EINTR) + fuse_invalidate_attr(inode); + ++ if (err == -ENOSYS) ++ err = -EPERM; + return err; + } + +diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c +index 2c0908a3021026..687670075d2256 100644 +--- a/fs/gfs2/glock.c ++++ b/fs/gfs2/glock.c +@@ -853,11 +853,12 @@ static void run_queue(struct gfs2_glock *gl, const int nonblock) + __releases(&gl->gl_lockref.lock) + __acquires(&gl->gl_lockref.lock) + { +- struct gfs2_holder *gh = NULL; ++ struct gfs2_holder *gh; + + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) + return; + ++ /* While a demote is in progress, the GLF_LOCK flag must be set. */ + GLOCK_BUG_ON(gl, test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)); + + if (test_bit(GLF_DEMOTE, &gl->gl_flags) && +@@ -869,18 +870,22 @@ __acquires(&gl->gl_lockref.lock) + set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); + GLOCK_BUG_ON(gl, gl->gl_demote_state == LM_ST_EXCLUSIVE); + gl->gl_target = gl->gl_demote_state; ++ do_xmote(gl, NULL, gl->gl_target); ++ return; + } else { + if (test_bit(GLF_DEMOTE, &gl->gl_flags)) + gfs2_demote_wake(gl); + if (do_promote(gl)) + goto out_unlock; + gh = find_first_waiter(gl); ++ if (!gh) ++ goto out_unlock; + gl->gl_target = gh->gh_state; + if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) + do_error(gl, 0); /* Fail queued try locks */ ++ do_xmote(gl, gh, gl->gl_target); ++ return; + } +- do_xmote(gl, gh, gl->gl_target); +- return; + + out_sched: + clear_bit(GLF_LOCK, &gl->gl_flags); +diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c +index 421c0d360836e0..19ec3253748331 100644 +--- a/fs/jbd2/recovery.c ++++ b/fs/jbd2/recovery.c +@@ -286,21 +286,22 @@ static int fc_do_one_pass(journal_t *journal, + int jbd2_journal_recover(journal_t *journal) + { + int err, err2; +- journal_superblock_t * sb; +- + struct recovery_info info; + errseq_t wb_err; + struct address_space *mapping; + + memset(&info, 0, sizeof(info)); +- sb = journal->j_superblock; + + /* + * The journal superblock's s_start field (the current log head) + * is always zero if, and only if, the journal was cleanly +- * unmounted. ++ * unmounted. We use its in-memory version j_tail here because ++ * jbd2_journal_wipe() could have updated it without updating journal ++ * superblock. + */ +- if (!sb->s_start) { ++ if (!journal->j_tail) { ++ journal_superblock_t *sb = journal->j_superblock; ++ + jbd2_debug(1, "No recovery required, last transaction %d, head block %u\n", + be32_to_cpu(sb->s_sequence), be32_to_cpu(sb->s_head)); + journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; +diff --git a/fs/namespace.c b/fs/namespace.c +index 450f4198b8cdd8..ef3b2ae2957ec3 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -636,12 +636,8 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq) + smp_mb(); // see mntput_no_expire() and do_umount() + if (likely(!read_seqretry(&mount_lock, seq))) + return 0; +- if (bastard->mnt_flags & MNT_SYNC_UMOUNT) { +- mnt_add_count(mnt, -1); +- return 1; +- } + lock_mount_hash(); +- if (unlikely(bastard->mnt_flags & MNT_DOOMED)) { ++ if (unlikely(bastard->mnt_flags & (MNT_SYNC_UMOUNT | MNT_DOOMED))) { + mnt_add_count(mnt, -1); + unlock_mount_hash(); + return 1; +diff --git a/fs/nfs/client.c b/fs/nfs/client.c +index 62607d52bfa5e7..aa09f930eeaf7e 100644 +--- a/fs/nfs/client.c ++++ b/fs/nfs/client.c +@@ -1080,6 +1080,8 @@ struct nfs_server *nfs_create_server(struct fs_context *fc) + if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) + server->namelen = NFS2_MAXNAMLEN; + } ++ /* Linux 'subtree_check' borkenness mandates this setting */ ++ server->fh_expire_type = NFS_FH_VOL_RENAME; + + if (!(fattr->valid & NFS_ATTR_FATTR)) { + error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh, +diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c +index 55cfa1c4e0a65d..bbd582d8a7dc93 100644 +--- a/fs/nfs/delegation.c ++++ b/fs/nfs/delegation.c +@@ -297,7 +297,8 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi) + if (delegation == NULL) + goto out; + spin_lock(&delegation->lock); +- if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { ++ if (delegation->inode && ++ !test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { + clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags); + /* Refcount matched in nfs_end_delegation_return() */ + ret = nfs_get_delegation(delegation); +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index 39f7549afcf5bd..38918638423596 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -2642,6 +2642,18 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data) + unblock_revalidate(new_dentry); + } + ++static bool nfs_rename_is_unsafe_cross_dir(struct dentry *old_dentry, ++ struct dentry *new_dentry) ++{ ++ struct nfs_server *server = NFS_SB(old_dentry->d_sb); ++ ++ if (old_dentry->d_parent != new_dentry->d_parent) ++ return false; ++ if (server->fh_expire_type & NFS_FH_RENAME_UNSAFE) ++ return !(server->fh_expire_type & NFS_FH_NOEXPIRE_WITH_OPEN); ++ return true; ++} ++ + /* + * RENAME + * FIXME: Some nfsds, like the Linux user space nfsd, may generate a +@@ -2729,7 +2741,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, + + } + +- if (S_ISREG(old_inode->i_mode)) ++ if (S_ISREG(old_inode->i_mode) && ++ nfs_rename_is_unsafe_cross_dir(old_dentry, new_dentry)) + nfs_sync_inode(old_inode); + task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, + must_unblock ? nfs_unblock_rename : NULL); +diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c +index acf4b88889dc38..d5f1fbfd9a0c7f 100644 +--- a/fs/nfs/filelayout/filelayoutdev.c ++++ b/fs/nfs/filelayout/filelayoutdev.c +@@ -75,6 +75,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + struct page *scratch; + struct list_head dsaddrs; + struct nfs4_pnfs_ds_addr *da; ++ struct net *net = server->nfs_client->cl_net; + + /* set up xdr stream */ + scratch = alloc_page(gfp_flags); +@@ -158,8 +159,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + + mp_count = be32_to_cpup(p); /* multipath count */ + for (j = 0; j < mp_count; j++) { +- da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net, +- &stream, gfp_flags); ++ da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); + if (da) + list_add_tail(&da->da_node, &dsaddrs); + } +@@ -169,7 +169,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + goto out_err_free_deviceid; + } + +- dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); ++ dsaddr->ds_list[i] = nfs4_pnfs_ds_add(net, &dsaddrs, gfp_flags); + if (!dsaddr->ds_list[i]) + goto out_err_drain_dsaddrs; + +diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c +index 2b3c5eea1f1345..0bc537de1b2958 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayout.c ++++ b/fs/nfs/flexfilelayout/flexfilelayout.c +@@ -1255,6 +1255,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg, + case -ECONNRESET: + case -EHOSTDOWN: + case -EHOSTUNREACH: ++ case -ENETDOWN: + case -ENETUNREACH: + case -EADDRINUSE: + case -ENOBUFS: +diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +index e028f5a0ef5f65..d21c5ecfbf1cc3 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c ++++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +@@ -49,6 +49,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + struct nfs4_pnfs_ds_addr *da; + struct nfs4_ff_layout_ds *new_ds = NULL; + struct nfs4_ff_ds_version *ds_versions = NULL; ++ struct net *net = server->nfs_client->cl_net; + u32 mp_count; + u32 version_count; + __be32 *p; +@@ -80,8 +81,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + + for (i = 0; i < mp_count; i++) { + /* multipath ds */ +- da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net, +- &stream, gfp_flags); ++ da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); + if (da) + list_add_tail(&da->da_node, &dsaddrs); + } +@@ -149,7 +149,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + new_ds->ds_versions = ds_versions; + new_ds->ds_versions_cnt = version_count; + +- new_ds->ds = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); ++ new_ds->ds = nfs4_pnfs_ds_add(net, &dsaddrs, gfp_flags); + if (!new_ds->ds) + goto out_err_drain_dsaddrs; + +diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c +index 56bbf59bda3cf6..06230baaa554e7 100644 +--- a/fs/nfs/inode.c ++++ b/fs/nfs/inode.c +@@ -74,6 +74,8 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) + + int nfs_wait_bit_killable(struct wait_bit_key *key, int mode) + { ++ if (unlikely(nfs_current_task_exiting())) ++ return -EINTR; + schedule(); + if (signal_pending_state(mode, current)) + return -ERESTARTSYS; +diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h +index ca49d999159eb1..c29ad2e1d41635 100644 +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -865,6 +865,11 @@ static inline u32 nfs_stateid_hash(const nfs4_stateid *stateid) + NFS4_STATEID_OTHER_SIZE); + } + ++static inline bool nfs_current_task_exiting(void) ++{ ++ return (current->flags & PF_EXITING) != 0; ++} ++ + static inline bool nfs_error_is_fatal(int err) + { + switch (err) { +diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c +index 4bf208a0a8e994..715753f41fb072 100644 +--- a/fs/nfs/nfs3proc.c ++++ b/fs/nfs/nfs3proc.c +@@ -39,7 +39,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) + __set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); + schedule_timeout(NFS_JUKEBOX_RETRY_TIME); + res = -ERESTARTSYS; +- } while (!fatal_signal_pending(current)); ++ } while (!fatal_signal_pending(current) && !nfs_current_task_exiting()); + return res; + } + +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index c140427e322ced..1b94a55215e7de 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -422,6 +422,8 @@ static int nfs4_delay_killable(long *timeout) + { + might_sleep(); + ++ if (unlikely(nfs_current_task_exiting())) ++ return -EINTR; + __set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); + schedule_timeout(nfs4_update_delay(timeout)); + if (!__fatal_signal_pending(current)) +@@ -433,6 +435,8 @@ static int nfs4_delay_interruptible(long *timeout) + { + might_sleep(); + ++ if (unlikely(nfs_current_task_exiting())) ++ return -EINTR; + __set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE_UNSAFE); + schedule_timeout(nfs4_update_delay(timeout)); + if (!signal_pending(current)) +@@ -1712,7 +1716,8 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, + rcu_read_unlock(); + trace_nfs4_open_stateid_update_wait(state->inode, stateid, 0); + +- if (!fatal_signal_pending(current)) { ++ if (!fatal_signal_pending(current) && ++ !nfs_current_task_exiting()) { + if (schedule_timeout(5*HZ) == 0) + status = -EAGAIN; + else +@@ -3494,7 +3499,7 @@ static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst, + write_sequnlock(&state->seqlock); + trace_nfs4_close_stateid_update_wait(state->inode, dst, 0); + +- if (fatal_signal_pending(current)) ++ if (fatal_signal_pending(current) || nfs_current_task_exiting()) + status = -EINTR; + else + if (schedule_timeout(5*HZ) != 0) +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index 794bb4aa588d39..9fc71dc090c254 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -2741,7 +2741,15 @@ static void nfs4_state_manager(struct nfs_client *clp) + pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s" + " with error %d\n", section_sep, section, + clp->cl_hostname, -status); +- ssleep(1); ++ switch (status) { ++ case -ENETDOWN: ++ case -ENETUNREACH: ++ nfs_mark_client_ready(clp, -EIO); ++ break; ++ default: ++ ssleep(1); ++ break; ++ } + out_drain: + memalloc_nofs_restore(memflags); + nfs4_end_drain_session(clp); +diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h +index d886c8226d8fec..79996d7dad0f76 100644 +--- a/fs/nfs/pnfs.h ++++ b/fs/nfs/pnfs.h +@@ -59,6 +59,7 @@ struct nfs4_pnfs_ds { + struct list_head ds_node; /* nfs4_pnfs_dev_hlist dev_dslist */ + char *ds_remotestr; /* comma sep list of addrs */ + struct list_head ds_addrs; ++ const struct net *ds_net; + struct nfs_client *ds_clp; + refcount_t ds_count; + unsigned long ds_state; +@@ -405,7 +406,8 @@ int pnfs_generic_commit_pagelist(struct inode *inode, + int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max); + void pnfs_generic_write_commit_done(struct rpc_task *task, void *data); + void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds); +-struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, ++struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(const struct net *net, ++ struct list_head *dsaddrs, + gfp_t gfp_flags); + void nfs4_pnfs_v3_ds_connect_unload(void); + int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, +diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c +index 88e061bd711b74..1b317c44da126b 100644 +--- a/fs/nfs/pnfs_nfs.c ++++ b/fs/nfs/pnfs_nfs.c +@@ -651,12 +651,12 @@ _same_data_server_addrs_locked(const struct list_head *dsaddrs1, + * Lookup DS by addresses. nfs4_ds_cache_lock is held + */ + static struct nfs4_pnfs_ds * +-_data_server_lookup_locked(const struct list_head *dsaddrs) ++_data_server_lookup_locked(const struct net *net, const struct list_head *dsaddrs) + { + struct nfs4_pnfs_ds *ds; + + list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) +- if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs)) ++ if (ds->ds_net == net && _same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs)) + return ds; + return NULL; + } +@@ -763,7 +763,7 @@ nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags) + * uncached and return cached struct nfs4_pnfs_ds. + */ + struct nfs4_pnfs_ds * +-nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) ++nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_flags) + { + struct nfs4_pnfs_ds *tmp_ds, *ds = NULL; + char *remotestr; +@@ -781,13 +781,14 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) + remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags); + + spin_lock(&nfs4_ds_cache_lock); +- tmp_ds = _data_server_lookup_locked(dsaddrs); ++ tmp_ds = _data_server_lookup_locked(net, dsaddrs); + if (tmp_ds == NULL) { + INIT_LIST_HEAD(&ds->ds_addrs); + list_splice_init(dsaddrs, &ds->ds_addrs); + ds->ds_remotestr = remotestr; + refcount_set(&ds->ds_count, 1); + INIT_LIST_HEAD(&ds->ds_node); ++ ds->ds_net = net; + ds->ds_clp = NULL; + list_add(&ds->ds_node, &nfs4_data_server_cache); + dprintk("%s add new data server %s\n", __func__, +diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c +index 0859122684425f..dd4dc70e4aaab7 100644 +--- a/fs/orangefs/inode.c ++++ b/fs/orangefs/inode.c +@@ -23,9 +23,9 @@ static int orangefs_writepage_locked(struct page *page, + struct orangefs_write_range *wr = NULL; + struct iov_iter iter; + struct bio_vec bv; +- size_t len, wlen; ++ size_t wlen; + ssize_t ret; +- loff_t off; ++ loff_t len, off; + + set_page_writeback(page); + +@@ -92,8 +92,7 @@ static int orangefs_writepages_work(struct orangefs_writepages *ow, + struct orangefs_write_range *wrp, wr; + struct iov_iter iter; + ssize_t ret; +- size_t len; +- loff_t off; ++ loff_t len, off; + int i; + + len = i_size_read(inode); +diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c +index 7dbbf3b6d98d3c..a1c97cd2720a68 100644 +--- a/fs/pstore/inode.c ++++ b/fs/pstore/inode.c +@@ -264,7 +264,7 @@ static void parse_options(char *options) + static int pstore_show_options(struct seq_file *m, struct dentry *root) + { + if (kmsg_bytes != CONFIG_PSTORE_DEFAULT_KMSG_BYTES) +- seq_printf(m, ",kmsg_bytes=%lu", kmsg_bytes); ++ seq_printf(m, ",kmsg_bytes=%u", kmsg_bytes); + return 0; + } + +diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h +index 801d6c0b170c3a..a0fc511969100c 100644 +--- a/fs/pstore/internal.h ++++ b/fs/pstore/internal.h +@@ -6,7 +6,7 @@ + #include + #include + +-extern unsigned long kmsg_bytes; ++extern unsigned int kmsg_bytes; + + #ifdef CONFIG_PSTORE_FTRACE + extern void pstore_register_ftrace(void); +@@ -35,7 +35,7 @@ static inline void pstore_unregister_pmsg(void) {} + + extern struct pstore_info *psinfo; + +-extern void pstore_set_kmsg_bytes(int); ++extern void pstore_set_kmsg_bytes(unsigned int bytes); + extern void pstore_get_records(int); + extern void pstore_get_backend_records(struct pstore_info *psi, + struct dentry *root, int quiet); +diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c +index 03425928d2fb3c..ef62389212b608 100644 +--- a/fs/pstore/platform.c ++++ b/fs/pstore/platform.c +@@ -92,8 +92,8 @@ module_param(compress, charp, 0444); + MODULE_PARM_DESC(compress, "compression to use"); + + /* How much of the kernel log to snapshot */ +-unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES; +-module_param(kmsg_bytes, ulong, 0444); ++unsigned int kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES; ++module_param(kmsg_bytes, uint, 0444); + MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)"); + + static void *compress_workspace; +@@ -107,9 +107,9 @@ static void *compress_workspace; + static char *big_oops_buf; + static size_t max_compressed_size; + +-void pstore_set_kmsg_bytes(int bytes) ++void pstore_set_kmsg_bytes(unsigned int bytes) + { +- kmsg_bytes = bytes; ++ WRITE_ONCE(kmsg_bytes, bytes); + } + + /* Tag each group of saved records with a sequence number */ +@@ -278,6 +278,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason) + { + struct kmsg_dump_iter iter; ++ unsigned int remaining = READ_ONCE(kmsg_bytes); + unsigned long total = 0; + const char *why; + unsigned int part = 1; +@@ -300,7 +301,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, + kmsg_dump_rewind(&iter); + + oopscount++; +- while (total < kmsg_bytes) { ++ while (total < remaining) { + char *dst; + size_t dst_size; + int header_size; +diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c +index db9076da2182ad..bf32bc22ebd69f 100644 +--- a/fs/smb/client/cifsacl.c ++++ b/fs/smb/client/cifsacl.c +@@ -811,7 +811,23 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, + return; + + for (i = 0; i < num_aces; ++i) { ++ if (end_of_acl - acl_base < acl_size) ++ break; ++ + ppace[i] = (struct smb_ace *) (acl_base + acl_size); ++ acl_base = (char *)ppace[i]; ++ acl_size = offsetof(struct smb_ace, sid) + ++ offsetof(struct smb_sid, sub_auth); ++ ++ if (end_of_acl - acl_base < acl_size || ++ ppace[i]->sid.num_subauth == 0 || ++ ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || ++ (end_of_acl - acl_base < ++ acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || ++ (le16_to_cpu(ppace[i]->size) < ++ acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) ++ break; ++ + #ifdef CONFIG_CIFS_DEBUG2 + dump_ace(ppace[i], end_of_acl); + #endif +@@ -855,7 +871,6 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, + (void *)ppace[i], + sizeof(struct smb_ace)); */ + +- acl_base = (char *)ppace[i]; + acl_size = le16_to_cpu(ppace[i]->size); + } + +diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h +index c46d418c1c0c3e..ca33f6cd6a8004 100644 +--- a/fs/smb/client/cifspdu.h ++++ b/fs/smb/client/cifspdu.h +@@ -1226,10 +1226,9 @@ typedef struct smb_com_query_information_rsp { + typedef struct smb_com_setattr_req { + struct smb_hdr hdr; /* wct = 8 */ + __le16 attr; +- __le16 time_low; +- __le16 time_high; ++ __le32 last_write_time; + __le16 reserved[5]; /* must be zero */ +- __u16 ByteCount; ++ __le16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char fileName[]; + } __attribute__((packed)) SETATTR_REQ; +diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h +index 7f97e54686524b..c6d325666b5cd8 100644 +--- a/fs/smb/client/cifsproto.h ++++ b/fs/smb/client/cifsproto.h +@@ -31,6 +31,9 @@ extern void cifs_small_buf_release(void *); + extern void free_rsp_buf(int, void *); + extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, + unsigned int /* length */); ++extern int smb_send_kvec(struct TCP_Server_Info *server, ++ struct msghdr *msg, ++ size_t *sent); + extern unsigned int _get_xid(void); + extern void _free_xid(unsigned int); + #define get_xid() \ +@@ -395,6 +398,10 @@ extern int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon); + extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, + struct kstatfs *FSData); + ++extern int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, ++ const char *fileName, __le32 attributes, __le64 write_time, ++ const struct nls_table *nls_codepage, ++ struct cifs_sb_info *cifs_sb); + extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, const FILE_BASIC_INFO *data, + const struct nls_table *nls_codepage, +diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c +index 769950adb7763b..b91184ebce02c5 100644 +--- a/fs/smb/client/cifssmb.c ++++ b/fs/smb/client/cifssmb.c +@@ -5157,6 +5157,63 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, + return rc; + } + ++int ++SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, ++ const char *fileName, __le32 attributes, __le64 write_time, ++ const struct nls_table *nls_codepage, ++ struct cifs_sb_info *cifs_sb) ++{ ++ SETATTR_REQ *pSMB; ++ SETATTR_RSP *pSMBr; ++ struct timespec64 ts; ++ int bytes_returned; ++ int name_len; ++ int rc; ++ ++ cifs_dbg(FYI, "In %s path %s\n", __func__, fileName); ++ ++retry: ++ rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifsConvertToUTF16((__le16 *) pSMB->fileName, ++ fileName, PATH_MAX, nls_codepage, ++ cifs_remap(cifs_sb)); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { ++ name_len = copy_path_name(pSMB->fileName, fileName); ++ } ++ /* Only few attributes can be set by this command, others are not accepted by Win9x. */ ++ pSMB->attr = cpu_to_le16(le32_to_cpu(attributes) & ++ (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE)); ++ /* Zero write time value (in both NT and SETATTR formats) means to not change it. */ ++ if (le64_to_cpu(write_time) != 0) { ++ ts = cifs_NTtimeToUnix(write_time); ++ pSMB->last_write_time = cpu_to_le32(ts.tv_sec); ++ } ++ pSMB->BufferFormat = 0x04; ++ name_len++; /* account for buffer type byte */ ++ inc_rfc1001_len(pSMB, (__u16)name_len); ++ pSMB->ByteCount = cpu_to_le16(name_len); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) ++ cifs_dbg(FYI, "Send error in %s = %d\n", __func__, rc); ++ ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto retry; ++ ++ return rc; ++} ++ + /* Some legacy servers such as NT4 require that the file times be set on + an open handle, rather than by pathname - this is awkward due to + potential access conflicts on the open, but it is unavoidable for these +diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c +index 54aba8d642ee75..3faaee33ad4558 100644 +--- a/fs/smb/client/connect.c ++++ b/fs/smb/client/connect.c +@@ -3051,8 +3051,10 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) + * sessinit is sent but no second negprot + */ + struct rfc1002_session_packet req = {}; +- struct smb_hdr *smb_buf = (struct smb_hdr *)&req; ++ struct msghdr msg = {}; ++ struct kvec iov = {}; + unsigned int len; ++ size_t sent; + + req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name); + +@@ -3081,10 +3083,18 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) + * As per rfc1002, @len must be the number of bytes that follows the + * length field of a rfc1002 session request payload. + */ +- len = sizeof(req) - offsetof(struct rfc1002_session_packet, trailer.session_req); ++ len = sizeof(req.trailer.session_req); ++ req.type = RFC1002_SESSION_REQUEST; ++ req.flags = 0; ++ req.length = cpu_to_be16(len); ++ len += offsetof(typeof(req), trailer.session_req); ++ iov.iov_base = &req; ++ iov.iov_len = len; ++ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, len); ++ rc = smb_send_kvec(server, &msg, &sent); ++ if (rc < 0 || len != sent) ++ return (rc == -EINTR || rc == -EAGAIN) ? rc : -ECONNABORTED; + +- smb_buf->smb_buf_length = cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | len); +- rc = smb_send(server, smb_buf, len); + /* + * RFC1001 layer in at least one server requires very short break before + * negprot presumably because not expecting negprot to follow so fast. +@@ -3093,7 +3103,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) + */ + usleep_range(1000, 2000); + +- return rc; ++ return 0; + } + + static int +@@ -3946,11 +3956,13 @@ int + cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server) + { ++ bool in_retry = false; + int rc = 0; + + if (!server->ops->need_neg || !server->ops->negotiate) + return -ENOSYS; + ++retry: + /* only send once per connect */ + spin_lock(&server->srv_lock); + if (server->tcpStatus != CifsGood && +@@ -3970,6 +3982,14 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, + spin_unlock(&server->srv_lock); + + rc = server->ops->negotiate(xid, ses, server); ++ if (rc == -EAGAIN) { ++ /* Allow one retry attempt */ ++ if (!in_retry) { ++ in_retry = true; ++ goto retry; ++ } ++ rc = -EHOSTDOWN; ++ } + if (rc == 0) { + spin_lock(&server->srv_lock); + if (server->tcpStatus == CifsInNegotiate) +diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c +index d2e291ef104ec0..137d03781d5268 100644 +--- a/fs/smb/client/fs_context.c ++++ b/fs/smb/client/fs_context.c +@@ -1249,6 +1249,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, + case Opt_rsize: + ctx->rsize = result.uint_32; + ctx->got_rsize = true; ++ ctx->vol_rsize = ctx->rsize; + break; + case Opt_wsize: + ctx->wsize = result.uint_32; +@@ -1264,6 +1265,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, + ctx->wsize, PAGE_SIZE); + } + } ++ ctx->vol_wsize = ctx->wsize; + break; + case Opt_acregmax: + if (result.uint_32 > CIFS_MAX_ACTIMEO / HZ) { +diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h +index bbd2063ab838d3..d0a2043ea44682 100644 +--- a/fs/smb/client/fs_context.h ++++ b/fs/smb/client/fs_context.h +@@ -253,6 +253,9 @@ struct smb3_fs_context { + bool use_client_guid:1; + /* reuse existing guid for multichannel */ + u8 client_guid[SMB2_CLIENT_GUID_SIZE]; ++ /* User-specified original r/wsize value */ ++ unsigned int vol_rsize; ++ unsigned int vol_wsize; + unsigned int bsize; + unsigned int rasize; + unsigned int rsize; +diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c +index d86da949a91905..007da0a699cb0a 100644 +--- a/fs/smb/client/link.c ++++ b/fs/smb/client/link.c +@@ -257,7 +257,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_open_parms oparms; + struct cifs_io_parms io_parms = {0}; + int buf_type = CIFS_NO_BUFFER; +- FILE_ALL_INFO file_info; ++ struct cifs_open_info_data query_data; + + oparms = (struct cifs_open_parms) { + .tcon = tcon, +@@ -269,11 +269,11 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + .fid = &fid, + }; + +- rc = CIFS_open(xid, &oparms, &oplock, &file_info); ++ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data); + if (rc) + return rc; + +- if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { ++ if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { + rc = -ENOENT; + /* it's not a symlink */ + goto out; +@@ -312,7 +312,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + .fid = &fid, + }; + +- rc = CIFS_open(xid, &oparms, &oplock, NULL); ++ rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); + if (rc) + return rc; + +diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c +index 75929a0a56f969..e616be8196deda 100644 +--- a/fs/smb/client/readdir.c ++++ b/fs/smb/client/readdir.c +@@ -733,7 +733,10 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, + else + cifs_buf_release(cfile->srch_inf. + ntwrk_buf_start); ++ /* Reset all pointers to the network buffer to prevent stale references */ + cfile->srch_inf.ntwrk_buf_start = NULL; ++ cfile->srch_inf.srch_entries_start = NULL; ++ cfile->srch_inf.last_entry = NULL; + } + rc = initiate_cifs_search(xid, file, full_path); + if (rc) { +@@ -756,11 +759,11 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, + rc = server->ops->query_dir_next(xid, tcon, &cfile->fid, + search_flags, + &cfile->srch_inf); ++ if (rc) ++ return -ENOENT; + /* FindFirst/Next set last_entry to NULL on malformed reply */ + if (cfile->srch_inf.last_entry) + cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); +- if (rc) +- return -ENOENT; + } + if (index_to_find < cfile->srch_inf.index_of_last_entry) { + /* we found the buffer that contains the entry */ +diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c +index caa1d852ece49c..e62d9cc592e0c8 100644 +--- a/fs/smb/client/smb1ops.c ++++ b/fs/smb/client/smb1ops.c +@@ -426,13 +426,6 @@ cifs_negotiate(const unsigned int xid, + { + int rc; + rc = CIFSSMBNegotiate(xid, ses, server); +- if (rc == -EAGAIN) { +- /* retry only once on 1st time connection */ +- set_credits(server, 1); +- rc = CIFSSMBNegotiate(xid, ses, server); +- if (rc == -EAGAIN) +- rc = -EHOSTDOWN; +- } + return rc; + } + +@@ -444,8 +437,8 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int wsize; + + /* start with specified wsize, or default */ +- if (ctx->wsize) +- wsize = ctx->wsize; ++ if (ctx->got_wsize) ++ wsize = ctx->vol_wsize; + else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) + wsize = CIFS_DEFAULT_IOSIZE; + else +@@ -497,7 +490,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + else + defsize = server->maxBuf - sizeof(READ_RSP); + +- rsize = ctx->rsize ? ctx->rsize : defsize; ++ rsize = ctx->got_rsize ? ctx->vol_rsize : defsize; + + /* + * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to +@@ -548,24 +541,104 @@ static int cifs_query_path_info(const unsigned int xid, + const char *full_path, + struct cifs_open_info_data *data) + { +- int rc; ++ int rc = -EOPNOTSUPP; + FILE_ALL_INFO fi = {}; ++ struct cifs_search_info search_info = {}; ++ bool non_unicode_wildcard = false; + + data->symlink = false; + data->adjust_tz = false; + +- /* could do find first instead but this returns more info */ +- rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls, +- cifs_remap(cifs_sb)); + /* +- * BB optimize code so we do not make the above call when server claims +- * no NT SMB support and the above call failed at least once - set flag +- * in tcon or mount. ++ * First try CIFSSMBQPathInfo() function which returns more info ++ * (NumberOfLinks) than CIFSFindFirst() fallback function. ++ * Some servers like Win9x do not support SMB_QUERY_FILE_ALL_INFO over ++ * TRANS2_QUERY_PATH_INFORMATION, but supports it with filehandle over ++ * TRANS2_QUERY_FILE_INFORMATION (function CIFSSMBQFileInfo(). But SMB ++ * Open command on non-NT servers works only for files, does not work ++ * for directories. And moreover Win9x SMB server returns bogus data in ++ * SMB_QUERY_FILE_ALL_INFO Attributes field. So for non-NT servers, ++ * do not even use CIFSSMBQPathInfo() or CIFSSMBQFileInfo() function. ++ */ ++ if (tcon->ses->capabilities & CAP_NT_SMBS) ++ rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, ++ cifs_sb->local_nls, cifs_remap(cifs_sb)); ++ ++ /* ++ * Non-UNICODE variant of fallback functions below expands wildcards, ++ * so they cannot be used for querying paths with wildcard characters. + */ +- if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { ++ if (rc && !(tcon->ses->capabilities & CAP_UNICODE) && strpbrk(full_path, "*?\"><")) ++ non_unicode_wildcard = true; ++ ++ /* ++ * Then fallback to CIFSFindFirst() which works also with non-NT servers ++ * but does not does not provide NumberOfLinks. ++ */ ++ if ((rc == -EOPNOTSUPP || rc == -EINVAL) && ++ !non_unicode_wildcard) { ++ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) ++ search_info.info_level = SMB_FIND_FILE_INFO_STANDARD; ++ else ++ search_info.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO; ++ rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb, NULL, ++ CIFS_SEARCH_CLOSE_ALWAYS | CIFS_SEARCH_CLOSE_AT_END, ++ &search_info, false); ++ if (rc == 0) { ++ if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) { ++ FIND_FILE_STANDARD_INFO *di; ++ int offset = tcon->ses->server->timeAdj; ++ ++ di = (FIND_FILE_STANDARD_INFO *)search_info.srch_entries_start; ++ fi.CreationTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( ++ di->CreationDate, di->CreationTime, offset))); ++ fi.LastAccessTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( ++ di->LastAccessDate, di->LastAccessTime, offset))); ++ fi.LastWriteTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( ++ di->LastWriteDate, di->LastWriteTime, offset))); ++ fi.ChangeTime = fi.LastWriteTime; ++ fi.Attributes = cpu_to_le32(le16_to_cpu(di->Attributes)); ++ fi.AllocationSize = cpu_to_le64(le32_to_cpu(di->AllocationSize)); ++ fi.EndOfFile = cpu_to_le64(le32_to_cpu(di->DataSize)); ++ } else { ++ FILE_FULL_DIRECTORY_INFO *di; ++ ++ di = (FILE_FULL_DIRECTORY_INFO *)search_info.srch_entries_start; ++ fi.CreationTime = di->CreationTime; ++ fi.LastAccessTime = di->LastAccessTime; ++ fi.LastWriteTime = di->LastWriteTime; ++ fi.ChangeTime = di->ChangeTime; ++ fi.Attributes = di->ExtFileAttributes; ++ fi.AllocationSize = di->AllocationSize; ++ fi.EndOfFile = di->EndOfFile; ++ fi.EASize = di->EaSize; ++ } ++ fi.NumberOfLinks = cpu_to_le32(1); ++ fi.DeletePending = 0; ++ fi.Directory = !!(le32_to_cpu(fi.Attributes) & ATTR_DIRECTORY); ++ cifs_buf_release(search_info.ntwrk_buf_start); ++ } else if (!full_path[0]) { ++ /* ++ * CIFSFindFirst() does not work on root path if the ++ * root path was exported on the server from the top ++ * level path (drive letter). ++ */ ++ rc = -EOPNOTSUPP; ++ } ++ } ++ ++ /* ++ * If everything failed then fallback to the legacy SMB command ++ * SMB_COM_QUERY_INFORMATION which works with all servers, but ++ * provide just few information. ++ */ ++ if ((rc == -EOPNOTSUPP || rc == -EINVAL) && !non_unicode_wildcard) { + rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls, + cifs_remap(cifs_sb)); + data->adjust_tz = true; ++ } else if ((rc == -EOPNOTSUPP || rc == -EINVAL) && non_unicode_wildcard) { ++ /* Path with non-UNICODE wildcard character cannot exist. */ ++ rc = -ENOENT; + } + + if (!rc) { +@@ -662,6 +735,13 @@ static int cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, + int rc; + FILE_ALL_INFO fi = {}; + ++ /* ++ * CIFSSMBQFileInfo() for non-NT servers returns bogus data in ++ * Attributes fields. So do not use this command for non-NT servers. ++ */ ++ if (!(tcon->ses->capabilities & CAP_NT_SMBS)) ++ return -EOPNOTSUPP; ++ + if (cfile->symlink_target) { + data->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); + if (!data->symlink_target) +@@ -832,6 +912,9 @@ smb_set_file_info(struct inode *inode, const char *full_path, + struct cifs_fid fid; + struct cifs_open_parms oparms; + struct cifsFileInfo *open_file; ++ FILE_BASIC_INFO new_buf; ++ struct cifs_open_info_data query_data; ++ __le64 write_time = buf->LastWriteTime; + struct cifsInodeInfo *cinode = CIFS_I(inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink = NULL; +@@ -839,20 +922,58 @@ smb_set_file_info(struct inode *inode, const char *full_path, + + /* if the file is already open for write, just use that fileid */ + open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY); ++ + if (open_file) { + fid.netfid = open_file->fid.netfid; + netpid = open_file->pid; + tcon = tlink_tcon(open_file->tlink); +- goto set_via_filehandle; ++ } else { ++ tlink = cifs_sb_tlink(cifs_sb); ++ if (IS_ERR(tlink)) { ++ rc = PTR_ERR(tlink); ++ tlink = NULL; ++ goto out; ++ } ++ tcon = tlink_tcon(tlink); + } + +- tlink = cifs_sb_tlink(cifs_sb); +- if (IS_ERR(tlink)) { +- rc = PTR_ERR(tlink); +- tlink = NULL; +- goto out; ++ /* ++ * Non-NT servers interprets zero time value in SMB_SET_FILE_BASIC_INFO ++ * over TRANS2_SET_FILE_INFORMATION as a valid time value. NT servers ++ * interprets zero time value as do not change existing value on server. ++ * API of ->set_file_info() callback expects that zero time value has ++ * the NT meaning - do not change. Therefore if server is non-NT and ++ * some time values in "buf" are zero, then fetch missing time values. ++ */ ++ if (!(tcon->ses->capabilities & CAP_NT_SMBS) && ++ (!buf->CreationTime || !buf->LastAccessTime || ++ !buf->LastWriteTime || !buf->ChangeTime)) { ++ rc = cifs_query_path_info(xid, tcon, cifs_sb, full_path, &query_data); ++ if (rc) { ++ if (open_file) { ++ cifsFileInfo_put(open_file); ++ open_file = NULL; ++ } ++ goto out; ++ } ++ /* ++ * Original write_time from buf->LastWriteTime is preserved ++ * as SMBSetInformation() interprets zero as do not change. ++ */ ++ new_buf = *buf; ++ buf = &new_buf; ++ if (!buf->CreationTime) ++ buf->CreationTime = query_data.fi.CreationTime; ++ if (!buf->LastAccessTime) ++ buf->LastAccessTime = query_data.fi.LastAccessTime; ++ if (!buf->LastWriteTime) ++ buf->LastWriteTime = query_data.fi.LastWriteTime; ++ if (!buf->ChangeTime) ++ buf->ChangeTime = query_data.fi.ChangeTime; + } +- tcon = tlink_tcon(tlink); ++ ++ if (open_file) ++ goto set_via_filehandle; + + rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, + cifs_sb); +@@ -873,8 +994,45 @@ smb_set_file_info(struct inode *inode, const char *full_path, + .fid = &fid, + }; + +- cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); +- rc = CIFS_open(xid, &oparms, &oplock, NULL); ++ if (S_ISDIR(inode->i_mode) && !(tcon->ses->capabilities & CAP_NT_SMBS)) { ++ /* Opening directory path is not possible on non-NT servers. */ ++ rc = -EOPNOTSUPP; ++ } else { ++ /* ++ * Use cifs_open_file() instead of CIFS_open() as the ++ * cifs_open_file() selects the correct function which ++ * works also on non-NT servers. ++ */ ++ rc = cifs_open_file(xid, &oparms, &oplock, NULL); ++ /* ++ * Opening path for writing on non-NT servers is not ++ * possible when the read-only attribute is already set. ++ * Non-NT server in this case returns -EACCES. For those ++ * servers the only possible way how to clear the read-only ++ * bit is via SMB_COM_SETATTR command. ++ */ ++ if (rc == -EACCES && ++ (cinode->cifsAttrs & ATTR_READONLY) && ++ le32_to_cpu(buf->Attributes) != 0 && /* 0 = do not change attrs */ ++ !(le32_to_cpu(buf->Attributes) & ATTR_READONLY) && ++ !(tcon->ses->capabilities & CAP_NT_SMBS)) ++ rc = -EOPNOTSUPP; ++ } ++ ++ /* Fallback to SMB_COM_SETATTR command when absolutelty needed. */ ++ if (rc == -EOPNOTSUPP) { ++ cifs_dbg(FYI, "calling SetInformation since SetPathInfo for attrs/times not supported by this server\n"); ++ rc = SMBSetInformation(xid, tcon, full_path, ++ buf->Attributes != 0 ? buf->Attributes : cpu_to_le32(cinode->cifsAttrs), ++ write_time, ++ cifs_sb->local_nls, cifs_sb); ++ if (rc == 0) ++ cinode->cifsAttrs = le32_to_cpu(buf->Attributes); ++ else ++ rc = -EACCES; ++ goto out; ++ } ++ + if (rc != 0) { + if (rc == -EIO) + rc = -EINVAL; +@@ -882,6 +1040,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, + } + + netpid = current->tgid; ++ cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for attrs/times not supported by this server\n"); + + set_via_filehandle: + rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid); +@@ -892,6 +1051,21 @@ smb_set_file_info(struct inode *inode, const char *full_path, + CIFSSMBClose(xid, tcon, fid.netfid); + else + cifsFileInfo_put(open_file); ++ ++ /* ++ * Setting the read-only bit is not honered on non-NT servers when done ++ * via open-semantics. So for setting it, use SMB_COM_SETATTR command. ++ * This command works only after the file is closed, so use it only when ++ * operation was called without the filehandle. ++ */ ++ if (open_file == NULL && ++ !(tcon->ses->capabilities & CAP_NT_SMBS) && ++ le32_to_cpu(buf->Attributes) & ATTR_READONLY) { ++ SMBSetInformation(xid, tcon, full_path, ++ buf->Attributes, ++ 0 /* do not change write time */, ++ cifs_sb->local_nls, cifs_sb); ++ } + out: + if (tlink != NULL) + cifs_put_tlink(tlink); +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index db9c807115c605..d7f2835e0b1cc1 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -107,16 +107,25 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 + int err_buftype = CIFS_NO_BUFFER; + struct cifs_fid *fid = oparms->fid; + struct network_resiliency_req nr_ioctl_req; ++ bool retry_without_read_attributes = false; + + smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb); + if (smb2_path == NULL) + return -ENOMEM; + +- oparms->desired_access |= FILE_READ_ATTRIBUTES; ++ if (!(oparms->desired_access & FILE_READ_ATTRIBUTES)) { ++ oparms->desired_access |= FILE_READ_ATTRIBUTES; ++ retry_without_read_attributes = true; ++ } + smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH; + + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + &err_buftype); ++ if (rc == -EACCES && retry_without_read_attributes) { ++ oparms->desired_access &= ~FILE_READ_ATTRIBUTES; ++ rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, ++ &err_buftype); ++ } + if (rc && data) { + struct smb2_hdr *hdr = err_iov.iov_base; + +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index b809a616728f27..4e3eacbec96d14 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -428,12 +428,20 @@ smb2_negotiate(const unsigned int xid, + server->CurrentMid = 0; + spin_unlock(&server->mid_lock); + rc = SMB2_negotiate(xid, ses, server); +- /* BB we probably don't need to retry with modern servers */ +- if (rc == -EAGAIN) +- rc = -EHOSTDOWN; + return rc; + } + ++static inline unsigned int ++prevent_zero_iosize(unsigned int size, const char *type) ++{ ++ if (size == 0) { ++ cifs_dbg(VFS, "SMB: Zero %ssize calculated, using minimum value %u\n", ++ type, CIFS_MIN_DEFAULT_IOSIZE); ++ return CIFS_MIN_DEFAULT_IOSIZE; ++ } ++ return size; ++} ++ + static unsigned int + smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + { +@@ -441,12 +449,12 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int wsize; + + /* start with specified wsize, or default */ +- wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE; ++ wsize = ctx->got_wsize ? ctx->vol_wsize : CIFS_DEFAULT_IOSIZE; + wsize = min_t(unsigned int, wsize, server->max_write); + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); + +- return wsize; ++ return prevent_zero_iosize(wsize, "w"); + } + + static unsigned int +@@ -456,7 +464,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int wsize; + + /* start with specified wsize, or default */ +- wsize = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE; ++ wsize = ctx->got_wsize ? ctx->vol_wsize : SMB3_DEFAULT_IOSIZE; + wsize = min_t(unsigned int, wsize, server->max_write); + #ifdef CONFIG_CIFS_SMB_DIRECT + if (server->rdma) { +@@ -478,7 +486,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); + +- return wsize; ++ return prevent_zero_iosize(wsize, "w"); + } + + static unsigned int +@@ -488,13 +496,13 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int rsize; + + /* start with specified rsize, or default */ +- rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE; ++ rsize = ctx->got_rsize ? ctx->vol_rsize : CIFS_DEFAULT_IOSIZE; + rsize = min_t(unsigned int, rsize, server->max_read); + + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); + +- return rsize; ++ return prevent_zero_iosize(rsize, "r"); + } + + static unsigned int +@@ -504,7 +512,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + unsigned int rsize; + + /* start with specified rsize, or default */ +- rsize = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE; ++ rsize = ctx->got_rsize ? ctx->vol_rsize : SMB3_DEFAULT_IOSIZE; + rsize = min_t(unsigned int, rsize, server->max_read); + #ifdef CONFIG_CIFS_SMB_DIRECT + if (server->rdma) { +@@ -527,7 +535,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); + +- return rsize; ++ return prevent_zero_iosize(rsize, "r"); + } + + /* +diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c +index ddf1a3aafee5c6..2269963e500819 100644 +--- a/fs/smb/client/transport.c ++++ b/fs/smb/client/transport.c +@@ -178,7 +178,7 @@ delete_mid(struct mid_q_entry *mid) + * Our basic "send data to server" function. Should be called with srv_mutex + * held. The caller is responsible for handling the results. + */ +-static int ++int + smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, + size_t *sent) + { +diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h +index c3ee42188d252e..1af827ae757e0d 100644 +--- a/fs/smb/common/smb2pdu.h ++++ b/fs/smb/common/smb2pdu.h +@@ -95,6 +95,9 @@ + */ + #define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024) + ++/* According to MS-SMB2 specification The minimum recommended value is 65536.*/ ++#define CIFS_MIN_DEFAULT_IOSIZE (65536) ++ + /* + * SMB2 Header Definition + * +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index 72294764d4c20c..e564432643ea30 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -146,12 +146,9 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) + { + struct oplock_info *opinfo; + +- if (list_empty(&ci->m_op_list)) +- return NULL; +- + down_read(&ci->m_lock); +- opinfo = list_first_entry(&ci->m_op_list, struct oplock_info, +- op_entry); ++ opinfo = list_first_entry_or_null(&ci->m_op_list, struct oplock_info, ++ op_entry); + if (opinfo) { + if (opinfo->conn == NULL || + !atomic_inc_not_zero(&opinfo->refcount)) +diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c +index f6616d687365a3..3bbf2382706056 100644 +--- a/fs/smb/server/vfs.c ++++ b/fs/smb/server/vfs.c +@@ -426,10 +426,15 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n", + *pos, count); + ++ if (*pos >= XATTR_SIZE_MAX) { ++ pr_err("stream write position %lld is out of bounds\n", *pos); ++ return -EINVAL; ++ } ++ + size = *pos + count; + if (size > XATTR_SIZE_MAX) { + size = XATTR_SIZE_MAX; +- count = (*pos + count) - XATTR_SIZE_MAX; ++ count = XATTR_SIZE_MAX - *pos; + } + + v_len = ksmbd_vfs_getcasexattr(idmap, +@@ -443,13 +448,6 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, + goto out; + } + +- if (v_len <= *pos) { +- pr_err("stream write position %lld is out of bounds (stream length: %zd)\n", +- *pos, v_len); +- err = -EINVAL; +- goto out; +- } +- + if (v_len < size) { + wbuf = kvzalloc(size, GFP_KERNEL); + if (!wbuf) { +diff --git a/include/crypto/hash.h b/include/crypto/hash.h +index f7c2a22cd776da..c0d472fdc82e6c 100644 +--- a/include/crypto/hash.h ++++ b/include/crypto/hash.h +@@ -153,6 +153,7 @@ struct ahash_request { + * This is a counterpart to @init_tfm, used to remove + * various changes set in @init_tfm. + * @clone_tfm: Copy transform into new object, may allocate memory. ++ * @reqsize: Size of the request context. + * @halg: see struct hash_alg_common + */ + struct ahash_alg { +@@ -169,6 +170,8 @@ struct ahash_alg { + void (*exit_tfm)(struct crypto_ahash *tfm); + int (*clone_tfm)(struct crypto_ahash *dst, struct crypto_ahash *src); + ++ unsigned int reqsize; ++ + struct hash_alg_common halg; + }; + +diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h +index 9a022caacf9361..f3e7e3e5078dbc 100644 +--- a/include/drm/drm_atomic.h ++++ b/include/drm/drm_atomic.h +@@ -372,8 +372,27 @@ struct drm_atomic_state { + * + * Allow full modeset. This is used by the ATOMIC IOCTL handler to + * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should +- * never consult this flag, instead looking at the output of +- * drm_atomic_crtc_needs_modeset(). ++ * generally not consult this flag, but instead look at the output of ++ * drm_atomic_crtc_needs_modeset(). The detailed rules are: ++ * ++ * - Drivers must not consult @allow_modeset in the atomic commit path. ++ * Use drm_atomic_crtc_needs_modeset() instead. ++ * ++ * - Drivers must consult @allow_modeset before adding unrelated struct ++ * drm_crtc_state to this commit by calling ++ * drm_atomic_get_crtc_state(). See also the warning in the ++ * documentation for that function. ++ * ++ * - Drivers must never change this flag, it is under the exclusive ++ * control of userspace. ++ * ++ * - Drivers may consult @allow_modeset in the atomic check path, if ++ * they have the choice between an optimal hardware configuration ++ * which requires a modeset, and a less optimal configuration which ++ * can be committed without a modeset. An example would be suboptimal ++ * scanout FIFO allocation resulting in increased idle power ++ * consumption. This allows userspace to avoid flickering and delays ++ * for the normal composition loop at reasonable cost. + */ + bool allow_modeset : 1; + /** +diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h +index 7c2ec139c464ad..a578068169f19a 100644 +--- a/include/drm/drm_gem.h ++++ b/include/drm/drm_gem.h +@@ -35,6 +35,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -557,6 +558,18 @@ static inline bool drm_gem_object_is_shared_for_memory_stats(struct drm_gem_obje + return (obj->handle_count > 1) || obj->dma_buf; + } + ++/** ++ * drm_gem_is_imported() - Tests if GEM object's buffer has been imported ++ * @obj: the GEM object ++ * ++ * Returns: ++ * True if the GEM object's buffer has been imported, false otherwise ++ */ ++static inline bool drm_gem_is_imported(const struct drm_gem_object *obj) ++{ ++ return !!obj->import_attach; ++} ++ + #ifdef CONFIG_LOCKDEP + /** + * drm_gem_gpuva_set_lock() - Set the lock protecting accesses to the gpuva list. +diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h +index d4f2c8706042cd..2331cd8174fe3f 100644 +--- a/include/linux/bpf-cgroup.h ++++ b/include/linux/bpf-cgroup.h +@@ -106,6 +106,7 @@ struct bpf_prog_list { + struct bpf_prog *prog; + struct bpf_cgroup_link *link; + struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]; ++ u32 flags; + }; + + int cgroup_bpf_inherit(struct cgroup *cgrp); +diff --git a/include/linux/coredump.h b/include/linux/coredump.h +index d3eba436015087..c1b4c8c70caebd 100644 +--- a/include/linux/coredump.h ++++ b/include/linux/coredump.h +@@ -28,6 +28,7 @@ struct coredump_params { + int vma_count; + size_t vma_data_size; + struct core_vma_metadata *vma_meta; ++ struct pid *pid; + }; + + /* +diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h +index f0ccca16a0aca1..608e8296ba206a 100644 +--- a/include/linux/dma-mapping.h ++++ b/include/linux/dma-mapping.h +@@ -600,10 +600,14 @@ static inline int dma_mmap_wc(struct device *dev, + #else + #define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) + #define DEFINE_DMA_UNMAP_LEN(LEN_NAME) +-#define dma_unmap_addr(PTR, ADDR_NAME) (0) +-#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +-#define dma_unmap_len(PTR, LEN_NAME) (0) +-#define dma_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) ++#define dma_unmap_addr(PTR, ADDR_NAME) \ ++ ({ typeof(PTR) __p __maybe_unused = PTR; 0; }) ++#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) \ ++ do { typeof(PTR) __p __maybe_unused = PTR; } while (0) ++#define dma_unmap_len(PTR, LEN_NAME) \ ++ ({ typeof(PTR) __p __maybe_unused = PTR; 0; }) ++#define dma_unmap_len_set(PTR, LEN_NAME, VAL) \ ++ do { typeof(PTR) __p __maybe_unused = PTR; } while (0) + #endif + + #endif /* _LINUX_DMA_MAPPING_H */ +diff --git a/include/linux/highmem.h b/include/linux/highmem.h +index 75607d4ba26cb7..714966d5701e00 100644 +--- a/include/linux/highmem.h ++++ b/include/linux/highmem.h +@@ -448,7 +448,7 @@ static inline void memcpy_from_folio(char *to, struct folio *folio, + const char *from = kmap_local_folio(folio, offset); + size_t chunk = len; + +- if (folio_test_highmem(folio) && ++ if (folio_test_partial_kmap(folio) && + chunk > PAGE_SIZE - offset_in_page(offset)) + chunk = PAGE_SIZE - offset_in_page(offset); + memcpy(to, from, chunk); +@@ -469,7 +469,7 @@ static inline void memcpy_to_folio(struct folio *folio, size_t offset, + char *to = kmap_local_folio(folio, offset); + size_t chunk = len; + +- if (folio_test_highmem(folio) && ++ if (folio_test_partial_kmap(folio) && + chunk > PAGE_SIZE - offset_in_page(offset)) + chunk = PAGE_SIZE - offset_in_page(offset); + memcpy(to, from, chunk); +@@ -501,7 +501,7 @@ static inline size_t memcpy_from_file_folio(char *to, struct folio *folio, + size_t offset = offset_in_folio(folio, pos); + char *from = kmap_local_folio(folio, offset); + +- if (folio_test_highmem(folio)) { ++ if (folio_test_partial_kmap(folio)) { + offset = offset_in_page(offset); + len = min_t(size_t, len, PAGE_SIZE - offset); + } else +diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h +index 8f77bb0f4ae0ca..05f8b7d7d1e968 100644 +--- a/include/linux/hrtimer.h ++++ b/include/linux/hrtimer.h +@@ -237,6 +237,7 @@ struct hrtimer_cpu_base { + ktime_t softirq_expires_next; + struct hrtimer *softirq_next_timer; + struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; ++ call_single_data_t csd; + } ____cacheline_aligned; + + static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) +diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h +index af8a771a053c51..d79851c5fabd86 100644 +--- a/include/linux/ipv6.h ++++ b/include/linux/ipv6.h +@@ -199,6 +199,7 @@ struct inet6_cork { + struct ipv6_txoptions *opt; + u8 hop_limit; + u8 tclass; ++ u8 dontfrag:1; + }; + + /* struct ipv6_pinfo - ipv6 private area */ +diff --git a/include/linux/lzo.h b/include/linux/lzo.h +index e95c7d1092b286..4d30e3624acd23 100644 +--- a/include/linux/lzo.h ++++ b/include/linux/lzo.h +@@ -24,10 +24,18 @@ + int lzo1x_1_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + ++/* Same as above but does not write more than dst_len to dst. */ ++int lzo1x_1_compress_safe(const unsigned char *src, size_t src_len, ++ unsigned char *dst, size_t *dst_len, void *wrkmem); ++ + /* This requires 'wrkmem' of size LZO1X_1_MEM_COMPRESS */ + int lzorle1x_1_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + ++/* Same as above but does not write more than dst_len to dst. */ ++int lzorle1x_1_compress_safe(const unsigned char *src, size_t src_len, ++ unsigned char *dst, size_t *dst_len, void *wrkmem); ++ + /* safe decompression with overrun testing */ + int lzo1x_decompress_safe(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len); +diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h +index 27f42f713c891c..86f0f2a25a3d63 100644 +--- a/include/linux/mlx4/device.h ++++ b/include/linux/mlx4/device.h +@@ -1135,7 +1135,7 @@ int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_buf *buf); + +-int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order); ++int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, unsigned int order); + void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db); + + int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, +diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h +index 3fb428ce7d1c7c..b6b9a4dfa4fb92 100644 +--- a/include/linux/mlx5/fs.h ++++ b/include/linux/mlx5/fs.h +@@ -40,6 +40,8 @@ + + #define MLX5_SET_CFG(p, f, v) MLX5_SET(create_flow_group_in, p, f, v) + ++#define MLX5_FS_MAX_POOL_SIZE BIT(30) ++ + enum mlx5_flow_destination_type { + MLX5_FLOW_DESTINATION_TYPE_NONE, + MLX5_FLOW_DESTINATION_TYPE_VPORT, +diff --git a/include/linux/msi.h b/include/linux/msi.h +index ddace8c34dcf95..2cf15cf5d060ad 100644 +--- a/include/linux/msi.h ++++ b/include/linux/msi.h +@@ -171,6 +171,10 @@ struct msi_desc_data { + * @dev: Pointer to the device which uses this descriptor + * @msg: The last set MSI message cached for reuse + * @affinity: Optional pointer to a cpu affinity mask for this descriptor ++ * @iommu_msi_iova: Optional shifted IOVA from the IOMMU to override the msi_addr. ++ * Only used if iommu_msi_shift != 0 ++ * @iommu_msi_shift: Indicates how many bits of the original address should be ++ * preserved when using iommu_msi_iova. + * @sysfs_attr: Pointer to sysfs device attribute + * + * @write_msi_msg: Callback that may be called when the MSI message +@@ -189,7 +193,8 @@ struct msi_desc { + struct msi_msg msg; + struct irq_affinity_desc *affinity; + #ifdef CONFIG_IRQ_MSI_IOMMU +- const void *iommu_cookie; ++ u64 iommu_msi_iova : 58; ++ u64 iommu_msi_shift : 6; + #endif + #ifdef CONFIG_SYSFS + struct device_attribute *sysfs_attrs; +@@ -306,28 +311,14 @@ struct msi_desc *msi_next_desc(struct device *dev, unsigned int domid, + + #define msi_desc_to_dev(desc) ((desc)->dev) + +-#ifdef CONFIG_IRQ_MSI_IOMMU +-static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc) +-{ +- return desc->iommu_cookie; +-} +- +-static inline void msi_desc_set_iommu_cookie(struct msi_desc *desc, +- const void *iommu_cookie) +-{ +- desc->iommu_cookie = iommu_cookie; +-} +-#else +-static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc) ++static inline void msi_desc_set_iommu_msi_iova(struct msi_desc *desc, u64 msi_iova, ++ unsigned int msi_shift) + { +- return NULL; +-} +- +-static inline void msi_desc_set_iommu_cookie(struct msi_desc *desc, +- const void *iommu_cookie) +-{ +-} ++#ifdef CONFIG_IRQ_MSI_IOMMU ++ desc->iommu_msi_iova = msi_iova >> msi_shift; ++ desc->iommu_msi_shift = msi_shift; + #endif ++} + + int msi_domain_insert_msi_desc(struct device *dev, unsigned int domid, + struct msi_desc *init_desc); +diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h +index 86d96e00c2e3de..374b1b208bd89e 100644 +--- a/include/linux/nfs_fs_sb.h ++++ b/include/linux/nfs_fs_sb.h +@@ -199,6 +199,15 @@ struct nfs_server { + char *fscache_uniq; /* Uniquifier (or NULL) */ + #endif + ++ /* The following #defines numerically match the NFSv4 equivalents */ ++#define NFS_FH_NOEXPIRE_WITH_OPEN (0x1) ++#define NFS_FH_VOLATILE_ANY (0x2) ++#define NFS_FH_VOL_MIGRATION (0x4) ++#define NFS_FH_VOL_RENAME (0x8) ++#define NFS_FH_RENAME_UNSAFE (NFS_FH_VOLATILE_ANY | NFS_FH_VOL_RENAME) ++ u32 fh_expire_type; /* V4 bitmask representing file ++ handle volatility type for ++ this filesystem */ + u32 pnfs_blksize; /* layout_blksize attr */ + #if IS_ENABLED(CONFIG_NFS_V4) + u32 attr_bitmask[3];/* V4 bitmask representing the set +@@ -222,9 +231,6 @@ struct nfs_server { + u32 acl_bitmask; /* V4 bitmask representing the ACEs + that are supported on this + filesystem */ +- u32 fh_expire_type; /* V4 bitmask representing file +- handle volatility type for +- this filesystem */ + struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */ + struct rpc_wait_queue roc_rpcwaitq; + void *pnfs_ld_data; /* per mount point data */ +diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h +index a77f3a7d21d12f..36d0961f1672fd 100644 +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -551,6 +551,13 @@ PAGEFLAG(Readahead, readahead, PF_NO_COMPOUND) + PAGEFLAG_FALSE(HighMem, highmem) + #endif + ++/* Does kmap_local_folio() only allow access to one page of the folio? */ ++#ifdef CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP ++#define folio_test_partial_kmap(f) true ++#else ++#define folio_test_partial_kmap(f) folio_test_highmem(f) ++#endif ++ + #ifdef CONFIG_SWAP + static __always_inline bool folio_test_swapcache(struct folio *folio) + { +diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h +index fcb834dd75c240..90c782749b0558 100644 +--- a/include/linux/perf_event.h ++++ b/include/linux/perf_event.h +@@ -1016,7 +1016,13 @@ struct perf_output_handle { + struct perf_buffer *rb; + unsigned long wakeup; + unsigned long size; +- u64 aux_flags; ++ union { ++ u64 flags; /* perf_output*() */ ++ u64 aux_flags; /* perf_aux_output*() */ ++ struct { ++ u64 skip_read : 1; ++ }; ++ }; + union { + void *addr; + unsigned long head; +diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h +index 72da69cc5764f3..27531a0b3a6e72 100644 +--- a/include/linux/rcupdate.h ++++ b/include/linux/rcupdate.h +@@ -97,9 +97,9 @@ static inline void __rcu_read_lock(void) + + static inline void __rcu_read_unlock(void) + { +- preempt_enable(); + if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD)) + rcu_read_unlock_strict(); ++ preempt_enable(); + } + + static inline int rcu_preempt_depth(void) +diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h +index 126f6b418f6afc..559f758bf2eaa8 100644 +--- a/include/linux/rcutree.h ++++ b/include/linux/rcutree.h +@@ -104,7 +104,7 @@ extern int rcu_scheduler_active; + void rcu_end_inkernel_boot(void); + bool rcu_inkernel_boot_has_ended(void); + bool rcu_is_watching(void); +-#ifndef CONFIG_PREEMPTION ++#ifndef CONFIG_PREEMPT_RCU + void rcu_all_qs(void); + #endif + +diff --git a/include/linux/trace.h b/include/linux/trace.h +index fdcd76b7be83d7..7eaad857dee04f 100644 +--- a/include/linux/trace.h ++++ b/include/linux/trace.h +@@ -72,8 +72,8 @@ static inline int unregister_ftrace_export(struct trace_export *export) + static inline void trace_printk_init_buffers(void) + { + } +-static inline int trace_array_printk(struct trace_array *tr, unsigned long ip, +- const char *fmt, ...) ++static inline __printf(3, 4) ++int trace_array_printk(struct trace_array *tr, unsigned long ip, const char *fmt, ...) + { + return 0; + } +diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h +index 3691e0e76a1a20..62147eecf931da 100644 +--- a/include/linux/trace_seq.h ++++ b/include/linux/trace_seq.h +@@ -79,8 +79,8 @@ extern __printf(2, 3) + void trace_seq_printf(struct trace_seq *s, const char *fmt, ...); + extern __printf(2, 0) + void trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args); +-extern void +-trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); ++extern __printf(2, 0) ++void trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); + extern int trace_print_seq(struct seq_file *m, struct trace_seq *s); + extern int trace_seq_to_user(struct trace_seq *s, char __user *ubuf, + int cnt); +@@ -104,8 +104,8 @@ static inline __printf(2, 3) + void trace_seq_printf(struct trace_seq *s, const char *fmt, ...) + { + } +-static inline void +-trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) ++static inline __printf(2, 0) ++void trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) + { + } + +diff --git a/include/linux/usb/r8152.h b/include/linux/usb/r8152.h +index 33a4c146dc19c4..2ca60828f28bb6 100644 +--- a/include/linux/usb/r8152.h ++++ b/include/linux/usb/r8152.h +@@ -30,6 +30,7 @@ + #define VENDOR_ID_NVIDIA 0x0955 + #define VENDOR_ID_TPLINK 0x2357 + #define VENDOR_ID_DLINK 0x2001 ++#define VENDOR_ID_DELL 0x413c + #define VENDOR_ID_ASUS 0x0b05 + + #if IS_REACHABLE(CONFIG_USB_RTL8152) +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index b4fcd0164048ed..0740dfc6c04881 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -822,7 +822,9 @@ struct v4l2_subdev_state { + * possible configuration from the remote end, likely calling + * this operation as close as possible to stream on time. The + * operation shall fail if the pad index it has been called on +- * is not valid or in case of unrecoverable failures. ++ * is not valid or in case of unrecoverable failures. The ++ * config argument has been memset to 0 just before calling ++ * the op. + * + * @set_routing: enable or disable data connection routes described in the + * subdevice routing table. +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index 77bf30203d3cf6..b6eedf7650da59 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -8,21 +8,46 @@ + #include + #include + +-void unix_inflight(struct user_struct *user, struct file *fp); +-void unix_notinflight(struct user_struct *user, struct file *fp); +-void unix_destruct_scm(struct sk_buff *skb); +-void io_uring_destruct_scm(struct sk_buff *skb); ++#if IS_ENABLED(CONFIG_UNIX) ++struct unix_sock *unix_get_socket(struct file *filp); ++#else ++static inline struct unix_sock *unix_get_socket(struct file *filp) ++{ ++ return NULL; ++} ++#endif ++ ++extern unsigned int unix_tot_inflight; ++void unix_add_edges(struct scm_fp_list *fpl, struct unix_sock *receiver); ++void unix_del_edges(struct scm_fp_list *fpl); ++void unix_update_edges(struct unix_sock *receiver); ++int unix_prepare_fpl(struct scm_fp_list *fpl); ++void unix_destroy_fpl(struct scm_fp_list *fpl); + void unix_gc(void); +-void wait_for_unix_gc(void); +-struct sock *unix_get_socket(struct file *filp); ++void wait_for_unix_gc(struct scm_fp_list *fpl); ++ ++struct unix_vertex { ++ struct list_head edges; ++ struct list_head entry; ++ struct list_head scc_entry; ++ unsigned long out_degree; ++ unsigned long index; ++ unsigned long scc_index; ++}; ++ ++struct unix_edge { ++ struct unix_sock *predecessor; ++ struct unix_sock *successor; ++ struct list_head vertex_entry; ++ struct list_head stack_entry; ++}; ++ + struct sock *unix_peer_get(struct sock *sk); + + #define UNIX_HASH_MOD (256 - 1) + #define UNIX_HASH_SIZE (256 * 2) + #define UNIX_HASH_BITS 8 + +-extern unsigned int unix_tot_inflight; +- + struct unix_address { + refcount_t refcnt; + int len; +@@ -42,6 +67,7 @@ struct unix_skb_parms { + + struct scm_stat { + atomic_t nr_fds; ++ unsigned long nr_unix_fds; + }; + + #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb)) +@@ -54,12 +80,9 @@ struct unix_sock { + struct path path; + struct mutex iolock, bindlock; + struct sock *peer; +- struct list_head link; +- unsigned long inflight; ++ struct sock *listener; ++ struct unix_vertex *vertex; + spinlock_t lock; +- unsigned long gc_flags; +-#define UNIX_GC_CANDIDATE 0 +-#define UNIX_GC_MAYBE_CYCLE 1 + struct socket_wq peer_wq; + wait_queue_entry_t peer_wake; + struct scm_stat scm_stat; +diff --git a/include/net/scm.h b/include/net/scm.h +index e8c76b4be2fe71..059e287745dc39 100644 +--- a/include/net/scm.h ++++ b/include/net/scm.h +@@ -22,9 +22,20 @@ struct scm_creds { + kgid_t gid; + }; + ++#ifdef CONFIG_UNIX ++struct unix_edge; ++#endif ++ + struct scm_fp_list { + short count; ++ short count_unix; + short max; ++#ifdef CONFIG_UNIX ++ bool inflight; ++ bool dead; ++ struct list_head vertices; ++ struct unix_edge *edges; ++#endif + struct user_struct *user; + struct file *fp[SCM_MAX_FD]; + }; +diff --git a/include/net/xfrm.h b/include/net/xfrm.h +index b33d27e42cff38..fd550c0b563450 100644 +--- a/include/net/xfrm.h ++++ b/include/net/xfrm.h +@@ -228,7 +228,6 @@ struct xfrm_state { + + /* Data for encapsulator */ + struct xfrm_encap_tmpl *encap; +- struct sock __rcu *encap_sk; + + /* Data for care-of address */ + xfrm_address_t *coaddr; +diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h +index fe05121169589f..555ea3d142a46b 100644 +--- a/include/rdma/uverbs_std_types.h ++++ b/include/rdma/uverbs_std_types.h +@@ -34,7 +34,7 @@ + static inline void *_uobj_get_obj_read(struct ib_uobject *uobj) + { + if (IS_ERR(uobj)) +- return NULL; ++ return ERR_CAST(uobj); + return uobj->object; + } + #define uobj_get_obj_read(_object, _type, _id, _attrs) \ +diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h +index 5497dc9c396a5a..b58dc869cf77eb 100644 +--- a/include/sound/hda_codec.h ++++ b/include/sound/hda_codec.h +@@ -196,6 +196,7 @@ struct hda_codec { + /* beep device */ + struct hda_beep *beep; + unsigned int beep_mode; ++ bool beep_just_power_on; + + /* widget capabilities cache */ + u32 *wcaps; +diff --git a/include/sound/pcm.h b/include/sound/pcm.h +index 2a815373dac1d9..ed4449cbdf8033 100644 +--- a/include/sound/pcm.h ++++ b/include/sound/pcm.h +@@ -1427,6 +1427,8 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s + #define snd_pcm_lib_mmap_iomem NULL + #endif + ++void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime); ++ + /** + * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer + * @dma: DMA number +diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h +index 3c4d5ef6d44636..8ea1674069fe81 100644 +--- a/include/trace/events/btrfs.h ++++ b/include/trace/events/btrfs.h +@@ -1956,7 +1956,7 @@ DECLARE_EVENT_CLASS(btrfs__prelim_ref, + TP_PROTO(const struct btrfs_fs_info *fs_info, + const struct prelim_ref *oldref, + const struct prelim_ref *newref, u64 tree_size), +- TP_ARGS(fs_info, newref, oldref, tree_size), ++ TP_ARGS(fs_info, oldref, newref, tree_size), + + TP_STRUCT__entry_btrfs( + __field( u64, root_id ) +diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h +index 431bc700bcfb93..c7f904a72af217 100644 +--- a/include/uapi/linux/bpf.h ++++ b/include/uapi/linux/bpf.h +@@ -1140,6 +1140,7 @@ enum bpf_perf_event_type { + #define BPF_F_BEFORE (1U << 3) + #define BPF_F_AFTER (1U << 4) + #define BPF_F_ID (1U << 5) ++#define BPF_F_PREORDER (1U << 6) + #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */ + + /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the +diff --git a/include/uapi/linux/idxd.h b/include/uapi/linux/idxd.h +index 606b52e88ce335..3d1987e1bb2dd6 100644 +--- a/include/uapi/linux/idxd.h ++++ b/include/uapi/linux/idxd.h +@@ -31,6 +31,7 @@ enum idxd_scmd_stat { + IDXD_SCMD_WQ_IRQ_ERR = 0x80100000, + IDXD_SCMD_WQ_USER_NO_IOMMU = 0x80110000, + IDXD_SCMD_DEV_EVL_ERR = 0x80120000, ++ IDXD_SCMD_WQ_NO_DRV_NAME = 0x80200000, + }; + + #define IDXD_SCMD_SOFTERR_MASK 0x80000000 +diff --git a/include/ufs/ufs_quirks.h b/include/ufs/ufs_quirks.h +index 41ff44dfa1db3f..f52de5ed1b3b6e 100644 +--- a/include/ufs/ufs_quirks.h ++++ b/include/ufs/ufs_quirks.h +@@ -107,4 +107,10 @@ struct ufs_dev_quirk { + */ + #define UFS_DEVICE_QUIRK_DELAY_AFTER_LPM (1 << 11) + ++/* ++ * Some ufs devices may need more time to be in hibern8 before exiting. ++ * Enable this quirk to give it an additional 100us. ++ */ ++#define UFS_DEVICE_QUIRK_PA_HIBER8TIME (1 << 12) ++ + #endif /* UFS_QUIRKS_H_ */ +diff --git a/io_uring/fdinfo.c b/io_uring/fdinfo.c +index 976e9500f6518c..a26cf840e623d6 100644 +--- a/io_uring/fdinfo.c ++++ b/io_uring/fdinfo.c +@@ -81,11 +81,11 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f) + seq_printf(m, "SqMask:\t0x%x\n", sq_mask); + seq_printf(m, "SqHead:\t%u\n", sq_head); + seq_printf(m, "SqTail:\t%u\n", sq_tail); +- seq_printf(m, "CachedSqHead:\t%u\n", ctx->cached_sq_head); ++ seq_printf(m, "CachedSqHead:\t%u\n", data_race(ctx->cached_sq_head)); + seq_printf(m, "CqMask:\t0x%x\n", cq_mask); + seq_printf(m, "CqHead:\t%u\n", cq_head); + seq_printf(m, "CqTail:\t%u\n", cq_tail); +- seq_printf(m, "CachedCqTail:\t%u\n", ctx->cached_cq_tail); ++ seq_printf(m, "CachedCqTail:\t%u\n", data_race(ctx->cached_cq_tail)); + seq_printf(m, "SQEs:\t%u\n", sq_tail - sq_head); + sq_entries = min(sq_tail - sq_head, ctx->sq_entries); + for (i = 0; i < sq_entries; i++) { +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index db592fa549b738..43b46098279a16 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -701,6 +701,7 @@ static void __io_cqring_overflow_flush(struct io_ring_ctx *ctx) + * to care for a non-real case. + */ + if (need_resched()) { ++ ctx->cqe_sentinel = ctx->cqe_cached; + io_cq_unlock_post(ctx); + mutex_unlock(&ctx->uring_lock); + cond_resched(); +diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c +index cf2eb0895d403c..684fb450ad086f 100644 +--- a/kernel/bpf/cgroup.c ++++ b/kernel/bpf/cgroup.c +@@ -369,7 +369,7 @@ static struct bpf_prog *prog_list_prog(struct bpf_prog_list *pl) + /* count number of elements in the list. + * it's slow but the list cannot be long + */ +-static u32 prog_list_length(struct hlist_head *head) ++static u32 prog_list_length(struct hlist_head *head, int *preorder_cnt) + { + struct bpf_prog_list *pl; + u32 cnt = 0; +@@ -377,6 +377,8 @@ static u32 prog_list_length(struct hlist_head *head) + hlist_for_each_entry(pl, head, node) { + if (!prog_list_prog(pl)) + continue; ++ if (preorder_cnt && (pl->flags & BPF_F_PREORDER)) ++ (*preorder_cnt)++; + cnt++; + } + return cnt; +@@ -400,7 +402,7 @@ static bool hierarchy_allows_attach(struct cgroup *cgrp, + + if (flags & BPF_F_ALLOW_MULTI) + return true; +- cnt = prog_list_length(&p->bpf.progs[atype]); ++ cnt = prog_list_length(&p->bpf.progs[atype], NULL); + WARN_ON_ONCE(cnt > 1); + if (cnt == 1) + return !!(flags & BPF_F_ALLOW_OVERRIDE); +@@ -423,12 +425,12 @@ static int compute_effective_progs(struct cgroup *cgrp, + struct bpf_prog_array *progs; + struct bpf_prog_list *pl; + struct cgroup *p = cgrp; +- int cnt = 0; ++ int i, j, cnt = 0, preorder_cnt = 0, fstart, bstart, init_bstart; + + /* count number of effective programs by walking parents */ + do { + if (cnt == 0 || (p->bpf.flags[atype] & BPF_F_ALLOW_MULTI)) +- cnt += prog_list_length(&p->bpf.progs[atype]); ++ cnt += prog_list_length(&p->bpf.progs[atype], &preorder_cnt); + p = cgroup_parent(p); + } while (p); + +@@ -439,20 +441,34 @@ static int compute_effective_progs(struct cgroup *cgrp, + /* populate the array with effective progs */ + cnt = 0; + p = cgrp; ++ fstart = preorder_cnt; ++ bstart = preorder_cnt - 1; + do { + if (cnt > 0 && !(p->bpf.flags[atype] & BPF_F_ALLOW_MULTI)) + continue; + ++ init_bstart = bstart; + hlist_for_each_entry(pl, &p->bpf.progs[atype], node) { + if (!prog_list_prog(pl)) + continue; + +- item = &progs->items[cnt]; ++ if (pl->flags & BPF_F_PREORDER) { ++ item = &progs->items[bstart]; ++ bstart--; ++ } else { ++ item = &progs->items[fstart]; ++ fstart++; ++ } + item->prog = prog_list_prog(pl); + bpf_cgroup_storages_assign(item->cgroup_storage, + pl->storage); + cnt++; + } ++ ++ /* reverse pre-ordering progs at this cgroup level */ ++ for (i = bstart + 1, j = init_bstart; i < j; i++, j--) ++ swap(progs->items[i], progs->items[j]); ++ + } while ((p = cgroup_parent(p))); + + *array = progs; +@@ -663,7 +679,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp, + */ + return -EPERM; + +- if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS) ++ if (prog_list_length(progs, NULL) >= BPF_CGROUP_MAX_PROGS) + return -E2BIG; + + pl = find_attach_entry(progs, prog, link, replace_prog, +@@ -698,6 +714,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp, + + pl->prog = prog; + pl->link = link; ++ pl->flags = flags; + bpf_cgroup_storages_assign(pl->storage, storage); + cgrp->bpf.flags[atype] = saved_flags; + +@@ -1073,7 +1090,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, + lockdep_is_held(&cgroup_mutex)); + total_cnt += bpf_prog_array_length(effective); + } else { +- total_cnt += prog_list_length(&cgrp->bpf.progs[atype]); ++ total_cnt += prog_list_length(&cgrp->bpf.progs[atype], NULL); + } + } + +@@ -1105,7 +1122,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, + u32 id; + + progs = &cgrp->bpf.progs[atype]; +- cnt = min_t(int, prog_list_length(progs), total_cnt); ++ cnt = min_t(int, prog_list_length(progs, NULL), total_cnt); + i = 0; + hlist_for_each_entry(pl, progs, node) { + prog = prog_list_prog(pl); +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index fc34f72702cc40..8a3eadf17f785d 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -2212,7 +2212,7 @@ static long bpf_for_each_hash_elem(struct bpf_map *map, bpf_callback_t callback_ + b = &htab->buckets[i]; + rcu_read_lock(); + head = &b->head; +- hlist_nulls_for_each_entry_rcu(elem, n, head, hash_node) { ++ hlist_nulls_for_each_entry_safe(elem, n, head, hash_node) { + key = elem->key; + if (is_percpu) { + /* current cpu value for percpu map */ +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index f089a616301119..b66349f892f25e 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -3900,7 +3900,8 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, + #define BPF_F_ATTACH_MASK_BASE \ + (BPF_F_ALLOW_OVERRIDE | \ + BPF_F_ALLOW_MULTI | \ +- BPF_F_REPLACE) ++ BPF_F_REPLACE | \ ++ BPF_F_PREORDER) + + #define BPF_F_ATTACH_MASK_MPROG \ + (BPF_F_REPLACE | \ +@@ -4442,6 +4443,8 @@ static int bpf_prog_get_info_by_fd(struct file *file, + info.recursion_misses = stats.misses; + + info.verified_insns = prog->aux->verified_insns; ++ if (prog->aux->btf) ++ info.btf_id = btf_obj_id(prog->aux->btf); + + if (!bpf_capable()) { + info.jited_prog_len = 0; +@@ -4588,8 +4591,6 @@ static int bpf_prog_get_info_by_fd(struct file *file, + } + } + +- if (prog->aux->btf) +- info.btf_id = btf_obj_id(prog->aux->btf); + info.attach_btf_id = prog->aux->attach_btf_id; + if (attach_btf) + info.attach_btf_obj_id = btf_obj_id(attach_btf); +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 756e179a1efe3e..1f9ae600e4455c 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -16014,12 +16014,16 @@ static void clean_verifier_state(struct bpf_verifier_env *env, + static void clean_live_states(struct bpf_verifier_env *env, int insn, + struct bpf_verifier_state *cur) + { ++ struct bpf_verifier_state *loop_entry; + struct bpf_verifier_state_list *sl; + + sl = *explored_state(env, insn); + while (sl) { + if (sl->state.branches) + goto next; ++ loop_entry = get_loop_entry(&sl->state); ++ if (loop_entry && loop_entry->branches) ++ goto next; + if (sl->state.insn_idx != insn || + !same_callsites(&sl->state, cur)) + goto next; +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 3ccf80dfa587a3..e8ef062f6ca058 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -90,7 +90,7 @@ + DEFINE_MUTEX(cgroup_mutex); + DEFINE_SPINLOCK(css_set_lock); + +-#ifdef CONFIG_PROVE_RCU ++#if (defined CONFIG_PROVE_RCU || defined CONFIG_LOCKDEP) + EXPORT_SYMBOL_GPL(cgroup_mutex); + EXPORT_SYMBOL_GPL(css_set_lock); + #endif +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 987807b1040ae0..5dd6424e62fa89 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -1163,6 +1163,12 @@ static void perf_assert_pmu_disabled(struct pmu *pmu) + WARN_ON_ONCE(*this_cpu_ptr(pmu->pmu_disable_count) == 0); + } + ++static inline void perf_pmu_read(struct perf_event *event) ++{ ++ if (event->state == PERF_EVENT_STATE_ACTIVE) ++ event->pmu->read(event); ++} ++ + static void get_ctx(struct perf_event_context *ctx) + { + refcount_inc(&ctx->refcount); +@@ -3397,8 +3403,7 @@ static void __perf_event_sync_stat(struct perf_event *event, + * we know the event must be on the current CPU, therefore we + * don't need to use it. + */ +- if (event->state == PERF_EVENT_STATE_ACTIVE) +- event->pmu->read(event); ++ perf_pmu_read(event); + + perf_event_update_time(event); + +@@ -4524,15 +4529,8 @@ static void __perf_event_read(void *info) + + pmu->read(event); + +- for_each_sibling_event(sub, event) { +- if (sub->state == PERF_EVENT_STATE_ACTIVE) { +- /* +- * Use sibling's PMU rather than @event's since +- * sibling could be on different (eg: software) PMU. +- */ +- sub->pmu->read(sub); +- } +- } ++ for_each_sibling_event(sub, event) ++ perf_pmu_read(sub); + + data->ret = pmu->commit_txn(pmu); + +@@ -7297,9 +7295,8 @@ static void perf_output_read_group(struct perf_output_handle *handle, + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = running; + +- if ((leader != event) && +- (leader->state == PERF_EVENT_STATE_ACTIVE)) +- leader->pmu->read(leader); ++ if ((leader != event) && !handle->skip_read) ++ perf_pmu_read(leader); + + values[n++] = perf_event_count(leader); + if (read_format & PERF_FORMAT_ID) +@@ -7312,9 +7309,8 @@ static void perf_output_read_group(struct perf_output_handle *handle, + for_each_sibling_event(sub, leader) { + n = 0; + +- if ((sub != event) && +- (sub->state == PERF_EVENT_STATE_ACTIVE)) +- sub->pmu->read(sub); ++ if ((sub != event) && !handle->skip_read) ++ perf_pmu_read(sub); + + values[n++] = perf_event_count(sub); + if (read_format & PERF_FORMAT_ID) +@@ -7369,6 +7365,9 @@ void perf_output_sample(struct perf_output_handle *handle, + { + u64 sample_type = data->type; + ++ if (data->sample_flags & PERF_SAMPLE_READ) ++ handle->skip_read = 1; ++ + perf_output_put(handle, *header); + + if (sample_type & PERF_SAMPLE_IDENTIFIER) +diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c +index 6c2cb4e4f48dab..8f3f624419aa92 100644 +--- a/kernel/events/hw_breakpoint.c ++++ b/kernel/events/hw_breakpoint.c +@@ -950,9 +950,10 @@ static int hw_breakpoint_event_init(struct perf_event *bp) + return -ENOENT; + + /* +- * no branch sampling for breakpoint events ++ * Check if breakpoint type is supported before proceeding. ++ * Also, no branch sampling for breakpoint events. + */ +- if (has_branch_stack(bp)) ++ if (!hw_breakpoint_slots_cached(find_slot_idx(bp->attr.bp_type)) || has_branch_stack(bp)) + return -EOPNOTSUPP; + + err = register_perf_hw_breakpoint(bp); +diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c +index 52de76ef8723b8..dc1193b779c080 100644 +--- a/kernel/events/ring_buffer.c ++++ b/kernel/events/ring_buffer.c +@@ -181,6 +181,7 @@ __perf_output_begin(struct perf_output_handle *handle, + + handle->rb = rb; + handle->event = event; ++ handle->flags = 0; + + have_lost = local_read(&rb->lost); + if (unlikely(have_lost)) { +diff --git a/kernel/fork.c b/kernel/fork.c +index 97f433fb4b5ef4..7966c9a1c163d1 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -518,10 +518,6 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) + vma_numab_state_init(new); + dup_anon_vma_name(orig, new); + +- /* track_pfn_copy() will later take care of copying internal state. */ +- if (unlikely(new->vm_flags & VM_PFNMAP)) +- untrack_pfn_clear(new); +- + return new; + } + +@@ -715,6 +711,11 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, + tmp = vm_area_dup(mpnt); + if (!tmp) + goto fail_nomem; ++ ++ /* track_pfn_copy() will later take care of copying internal state. */ ++ if (unlikely(tmp->vm_flags & VM_PFNMAP)) ++ untrack_pfn_clear(tmp); ++ + retval = vma_dup_policy(mpnt, tmp); + if (retval) + goto fail_nomem_policy; +diff --git a/kernel/padata.c b/kernel/padata.c +index 071d8cad807871..93cd7704ab63e6 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -358,7 +358,8 @@ static void padata_reorder(struct parallel_data *pd) + * To avoid UAF issue, add pd ref here, and put pd ref after reorder_work finish. + */ + padata_get_pd(pd); +- queue_work(pinst->serial_wq, &pd->reorder_work); ++ if (!queue_work(pinst->serial_wq, &pd->reorder_work)) ++ padata_put_pd(pd); + } + } + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index dcdf449615bdac..51c43e0f9b29b5 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3119,7 +3119,12 @@ void console_unblank(void) + */ + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +- if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) { ++ short flags = console_srcu_read_flags(c); ++ ++ if (flags & CON_SUSPENDED) ++ continue; ++ ++ if ((flags & CON_ENABLED) && c->unblank) { + found_unblank = true; + break; + } +@@ -3156,7 +3161,12 @@ void console_unblank(void) + + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +- if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) ++ short flags = console_srcu_read_flags(c); ++ ++ if (flags & CON_SUSPENDED) ++ continue; ++ ++ if ((flags & CON_ENABLED) && c->unblank) + c->unblank(); + } + console_srcu_read_unlock(cookie); +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 41021080ad258d..94b715139f52d9 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -821,8 +821,17 @@ void rcu_read_unlock_strict(void) + { + struct rcu_data *rdp; + +- if (irqs_disabled() || preempt_count() || !rcu_state.gp_kthread) ++ if (irqs_disabled() || in_atomic_preempt_off() || !rcu_state.gp_kthread) + return; ++ ++ /* ++ * rcu_report_qs_rdp() can only be invoked with a stable rdp and ++ * from the local CPU. ++ * ++ * The in_atomic_preempt_off() check ensures that we come here holding ++ * the last preempt_count (which will get dropped once we return to ++ * __rcu_read_unlock(). ++ */ + rdp = this_cpu_ptr(&rcu_data); + rdp->cpu_no_qs.b.norm = false; + rcu_report_qs_rdp(rdp); +@@ -963,13 +972,16 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) + */ + static void rcu_flavor_sched_clock_irq(int user) + { +- if (user || rcu_is_cpu_rrupt_from_idle()) { ++ if (user || rcu_is_cpu_rrupt_from_idle() || ++ (IS_ENABLED(CONFIG_PREEMPT_COUNT) && ++ (preempt_count() == HARDIRQ_OFFSET))) { + + /* + * Get here if this CPU took its interrupt from user +- * mode or from the idle loop, and if this is not a +- * nested interrupt. In this case, the CPU is in +- * a quiescent state, so note it. ++ * mode, from the idle loop without this being a nested ++ * interrupt, or while not holding the task preempt count ++ * (with PREEMPT_COUNT=y). In this case, the CPU is in a ++ * quiescent state, so note it. + * + * No memory barrier is required here because rcu_qs() + * references only CPU-local variables that other CPUs +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 268e2a49b964e0..6ce3028e6e852f 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -73,10 +73,10 @@ unsigned int sysctl_sched_tunable_scaling = SCHED_TUNABLESCALING_LOG; + /* + * Minimal preemption granularity for CPU-bound tasks: + * +- * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds) ++ * (default: 0.70 msec * (1 + ilog(ncpus)), units: nanoseconds) + */ +-unsigned int sysctl_sched_base_slice = 750000ULL; +-static unsigned int normalized_sysctl_sched_base_slice = 750000ULL; ++unsigned int sysctl_sched_base_slice = 700000ULL; ++static unsigned int normalized_sysctl_sched_base_slice = 700000ULL; + + /* + * After fork, child runs first. If set to 0 (default) then +diff --git a/kernel/softirq.c b/kernel/softirq.c +index f24d80cf20bd35..d9e37f3fa13039 100644 +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -125,6 +125,18 @@ static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = { + .lock = INIT_LOCAL_LOCK(softirq_ctrl.lock), + }; + ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++static struct lock_class_key bh_lock_key; ++struct lockdep_map bh_lock_map = { ++ .name = "local_bh", ++ .key = &bh_lock_key, ++ .wait_type_outer = LD_WAIT_FREE, ++ .wait_type_inner = LD_WAIT_CONFIG, /* PREEMPT_RT makes BH preemptible. */ ++ .lock_type = LD_LOCK_PERCPU, ++}; ++EXPORT_SYMBOL_GPL(bh_lock_map); ++#endif ++ + /** + * local_bh_blocked() - Check for idle whether BH processing is blocked + * +@@ -147,6 +159,8 @@ void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) + + WARN_ON_ONCE(in_hardirq()); + ++ lock_map_acquire_read(&bh_lock_map); ++ + /* First entry of a task into a BH disabled section? */ + if (!current->softirq_disable_cnt) { + if (preemptible()) { +@@ -210,6 +224,8 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) + WARN_ON_ONCE(in_hardirq()); + lockdep_assert_irqs_enabled(); + ++ lock_map_release(&bh_lock_map); ++ + local_irq_save(flags); + curcnt = __this_cpu_read(softirq_ctrl.cnt); + +@@ -260,6 +276,8 @@ static inline void ksoftirqd_run_begin(void) + /* Counterpart to ksoftirqd_run_begin() */ + static inline void ksoftirqd_run_end(void) + { ++ /* pairs with the lock_map_acquire_read() in ksoftirqd_run_begin() */ ++ lock_map_release(&bh_lock_map); + __local_bh_enable(SOFTIRQ_OFFSET, true); + WARN_ON_ONCE(in_interrupt()); + local_irq_enable(); +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 877535b06e73aa..6d9da768604d68 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -58,6 +58,8 @@ + #define HRTIMER_ACTIVE_SOFT (HRTIMER_ACTIVE_HARD << MASK_SHIFT) + #define HRTIMER_ACTIVE_ALL (HRTIMER_ACTIVE_SOFT | HRTIMER_ACTIVE_HARD) + ++static void retrigger_next_event(void *arg); ++ + /* + * The timer bases: + * +@@ -111,7 +113,8 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = + .clockid = CLOCK_TAI, + .get_time = &ktime_get_clocktai, + }, +- } ++ }, ++ .csd = CSD_INIT(retrigger_next_event, NULL) + }; + + static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = { +@@ -124,6 +127,14 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = { + [CLOCK_TAI] = HRTIMER_BASE_TAI, + }; + ++static inline bool hrtimer_base_is_online(struct hrtimer_cpu_base *base) ++{ ++ if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) ++ return true; ++ else ++ return likely(base->online); ++} ++ + /* + * Functions and macros which are different for UP/SMP systems are kept in a + * single place +@@ -178,27 +189,54 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, + } + + /* +- * We do not migrate the timer when it is expiring before the next +- * event on the target cpu. When high resolution is enabled, we cannot +- * reprogram the target cpu hardware and we would cause it to fire +- * late. To keep it simple, we handle the high resolution enabled and +- * disabled case similar. ++ * Check if the elected target is suitable considering its next ++ * event and the hotplug state of the current CPU. ++ * ++ * If the elected target is remote and its next event is after the timer ++ * to queue, then a remote reprogram is necessary. However there is no ++ * guarantee the IPI handling the operation would arrive in time to meet ++ * the high resolution deadline. In this case the local CPU becomes a ++ * preferred target, unless it is offline. ++ * ++ * High and low resolution modes are handled the same way for simplicity. + * + * Called with cpu_base->lock of target cpu held. + */ +-static int +-hrtimer_check_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base) ++static bool hrtimer_suitable_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base, ++ struct hrtimer_cpu_base *new_cpu_base, ++ struct hrtimer_cpu_base *this_cpu_base) + { + ktime_t expires; + ++ /* ++ * The local CPU clockevent can be reprogrammed. Also get_target_base() ++ * guarantees it is online. ++ */ ++ if (new_cpu_base == this_cpu_base) ++ return true; ++ ++ /* ++ * The offline local CPU can't be the default target if the ++ * next remote target event is after this timer. Keep the ++ * elected new base. An IPI will we issued to reprogram ++ * it as a last resort. ++ */ ++ if (!hrtimer_base_is_online(this_cpu_base)) ++ return true; ++ + expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset); +- return expires < new_base->cpu_base->expires_next; ++ ++ return expires >= new_base->cpu_base->expires_next; + } + +-static inline +-struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, +- int pinned) ++static inline struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, int pinned) + { ++ if (!hrtimer_base_is_online(base)) { ++ int cpu = cpumask_any_and(cpu_online_mask, housekeeping_cpumask(HK_TYPE_TIMER)); ++ ++ return &per_cpu(hrtimer_bases, cpu); ++ } ++ + #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) + if (static_branch_likely(&timers_migration_enabled) && !pinned) + return &per_cpu(hrtimer_bases, get_nohz_timer_target()); +@@ -249,8 +287,8 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, + raw_spin_unlock(&base->cpu_base->lock); + raw_spin_lock(&new_base->cpu_base->lock); + +- if (new_cpu_base != this_cpu_base && +- hrtimer_check_target(timer, new_base)) { ++ if (!hrtimer_suitable_target(timer, new_base, new_cpu_base, ++ this_cpu_base)) { + raw_spin_unlock(&new_base->cpu_base->lock); + raw_spin_lock(&base->cpu_base->lock); + new_cpu_base = this_cpu_base; +@@ -259,8 +297,7 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, + } + WRITE_ONCE(timer->base, new_base); + } else { +- if (new_cpu_base != this_cpu_base && +- hrtimer_check_target(timer, new_base)) { ++ if (!hrtimer_suitable_target(timer, new_base, new_cpu_base, this_cpu_base)) { + new_cpu_base = this_cpu_base; + goto again; + } +@@ -720,8 +757,6 @@ static inline int hrtimer_is_hres_enabled(void) + return hrtimer_hres_enabled; + } + +-static void retrigger_next_event(void *arg); +- + /* + * Switch to high resolution mode + */ +@@ -1208,6 +1243,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + u64 delta_ns, const enum hrtimer_mode mode, + struct hrtimer_clock_base *base) + { ++ struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); + struct hrtimer_clock_base *new_base; + bool force_local, first; + +@@ -1219,9 +1255,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + * and enforce reprogramming after it is queued no matter whether + * it is the new first expiring timer again or not. + */ +- force_local = base->cpu_base == this_cpu_ptr(&hrtimer_bases); ++ force_local = base->cpu_base == this_cpu_base; + force_local &= base->cpu_base->next_timer == timer; + ++ /* ++ * Don't force local queuing if this enqueue happens on a unplugged ++ * CPU after hrtimer_cpu_dying() has been invoked. ++ */ ++ force_local &= this_cpu_base->online; ++ + /* + * Remove an active timer from the queue. In case it is not queued + * on the current CPU, make sure that remove_hrtimer() updates the +@@ -1251,8 +1293,27 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + } + + first = enqueue_hrtimer(timer, new_base, mode); +- if (!force_local) +- return first; ++ if (!force_local) { ++ /* ++ * If the current CPU base is online, then the timer is ++ * never queued on a remote CPU if it would be the first ++ * expiring timer there. ++ */ ++ if (hrtimer_base_is_online(this_cpu_base)) ++ return first; ++ ++ /* ++ * Timer was enqueued remote because the current base is ++ * already offline. If the timer is the first to expire, ++ * kick the remote CPU to reprogram the clock event. ++ */ ++ if (first) { ++ struct hrtimer_cpu_base *new_cpu_base = new_base->cpu_base; ++ ++ smp_call_function_single_async(new_cpu_base->cpu, &new_cpu_base->csd); ++ } ++ return 0; ++ } + + /* + * Timer was forced to stay on the current CPU to avoid +diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c +index b924f0f096fa44..7534069f603334 100644 +--- a/kernel/time/posix-timers.c ++++ b/kernel/time/posix-timers.c +@@ -118,6 +118,7 @@ static int posix_timer_add(struct k_itimer *timer) + return id; + } + spin_unlock(&hash_lock); ++ cond_resched(); + } + /* POSIX return code when no timer ID could be allocated */ + return -EAGAIN; +diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c +index ed7d6ad694fba6..20a5e6962b6967 100644 +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -46,7 +46,7 @@ static void + print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer, + int idx, u64 now) + { +- SEQ_printf(m, " #%d: <%pK>, %ps", idx, taddr, timer->function); ++ SEQ_printf(m, " #%d: <%p>, %ps", idx, taddr, timer->function); + SEQ_printf(m, ", S:%02x", timer->state); + SEQ_printf(m, "\n"); + SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n", +@@ -98,7 +98,7 @@ print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, + static void + print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now) + { +- SEQ_printf(m, " .base: %pK\n", base); ++ SEQ_printf(m, " .base: %p\n", base); + SEQ_printf(m, " .index: %d\n", base->index); + + SEQ_printf(m, " .resolution: %u nsecs\n", hrtimer_resolution); +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 95868c31573007..43d19b69c635b2 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -3487,10 +3487,9 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) + } + EXPORT_SYMBOL_GPL(trace_vbprintk); + +-__printf(3, 0) +-static int +-__trace_array_vprintk(struct trace_buffer *buffer, +- unsigned long ip, const char *fmt, va_list args) ++static __printf(3, 0) ++int __trace_array_vprintk(struct trace_buffer *buffer, ++ unsigned long ip, const char *fmt, va_list args) + { + struct trace_event_call *call = &event_print; + struct ring_buffer_event *event; +@@ -3543,7 +3542,6 @@ __trace_array_vprintk(struct trace_buffer *buffer, + return len; + } + +-__printf(3, 0) + int trace_array_vprintk(struct trace_array *tr, + unsigned long ip, const char *fmt, va_list args) + { +@@ -3573,7 +3571,6 @@ int trace_array_vprintk(struct trace_array *tr, + * Note, trace_array_init_printk() must be called on @tr before this + * can be used. + */ +-__printf(3, 0) + int trace_array_printk(struct trace_array *tr, + unsigned long ip, const char *fmt, ...) + { +@@ -3618,7 +3615,6 @@ int trace_array_init_printk(struct trace_array *tr) + } + EXPORT_SYMBOL_GPL(trace_array_init_printk); + +-__printf(3, 4) + int trace_array_printk_buf(struct trace_buffer *buffer, + unsigned long ip, const char *fmt, ...) + { +@@ -3634,7 +3630,6 @@ int trace_array_printk_buf(struct trace_buffer *buffer, + return ret; + } + +-__printf(2, 0) + int trace_vprintk(unsigned long ip, const char *fmt, va_list args) + { + return trace_array_vprintk(&global_trace, ip, fmt, args); +diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h +index db0d2641125e7e..faf892aecdf490 100644 +--- a/kernel/trace/trace.h ++++ b/kernel/trace/trace.h +@@ -800,13 +800,15 @@ static inline void __init disable_tracing_selftest(const char *reason) + + extern void *head_page(struct trace_array_cpu *data); + extern unsigned long long ns2usecs(u64 nsec); +-extern int +-trace_vbprintk(unsigned long ip, const char *fmt, va_list args); +-extern int +-trace_vprintk(unsigned long ip, const char *fmt, va_list args); +-extern int +-trace_array_vprintk(struct trace_array *tr, +- unsigned long ip, const char *fmt, va_list args); ++ ++__printf(2, 0) ++int trace_vbprintk(unsigned long ip, const char *fmt, va_list args); ++__printf(2, 0) ++int trace_vprintk(unsigned long ip, const char *fmt, va_list args); ++__printf(3, 0) ++int trace_array_vprintk(struct trace_array *tr, ++ unsigned long ip, const char *fmt, va_list args); ++__printf(3, 4) + int trace_array_printk_buf(struct trace_buffer *buffer, + unsigned long ip, const char *fmt, ...); + void trace_printk_seq(struct trace_seq *s); +diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c +index fde0aa24414800..a75a9ca46b5940 100644 +--- a/lib/dynamic_queue_limits.c ++++ b/lib/dynamic_queue_limits.c +@@ -116,7 +116,7 @@ EXPORT_SYMBOL(dql_completed); + void dql_reset(struct dql *dql) + { + /* Reset all dynamic values */ +- dql->limit = 0; ++ dql->limit = dql->min_limit; + dql->num_queued = 0; + dql->num_completed = 0; + dql->last_obj_cnt = 0; +diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile +index 2f58fafbbdddc0..fc7b2b7ef4b20e 100644 +--- a/lib/lzo/Makefile ++++ b/lib/lzo/Makefile +@@ -1,5 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0-only +-lzo_compress-objs := lzo1x_compress.o ++lzo_compress-objs := lzo1x_compress.o lzo1x_compress_safe.o + lzo_decompress-objs := lzo1x_decompress_safe.o + + obj-$(CONFIG_LZO_COMPRESS) += lzo_compress.o +diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c +index 9d31e7126606ac..f00dff9b9d4e1b 100644 +--- a/lib/lzo/lzo1x_compress.c ++++ b/lib/lzo/lzo1x_compress.c +@@ -18,11 +18,22 @@ + #include + #include "lzodefs.h" + +-static noinline size_t +-lzo1x_1_do_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- size_t ti, void *wrkmem, signed char *state_offset, +- const unsigned char bitstream_version) ++#undef LZO_UNSAFE ++ ++#ifndef LZO_SAFE ++#define LZO_UNSAFE 1 ++#define LZO_SAFE(name) name ++#define HAVE_OP(x) 1 ++#endif ++ ++#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun ++ ++static noinline int ++LZO_SAFE(lzo1x_1_do_compress)(const unsigned char *in, size_t in_len, ++ unsigned char **out, unsigned char *op_end, ++ size_t *tp, void *wrkmem, ++ signed char *state_offset, ++ const unsigned char bitstream_version) + { + const unsigned char *ip; + unsigned char *op; +@@ -30,8 +41,9 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + const unsigned char * const ip_end = in + in_len - 20; + const unsigned char *ii; + lzo_dict_t * const dict = (lzo_dict_t *) wrkmem; ++ size_t ti = *tp; + +- op = out; ++ op = *out; + ip = in; + ii = ip; + ip += ti < 4 ? 4 - ti : 0; +@@ -116,25 +128,32 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + if (t != 0) { + if (t <= 3) { + op[*state_offset] |= t; ++ NEED_OP(4); + COPY4(op, ii); + op += t; + } else if (t <= 16) { ++ NEED_OP(17); + *op++ = (t - 3); + COPY8(op, ii); + COPY8(op + 8, ii + 8); + op += t; + } else { + if (t <= 18) { ++ NEED_OP(1); + *op++ = (t - 3); + } else { + size_t tt = t - 18; ++ NEED_OP(1); + *op++ = 0; + while (unlikely(tt > 255)) { + tt -= 255; ++ NEED_OP(1); + *op++ = 0; + } ++ NEED_OP(1); + *op++ = tt; + } ++ NEED_OP(t); + do { + COPY8(op, ii); + COPY8(op + 8, ii + 8); +@@ -151,6 +170,7 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + if (unlikely(run_length)) { + ip += run_length; + run_length -= MIN_ZERO_RUN_LENGTH; ++ NEED_OP(4); + put_unaligned_le32((run_length << 21) | 0xfffc18 + | (run_length & 0x7), op); + op += 4; +@@ -243,10 +263,12 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + ip += m_len; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { + m_off -= 1; ++ NEED_OP(2); + *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = (m_off >> 3); + } else if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; ++ NEED_OP(1); + if (m_len <= M3_MAX_LEN) + *op++ = (M3_MARKER | (m_len - 2)); + else { +@@ -254,14 +276,18 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + *op++ = M3_MARKER | 0; + while (unlikely(m_len > 255)) { + m_len -= 255; ++ NEED_OP(1); + *op++ = 0; + } ++ NEED_OP(1); + *op++ = (m_len); + } ++ NEED_OP(2); + *op++ = (m_off << 2); + *op++ = (m_off >> 6); + } else { + m_off -= 0x4000; ++ NEED_OP(1); + if (m_len <= M4_MAX_LEN) + *op++ = (M4_MARKER | ((m_off >> 11) & 8) + | (m_len - 2)); +@@ -282,11 +308,14 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + m_len -= M4_MAX_LEN; + *op++ = (M4_MARKER | ((m_off >> 11) & 8)); + while (unlikely(m_len > 255)) { ++ NEED_OP(1); + m_len -= 255; + *op++ = 0; + } ++ NEED_OP(1); + *op++ = (m_len); + } ++ NEED_OP(2); + *op++ = (m_off << 2); + *op++ = (m_off >> 6); + } +@@ -295,14 +324,20 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + ii = ip; + goto next; + } +- *out_len = op - out; +- return in_end - (ii - ti); ++ *out = op; ++ *tp = in_end - (ii - ti); ++ return LZO_E_OK; ++ ++output_overrun: ++ return LZO_E_OUTPUT_OVERRUN; + } + +-static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- void *wrkmem, const unsigned char bitstream_version) ++static int LZO_SAFE(lzogeneric1x_1_compress)( ++ const unsigned char *in, size_t in_len, ++ unsigned char *out, size_t *out_len, ++ void *wrkmem, const unsigned char bitstream_version) + { ++ unsigned char * const op_end = out + *out_len; + const unsigned char *ip = in; + unsigned char *op = out; + unsigned char *data_start; +@@ -326,14 +361,18 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, + while (l > 20) { + size_t ll = min_t(size_t, l, m4_max_offset + 1); + uintptr_t ll_end = (uintptr_t) ip + ll; ++ int err; ++ + if ((ll_end + ((t + ll) >> 5)) <= ll_end) + break; + BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS); + memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); +- t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem, +- &state_offset, bitstream_version); ++ err = LZO_SAFE(lzo1x_1_do_compress)( ++ ip, ll, &op, op_end, &t, wrkmem, ++ &state_offset, bitstream_version); ++ if (err != LZO_E_OK) ++ return err; + ip += ll; +- op += *out_len; + l -= ll; + } + t += l; +@@ -342,20 +381,26 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, + const unsigned char *ii = in + in_len - t; + + if (op == data_start && t <= 238) { ++ NEED_OP(1); + *op++ = (17 + t); + } else if (t <= 3) { + op[state_offset] |= t; + } else if (t <= 18) { ++ NEED_OP(1); + *op++ = (t - 3); + } else { + size_t tt = t - 18; ++ NEED_OP(1); + *op++ = 0; + while (tt > 255) { + tt -= 255; ++ NEED_OP(1); + *op++ = 0; + } ++ NEED_OP(1); + *op++ = tt; + } ++ NEED_OP(t); + if (t >= 16) do { + COPY8(op, ii); + COPY8(op + 8, ii + 8); +@@ -368,31 +413,38 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, + } while (--t > 0); + } + ++ NEED_OP(3); + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = op - out; + return LZO_E_OK; ++ ++output_overrun: ++ return LZO_E_OUTPUT_OVERRUN; + } + +-int lzo1x_1_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- void *wrkmem) ++int LZO_SAFE(lzo1x_1_compress)(const unsigned char *in, size_t in_len, ++ unsigned char *out, size_t *out_len, ++ void *wrkmem) + { +- return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0); ++ return LZO_SAFE(lzogeneric1x_1_compress)( ++ in, in_len, out, out_len, wrkmem, 0); + } + +-int lzorle1x_1_compress(const unsigned char *in, size_t in_len, +- unsigned char *out, size_t *out_len, +- void *wrkmem) ++int LZO_SAFE(lzorle1x_1_compress)(const unsigned char *in, size_t in_len, ++ unsigned char *out, size_t *out_len, ++ void *wrkmem) + { +- return lzogeneric1x_1_compress(in, in_len, out, out_len, +- wrkmem, LZO_VERSION); ++ return LZO_SAFE(lzogeneric1x_1_compress)( ++ in, in_len, out, out_len, wrkmem, LZO_VERSION); + } + +-EXPORT_SYMBOL_GPL(lzo1x_1_compress); +-EXPORT_SYMBOL_GPL(lzorle1x_1_compress); ++EXPORT_SYMBOL_GPL(LZO_SAFE(lzo1x_1_compress)); ++EXPORT_SYMBOL_GPL(LZO_SAFE(lzorle1x_1_compress)); + ++#ifndef LZO_UNSAFE + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("LZO1X-1 Compressor"); ++#endif +diff --git a/lib/lzo/lzo1x_compress_safe.c b/lib/lzo/lzo1x_compress_safe.c +new file mode 100644 +index 00000000000000..371c9f84949281 +--- /dev/null ++++ b/lib/lzo/lzo1x_compress_safe.c +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * LZO1X Compressor from LZO ++ * ++ * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer ++ * ++ * The full LZO package can be found at: ++ * http://www.oberhumer.com/opensource/lzo/ ++ * ++ * Changed for Linux kernel use by: ++ * Nitin Gupta ++ * Richard Purdie ++ */ ++ ++#define LZO_SAFE(name) name##_safe ++#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) ++ ++#include "lzo1x_compress.c" +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index 9bf5a69e20d87a..2d2cada8a8a4c8 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -1266,7 +1266,6 @@ void mem_cgroup_scan_tasks(struct mem_cgroup *memcg, + { + struct mem_cgroup *iter; + int ret = 0; +- int i = 0; + + BUG_ON(mem_cgroup_is_root(memcg)); + +@@ -1276,10 +1275,9 @@ void mem_cgroup_scan_tasks(struct mem_cgroup *memcg, + + css_task_iter_start(&iter->css, CSS_TASK_ITER_PROCS, &it); + while (!ret && (task = css_task_iter_next(&it))) { +- /* Avoid potential softlockup warning */ +- if ((++i & 1023) == 0) +- cond_resched(); + ret = fn(task, arg); ++ /* Avoid potential softlockup warning */ ++ cond_resched(); + } + css_task_iter_end(&it); + if (ret) { +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 74737c35082b45..44011ebecddf01 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -4038,6 +4038,14 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, + } + + retry: ++ /* ++ * Deal with possible cpuset update races or zonelist updates to avoid ++ * infinite retries. ++ */ ++ if (check_retry_cpuset(cpuset_mems_cookie, ac) || ++ check_retry_zonelist(zonelist_iter_cookie)) ++ goto restart; ++ + /* Ensure kswapd doesn't accidentally go to sleep as long as we loop */ + if (alloc_flags & ALLOC_KSWAPD) + wake_all_kswapds(order, gfp_mask, ac); +diff --git a/net/Makefile b/net/Makefile +index 4c4dc535453dff..45f3fbaae644e1 100644 +--- a/net/Makefile ++++ b/net/Makefile +@@ -17,7 +17,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/ + obj-$(CONFIG_INET) += ipv4/ + obj-$(CONFIG_TLS) += tls/ + obj-$(CONFIG_XFRM) += xfrm/ +-obj-$(CONFIG_UNIX_SCM) += unix/ ++obj-$(CONFIG_UNIX) += unix/ + obj-y += ipv6/ + obj-$(CONFIG_BPFILTER) += bpfilter/ + obj-$(CONFIG_PACKET) += packet/ +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 72ee41b894a520..1c54e812ef1f78 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -1411,7 +1411,8 @@ static void l2cap_request_info(struct l2cap_conn *conn) + sizeof(req), &req); + } + +-static bool l2cap_check_enc_key_size(struct hci_conn *hcon) ++static bool l2cap_check_enc_key_size(struct hci_conn *hcon, ++ struct l2cap_chan *chan) + { + /* The minimum encryption key size needs to be enforced by the + * host stack before establishing any L2CAP connections. The +@@ -1425,7 +1426,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon) + int min_key_size = hcon->hdev->min_enc_key_size; + + /* On FIPS security level, key size must be 16 bytes */ +- if (hcon->sec_level == BT_SECURITY_FIPS) ++ if (chan->sec_level == BT_SECURITY_FIPS) + min_key_size = 16; + + return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) || +@@ -1453,7 +1454,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) + !__l2cap_no_conn_pending(chan)) + return; + +- if (l2cap_check_enc_key_size(conn->hcon)) ++ if (l2cap_check_enc_key_size(conn->hcon, chan)) + l2cap_start_connection(chan); + else + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); +@@ -1528,7 +1529,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) + continue; + } + +- if (l2cap_check_enc_key_size(conn->hcon)) ++ if (l2cap_check_enc_key_size(conn->hcon, chan)) + l2cap_start_connection(chan); + else + l2cap_chan_close(chan, ECONNREFUSED); +@@ -3955,7 +3956,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, + /* Check if the ACL is secure enough (if not SDP) */ + if (psm != cpu_to_le16(L2CAP_PSM_SDP) && + (!hci_conn_check_link_mode(conn->hcon) || +- !l2cap_check_enc_key_size(conn->hcon))) { ++ !l2cap_check_enc_key_size(conn->hcon, pchan))) { + conn->disc_reason = HCI_ERROR_AUTH_FAILURE; + result = L2CAP_CR_SEC_BLOCK; + goto response; +@@ -7323,7 +7324,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) + } + + if (chan->state == BT_CONNECT) { +- if (!status && l2cap_check_enc_key_size(hcon)) ++ if (!status && l2cap_check_enc_key_size(hcon, chan)) + l2cap_start_connection(chan); + else + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); +@@ -7333,7 +7334,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) + struct l2cap_conn_rsp rsp; + __u16 res, stat; + +- if (!status && l2cap_check_enc_key_size(hcon)) { ++ if (!status && l2cap_check_enc_key_size(hcon, chan)) { + if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { + res = L2CAP_CR_PEND; + stat = L2CAP_CS_AUTHOR_PEND; +diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c +index 7305f5f8215cac..96bea0c8408fec 100644 +--- a/net/bridge/br_mdb.c ++++ b/net/bridge/br_mdb.c +@@ -1030,7 +1030,7 @@ static int br_mdb_add_group(const struct br_mdb_config *cfg, + + /* host join */ + if (!port) { +- if (mp->host_joined) { ++ if (mp->host_joined && !(cfg->nlflags & NLM_F_REPLACE)) { + NL_SET_ERR_MSG_MOD(extack, "Group is already joined by host"); + return -EEXIST; + } +diff --git a/net/bridge/br_nf_core.c b/net/bridge/br_nf_core.c +index 98aea5485aaef4..a8c67035e23c00 100644 +--- a/net/bridge/br_nf_core.c ++++ b/net/bridge/br_nf_core.c +@@ -65,17 +65,14 @@ static struct dst_ops fake_dst_ops = { + * ipt_REJECT needs it. Future netfilter modules might + * require us to fill additional fields. + */ +-static const u32 br_dst_default_metrics[RTAX_MAX] = { +- [RTAX_MTU - 1] = 1500, +-}; +- + void br_netfilter_rtable_init(struct net_bridge *br) + { + struct rtable *rt = &br->fake_rtable; + + rcuref_init(&rt->dst.__rcuref, 1); + rt->dst.dev = br->dev; +- dst_init_metrics(&rt->dst, br_dst_default_metrics, true); ++ dst_init_metrics(&rt->dst, br->metrics, false); ++ dst_metric_set(&rt->dst, RTAX_MTU, br->dev->mtu); + rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE; + rt->dst.ops = &fake_dst_ops; + } +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h +index 72d80fd943a8a2..9197b511e45972 100644 +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -502,6 +502,7 @@ struct net_bridge { + struct rtable fake_rtable; + struct rt6_info fake_rt6_info; + }; ++ u32 metrics[RTAX_MAX]; + #endif + u16 group_fwd_mask; + u16 group_fwd_mask_required; +diff --git a/net/can/bcm.c b/net/can/bcm.c +index a1f5db0fd5d4fd..75653584f31b94 100644 +--- a/net/can/bcm.c ++++ b/net/can/bcm.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -120,6 +121,7 @@ struct bcm_op { + struct canfd_frame last_sframe; + struct sock *sk; + struct net_device *rx_reg_dev; ++ spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */ + }; + + struct bcm_sock { +@@ -205,7 +207,9 @@ static int bcm_proc_show(struct seq_file *m, void *v) + seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex)); + seq_printf(m, " <<<\n"); + +- list_for_each_entry(op, &bo->rx_ops, list) { ++ rcu_read_lock(); ++ ++ list_for_each_entry_rcu(op, &bo->rx_ops, list) { + + unsigned long reduction; + +@@ -261,6 +265,9 @@ static int bcm_proc_show(struct seq_file *m, void *v) + seq_printf(m, "# sent %ld\n", op->frames_abs); + } + seq_putc(m, '\n'); ++ ++ rcu_read_unlock(); ++ + return 0; + } + #endif /* CONFIG_PROC_FS */ +@@ -273,13 +280,18 @@ static void bcm_can_tx(struct bcm_op *op) + { + struct sk_buff *skb; + struct net_device *dev; +- struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe; ++ struct canfd_frame *cf; + int err; + + /* no target device? => exit */ + if (!op->ifindex) + return; + ++ /* read currframe under lock protection */ ++ spin_lock_bh(&op->bcm_tx_lock); ++ cf = op->frames + op->cfsiz * op->currframe; ++ spin_unlock_bh(&op->bcm_tx_lock); ++ + dev = dev_get_by_index(sock_net(op->sk), op->ifindex); + if (!dev) { + /* RFC: should this bcm_op remove itself here? */ +@@ -300,6 +312,10 @@ static void bcm_can_tx(struct bcm_op *op) + skb->dev = dev; + can_skb_set_owner(skb, op->sk); + err = can_send(skb, 1); ++ ++ /* update currframe and count under lock protection */ ++ spin_lock_bh(&op->bcm_tx_lock); ++ + if (!err) + op->frames_abs++; + +@@ -308,6 +324,11 @@ static void bcm_can_tx(struct bcm_op *op) + /* reached last frame? */ + if (op->currframe >= op->nframes) + op->currframe = 0; ++ ++ if (op->count > 0) ++ op->count--; ++ ++ spin_unlock_bh(&op->bcm_tx_lock); + out: + dev_put(dev); + } +@@ -404,7 +425,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) + struct bcm_msg_head msg_head; + + if (op->kt_ival1 && (op->count > 0)) { +- op->count--; ++ bcm_can_tx(op); + if (!op->count && (op->flags & TX_COUNTEVT)) { + + /* create notification to user */ +@@ -419,7 +440,6 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) + + bcm_send_to_user(op, &msg_head, NULL, 0); + } +- bcm_can_tx(op); + + } else if (op->kt_ival2) { + bcm_can_tx(op); +@@ -801,7 +821,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, + REGMASK(op->can_id), + bcm_rx_handler, op); + +- list_del(&op->list); ++ list_del_rcu(&op->list); + bcm_remove_op(op); + return 1; /* done */ + } +@@ -821,7 +841,7 @@ static int bcm_delete_tx_op(struct list_head *ops, struct bcm_msg_head *mh, + list_for_each_entry_safe(op, n, ops, list) { + if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) && + (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) { +- list_del(&op->list); ++ list_del_rcu(&op->list); + bcm_remove_op(op); + return 1; /* done */ + } +@@ -914,6 +934,27 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + } + op->flags = msg_head->flags; + ++ /* only lock for unlikely count/nframes/currframe changes */ ++ if (op->nframes != msg_head->nframes || ++ op->flags & TX_RESET_MULTI_IDX || ++ op->flags & SETTIMER) { ++ ++ spin_lock_bh(&op->bcm_tx_lock); ++ ++ if (op->nframes != msg_head->nframes || ++ op->flags & TX_RESET_MULTI_IDX) { ++ /* potentially update changed nframes */ ++ op->nframes = msg_head->nframes; ++ /* restart multiple frame transmission */ ++ op->currframe = 0; ++ } ++ ++ if (op->flags & SETTIMER) ++ op->count = msg_head->count; ++ ++ spin_unlock_bh(&op->bcm_tx_lock); ++ } ++ + } else { + /* insert new BCM operation for the given can_id */ + +@@ -921,9 +962,14 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + if (!op) + return -ENOMEM; + ++ spin_lock_init(&op->bcm_tx_lock); + op->can_id = msg_head->can_id; + op->cfsiz = CFSIZ(msg_head->flags); + op->flags = msg_head->flags; ++ op->nframes = msg_head->nframes; ++ ++ if (op->flags & SETTIMER) ++ op->count = msg_head->count; + + /* create array for CAN frames and copy the data */ + if (msg_head->nframes > 1) { +@@ -982,22 +1028,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + + } /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */ + +- if (op->nframes != msg_head->nframes) { +- op->nframes = msg_head->nframes; +- /* start multiple frame transmission with index 0 */ +- op->currframe = 0; +- } +- +- /* check flags */ +- +- if (op->flags & TX_RESET_MULTI_IDX) { +- /* start multiple frame transmission with index 0 */ +- op->currframe = 0; +- } +- + if (op->flags & SETTIMER) { + /* set timer values */ +- op->count = msg_head->count; + op->ival1 = msg_head->ival1; + op->ival2 = msg_head->ival2; + op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1); +@@ -1014,11 +1046,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + op->flags |= TX_ANNOUNCE; + } + +- if (op->flags & TX_ANNOUNCE) { ++ if (op->flags & TX_ANNOUNCE) + bcm_can_tx(op); +- if (op->count) +- op->count--; +- } + + if (op->flags & STARTTIMER) + bcm_tx_start_timer(op); +@@ -1234,7 +1263,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, + bcm_rx_handler, op, "bcm", sk); + if (err) { + /* this bcm rx op is broken -> remove it */ +- list_del(&op->list); ++ list_del_rcu(&op->list); + bcm_remove_op(op); + return err; + } +diff --git a/net/core/pktgen.c b/net/core/pktgen.c +index 359e24c3f22cab..6afea369ca2132 100644 +--- a/net/core/pktgen.c ++++ b/net/core/pktgen.c +@@ -897,6 +897,10 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) + pkt_dev->nr_labels = 0; + do { + __u32 tmp; ++ ++ if (n >= MAX_MPLS_LABELS) ++ return -E2BIG; ++ + len = hex32_arg(&buffer[i], 8, &tmp); + if (len <= 0) + return len; +@@ -908,8 +912,6 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) + return -EFAULT; + i++; + n++; +- if (n >= MAX_MPLS_LABELS) +- return -E2BIG; + } while (c == ','); + + pkt_dev->nr_labels = n; +@@ -1875,8 +1877,8 @@ static ssize_t pktgen_thread_write(struct file *file, + i = len; + + /* Read variable name */ +- +- len = strn_len(&user_buffer[i], sizeof(name) - 1); ++ max = min(sizeof(name) - 1, count - i); ++ len = strn_len(&user_buffer[i], max); + if (len < 0) + return len; + +@@ -1906,7 +1908,8 @@ static ssize_t pktgen_thread_write(struct file *file, + if (!strcmp(name, "add_device")) { + char f[32]; + memset(f, 0, 32); +- len = strn_len(&user_buffer[i], sizeof(f) - 1); ++ max = min(sizeof(f) - 1, count - i); ++ len = strn_len(&user_buffer[i], max); + if (len < 0) { + ret = len; + goto out; +diff --git a/net/core/scm.c b/net/core/scm.c +index 737917c7ac6276..431bfb3ea39290 100644 +--- a/net/core/scm.c ++++ b/net/core/scm.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + + /* +@@ -85,8 +86,15 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + return -ENOMEM; + *fplp = fpl; + fpl->count = 0; ++ fpl->count_unix = 0; + fpl->max = SCM_MAX_FD; + fpl->user = NULL; ++#if IS_ENABLED(CONFIG_UNIX) ++ fpl->inflight = false; ++ fpl->dead = false; ++ fpl->edges = NULL; ++ INIT_LIST_HEAD(&fpl->vertices); ++#endif + } + fpp = &fpl->fp[fpl->count]; + +@@ -109,6 +117,9 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + fput(file); + return -EINVAL; + } ++ if (unix_get_socket(file)) ++ fpl->count_unix++; ++ + *fpp++ = file; + fpl->count++; + } +@@ -371,8 +382,14 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) + if (new_fpl) { + for (i = 0; i < fpl->count; i++) + get_file(fpl->fp[i]); ++ + new_fpl->max = new_fpl->count; + new_fpl->user = get_uid(fpl->user); ++#if IS_ENABLED(CONFIG_UNIX) ++ new_fpl->inflight = false; ++ new_fpl->edges = NULL; ++ INIT_LIST_HEAD(&new_fpl->vertices); ++#endif + } + return new_fpl; + } +diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c +index eeace9b509cec7..49fd664f50fc01 100644 +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -118,47 +118,16 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + } + + #ifdef CONFIG_INET_ESPINTCP +-struct esp_tcp_sk { +- struct sock *sk; +- struct rcu_head rcu; +-}; +- +-static void esp_free_tcp_sk(struct rcu_head *head) +-{ +- struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu); +- +- sock_put(esk->sk); +- kfree(esk); +-} +- + static struct sock *esp_find_tcp_sk(struct xfrm_state *x) + { + struct xfrm_encap_tmpl *encap = x->encap; + struct net *net = xs_net(x); +- struct esp_tcp_sk *esk; + __be16 sport, dport; +- struct sock *nsk; + struct sock *sk; + +- sk = rcu_dereference(x->encap_sk); +- if (sk && sk->sk_state == TCP_ESTABLISHED) +- return sk; +- + spin_lock_bh(&x->lock); + sport = encap->encap_sport; + dport = encap->encap_dport; +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (sk && sk == nsk) { +- esk = kmalloc(sizeof(*esk), GFP_ATOMIC); +- if (!esk) { +- spin_unlock_bh(&x->lock); +- return ERR_PTR(-ENOMEM); +- } +- RCU_INIT_POINTER(x->encap_sk, NULL); +- esk->sk = sk; +- call_rcu(&esk->rcu, esp_free_tcp_sk); +- } + spin_unlock_bh(&x->lock); + + sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, x->id.daddr.a4, +@@ -171,20 +140,6 @@ static struct sock *esp_find_tcp_sk(struct xfrm_state *x) + return ERR_PTR(-EINVAL); + } + +- spin_lock_bh(&x->lock); +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (encap->encap_sport != sport || +- encap->encap_dport != dport) { +- sock_put(sk); +- sk = nsk ?: ERR_PTR(-EREMCHG); +- } else if (sk == nsk) { +- sock_put(sk); +- } else { +- rcu_assign_pointer(x->encap_sk, sk); +- } +- spin_unlock_bh(&x->lock); +- + return sk; + } + +@@ -207,6 +162,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb) + err = espintcp_push_skb(sk, skb); + bh_unlock_sock(sk); + ++ sock_put(sk); ++ + out: + rcu_read_unlock(); + return err; +@@ -391,6 +348,8 @@ static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x, + if (IS_ERR(sk)) + return ERR_CAST(sk); + ++ sock_put(sk); ++ + *lenp = htons(len); + esph = (struct ip_esp_hdr *)(lenp + 1); + +diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c +index 90ce87ffed4617..7993ff46de23ca 100644 +--- a/net/ipv4/fib_frontend.c ++++ b/net/ipv4/fib_frontend.c +@@ -829,19 +829,33 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, + } + } + ++ if (cfg->fc_dst_len > 32) { ++ NL_SET_ERR_MSG(extack, "Invalid prefix length"); ++ err = -EINVAL; ++ goto errout; ++ } ++ ++ if (cfg->fc_dst_len < 32 && (ntohl(cfg->fc_dst) << cfg->fc_dst_len)) { ++ NL_SET_ERR_MSG(extack, "Invalid prefix for given prefix length"); ++ err = -EINVAL; ++ goto errout; ++ } ++ + if (cfg->fc_nh_id) { + if (cfg->fc_oif || cfg->fc_gw_family || + cfg->fc_encap || cfg->fc_mp) { + NL_SET_ERR_MSG(extack, + "Nexthop specification and nexthop id are mutually exclusive"); +- return -EINVAL; ++ err = -EINVAL; ++ goto errout; + } + } + + if (has_gw && has_via) { + NL_SET_ERR_MSG(extack, + "Nexthop configuration can not contain both GATEWAY and VIA"); +- return -EINVAL; ++ err = -EINVAL; ++ goto errout; + } + + if (!cfg->fc_table) +diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c +index 513f475c6a534e..298a9944a3d1e8 100644 +--- a/net/ipv4/fib_rules.c ++++ b/net/ipv4/fib_rules.c +@@ -222,9 +222,9 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, + struct nlattr **tb, + struct netlink_ext_ack *extack) + { +- struct net *net = sock_net(skb->sk); ++ struct fib4_rule *rule4 = (struct fib4_rule *)rule; ++ struct net *net = rule->fr_net; + int err = -EINVAL; +- struct fib4_rule *rule4 = (struct fib4_rule *) rule; + + if (!inet_validate_dscp(frh->tos)) { + NL_SET_ERR_MSG(extack, +diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c +index 77b97c48da5ea8..fa54b36b241ac0 100644 +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1192,22 +1192,6 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp, + return 0; + } + +-static bool fib_valid_key_len(u32 key, u8 plen, struct netlink_ext_ack *extack) +-{ +- if (plen > KEYLENGTH) { +- NL_SET_ERR_MSG(extack, "Invalid prefix length"); +- return false; +- } +- +- if ((plen < KEYLENGTH) && (key << plen)) { +- NL_SET_ERR_MSG(extack, +- "Invalid prefix for given prefix length"); +- return false; +- } +- +- return true; +-} +- + static void fib_remove_alias(struct trie *t, struct key_vector *tp, + struct key_vector *l, struct fib_alias *old); + +@@ -1228,9 +1212,6 @@ int fib_table_insert(struct net *net, struct fib_table *tb, + + key = ntohl(cfg->fc_dst); + +- if (!fib_valid_key_len(key, plen, extack)) +- return -EINVAL; +- + pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); + + fi = fib_create_info(cfg, extack); +@@ -1723,9 +1704,6 @@ int fib_table_delete(struct net *net, struct fib_table *tb, + + key = ntohl(cfg->fc_dst); + +- if (!fib_valid_key_len(key, plen, extack)) +- return -EINVAL; +- + l = fib_find_node(t, &tp, key); + if (!l) + return -ESRCH; +diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c +index 7967ff7e02f794..60e81f6b1c6d4e 100644 +--- a/net/ipv4/inet_hashtables.c ++++ b/net/ipv4/inet_hashtables.c +@@ -1231,22 +1231,37 @@ int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo) + { + unsigned int locksz = sizeof(spinlock_t); + unsigned int i, nblocks = 1; ++ spinlock_t *ptr = NULL; + +- if (locksz != 0) { +- /* allocate 2 cache lines or at least one spinlock per cpu */ +- nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U); +- nblocks = roundup_pow_of_two(nblocks * num_possible_cpus()); ++ if (locksz == 0) ++ goto set_mask; + +- /* no more locks than number of hash buckets */ +- nblocks = min(nblocks, hashinfo->ehash_mask + 1); ++ /* Allocate 2 cache lines or at least one spinlock per cpu. */ ++ nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U) * num_possible_cpus(); + +- hashinfo->ehash_locks = kvmalloc_array(nblocks, locksz, GFP_KERNEL); +- if (!hashinfo->ehash_locks) +- return -ENOMEM; ++ /* At least one page per NUMA node. */ ++ nblocks = max(nblocks, num_online_nodes() * PAGE_SIZE / locksz); ++ ++ nblocks = roundup_pow_of_two(nblocks); ++ ++ /* No more locks than number of hash buckets. */ ++ nblocks = min(nblocks, hashinfo->ehash_mask + 1); + +- for (i = 0; i < nblocks; i++) +- spin_lock_init(&hashinfo->ehash_locks[i]); ++ if (num_online_nodes() > 1) { ++ /* Use vmalloc() to allow NUMA policy to spread pages ++ * on all available nodes if desired. ++ */ ++ ptr = vmalloc_array(nblocks, locksz); ++ } ++ if (!ptr) { ++ ptr = kvmalloc_array(nblocks, locksz, GFP_KERNEL); ++ if (!ptr) ++ return -ENOMEM; + } ++ for (i = 0; i < nblocks; i++) ++ spin_lock_init(&ptr[i]); ++ hashinfo->ehash_locks = ptr; ++set_mask: + hashinfo->ehash_locks_mask = nblocks - 1; + return 0; + } +diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c +index 890c15510b4210..f261e29adc7c2e 100644 +--- a/net/ipv4/ip_gre.c ++++ b/net/ipv4/ip_gre.c +@@ -140,7 +140,6 @@ static int ipgre_err(struct sk_buff *skb, u32 info, + const struct iphdr *iph; + const int type = icmp_hdr(skb)->type; + const int code = icmp_hdr(skb)->code; +- unsigned int data_len = 0; + struct ip_tunnel *t; + + if (tpi->proto == htons(ETH_P_TEB)) +@@ -181,7 +180,6 @@ static int ipgre_err(struct sk_buff *skb, u32 info, + case ICMP_TIME_EXCEEDED: + if (code != ICMP_EXC_TTL) + return 0; +- data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ + break; + + case ICMP_REDIRECT: +@@ -189,10 +187,16 @@ static int ipgre_err(struct sk_buff *skb, u32 info, + } + + #if IS_ENABLED(CONFIG_IPV6) +- if (tpi->proto == htons(ETH_P_IPV6) && +- !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, +- type, data_len)) +- return 0; ++ if (tpi->proto == htons(ETH_P_IPV6)) { ++ unsigned int data_len = 0; ++ ++ if (type == ICMP_TIME_EXCEEDED) ++ data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ ++ ++ if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, ++ type, data_len)) ++ return 0; ++ } + #endif + + if (t->parms.iph.daddr == 0 || +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 10d38ec0ff5acd..a172248b667837 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -425,6 +425,20 @@ static bool tcp_ecn_rcv_ecn_echo(const struct tcp_sock *tp, const struct tcphdr + return false; + } + ++static void tcp_count_delivered_ce(struct tcp_sock *tp, u32 ecn_count) ++{ ++ tp->delivered_ce += ecn_count; ++} ++ ++/* Updates the delivered and delivered_ce counts */ ++static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered, ++ bool ece_ack) ++{ ++ tp->delivered += delivered; ++ if (ece_ack) ++ tcp_count_delivered_ce(tp, delivered); ++} ++ + /* Buffer size and advertised window tuning. + * + * 1. Tuning sk->sk_sndbuf, when connection enters established state. +@@ -1137,15 +1151,6 @@ void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb) + } + } + +-/* Updates the delivered and delivered_ce counts */ +-static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered, +- bool ece_ack) +-{ +- tp->delivered += delivered; +- if (ece_ack) +- tp->delivered_ce += delivered; +-} +- + /* This procedure tags the retransmission queue when SACKs arrive. + * + * We have three tag bits: SACKED(S), RETRANS(R) and LOST(L). +@@ -3816,12 +3821,23 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) + } + } + +-static inline void tcp_in_ack_event(struct sock *sk, u32 flags) ++static void tcp_in_ack_event(struct sock *sk, int flag) + { + const struct inet_connection_sock *icsk = inet_csk(sk); + +- if (icsk->icsk_ca_ops->in_ack_event) +- icsk->icsk_ca_ops->in_ack_event(sk, flags); ++ if (icsk->icsk_ca_ops->in_ack_event) { ++ u32 ack_ev_flags = 0; ++ ++ if (flag & FLAG_WIN_UPDATE) ++ ack_ev_flags |= CA_ACK_WIN_UPDATE; ++ if (flag & FLAG_SLOWPATH) { ++ ack_ev_flags |= CA_ACK_SLOWPATH; ++ if (flag & FLAG_ECE) ++ ack_ev_flags |= CA_ACK_ECE; ++ } ++ ++ icsk->icsk_ca_ops->in_ack_event(sk, ack_ev_flags); ++ } + } + + /* Congestion control has updated the cwnd already. So if we're in +@@ -3938,12 +3954,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + tcp_snd_una_update(tp, ack); + flag |= FLAG_WIN_UPDATE; + +- tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE); +- + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPACKS); + } else { +- u32 ack_ev_flags = CA_ACK_SLOWPATH; +- + if (ack_seq != TCP_SKB_CB(skb)->end_seq) + flag |= FLAG_DATA; + else +@@ -3955,19 +3967,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, + &sack_state); + +- if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) { ++ if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) + flag |= FLAG_ECE; +- ack_ev_flags |= CA_ACK_ECE; +- } + + if (sack_state.sack_delivered) + tcp_count_delivered(tp, sack_state.sack_delivered, + flag & FLAG_ECE); +- +- if (flag & FLAG_WIN_UPDATE) +- ack_ev_flags |= CA_ACK_WIN_UPDATE; +- +- tcp_in_ack_event(sk, ack_ev_flags); + } + + /* This is a deviation from RFC3168 since it states that: +@@ -3994,6 +3999,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + + tcp_rack_update_reo_wnd(sk, &rs); + ++ tcp_in_ack_event(sk, flag); ++ + if (tp->tlp_high_seq) + tcp_process_tlp_ack(sk, ack, flag); + +@@ -4025,6 +4032,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + return 1; + + no_queue: ++ tcp_in_ack_event(sk, flag); + /* If data was DSACKed, see if we can undo a cwnd reduction. */ + if (flag & FLAG_DSACKING_ACK) { + tcp_fastretrans_alert(sk, prior_snd_una, num_dupack, &flag, +diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c +index 62bb9651133c4d..7e4c8628cf9835 100644 +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -135,47 +135,16 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + } + + #ifdef CONFIG_INET6_ESPINTCP +-struct esp_tcp_sk { +- struct sock *sk; +- struct rcu_head rcu; +-}; +- +-static void esp_free_tcp_sk(struct rcu_head *head) +-{ +- struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu); +- +- sock_put(esk->sk); +- kfree(esk); +-} +- + static struct sock *esp6_find_tcp_sk(struct xfrm_state *x) + { + struct xfrm_encap_tmpl *encap = x->encap; + struct net *net = xs_net(x); +- struct esp_tcp_sk *esk; + __be16 sport, dport; +- struct sock *nsk; + struct sock *sk; + +- sk = rcu_dereference(x->encap_sk); +- if (sk && sk->sk_state == TCP_ESTABLISHED) +- return sk; +- + spin_lock_bh(&x->lock); + sport = encap->encap_sport; + dport = encap->encap_dport; +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (sk && sk == nsk) { +- esk = kmalloc(sizeof(*esk), GFP_ATOMIC); +- if (!esk) { +- spin_unlock_bh(&x->lock); +- return ERR_PTR(-ENOMEM); +- } +- RCU_INIT_POINTER(x->encap_sk, NULL); +- esk->sk = sk; +- call_rcu(&esk->rcu, esp_free_tcp_sk); +- } + spin_unlock_bh(&x->lock); + + sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, &x->id.daddr.in6, +@@ -188,20 +157,6 @@ static struct sock *esp6_find_tcp_sk(struct xfrm_state *x) + return ERR_PTR(-EINVAL); + } + +- spin_lock_bh(&x->lock); +- nsk = rcu_dereference_protected(x->encap_sk, +- lockdep_is_held(&x->lock)); +- if (encap->encap_sport != sport || +- encap->encap_dport != dport) { +- sock_put(sk); +- sk = nsk ?: ERR_PTR(-EREMCHG); +- } else if (sk == nsk) { +- sock_put(sk); +- } else { +- rcu_assign_pointer(x->encap_sk, sk); +- } +- spin_unlock_bh(&x->lock); +- + return sk; + } + +@@ -224,6 +179,8 @@ static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb) + err = espintcp_push_skb(sk, skb); + bh_unlock_sock(sk); + ++ sock_put(sk); ++ + out: + rcu_read_unlock(); + return err; +@@ -427,6 +384,8 @@ static struct ip_esp_hdr *esp6_output_tcp_encap(struct xfrm_state *x, + if (IS_ERR(sk)) + return ERR_CAST(sk); + ++ sock_put(sk); ++ + *lenp = htons(len); + esph = (struct ip_esp_hdr *)(lenp + 1); + +diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c +index 6eeab21512ba98..e0f0c5f8cccdaa 100644 +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -350,9 +350,9 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, + struct nlattr **tb, + struct netlink_ext_ack *extack) + { ++ struct fib6_rule *rule6 = (struct fib6_rule *)rule; ++ struct net *net = rule->fr_net; + int err = -EINVAL; +- struct net *net = sock_net(skb->sk); +- struct fib6_rule *rule6 = (struct fib6_rule *) rule; + + if (!inet_validate_dscp(frh->tos)) { + NL_SET_ERR_MSG(extack, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index c86d5dca29df01..28777b14224048 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1452,6 +1452,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, + } + v6_cork->hop_limit = ipc6->hlimit; + v6_cork->tclass = ipc6->tclass; ++ v6_cork->dontfrag = ipc6->dontfrag; + if (rt->dst.flags & DST_XFRM_TUNNEL) + mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? + READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst); +@@ -1485,7 +1486,7 @@ static int __ip6_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, + int len, int odd, struct sk_buff *skb), + void *from, size_t length, int transhdrlen, +- unsigned int flags, struct ipcm6_cookie *ipc6) ++ unsigned int flags) + { + struct sk_buff *skb, *skb_prev = NULL; + struct inet_cork *cork = &cork_full->base; +@@ -1541,7 +1542,7 @@ static int __ip6_append_data(struct sock *sk, + if (headersize + transhdrlen > mtu) + goto emsgsize; + +- if (cork->length + length > mtu - headersize && ipc6->dontfrag && ++ if (cork->length + length > mtu - headersize && v6_cork->dontfrag && + (sk->sk_protocol == IPPROTO_UDP || + sk->sk_protocol == IPPROTO_ICMPV6 || + sk->sk_protocol == IPPROTO_RAW)) { +@@ -1913,7 +1914,7 @@ int ip6_append_data(struct sock *sk, + + return __ip6_append_data(sk, &sk->sk_write_queue, &inet->cork, + &np->cork, sk_page_frag(sk), getfrag, +- from, length, transhdrlen, flags, ipc6); ++ from, length, transhdrlen, flags); + } + EXPORT_SYMBOL_GPL(ip6_append_data); + +@@ -2118,7 +2119,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk, + err = __ip6_append_data(sk, &queue, cork, &v6_cork, + ¤t->task_frag, getfrag, from, + length + exthdrlen, transhdrlen + exthdrlen, +- flags, ipc6); ++ flags); + if (err) { + __ip6_flush_pending_frames(sk, &queue, cork, &v6_cork); + return ERR_PTR(err); +diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c +index cc25fec44f8502..19f3de3c24ef1c 100644 +--- a/net/llc/af_llc.c ++++ b/net/llc/af_llc.c +@@ -888,15 +888,15 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + if (sk->sk_type != SOCK_STREAM) + goto copy_uaddr; + ++ /* Partial read */ ++ if (used + offset < skb_len) ++ continue; ++ + if (!(flags & MSG_PEEK)) { + skb_unlink(skb, &sk->sk_receive_queue); + kfree_skb(skb); + *seq = 0; + } +- +- /* Partial read */ +- if (used + offset < skb_len) +- continue; + } while (len > 0); + + out: +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 42e2c84ed2484a..2c7e139efd532f 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2959,7 +2959,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, + if (tx) + ieee80211_flush_queues(local, sdata, false); + +- drv_mgd_complete_tx(sdata->local, sdata, &info); ++ if (tx || frame_buf) ++ drv_mgd_complete_tx(sdata->local, sdata, &info); + + /* clear AP addr only after building the needed mgmt frames */ + eth_zero_addr(sdata->deflink.u.mgd.bssid); +@@ -7821,7 +7822,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, + req->reason_code, false); +- drv_mgd_complete_tx(sdata->local, sdata, &info); + return 0; + } + +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index 559665467b04dd..1d5de1d9f008d8 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -621,7 +621,9 @@ static struct ctl_table nf_ct_sysctl_table[] = { + .data = &nf_conntrack_max, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_INT_MAX, + }, + [NF_SYSCTL_CT_COUNT] = { + .procname = "nf_conntrack_count", +@@ -657,7 +659,9 @@ static struct ctl_table nf_ct_sysctl_table[] = { + .data = &nf_ct_expect_max, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ONE, ++ .extra2 = SYSCTL_INT_MAX, + }, + [NF_SYSCTL_CT_ACCT] = { + .procname = "nf_conntrack_acct", +@@ -951,7 +955,9 @@ static struct ctl_table nf_ct_netfilter_table[] = { + .data = &nf_conntrack_max, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_INT_MAX, + }, + { } + }; +diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c +index 5d9cccfac4a155..afcb83d469ff60 100644 +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -175,6 +175,11 @@ struct hfsc_sched { + + #define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */ + ++static bool cl_in_el_or_vttree(struct hfsc_class *cl) ++{ ++ return ((cl->cl_flags & HFSC_FSC) && cl->cl_nactive) || ++ ((cl->cl_flags & HFSC_RSC) && !RB_EMPTY_NODE(&cl->el_node)); ++} + + /* + * eligible tree holds backlogged classes being sorted by their eligible times. +@@ -1040,6 +1045,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + if (cl == NULL) + return -ENOBUFS; + ++ RB_CLEAR_NODE(&cl->el_node); ++ + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); + if (err) { + kfree(cl); +@@ -1570,7 +1577,10 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) + return err; + } + +- if (first && !cl->cl_nactive) { ++ sch->qstats.backlog += len; ++ sch->q.qlen++; ++ ++ if (first && !cl_in_el_or_vttree(cl)) { + if (cl->cl_flags & HFSC_RSC) + init_ed(cl, len); + if (cl->cl_flags & HFSC_FSC) +@@ -1585,9 +1595,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) + + } + +- sch->qstats.backlog += len; +- sch->q.qlen++; +- + return NET_XMIT_SUCCESS; + } + +diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c +index dbcc72b43d0c08..d44d7f427fc948 100644 +--- a/net/smc/smc_pnet.c ++++ b/net/smc/smc_pnet.c +@@ -1084,14 +1084,16 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev, + struct smc_init_info *ini) + { + u8 ndev_pnetid[SMC_MAX_PNETID_LEN]; ++ struct net_device *base_ndev; + struct net *net; + +- ndev = pnet_find_base_ndev(ndev); ++ base_ndev = pnet_find_base_ndev(ndev); + net = dev_net(ndev); +- if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port, ++ if (smc_pnetid_by_dev_port(base_ndev->dev.parent, base_ndev->dev_port, + ndev_pnetid) && ++ smc_pnet_find_ndev_pnetid_by_table(base_ndev, ndev_pnetid) && + smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid)) { +- smc_pnet_find_rdma_dev(ndev, ini); ++ smc_pnet_find_rdma_dev(base_ndev, ini); + return; /* pnetid could not be determined */ + } + _smc_pnet_find_roce_by_pnetid(ndev_pnetid, ini, NULL, net); +diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c +index 142ee6554848a6..4ffb2bcaf3648e 100644 +--- a/net/sunrpc/clnt.c ++++ b/net/sunrpc/clnt.c +@@ -275,9 +275,6 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt, + old = rcu_dereference_protected(clnt->cl_xprt, + lockdep_is_held(&clnt->cl_lock)); + +- if (!xprt_bound(xprt)) +- clnt->cl_autobind = 1; +- + clnt->cl_timeout = timeout; + rcu_assign_pointer(clnt->cl_xprt, xprt); + spin_unlock(&clnt->cl_lock); +diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c +index 102c3818bc54d4..53bcca365fb1cd 100644 +--- a/net/sunrpc/rpcb_clnt.c ++++ b/net/sunrpc/rpcb_clnt.c +@@ -820,9 +820,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) + } + + trace_rpcb_setport(child, map->r_status, map->r_port); +- xprt->ops->set_port(xprt, map->r_port); +- if (map->r_port) ++ if (map->r_port) { ++ xprt->ops->set_port(xprt, map->r_port); + xprt_set_bound(xprt); ++ } + } + + /* +diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c +index 9b45fbdc90cabe..73bc39281ef5f5 100644 +--- a/net/sunrpc/sched.c ++++ b/net/sunrpc/sched.c +@@ -276,6 +276,8 @@ EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); + + static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode) + { ++ if (unlikely(current->flags & PF_EXITING)) ++ return -EINTR; + schedule(); + if (signal_pending_state(mode, current)) + return -ERESTARTSYS; +diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c +index c524421ec65252..8584893b478510 100644 +--- a/net/tipc/crypto.c ++++ b/net/tipc/crypto.c +@@ -817,12 +817,16 @@ static int tipc_aead_encrypt(struct tipc_aead *aead, struct sk_buff *skb, + goto exit; + } + ++ /* Get net to avoid freed tipc_crypto when delete namespace */ ++ get_net(aead->crypto->net); ++ + /* Now, do encrypt */ + rc = crypto_aead_encrypt(req); + if (rc == -EINPROGRESS || rc == -EBUSY) + return rc; + + tipc_bearer_put(b); ++ put_net(aead->crypto->net); + + exit: + kfree(ctx); +@@ -860,6 +864,7 @@ static void tipc_aead_encrypt_done(void *data, int err) + kfree(tx_ctx); + tipc_bearer_put(b); + tipc_aead_put(aead); ++ put_net(net); + } + + /** +diff --git a/net/unix/Kconfig b/net/unix/Kconfig +index 28b232f281ab16..8b5d04210d7cf1 100644 +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -16,11 +16,6 @@ config UNIX + + Say Y unless you know what you are doing. + +-config UNIX_SCM +- bool +- depends on UNIX +- default y +- + config AF_UNIX_OOB + bool + depends on UNIX +diff --git a/net/unix/Makefile b/net/unix/Makefile +index 20491825b4d0da..4ddd125c4642c7 100644 +--- a/net/unix/Makefile ++++ b/net/unix/Makefile +@@ -11,5 +11,3 @@ unix-$(CONFIG_BPF_SYSCALL) += unix_bpf.o + + obj-$(CONFIG_UNIX_DIAG) += unix_diag.o + unix_diag-y := diag.o +- +-obj-$(CONFIG_UNIX_SCM) += scm.o +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index ab23c8d72122b2..236a2cd2bc93d2 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -117,8 +117,6 @@ + #include + #include + +-#include "scm.h" +- + static atomic_long_t unix_nr_socks; + static struct hlist_head bsd_socket_buckets[UNIX_HASH_SIZE / 2]; + static spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2]; +@@ -980,11 +978,11 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern, + sk->sk_max_ack_backlog = READ_ONCE(net->unx.sysctl_max_dgram_qlen); + sk->sk_destruct = unix_sock_destructor; + u = unix_sk(sk); +- u->inflight = 0; ++ u->listener = NULL; ++ u->vertex = NULL; + u->path.dentry = NULL; + u->path.mnt = NULL; + spin_lock_init(&u->lock); +- INIT_LIST_HEAD(&u->link); + mutex_init(&u->iolock); /* single task reading lock */ + mutex_init(&u->bindlock); /* single task binding lock */ + init_waitqueue_head(&u->peer_wait); +@@ -1583,6 +1581,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, + newsk->sk_type = sk->sk_type; + init_peercred(newsk); + newu = unix_sk(newsk); ++ newu->listener = other; + RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); + otheru = unix_sk(other); + +@@ -1678,8 +1677,8 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags, + bool kern) + { + struct sock *sk = sock->sk; +- struct sock *tsk; + struct sk_buff *skb; ++ struct sock *tsk; + int err; + + err = -EOPNOTSUPP; +@@ -1709,6 +1708,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags, + + /* attach accepted sock to socket */ + unix_state_lock(tsk); ++ unix_update_edges(unix_sk(tsk)); + newsock->state = SS_CONNECTED; + unix_sock_inherit_flags(sock, newsock); + sock_graft(tsk, newsock); +@@ -1752,51 +1752,65 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) + return err; + } + ++/* The "user->unix_inflight" variable is protected by the garbage ++ * collection lock, and we just read it locklessly here. If you go ++ * over the limit, there might be a tiny race in actually noticing ++ * it across threads. Tough. ++ */ ++static inline bool too_many_unix_fds(struct task_struct *p) ++{ ++ struct user_struct *user = current_user(); ++ ++ if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) ++ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); ++ return false; ++} ++ ++static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ if (too_many_unix_fds(current)) ++ return -ETOOMANYREFS; ++ ++ /* Need to duplicate file references for the sake of garbage ++ * collection. Otherwise a socket in the fps might become a ++ * candidate for GC while the skb is not yet queued. ++ */ ++ UNIXCB(skb).fp = scm_fp_dup(scm->fp); ++ if (!UNIXCB(skb).fp) ++ return -ENOMEM; ++ ++ if (unix_prepare_fpl(UNIXCB(skb).fp)) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ scm->fp = UNIXCB(skb).fp; ++ UNIXCB(skb).fp = NULL; ++ ++ unix_destroy_fpl(scm->fp); ++} ++ + static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) + { + scm->fp = scm_fp_dup(UNIXCB(skb).fp); ++} + +- /* +- * Garbage collection of unix sockets starts by selecting a set of +- * candidate sockets which have reference only from being in flight +- * (total_refs == inflight_refs). This condition is checked once during +- * the candidate collection phase, and candidates are marked as such, so +- * that non-candidates can later be ignored. While inflight_refs is +- * protected by unix_gc_lock, total_refs (file count) is not, hence this +- * is an instantaneous decision. +- * +- * Once a candidate, however, the socket must not be reinstalled into a +- * file descriptor while the garbage collection is in progress. +- * +- * If the above conditions are met, then the directed graph of +- * candidates (*) does not change while unix_gc_lock is held. +- * +- * Any operations that changes the file count through file descriptors +- * (dup, close, sendmsg) does not change the graph since candidates are +- * not installed in fds. +- * +- * Dequeing a candidate via recvmsg would install it into an fd, but +- * that takes unix_gc_lock to decrement the inflight count, so it's +- * serialized with garbage collection. +- * +- * MSG_PEEK is special in that it does not change the inflight count, +- * yet does install the socket into an fd. The following lock/unlock +- * pair is to ensure serialization with garbage collection. It must be +- * done between incrementing the file count and installing the file into +- * an fd. +- * +- * If garbage collection starts after the barrier provided by the +- * lock/unlock, then it will see the elevated refcount and not mark this +- * as a candidate. If a garbage collection is already in progress +- * before the file count was incremented, then the lock/unlock pair will +- * ensure that garbage collection is finished before progressing to +- * installing the fd. +- * +- * (*) A -> B where B is on the queue of A or B is on the queue of C +- * which is on the queue of listening socket A. +- */ +- spin_lock(&unix_gc_lock); +- spin_unlock(&unix_gc_lock); ++static void unix_destruct_scm(struct sk_buff *skb) ++{ ++ struct scm_cookie scm; ++ ++ memset(&scm, 0, sizeof(scm)); ++ scm.pid = UNIXCB(skb).pid; ++ if (UNIXCB(skb).fp) ++ unix_detach_fds(&scm, skb); ++ ++ /* Alas, it calls VFS */ ++ /* So fscking what? fput() had been SMP-safe since the last Summer */ ++ scm_destroy(&scm); ++ sock_wfree(skb); + } + + static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) +@@ -1855,8 +1869,10 @@ static void scm_stat_add(struct sock *sk, struct sk_buff *skb) + struct scm_fp_list *fp = UNIXCB(skb).fp; + struct unix_sock *u = unix_sk(sk); + +- if (unlikely(fp && fp->count)) ++ if (unlikely(fp && fp->count)) { + atomic_add(fp->count, &u->scm_stat.nr_fds); ++ unix_add_edges(fp, u); ++ } + } + + static void scm_stat_del(struct sock *sk, struct sk_buff *skb) +@@ -1864,8 +1880,10 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb) + struct scm_fp_list *fp = UNIXCB(skb).fp; + struct unix_sock *u = unix_sk(sk); + +- if (unlikely(fp && fp->count)) ++ if (unlikely(fp && fp->count)) { + atomic_sub(fp->count, &u->scm_stat.nr_fds); ++ unix_del_edges(fp); ++ } + } + + /* +@@ -1885,11 +1903,12 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, + long timeo; + int err; + +- wait_for_unix_gc(); + err = scm_send(sock, msg, &scm, false); + if (err < 0) + return err; + ++ wait_for_unix_gc(scm.fp); ++ + err = -EOPNOTSUPP; + if (msg->msg_flags&MSG_OOB) + goto out; +@@ -2157,11 +2176,12 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, + bool fds_sent = false; + int data_len; + +- wait_for_unix_gc(); + err = scm_send(sock, msg, &scm, false); + if (err < 0) + return err; + ++ wait_for_unix_gc(scm.fp); ++ + err = -EOPNOTSUPP; + if (msg->msg_flags & MSG_OOB) { + #if IS_ENABLED(CONFIG_AF_UNIX_OOB) +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 2a758531e10271..23efb78fe9ef4b 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -81,278 +81,551 @@ + #include + #include + +-#include "scm.h" ++struct unix_sock *unix_get_socket(struct file *filp) ++{ ++ struct inode *inode = file_inode(filp); ++ ++ /* Socket ? */ ++ if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { ++ struct socket *sock = SOCKET_I(inode); ++ const struct proto_ops *ops; ++ struct sock *sk = sock->sk; + +-/* Internal data structures and random procedures: */ ++ ops = READ_ONCE(sock->ops); + +-static LIST_HEAD(gc_candidates); +-static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); ++ /* PF_UNIX ? */ ++ if (sk && ops && ops->family == PF_UNIX) ++ return unix_sk(sk); ++ } + +-static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), +- struct sk_buff_head *hitlist) ++ return NULL; ++} ++ ++static struct unix_vertex *unix_edge_successor(struct unix_edge *edge) + { +- struct sk_buff *skb; +- struct sk_buff *next; +- +- spin_lock(&x->sk_receive_queue.lock); +- skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { +- /* Do we have file descriptors ? */ +- if (UNIXCB(skb).fp) { +- bool hit = false; +- /* Process the descriptors of this socket */ +- int nfd = UNIXCB(skb).fp->count; +- struct file **fp = UNIXCB(skb).fp->fp; +- +- while (nfd--) { +- /* Get the socket the fd matches if it indeed does so */ +- struct sock *sk = unix_get_socket(*fp++); +- +- if (sk) { +- struct unix_sock *u = unix_sk(sk); +- +- /* Ignore non-candidates, they could +- * have been added to the queues after +- * starting the garbage collection +- */ +- if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { +- hit = true; +- +- func(u); +- } +- } +- } +- if (hit && hitlist != NULL) { +- __skb_unlink(skb, &x->sk_receive_queue); +- __skb_queue_tail(hitlist, skb); +- } +- } ++ /* If an embryo socket has a fd, ++ * the listener indirectly holds the fd's refcnt. ++ */ ++ if (edge->successor->listener) ++ return unix_sk(edge->successor->listener)->vertex; ++ ++ return edge->successor->vertex; ++} ++ ++static bool unix_graph_maybe_cyclic; ++static bool unix_graph_grouped; ++ ++static void unix_update_graph(struct unix_vertex *vertex) ++{ ++ /* If the receiver socket is not inflight, no cyclic ++ * reference could be formed. ++ */ ++ if (!vertex) ++ return; ++ ++ unix_graph_maybe_cyclic = true; ++ unix_graph_grouped = false; ++} ++ ++static LIST_HEAD(unix_unvisited_vertices); ++ ++enum unix_vertex_index { ++ UNIX_VERTEX_INDEX_MARK1, ++ UNIX_VERTEX_INDEX_MARK2, ++ UNIX_VERTEX_INDEX_START, ++}; ++ ++static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1; ++ ++static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge) ++{ ++ struct unix_vertex *vertex = edge->predecessor->vertex; ++ ++ if (!vertex) { ++ vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry); ++ vertex->index = unix_vertex_unvisited_index; ++ vertex->out_degree = 0; ++ INIT_LIST_HEAD(&vertex->edges); ++ INIT_LIST_HEAD(&vertex->scc_entry); ++ ++ list_move_tail(&vertex->entry, &unix_unvisited_vertices); ++ edge->predecessor->vertex = vertex; + } +- spin_unlock(&x->sk_receive_queue.lock); ++ ++ vertex->out_degree++; ++ list_add_tail(&edge->vertex_entry, &vertex->edges); ++ ++ unix_update_graph(unix_edge_successor(edge)); + } + +-static void scan_children(struct sock *x, void (*func)(struct unix_sock *), +- struct sk_buff_head *hitlist) ++static void unix_del_edge(struct scm_fp_list *fpl, struct unix_edge *edge) + { +- if (x->sk_state != TCP_LISTEN) { +- scan_inflight(x, func, hitlist); +- } else { +- struct sk_buff *skb; +- struct sk_buff *next; +- struct unix_sock *u; +- LIST_HEAD(embryos); ++ struct unix_vertex *vertex = edge->predecessor->vertex; + +- /* For a listening socket collect the queued embryos +- * and perform a scan on them as well. +- */ +- spin_lock(&x->sk_receive_queue.lock); +- skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { +- u = unix_sk(skb->sk); ++ if (!fpl->dead) ++ unix_update_graph(unix_edge_successor(edge)); + +- /* An embryo cannot be in-flight, so it's safe +- * to use the list link. +- */ +- BUG_ON(!list_empty(&u->link)); +- list_add_tail(&u->link, &embryos); +- } +- spin_unlock(&x->sk_receive_queue.lock); ++ list_del(&edge->vertex_entry); ++ vertex->out_degree--; + +- while (!list_empty(&embryos)) { +- u = list_entry(embryos.next, struct unix_sock, link); +- scan_inflight(&u->sk, func, hitlist); +- list_del_init(&u->link); +- } ++ if (!vertex->out_degree) { ++ edge->predecessor->vertex = NULL; ++ list_move_tail(&vertex->entry, &fpl->vertices); + } + } + +-static void dec_inflight(struct unix_sock *usk) ++static void unix_free_vertices(struct scm_fp_list *fpl) + { +- usk->inflight--; ++ struct unix_vertex *vertex, *next_vertex; ++ ++ list_for_each_entry_safe(vertex, next_vertex, &fpl->vertices, entry) { ++ list_del(&vertex->entry); ++ kfree(vertex); ++ } + } + +-static void inc_inflight(struct unix_sock *usk) ++static DEFINE_SPINLOCK(unix_gc_lock); ++unsigned int unix_tot_inflight; ++ ++void unix_add_edges(struct scm_fp_list *fpl, struct unix_sock *receiver) + { +- usk->inflight++; ++ int i = 0, j = 0; ++ ++ spin_lock(&unix_gc_lock); ++ ++ if (!fpl->count_unix) ++ goto out; ++ ++ do { ++ struct unix_sock *inflight = unix_get_socket(fpl->fp[j++]); ++ struct unix_edge *edge; ++ ++ if (!inflight) ++ continue; ++ ++ edge = fpl->edges + i++; ++ edge->predecessor = inflight; ++ edge->successor = receiver; ++ ++ unix_add_edge(fpl, edge); ++ } while (i < fpl->count_unix); ++ ++ receiver->scm_stat.nr_unix_fds += fpl->count_unix; ++ WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + fpl->count_unix); ++out: ++ WRITE_ONCE(fpl->user->unix_inflight, fpl->user->unix_inflight + fpl->count); ++ ++ spin_unlock(&unix_gc_lock); ++ ++ fpl->inflight = true; ++ ++ unix_free_vertices(fpl); + } + +-static void inc_inflight_move_tail(struct unix_sock *u) ++void unix_del_edges(struct scm_fp_list *fpl) + { +- u->inflight++; ++ struct unix_sock *receiver; ++ int i = 0; ++ ++ spin_lock(&unix_gc_lock); + +- /* If this still might be part of a cycle, move it to the end +- * of the list, so that it's checked even if it was already +- * passed over ++ if (!fpl->count_unix) ++ goto out; ++ ++ do { ++ struct unix_edge *edge = fpl->edges + i++; ++ ++ unix_del_edge(fpl, edge); ++ } while (i < fpl->count_unix); ++ ++ if (!fpl->dead) { ++ receiver = fpl->edges[0].successor; ++ receiver->scm_stat.nr_unix_fds -= fpl->count_unix; ++ } ++ WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - fpl->count_unix); ++out: ++ WRITE_ONCE(fpl->user->unix_inflight, fpl->user->unix_inflight - fpl->count); ++ ++ spin_unlock(&unix_gc_lock); ++ ++ fpl->inflight = false; ++} ++ ++void unix_update_edges(struct unix_sock *receiver) ++{ ++ /* nr_unix_fds is only updated under unix_state_lock(). ++ * If it's 0 here, the embryo socket is not part of the ++ * inflight graph, and GC will not see it, so no lock needed. + */ +- if (test_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags)) +- list_move_tail(&u->link, &gc_candidates); ++ if (!receiver->scm_stat.nr_unix_fds) { ++ receiver->listener = NULL; ++ } else { ++ spin_lock(&unix_gc_lock); ++ unix_update_graph(unix_sk(receiver->listener)->vertex); ++ receiver->listener = NULL; ++ spin_unlock(&unix_gc_lock); ++ } + } + +-static bool gc_in_progress; +-#define UNIX_INFLIGHT_TRIGGER_GC 16000 ++int unix_prepare_fpl(struct scm_fp_list *fpl) ++{ ++ struct unix_vertex *vertex; ++ int i; ++ ++ if (!fpl->count_unix) ++ return 0; ++ ++ for (i = 0; i < fpl->count_unix; i++) { ++ vertex = kmalloc(sizeof(*vertex), GFP_KERNEL); ++ if (!vertex) ++ goto err; ++ ++ list_add(&vertex->entry, &fpl->vertices); ++ } ++ ++ fpl->edges = kvmalloc_array(fpl->count_unix, sizeof(*fpl->edges), ++ GFP_KERNEL_ACCOUNT); ++ if (!fpl->edges) ++ goto err; ++ ++ return 0; + +-void wait_for_unix_gc(void) ++err: ++ unix_free_vertices(fpl); ++ return -ENOMEM; ++} ++ ++void unix_destroy_fpl(struct scm_fp_list *fpl) + { +- /* If number of inflight sockets is insane, +- * force a garbage collect right now. +- * Paired with the WRITE_ONCE() in unix_inflight(), +- * unix_notinflight() and gc_in_progress(). +- */ +- if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && +- !READ_ONCE(gc_in_progress)) +- unix_gc(); +- wait_event(unix_gc_wait, !READ_ONCE(gc_in_progress)); ++ if (fpl->inflight) ++ unix_del_edges(fpl); ++ ++ kvfree(fpl->edges); ++ unix_free_vertices(fpl); + } + +-/* The external entry point: unix_gc() */ +-void unix_gc(void) ++static bool unix_vertex_dead(struct unix_vertex *vertex) + { +- struct sk_buff *next_skb, *skb; ++ struct unix_edge *edge; + struct unix_sock *u; +- struct unix_sock *next; +- struct sk_buff_head hitlist; +- struct list_head cursor; +- LIST_HEAD(not_cycle_list); ++ long total_ref; + +- spin_lock(&unix_gc_lock); ++ list_for_each_entry(edge, &vertex->edges, vertex_entry) { ++ struct unix_vertex *next_vertex = unix_edge_successor(edge); + +- /* Avoid a recursive GC. */ +- if (gc_in_progress) +- goto out; ++ /* The vertex's fd can be received by a non-inflight socket. */ ++ if (!next_vertex) ++ return false; + +- /* Paired with READ_ONCE() in wait_for_unix_gc(). */ +- WRITE_ONCE(gc_in_progress, true); ++ /* The vertex's fd can be received by an inflight socket in ++ * another SCC. ++ */ ++ if (next_vertex->scc_index != vertex->scc_index) ++ return false; ++ } + +- /* First, select candidates for garbage collection. Only +- * in-flight sockets are considered, and from those only ones +- * which don't have any external reference. +- * +- * Holding unix_gc_lock will protect these candidates from +- * being detached, and hence from gaining an external +- * reference. Since there are no possible receivers, all +- * buffers currently on the candidates' queues stay there +- * during the garbage collection. +- * +- * We also know that no new candidate can be added onto the +- * receive queues. Other, non candidate sockets _can_ be +- * added to queue, so we must make sure only to touch +- * candidates. +- * +- * Embryos, though never candidates themselves, affect which +- * candidates are reachable by the garbage collector. Before +- * being added to a listener's queue, an embryo may already +- * receive data carrying SCM_RIGHTS, potentially making the +- * passed socket a candidate that is not yet reachable by the +- * collector. It becomes reachable once the embryo is +- * enqueued. Therefore, we must ensure that no SCM-laden +- * embryo appears in a (candidate) listener's queue between +- * consecutive scan_children() calls. +- */ +- list_for_each_entry_safe(u, next, &gc_inflight_list, link) { +- struct sock *sk = &u->sk; +- long total_refs; +- +- total_refs = file_count(sk->sk_socket->file); +- +- BUG_ON(!u->inflight); +- BUG_ON(total_refs < u->inflight); +- if (total_refs == u->inflight) { +- list_move_tail(&u->link, &gc_candidates); +- __set_bit(UNIX_GC_CANDIDATE, &u->gc_flags); +- __set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags); +- +- if (sk->sk_state == TCP_LISTEN) { +- unix_state_lock_nested(sk, U_LOCK_GC_LISTENER); +- unix_state_unlock(sk); ++ /* No receiver exists out of the same SCC. */ ++ ++ edge = list_first_entry(&vertex->edges, typeof(*edge), vertex_entry); ++ u = edge->predecessor; ++ total_ref = file_count(u->sk.sk_socket->file); ++ ++ /* If not close()d, total_ref > out_degree. */ ++ if (total_ref != vertex->out_degree) ++ return false; ++ ++ return true; ++} ++ ++enum unix_recv_queue_lock_class { ++ U_RECVQ_LOCK_NORMAL, ++ U_RECVQ_LOCK_EMBRYO, ++}; ++ ++static void unix_collect_queue(struct unix_sock *u, struct sk_buff_head *hitlist) ++{ ++ skb_queue_splice_init(&u->sk.sk_receive_queue, hitlist); ++ ++#if IS_ENABLED(CONFIG_AF_UNIX_OOB) ++ if (u->oob_skb) { ++ WARN_ON_ONCE(skb_unref(u->oob_skb)); ++ u->oob_skb = NULL; ++ } ++#endif ++} ++ ++static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist) ++{ ++ struct unix_vertex *vertex; ++ ++ list_for_each_entry_reverse(vertex, scc, scc_entry) { ++ struct sk_buff_head *queue; ++ struct unix_edge *edge; ++ struct unix_sock *u; ++ ++ edge = list_first_entry(&vertex->edges, typeof(*edge), vertex_entry); ++ u = edge->predecessor; ++ queue = &u->sk.sk_receive_queue; ++ ++ spin_lock(&queue->lock); ++ ++ if (u->sk.sk_state == TCP_LISTEN) { ++ struct sk_buff *skb; ++ ++ skb_queue_walk(queue, skb) { ++ struct sk_buff_head *embryo_queue = &skb->sk->sk_receive_queue; ++ ++ /* listener -> embryo order, the inversion never happens. */ ++ spin_lock_nested(&embryo_queue->lock, U_RECVQ_LOCK_EMBRYO); ++ unix_collect_queue(unix_sk(skb->sk), hitlist); ++ spin_unlock(&embryo_queue->lock); + } ++ } else { ++ unix_collect_queue(u, hitlist); + } ++ ++ spin_unlock(&queue->lock); + } ++} + +- /* Now remove all internal in-flight reference to children of +- * the candidates. +- */ +- list_for_each_entry(u, &gc_candidates, link) +- scan_children(&u->sk, dec_inflight, NULL); ++static bool unix_scc_cyclic(struct list_head *scc) ++{ ++ struct unix_vertex *vertex; ++ struct unix_edge *edge; + +- /* Restore the references for children of all candidates, +- * which have remaining references. Do this recursively, so +- * only those remain, which form cyclic references. +- * +- * Use a "cursor" link, to make the list traversal safe, even +- * though elements might be moved about. ++ /* SCC containing multiple vertices ? */ ++ if (!list_is_singular(scc)) ++ return true; ++ ++ vertex = list_first_entry(scc, typeof(*vertex), scc_entry); ++ ++ /* Self-reference or a embryo-listener circle ? */ ++ list_for_each_entry(edge, &vertex->edges, vertex_entry) { ++ if (unix_edge_successor(edge) == vertex) ++ return true; ++ } ++ ++ return false; ++} ++ ++static LIST_HEAD(unix_visited_vertices); ++static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2; ++ ++static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_index, ++ struct sk_buff_head *hitlist) ++{ ++ LIST_HEAD(vertex_stack); ++ struct unix_edge *edge; ++ LIST_HEAD(edge_stack); ++ ++next_vertex: ++ /* Push vertex to vertex_stack and mark it as on-stack ++ * (index >= UNIX_VERTEX_INDEX_START). ++ * The vertex will be popped when finalising SCC later. + */ +- list_add(&cursor, &gc_candidates); +- while (cursor.next != &gc_candidates) { +- u = list_entry(cursor.next, struct unix_sock, link); ++ list_add(&vertex->scc_entry, &vertex_stack); ++ ++ vertex->index = *last_index; ++ vertex->scc_index = *last_index; ++ (*last_index)++; ++ ++ /* Explore neighbour vertices (receivers of the current vertex's fd). */ ++ list_for_each_entry(edge, &vertex->edges, vertex_entry) { ++ struct unix_vertex *next_vertex = unix_edge_successor(edge); ++ ++ if (!next_vertex) ++ continue; ++ ++ if (next_vertex->index == unix_vertex_unvisited_index) { ++ /* Iterative deepening depth first search ++ * ++ * 1. Push a forward edge to edge_stack and set ++ * the successor to vertex for the next iteration. ++ */ ++ list_add(&edge->stack_entry, &edge_stack); + +- /* Move cursor to after the current position. */ +- list_move(&cursor, &u->link); ++ vertex = next_vertex; ++ goto next_vertex; + +- if (u->inflight) { +- list_move_tail(&u->link, ¬_cycle_list); +- __clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags); +- scan_children(&u->sk, inc_inflight_move_tail, NULL); ++ /* 2. Pop the edge directed to the current vertex ++ * and restore the ancestor for backtracking. ++ */ ++prev_vertex: ++ edge = list_first_entry(&edge_stack, typeof(*edge), stack_entry); ++ list_del_init(&edge->stack_entry); ++ ++ next_vertex = vertex; ++ vertex = edge->predecessor->vertex; ++ ++ /* If the successor has a smaller scc_index, two vertices ++ * are in the same SCC, so propagate the smaller scc_index ++ * to skip SCC finalisation. ++ */ ++ vertex->scc_index = min(vertex->scc_index, next_vertex->scc_index); ++ } else if (next_vertex->index != unix_vertex_grouped_index) { ++ /* Loop detected by a back/cross edge. ++ * ++ * The successor is on vertex_stack, so two vertices are in ++ * the same SCC. If the successor has a smaller *scc_index*, ++ * propagate it to skip SCC finalisation. ++ */ ++ vertex->scc_index = min(vertex->scc_index, next_vertex->scc_index); ++ } else { ++ /* The successor was already grouped as another SCC */ + } + } +- list_del(&cursor); + +- /* Now gc_candidates contains only garbage. Restore original +- * inflight counters for these as well, and remove the skbuffs +- * which are creating the cycle(s). +- */ +- skb_queue_head_init(&hitlist); +- list_for_each_entry(u, &gc_candidates, link) { +- scan_children(&u->sk, inc_inflight, &hitlist); ++ if (vertex->index == vertex->scc_index) { ++ struct unix_vertex *v; ++ struct list_head scc; ++ bool scc_dead = true; + +-#if IS_ENABLED(CONFIG_AF_UNIX_OOB) +- if (u->oob_skb) { +- kfree_skb(u->oob_skb); +- u->oob_skb = NULL; ++ /* SCC finalised. ++ * ++ * If the scc_index was not updated, all the vertices above on ++ * vertex_stack are in the same SCC. Group them using scc_entry. ++ */ ++ __list_cut_position(&scc, &vertex_stack, &vertex->scc_entry); ++ ++ list_for_each_entry_reverse(v, &scc, scc_entry) { ++ /* Don't restart DFS from this vertex in unix_walk_scc(). */ ++ list_move_tail(&v->entry, &unix_visited_vertices); ++ ++ /* Mark vertex as off-stack. */ ++ v->index = unix_vertex_grouped_index; ++ ++ if (scc_dead) ++ scc_dead = unix_vertex_dead(v); + } +-#endif ++ ++ if (scc_dead) ++ unix_collect_skb(&scc, hitlist); ++ else if (!unix_graph_maybe_cyclic) ++ unix_graph_maybe_cyclic = unix_scc_cyclic(&scc); ++ ++ list_del(&scc); + } + +- /* not_cycle_list contains those sockets which do not make up a +- * cycle. Restore these to the inflight list. ++ /* Need backtracking ? */ ++ if (!list_empty(&edge_stack)) ++ goto prev_vertex; ++} ++ ++static void unix_walk_scc(struct sk_buff_head *hitlist) ++{ ++ unsigned long last_index = UNIX_VERTEX_INDEX_START; ++ ++ unix_graph_maybe_cyclic = false; ++ ++ /* Visit every vertex exactly once. ++ * __unix_walk_scc() moves visited vertices to unix_visited_vertices. + */ +- while (!list_empty(¬_cycle_list)) { +- u = list_entry(not_cycle_list.next, struct unix_sock, link); +- __clear_bit(UNIX_GC_CANDIDATE, &u->gc_flags); +- list_move_tail(&u->link, &gc_inflight_list); ++ while (!list_empty(&unix_unvisited_vertices)) { ++ struct unix_vertex *vertex; ++ ++ vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry); ++ __unix_walk_scc(vertex, &last_index, hitlist); + } + +- spin_unlock(&unix_gc_lock); ++ list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices); ++ swap(unix_vertex_unvisited_index, unix_vertex_grouped_index); + +- /* We need io_uring to clean its registered files, ignore all io_uring +- * originated skbs. It's fine as io_uring doesn't keep references to +- * other io_uring instances and so killing all other files in the cycle +- * will put all io_uring references forcing it to go through normal +- * release.path eventually putting registered files. +- */ +- skb_queue_walk_safe(&hitlist, skb, next_skb) { +- if (skb->destructor == io_uring_destruct_scm) { +- __skb_unlink(skb, &hitlist); +- skb_queue_tail(&skb->sk->sk_receive_queue, skb); ++ unix_graph_grouped = true; ++} ++ ++static void unix_walk_scc_fast(struct sk_buff_head *hitlist) ++{ ++ unix_graph_maybe_cyclic = false; ++ ++ while (!list_empty(&unix_unvisited_vertices)) { ++ struct unix_vertex *vertex; ++ struct list_head scc; ++ bool scc_dead = true; ++ ++ vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry); ++ list_add(&scc, &vertex->scc_entry); ++ ++ list_for_each_entry_reverse(vertex, &scc, scc_entry) { ++ list_move_tail(&vertex->entry, &unix_visited_vertices); ++ ++ if (scc_dead) ++ scc_dead = unix_vertex_dead(vertex); + } ++ ++ if (scc_dead) ++ unix_collect_skb(&scc, hitlist); ++ else if (!unix_graph_maybe_cyclic) ++ unix_graph_maybe_cyclic = unix_scc_cyclic(&scc); ++ ++ list_del(&scc); + } + +- /* Here we are. Hitlist is filled. Die. */ +- __skb_queue_purge(&hitlist); ++ list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices); ++} ++ ++static bool gc_in_progress; ++ ++static void __unix_gc(struct work_struct *work) ++{ ++ struct sk_buff_head hitlist; ++ struct sk_buff *skb; + + spin_lock(&unix_gc_lock); + +- /* There could be io_uring registered files, just push them back to +- * the inflight list +- */ +- list_for_each_entry_safe(u, next, &gc_candidates, link) +- list_move_tail(&u->link, &gc_inflight_list); ++ if (!unix_graph_maybe_cyclic) { ++ spin_unlock(&unix_gc_lock); ++ goto skip_gc; ++ } ++ ++ __skb_queue_head_init(&hitlist); ++ ++ if (unix_graph_grouped) ++ unix_walk_scc_fast(&hitlist); ++ else ++ unix_walk_scc(&hitlist); + +- /* All candidates should have been detached by now. */ +- BUG_ON(!list_empty(&gc_candidates)); ++ spin_unlock(&unix_gc_lock); ++ ++ skb_queue_walk(&hitlist, skb) { ++ if (UNIXCB(skb).fp) ++ UNIXCB(skb).fp->dead = true; ++ } + +- /* Paired with READ_ONCE() in wait_for_unix_gc(). */ ++ __skb_queue_purge(&hitlist); ++skip_gc: + WRITE_ONCE(gc_in_progress, false); ++} + +- wake_up(&unix_gc_wait); ++static DECLARE_WORK(unix_gc_work, __unix_gc); + +- out: +- spin_unlock(&unix_gc_lock); ++void unix_gc(void) ++{ ++ WRITE_ONCE(gc_in_progress, true); ++ queue_work(system_unbound_wq, &unix_gc_work); ++} ++ ++#define UNIX_INFLIGHT_TRIGGER_GC 16000 ++#define UNIX_INFLIGHT_SANE_USER (SCM_MAX_FD * 8) ++ ++void wait_for_unix_gc(struct scm_fp_list *fpl) ++{ ++ /* If number of inflight sockets is insane, ++ * force a garbage collect right now. ++ * ++ * Paired with the WRITE_ONCE() in unix_inflight(), ++ * unix_notinflight(), and __unix_gc(). ++ */ ++ if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && ++ !READ_ONCE(gc_in_progress)) ++ unix_gc(); ++ ++ /* Penalise users who want to send AF_UNIX sockets ++ * but whose sockets have not been received yet. ++ */ ++ if (!fpl || !fpl->count_unix || ++ READ_ONCE(fpl->user->unix_inflight) < UNIX_INFLIGHT_SANE_USER) ++ return; ++ ++ if (READ_ONCE(gc_in_progress)) ++ flush_work(&unix_gc_work); + } +diff --git a/net/unix/scm.c b/net/unix/scm.c +deleted file mode 100644 +index e92f2fad64105d..00000000000000 +--- a/net/unix/scm.c ++++ /dev/null +@@ -1,161 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "scm.h" +- +-unsigned int unix_tot_inflight; +-EXPORT_SYMBOL(unix_tot_inflight); +- +-LIST_HEAD(gc_inflight_list); +-EXPORT_SYMBOL(gc_inflight_list); +- +-DEFINE_SPINLOCK(unix_gc_lock); +-EXPORT_SYMBOL(unix_gc_lock); +- +-struct sock *unix_get_socket(struct file *filp) +-{ +- struct sock *u_sock = NULL; +- struct inode *inode = file_inode(filp); +- +- /* Socket ? */ +- if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { +- struct socket *sock = SOCKET_I(inode); +- const struct proto_ops *ops = READ_ONCE(sock->ops); +- struct sock *s = sock->sk; +- +- /* PF_UNIX ? */ +- if (s && ops && ops->family == PF_UNIX) +- u_sock = s; +- } +- +- return u_sock; +-} +-EXPORT_SYMBOL(unix_get_socket); +- +-/* Keep the number of times in flight count for the file +- * descriptor if it is for an AF_UNIX socket. +- */ +-void unix_inflight(struct user_struct *user, struct file *fp) +-{ +- struct sock *s = unix_get_socket(fp); +- +- spin_lock(&unix_gc_lock); +- +- if (s) { +- struct unix_sock *u = unix_sk(s); +- +- if (!u->inflight) { +- BUG_ON(!list_empty(&u->link)); +- list_add_tail(&u->link, &gc_inflight_list); +- } else { +- BUG_ON(list_empty(&u->link)); +- } +- u->inflight++; +- /* Paired with READ_ONCE() in wait_for_unix_gc() */ +- WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1); +- } +- WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1); +- spin_unlock(&unix_gc_lock); +-} +- +-void unix_notinflight(struct user_struct *user, struct file *fp) +-{ +- struct sock *s = unix_get_socket(fp); +- +- spin_lock(&unix_gc_lock); +- +- if (s) { +- struct unix_sock *u = unix_sk(s); +- +- BUG_ON(!u->inflight); +- BUG_ON(list_empty(&u->link)); +- +- u->inflight--; +- if (!u->inflight) +- list_del_init(&u->link); +- /* Paired with READ_ONCE() in wait_for_unix_gc() */ +- WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1); +- } +- WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1); +- spin_unlock(&unix_gc_lock); +-} +- +-/* +- * The "user->unix_inflight" variable is protected by the garbage +- * collection lock, and we just read it locklessly here. If you go +- * over the limit, there might be a tiny race in actually noticing +- * it across threads. Tough. +- */ +-static inline bool too_many_unix_fds(struct task_struct *p) +-{ +- struct user_struct *user = current_user(); +- +- if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) +- return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); +- return false; +-} +- +-int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +-{ +- int i; +- +- if (too_many_unix_fds(current)) +- return -ETOOMANYREFS; +- +- /* +- * Need to duplicate file references for the sake of garbage +- * collection. Otherwise a socket in the fps might become a +- * candidate for GC while the skb is not yet queued. +- */ +- UNIXCB(skb).fp = scm_fp_dup(scm->fp); +- if (!UNIXCB(skb).fp) +- return -ENOMEM; +- +- for (i = scm->fp->count - 1; i >= 0; i--) +- unix_inflight(scm->fp->user, scm->fp->fp[i]); +- return 0; +-} +-EXPORT_SYMBOL(unix_attach_fds); +- +-void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) +-{ +- int i; +- +- scm->fp = UNIXCB(skb).fp; +- UNIXCB(skb).fp = NULL; +- +- for (i = scm->fp->count-1; i >= 0; i--) +- unix_notinflight(scm->fp->user, scm->fp->fp[i]); +-} +-EXPORT_SYMBOL(unix_detach_fds); +- +-void unix_destruct_scm(struct sk_buff *skb) +-{ +- struct scm_cookie scm; +- +- memset(&scm, 0, sizeof(scm)); +- scm.pid = UNIXCB(skb).pid; +- if (UNIXCB(skb).fp) +- unix_detach_fds(&scm, skb); +- +- /* Alas, it calls VFS */ +- /* So fscking what? fput() had been SMP-safe since the last Summer */ +- scm_destroy(&scm); +- sock_wfree(skb); +-} +-EXPORT_SYMBOL(unix_destruct_scm); +- +-void io_uring_destruct_scm(struct sk_buff *skb) +-{ +- unix_destruct_scm(skb); +-} +-EXPORT_SYMBOL(io_uring_destruct_scm); +diff --git a/net/unix/scm.h b/net/unix/scm.h +deleted file mode 100644 +index 5a255a477f1609..00000000000000 +--- a/net/unix/scm.h ++++ /dev/null +@@ -1,10 +0,0 @@ +-#ifndef NET_UNIX_SCM_H +-#define NET_UNIX_SCM_H +- +-extern struct list_head gc_inflight_list; +-extern spinlock_t unix_gc_lock; +- +-int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb); +-void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb); +- +-#endif +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index 68b3f9e7edffd4..2edb0f868c5738 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1603,6 +1603,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) + struct xfrm_policy *delpol; + struct hlist_head *chain; + ++ /* Sanitize mark before store */ ++ policy->mark.v &= policy->mark.m; ++ + spin_lock_bh(&net->xfrm.xfrm_policy_lock); + chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); + if (chain) +diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c +index 8a6e8656d014f2..86029cf5358c7a 100644 +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -754,9 +754,6 @@ int __xfrm_state_delete(struct xfrm_state *x) + net->xfrm.state_num--; + spin_unlock(&net->xfrm.xfrm_state_lock); + +- if (x->encap_sk) +- sock_put(rcu_dereference_raw(x->encap_sk)); +- + xfrm_dev_state_delete(x); + + /* All xfrm_state objects are created by xfrm_state_alloc. +@@ -1478,6 +1475,9 @@ static void __xfrm_state_insert(struct xfrm_state *x) + + list_add(&x->km.all, &net->xfrm.state_all); + ++ /* Sanitize mark before store */ ++ x->mark.v &= x->mark.m; ++ + h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, + x->props.reqid, x->props.family); + XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h, +diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile +index 3fa16412db15ca..927d72659173e0 100644 +--- a/samples/bpf/Makefile ++++ b/samples/bpf/Makefile +@@ -392,7 +392,7 @@ $(obj)/%.o: $(src)/%.c + @echo " CLANG-bpf " $@ + $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(BPF_EXTRA_CFLAGS) \ + -I$(obj) -I$(srctree)/tools/testing/selftests/bpf/ \ +- -I$(LIBBPF_INCLUDE) \ ++ -I$(LIBBPF_INCLUDE) $(CLANG_SYS_INCLUDES) \ + -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ + -D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \ + -Wno-gnu-variable-sized-type-not-at-end \ +diff --git a/scripts/config b/scripts/config +index ff88e2faefd35c..ea475c07de283e 100755 +--- a/scripts/config ++++ b/scripts/config +@@ -32,6 +32,7 @@ commands: + Disable option directly after other option + --module-after|-M beforeopt option + Turn option into module directly after other option ++ --refresh Refresh the config using old settings + + commands can be repeated multiple times + +@@ -124,16 +125,22 @@ undef_var() { + txt_delete "^# $name is not set" "$FN" + } + +-if [ "$1" = "--file" ]; then +- FN="$2" +- if [ "$FN" = "" ] ; then +- usage ++FN=.config ++CMDS=() ++while [[ $# -gt 0 ]]; do ++ if [ "$1" = "--file" ]; then ++ if [ "$2" = "" ]; then ++ usage ++ fi ++ FN="$2" ++ shift 2 ++ else ++ CMDS+=("$1") ++ shift + fi +- shift 2 +-else +- FN=.config +-fi ++done + ++set -- "${CMDS[@]}" + if [ "$1" = "" ] ; then + usage + fi +@@ -217,9 +224,8 @@ while [ "$1" != "" ] ; do + set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A" + ;; + +- # undocumented because it ignores --file (fixme) + --refresh) +- yes "" | make oldconfig ++ yes "" | make oldconfig KCONFIG_CONFIG=$FN + ;; + + *) +diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh +index 0b7952471c18f6..79c09b378be816 100755 +--- a/scripts/kconfig/merge_config.sh ++++ b/scripts/kconfig/merge_config.sh +@@ -112,8 +112,8 @@ INITFILE=$1 + shift; + + if [ ! -r "$INITFILE" ]; then +- echo "The base file '$INITFILE' does not exist. Exit." >&2 +- exit 1 ++ echo "The base file '$INITFILE' does not exist. Creating one..." >&2 ++ touch "$INITFILE" + fi + + MERGE_LIST=$* +diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c +index 98308a2bdef6e0..068edb0d79f736 100644 +--- a/security/integrity/ima/ima_main.c ++++ b/security/integrity/ima/ima_main.c +@@ -235,7 +235,9 @@ static int process_measurement(struct file *file, const struct cred *cred, + &allowed_algos); + violation_check = ((func == FILE_CHECK || func == MMAP_CHECK || + func == MMAP_CHECK_REQPROT) && +- (ima_policy_flag & IMA_MEASURE)); ++ (ima_policy_flag & IMA_MEASURE) && ++ ((action & IMA_MEASURE) || ++ (file->f_mode & FMODE_WRITE))); + if (!action && !violation_check) + return 0; + +diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c +index 5dd1e164f9b13d..1e35c9f807b2b6 100644 +--- a/security/smack/smackfs.c ++++ b/security/smack/smackfs.c +@@ -830,7 +830,7 @@ static int smk_open_cipso(struct inode *inode, struct file *file) + static ssize_t smk_set_cipso(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, int format) + { +- struct netlbl_lsm_catmap *old_cat, *new_cat = NULL; ++ struct netlbl_lsm_catmap *old_cat; + struct smack_known *skp; + struct netlbl_lsm_secattr ncats; + char mapcatset[SMK_CIPSOLEN]; +@@ -917,22 +917,15 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, + + smack_catset_bit(cat, mapcatset); + } +- ncats.flags = 0; +- if (catlen == 0) { +- ncats.attr.mls.cat = NULL; +- ncats.attr.mls.lvl = maplevel; +- new_cat = netlbl_catmap_alloc(GFP_ATOMIC); +- if (new_cat) +- new_cat->next = ncats.attr.mls.cat; +- ncats.attr.mls.cat = new_cat; +- skp->smk_netlabel.flags &= ~(1U << 3); +- rc = 0; +- } else { +- rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); +- } ++ ++ rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); + if (rc >= 0) { + old_cat = skp->smk_netlabel.attr.mls.cat; + rcu_assign_pointer(skp->smk_netlabel.attr.mls.cat, ncats.attr.mls.cat); ++ if (ncats.attr.mls.cat) ++ skp->smk_netlabel.flags |= NETLBL_SECATTR_MLS_CAT; ++ else ++ skp->smk_netlabel.flags &= ~(u32)NETLBL_SECATTR_MLS_CAT; + skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; + synchronize_rcu(); + netlbl_catmap_free(old_cat); +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index 728c211142d145..471de2d1b37ad1 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -1085,8 +1085,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) + runtime->oss.params = 0; + runtime->oss.prepare = 1; + runtime->oss.buffer_used = 0; +- if (runtime->dma_area) +- snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); ++ snd_pcm_runtime_buffer_set_silence(runtime); + + runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index e40de64ec85cb5..31fc20350fd96e 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -703,6 +703,17 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) + atomic_inc(&runtime->buffer_accessing); + } + ++/* fill the PCM buffer with the current silence format; called from pcm_oss.c */ ++void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime) ++{ ++ snd_pcm_buffer_access_lock(runtime); ++ if (runtime->dma_area) ++ snd_pcm_format_set_silence(runtime->format, runtime->dma_area, ++ bytes_to_samples(runtime, runtime->dma_bytes)); ++ snd_pcm_buffer_access_unlock(runtime); ++} ++EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence); ++ + #if IS_ENABLED(CONFIG_SND_PCM_OSS) + #define is_oss_stream(substream) ((substream)->oss.oss) + #else +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 49f6763c3250dd..31428cdc0f63d7 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -1169,8 +1169,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait) + if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) { + + /* check if data is available in the pool */ +- if (!snd_seq_write_pool_allocated(client) || +- snd_seq_pool_poll_wait(client->pool, file, wait)) ++ if (snd_seq_pool_poll_wait(client->pool, file, wait)) + mask |= EPOLLOUT | EPOLLWRNORM; + } + +@@ -2584,8 +2583,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table + if (client == NULL) + return -ENXIO; + +- if (! snd_seq_write_pool_allocated(client)) +- return 1; + if (snd_seq_pool_poll_wait(client->pool, file, wait)) + return 1; + return 0; +diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c +index b603bb93f89603..692860deec0c3d 100644 +--- a/sound/core/seq/seq_memory.c ++++ b/sound/core/seq/seq_memory.c +@@ -429,6 +429,7 @@ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, + poll_table *wait) + { + poll_wait(file, &pool->output_sleep, wait); ++ guard(spinlock_irq)(&pool->lock); + return snd_seq_output_ok(pool); + } + +diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c +index e63621bcb21427..1a684e47d4d189 100644 +--- a/sound/pci/hda/hda_beep.c ++++ b/sound/pci/hda/hda_beep.c +@@ -31,8 +31,9 @@ static void generate_tone(struct hda_beep *beep, int tone) + beep->power_hook(beep, true); + beep->playing = 1; + } +- snd_hda_codec_write(codec, beep->nid, 0, +- AC_VERB_SET_BEEP_CONTROL, tone); ++ if (!codec->beep_just_power_on) ++ snd_hda_codec_write(codec, beep->nid, 0, ++ AC_VERB_SET_BEEP_CONTROL, tone); + if (!tone && beep->playing) { + beep->playing = 0; + if (beep->power_hook) +@@ -212,10 +213,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) + struct hda_beep *beep; + int err; + +- if (!snd_hda_get_bool_hint(codec, "beep")) +- return 0; /* disabled explicitly by hints */ +- if (codec->beep_mode == HDA_BEEP_MODE_OFF) +- return 0; /* disabled by module option */ ++ if (!codec->beep_just_power_on) { ++ if (!snd_hda_get_bool_hint(codec, "beep")) ++ return 0; /* disabled explicitly by hints */ ++ if (codec->beep_mode == HDA_BEEP_MODE_OFF) ++ return 0; /* disabled by module option */ ++ } + + beep = kzalloc(sizeof(*beep), GFP_KERNEL); + if (beep == NULL) +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 2f3f295f2b0cb5..440b934cdc284a 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -24,6 +24,7 @@ + #include + #include "hda_local.h" + #include "hda_auto_parser.h" ++#include "hda_beep.h" + #include "hda_jack.h" + #include "hda_generic.h" + #include "hda_component.h" +@@ -6789,6 +6790,41 @@ static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec, + } + } + ++/* GPIO1 = amplifier on/off */ ++static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec, ++ const struct hda_fixup *fix, ++ int action) ++{ ++ struct alc_spec *spec = codec->spec; ++ static const hda_nid_t conn[] = { 0x02 }; ++ static const struct hda_pintbl pincfgs[] = { ++ { 0x14, 0x90170110 }, /* front/high speakers */ ++ { 0x17, 0x90170130 }, /* back/bass speakers */ ++ { } ++ }; ++ ++ // enable mute led ++ alc285_fixup_hp_mute_led_coefbit(codec, fix, action); ++ ++ switch (action) { ++ case HDA_FIXUP_ACT_PRE_PROBE: ++ /* needed for amp of back speakers */ ++ spec->gpio_mask |= 0x01; ++ spec->gpio_dir |= 0x01; ++ snd_hda_apply_pincfgs(codec, pincfgs); ++ /* share DAC to have unified volume control */ ++ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn); ++ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); ++ break; ++ case HDA_FIXUP_ACT_INIT: ++ /* need to toggle GPIO to enable the amp of back speakers */ ++ alc_update_gpio_data(codec, 0x01, true); ++ msleep(100); ++ alc_update_gpio_data(codec, 0x01, false); ++ break; ++ } ++} ++ + static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec, + const struct hda_fixup *fix, int action) + { +@@ -6861,6 +6897,30 @@ static void alc285_fixup_hp_envy_x360(struct hda_codec *codec, + } + } + ++static void alc285_fixup_hp_beep(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ if (action == HDA_FIXUP_ACT_PRE_PROBE) { ++ codec->beep_just_power_on = true; ++ } else if (action == HDA_FIXUP_ACT_INIT) { ++#ifdef CONFIG_SND_HDA_INPUT_BEEP ++ /* ++ * Just enable loopback to internal speaker and headphone jack. ++ * Disable amplification to get about the same beep volume as ++ * was on pure BIOS setup before loading the driver. ++ */ ++ alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13)); ++ ++ snd_hda_enable_beep_device(codec, 1); ++ ++#if !IS_ENABLED(CONFIG_INPUT_PCSPKR) ++ dev_warn_once(hda_codec_dev(codec), ++ "enable CONFIG_INPUT_PCSPKR to get PC beeps\n"); ++#endif ++#endif ++ } ++} ++ + /* for hda_fixup_thinkpad_acpi() */ + #include "thinkpad_helper.c" + +@@ -7376,6 +7436,7 @@ enum { + ALC280_FIXUP_HP_9480M, + ALC245_FIXUP_HP_X360_AMP, + ALC285_FIXUP_HP_SPECTRE_X360_EB1, ++ ALC285_FIXUP_HP_SPECTRE_X360_DF1, + ALC285_FIXUP_HP_ENVY_X360, + ALC288_FIXUP_DELL_HEADSET_MODE, + ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, +@@ -7477,6 +7538,7 @@ enum { + ALC285_FIXUP_HP_GPIO_LED, + ALC285_FIXUP_HP_MUTE_LED, + ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED, ++ ALC285_FIXUP_HP_BEEP_MICMUTE_LED, + ALC236_FIXUP_HP_MUTE_LED_COEFBIT2, + ALC236_FIXUP_HP_GPIO_LED, + ALC236_FIXUP_HP_MUTE_LED, +@@ -9064,6 +9126,12 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_spectre_x360_mute_led, + }, ++ [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc285_fixup_hp_beep, ++ .chained = true, ++ .chain_id = ALC285_FIXUP_HP_MUTE_LED, ++ }, + [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc236_fixup_hp_mute_led_coefbit2, +@@ -9407,6 +9475,10 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_spectre_x360_eb1 + }, ++ [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc285_fixup_hp_spectre_x360_df1 ++ }, + [ALC285_FIXUP_HP_ENVY_X360] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_envy_x360, +@@ -10006,6 +10078,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), + SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), ++ SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1), + SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), + SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), +@@ -10016,7 +10089,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), +- SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), ++ SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED), + SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), + SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED), +@@ -10501,6 +10574,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), ++ SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC), + SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), + SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), +@@ -10754,6 +10828,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { + {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"}, ++ {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"}, + {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"}, + {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"}, + {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"}, +diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c +index 0b8e88b19888ec..6d8455c1bee6d8 100644 +--- a/sound/soc/codecs/cs42l43-jack.c ++++ b/sound/soc/codecs/cs42l43-jack.c +@@ -642,6 +642,10 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv) + + reinit_completion(&priv->type_detect); + ++ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK); ++ + cs42l43_start_hs_bias(priv, true); + regmap_update_bits(cs42l43->regmap, CS42L43_HS2, + CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT); +@@ -653,6 +657,9 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv) + CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT); + cs42l43_stop_hs_bias(priv); + ++ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, ++ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, 0); ++ + if (!time_left) + return -ETIMEDOUT; + +diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h +index c234f2f4276a12..78ada3a5bfae55 100644 +--- a/sound/soc/codecs/mt6359-accdet.h ++++ b/sound/soc/codecs/mt6359-accdet.h +@@ -123,6 +123,15 @@ struct mt6359_accdet { + struct workqueue_struct *jd_workqueue; + }; + ++#if IS_ENABLED(CONFIG_SND_SOC_MT6359_ACCDET) + int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack); ++#else ++static inline int ++mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, ++ struct snd_soc_jack *jack) ++{ ++ return -EOPNOTSUPP; ++} ++#endif + #endif +diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c +index 9d6431338fb715..329549936bd5c3 100644 +--- a/sound/soc/codecs/pcm3168a.c ++++ b/sound/soc/codecs/pcm3168a.c +@@ -494,9 +494,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, + } + break; + case 24: +- if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) || +- (format == SND_SOC_DAIFMT_DSP_B)) { +- dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n"); ++ if (!provider_mode && ((format == SND_SOC_DAIFMT_DSP_A) || ++ (format == SND_SOC_DAIFMT_DSP_B))) { ++ dev_err(component->dev, "24-bit slots not supported in consumer mode using DSP\n"); + return -EINVAL; + } + break; +diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c +index c382cb6be60256..c0bb1b4b2dcb59 100644 +--- a/sound/soc/codecs/rt722-sdca-sdw.c ++++ b/sound/soc/codecs/rt722-sdca-sdw.c +@@ -28,9 +28,50 @@ static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) + 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, + 0): +- case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, +- 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, +- RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, RT722_SDCA_CTL_SELECTED_MODE, ++ 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, ++ RT722_SDCA_CTL_FU_MUTE, CH_L) ... ++ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, ++ RT722_SDCA_CTL_FU_MUTE, CH_R): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D, ++ RT722_SDCA_CTL_SELECTED_MODE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, ++ RT722_SDCA_CTL_FU_MUTE, CH_L) ... ++ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, ++ RT722_SDCA_CTL_FU_MUTE, CH_R): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, ++ RT722_SDCA_CTL_FU_MUTE, CH_01) ... ++ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, ++ RT722_SDCA_CTL_FU_MUTE, CH_04): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, ++ RT722_SDCA_CTL_VENDOR_DEF, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, ++ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... ++ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, ++ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, ++ RT722_SDCA_CTL_FU_MUTE, CH_L) ... ++ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, ++ RT722_SDCA_CTL_FU_MUTE, CH_R): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, ++ RT722_SDCA_CTL_VENDOR_DEF, CH_08): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, ++ RT722_SDCA_CTL_REQ_POWER_STATE, 0): ++ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, ++ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: + return true; + default: +@@ -74,6 +115,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re + case 0x5600000 ... 0x5600007: + case 0x5700000 ... 0x5700004: + case 0x5800000 ... 0x5800004: ++ case 0x5810000: + case 0x5b00003: + case 0x5c00011: + case 0x5d00006: +@@ -81,6 +123,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re + case 0x5f00030: + case 0x6100000 ... 0x6100051: + case 0x6100055 ... 0x6100057: ++ case 0x6100060: + case 0x6100062: + case 0x6100064 ... 0x6100065: + case 0x6100067: +diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c +index e87a07eee97377..72d6356b898148 100644 +--- a/sound/soc/codecs/tas2764.c ++++ b/sound/soc/codecs/tas2764.c +@@ -182,33 +182,6 @@ static SOC_ENUM_SINGLE_DECL( + static const struct snd_kcontrol_new tas2764_asi1_mux = + SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum); + +-static int tas2764_dac_event(struct snd_soc_dapm_widget *w, +- struct snd_kcontrol *kcontrol, int event) +-{ +- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); +- struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); +- int ret; +- +- switch (event) { +- case SND_SOC_DAPM_POST_PMU: +- tas2764->dac_powered = true; +- ret = tas2764_update_pwr_ctrl(tas2764); +- break; +- case SND_SOC_DAPM_PRE_PMD: +- tas2764->dac_powered = false; +- ret = tas2764_update_pwr_ctrl(tas2764); +- break; +- default: +- dev_err(tas2764->dev, "Unsupported event\n"); +- return -EINVAL; +- } +- +- if (ret < 0) +- return ret; +- +- return 0; +-} +- + static const struct snd_kcontrol_new isense_switch = + SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1); + static const struct snd_kcontrol_new vsense_switch = +@@ -221,8 +194,7 @@ static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = { + 1, &isense_switch), + SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, + 1, &vsense_switch), +- SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event, +- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), ++ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OUT"), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON") +@@ -243,9 +215,28 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) + { + struct tas2764_priv *tas2764 = + snd_soc_component_get_drvdata(dai->component); ++ int ret; ++ ++ if (!mute) { ++ tas2764->dac_powered = true; ++ ret = tas2764_update_pwr_ctrl(tas2764); ++ if (ret) ++ return ret; ++ } + + tas2764->unmuted = !mute; +- return tas2764_update_pwr_ctrl(tas2764); ++ ret = tas2764_update_pwr_ctrl(tas2764); ++ if (ret) ++ return ret; ++ ++ if (mute) { ++ tas2764->dac_powered = false; ++ ret = tas2764_update_pwr_ctrl(tas2764); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; + } + + static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) +@@ -636,6 +627,7 @@ static const struct reg_default tas2764_reg_defaults[] = { + { TAS2764_TDM_CFG2, 0x0a }, + { TAS2764_TDM_CFG3, 0x10 }, + { TAS2764_TDM_CFG5, 0x42 }, ++ { TAS2764_INT_CLK_CFG, 0x19 }, + }; + + static const struct regmap_range_cfg tas2764_regmap_ranges[] = { +@@ -653,6 +645,7 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = { + static bool tas2764_volatile_register(struct device *dev, unsigned int reg) + { + switch (reg) { ++ case TAS2764_SW_RST: + case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: + case TAS2764_INT_CLK_CFG: + return true; +diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c +index 7128bcf3a743e1..bb304de5cc38a3 100644 +--- a/sound/soc/fsl/imx-card.c ++++ b/sound/soc/fsl/imx-card.c +@@ -517,7 +517,7 @@ static int imx_card_parse_of(struct imx_card_data *data) + if (!card->dai_link) + return -ENOMEM; + +- data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); ++ data->link_data = devm_kcalloc(dev, num_links, sizeof(*link_data), GFP_KERNEL); + if (!data->link_data) + return -ENOMEM; + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index ce80adc30fe946..6a85e8fdcae646 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -576,6 +576,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, ++ { /* Acer Aspire SW3-013 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"), ++ }, ++ .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | ++ BYT_RT5640_JD_SRC_JD2_IN4N | ++ BYT_RT5640_OVCD_TH_2000UA | ++ BYT_RT5640_OVCD_SF_0P75 | ++ BYT_RT5640_DIFF_MIC | ++ BYT_RT5640_SSP0_AIF1 | ++ BYT_RT5640_MCLK_EN), ++ }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +index e69c1bb2cb2395..7f411b85778237 100644 +--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c ++++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +@@ -58,7 +58,15 @@ static const char *aud_clks[MT8188_CLK_NUM] = { + [MT8188_CLK_AUD_ADC] = "aud_adc", + [MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires", + [MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp", ++ [MT8188_CLK_AUD_AFE_DMIC1] = "aud_afe_dmic1", ++ [MT8188_CLK_AUD_AFE_DMIC2] = "aud_afe_dmic2", ++ [MT8188_CLK_AUD_AFE_DMIC3] = "aud_afe_dmic3", ++ [MT8188_CLK_AUD_AFE_DMIC4] = "aud_afe_dmic4", + [MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires", ++ [MT8188_CLK_AUD_DMIC_HIRES1] = "aud_dmic_hires1", ++ [MT8188_CLK_AUD_DMIC_HIRES2] = "aud_dmic_hires2", ++ [MT8188_CLK_AUD_DMIC_HIRES3] = "aud_dmic_hires3", ++ [MT8188_CLK_AUD_DMIC_HIRES4] = "aud_dmic_hires4", + [MT8188_CLK_AUD_I2SIN] = "aud_i2sin", + [MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in", + [MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out", +diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +index ec53c171c170a8..c6c78d684f3ee1 100644 +--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h ++++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +@@ -54,7 +54,15 @@ enum { + MT8188_CLK_AUD_ADC, + MT8188_CLK_AUD_DAC_HIRES, + MT8188_CLK_AUD_A1SYS_HP, ++ MT8188_CLK_AUD_AFE_DMIC1, ++ MT8188_CLK_AUD_AFE_DMIC2, ++ MT8188_CLK_AUD_AFE_DMIC3, ++ MT8188_CLK_AUD_AFE_DMIC4, + MT8188_CLK_AUD_ADC_HIRES, ++ MT8188_CLK_AUD_DMIC_HIRES1, ++ MT8188_CLK_AUD_DMIC_HIRES2, ++ MT8188_CLK_AUD_DMIC_HIRES3, ++ MT8188_CLK_AUD_DMIC_HIRES4, + MT8188_CLK_AUD_I2SIN, + MT8188_CLK_AUD_TDM_IN, + MT8188_CLK_AUD_I2S_OUT, +diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +index 11f30b183520ff..4a304bffef8bab 100644 +--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c ++++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +@@ -2855,10 +2855,6 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg) + case AFE_DMIC3_SRC_DEBUG_MON0: + case AFE_DMIC3_UL_SRC_MON0: + case AFE_DMIC3_UL_SRC_MON1: +- case DMIC_GAIN1_CUR: +- case DMIC_GAIN2_CUR: +- case DMIC_GAIN3_CUR: +- case DMIC_GAIN4_CUR: + case ETDM_IN1_MONITOR: + case ETDM_IN2_MONITOR: + case ETDM_OUT1_MONITOR: +diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c +index 88a7169336d61f..580eb20b0771a8 100644 +--- a/sound/soc/qcom/sm8250.c ++++ b/sound/soc/qcom/sm8250.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -39,9 +40,11 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); ++ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; ++ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; + } +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 9a828e55c4f9e7..507743c87e402d 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -275,10 +275,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + + if (dai->driver->ops && + dai->driver->ops->xlate_tdm_slot_mask) +- dai->driver->ops->xlate_tdm_slot_mask(slots, +- &tx_mask, &rx_mask); ++ ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + else +- snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); ++ ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); ++ if (ret) ++ goto err; + + for_each_pcm_streams(stream) + snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]); +@@ -287,6 +288,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + dai->driver->ops->set_tdm_slot) + ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, + slots, slot_width); ++err: + return soc_dai_ret(dai, ret); + } + EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); +diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c +index b4cfc34d00ee63..eff1355cc3df00 100644 +--- a/sound/soc/soc-ops.c ++++ b/sound/soc/soc-ops.c +@@ -638,6 +638,33 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, + } + EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); + ++static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl) ++{ ++ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; ++ struct snd_ctl_elem_value uctl; ++ int ret; ++ ++ if (!mc->platform_max) ++ return 0; ++ ++ ret = kctl->get(kctl, &uctl); ++ if (ret < 0) ++ return ret; ++ ++ if (uctl.value.integer.value[0] > mc->platform_max) ++ uctl.value.integer.value[0] = mc->platform_max; ++ ++ if (snd_soc_volsw_is_stereo(mc) && ++ uctl.value.integer.value[1] > mc->platform_max) ++ uctl.value.integer.value[1] = mc->platform_max; ++ ++ ret = kctl->put(kctl, &uctl); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ + /** + * snd_soc_limit_volume - Set new limit to an existing volume control. + * +@@ -662,7 +689,7 @@ int snd_soc_limit_volume(struct snd_soc_card *card, + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + if (max <= mc->max - mc->min) { + mc->platform_max = max; +- ret = 0; ++ ret = snd_soc_clip_to_platform_max(kctl); + } + } + return ret; +diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c +index b4cdcec33e1209..84145209dec493 100644 +--- a/sound/soc/sof/ipc4-control.c ++++ b/sound/soc/sof/ipc4-control.c +@@ -483,6 +483,14 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, + return -EINVAL; + } + ++ /* Check header id */ ++ if (header.numid != SOF_CTRL_CMD_BINARY) { ++ dev_err_ratelimited(scomp->dev, ++ "Incorrect numid for bytes put %d\n", ++ header.numid); ++ return -EINVAL; ++ } ++ + /* Verify the ABI header first */ + if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr))) + return -EFAULT; +@@ -565,7 +573,8 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, + if (data_size > size) + return -ENOSPC; + +- header.numid = scontrol->comp_id; ++ /* Set header id and length */ ++ header.numid = SOF_CTRL_CMD_BINARY; + header.length = data_size; + + if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) +diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c +index e8acf60c27a743..bb5df0d214e367 100644 +--- a/sound/soc/sof/ipc4-pcm.c ++++ b/sound/soc/sof/ipc4-pcm.c +@@ -621,7 +621,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm + return -ENOMEM; + } + +- if (!support_info) ++ /* Delay reporting is only supported on playback */ ++ if (!support_info || stream == SNDRV_PCM_STREAM_CAPTURE) + continue; + + stream_info = kzalloc(sizeof(*stream_info), GFP_KERNEL); +diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c +index 7afded323150c8..c18a1fdd40ee38 100644 +--- a/sound/soc/sof/topology.c ++++ b/sound/soc/sof/topology.c +@@ -1057,7 +1057,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, + struct snd_sof_dai *dai) + { + struct snd_soc_card *card = scomp->card; +- struct snd_soc_pcm_runtime *rtd; ++ struct snd_soc_pcm_runtime *rtd, *full, *partial; + struct snd_soc_dai *cpu_dai; + int stream; + int i; +@@ -1074,12 +1074,22 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, + else + goto end; + ++ full = NULL; ++ partial = NULL; + list_for_each_entry(rtd, &card->rtd_list, list) { + /* does stream match DAI link ? */ +- if (!rtd->dai_link->stream_name || +- !strstr(rtd->dai_link->stream_name, w->sname)) +- continue; ++ if (rtd->dai_link->stream_name) { ++ if (!strcmp(rtd->dai_link->stream_name, w->sname)) { ++ full = rtd; ++ break; ++ } else if (strstr(rtd->dai_link->stream_name, w->sname)) { ++ partial = rtd; ++ } ++ } ++ } + ++ rtd = full ? full : partial; ++ if (rtd) { + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + /* + * Please create DAI widget in the right order +diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c +index f0a5fd90110182..0d7758cc84c638 100644 +--- a/sound/soc/sunxi/sun4i-codec.c ++++ b/sound/soc/sunxi/sun4i-codec.c +@@ -25,6 +25,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -239,6 +240,7 @@ struct sun4i_codec { + struct clk *clk_module; + struct reset_control *rst; + struct gpio_desc *gpio_pa; ++ struct gpio_desc *gpio_hp; + + /* ADC_FIFOC register is at different offset on different SoCs */ + struct regmap_field *reg_adc_fifoc; +@@ -1277,6 +1279,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { + .ops = &dummy_dai_ops, + }; + ++static struct snd_soc_jack sun4i_headphone_jack; ++ ++static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = { ++ { .pin = "Headphone", .mask = SND_JACK_HEADPHONE }, ++}; ++ ++static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = { ++ .name = "hp-det", ++ .report = SND_JACK_HEADPHONE, ++ .debounce_time = 150, ++}; ++ ++static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_card *card = rtd->card; ++ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); ++ int ret; ++ ++ if (scodec->gpio_hp) { ++ ret = snd_soc_card_jack_new_pins(card, "Headphone Jack", ++ SND_JACK_HEADPHONE, ++ &sun4i_headphone_jack, ++ sun4i_headphone_jack_pins, ++ ARRAY_SIZE(sun4i_headphone_jack_pins)); ++ if (ret) { ++ dev_err(rtd->dev, ++ "Headphone jack creation failed: %d\n", ret); ++ return ret; ++ } ++ ++ sun4i_headphone_jack_gpio.desc = scodec->gpio_hp; ++ ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1, ++ &sun4i_headphone_jack_gpio); ++ ++ if (ret) { ++ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, + int *num_links) + { +@@ -1302,6 +1347,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, + link->codecs->name = dev_name(dev); + link->platforms->name = dev_name(dev); + link->dai_fmt = SND_SOC_DAIFMT_I2S; ++ link->init = sun4i_codec_machine_init; + + *num_links = 1; + +@@ -1742,6 +1788,13 @@ static int sun4i_codec_probe(struct platform_device *pdev) + return ret; + } + ++ scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); ++ if (IS_ERR(scodec->gpio_hp)) { ++ ret = PTR_ERR(scodec->gpio_hp); ++ dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n"); ++ return ret; ++ } ++ + /* reg_field setup */ + scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, + scodec->regmap, +diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c +index 9b75639434b815..0a764426d93586 100644 +--- a/tools/bpf/bpftool/common.c ++++ b/tools/bpf/bpftool/common.c +@@ -461,10 +461,11 @@ int get_fd_type(int fd) + p_err("can't read link type: %s", strerror(errno)); + return -1; + } +- if (n == sizeof(path)) { ++ if (n == sizeof(buf)) { + p_err("can't read link type: path too long!"); + return -1; + } ++ buf[n] = '\0'; + + if (strstr(buf, "bpf-map")) + return BPF_OBJ_MAP; +diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build +index fac42486a8cf0b..27f4ee9cb4db4a 100644 +--- a/tools/build/Makefile.build ++++ b/tools/build/Makefile.build +@@ -141,6 +141,10 @@ objprefix := $(subst ./,,$(OUTPUT)$(dir)/) + obj-y := $(addprefix $(objprefix),$(obj-y)) + subdir-obj-y := $(addprefix $(objprefix),$(subdir-obj-y)) + ++# Separate out test log files from real build objects. ++test-y := $(filter %_log, $(obj-y)) ++obj-y := $(filter-out %_log, $(obj-y)) ++ + # Final '$(obj)-in.o' object + in-target := $(objprefix)$(obj)-in.o + +@@ -151,7 +155,7 @@ $(subdir-y): + + $(sort $(subdir-obj-y)): $(subdir-y) ; + +-$(in-target): $(obj-y) FORCE ++$(in-target): $(obj-y) $(test-y) FORCE + $(call rule_mkdir) + $(call if_changed,$(host)ld_multi) + +diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h +index 977ec094bc2a6c..2a90f04a4160db 100644 +--- a/tools/include/uapi/linux/bpf.h ++++ b/tools/include/uapi/linux/bpf.h +@@ -1140,6 +1140,7 @@ enum bpf_perf_event_type { + #define BPF_F_BEFORE (1U << 3) + #define BPF_F_AFTER (1U << 4) + #define BPF_F_ID (1U << 5) ++#define BPF_F_PREORDER (1U << 6) + #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */ + + /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 2fad178949efe9..fa2abe56e845d9 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -1802,7 +1802,7 @@ static int set_kcfg_value_str(struct extern_desc *ext, char *ext_val, + } + + len = strlen(value); +- if (value[len - 1] != '"') { ++ if (len < 2 || value[len - 1] != '"') { + pr_warn("extern (kcfg) '%s': invalid string config '%s'\n", + ext->name, value); + return -EINVAL; +diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c +index ae61ae5b02bf88..0871f86c6b6666 100644 +--- a/tools/net/ynl/lib/ynl.c ++++ b/tools/net/ynl/lib/ynl.c +@@ -368,7 +368,7 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) + "Invalid attribute (binary %s)", policy->name); + return -1; + case YNL_PT_NUL_STR: +- if ((!policy->len || len <= policy->len) && !data[len - 1]) ++ if (len && (!policy->len || len <= policy->len) && !data[len - 1]) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (string %s)", policy->name); +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index a1b14378bab045..f8e676a6e6f8e9 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -3287,7 +3287,7 @@ static int handle_insn_ops(struct instruction *insn, + if (update_cfi_state(insn, next_insn, &state->cfi, op)) + return 1; + +- if (!insn->alt_group) ++ if (!opts.uaccess || !insn->alt_group) + continue; + + if (op->dest.type == OP_DEST_PUSHF) { +@@ -3754,6 +3754,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + return 0; + + case INSN_STAC: ++ if (!opts.uaccess) ++ break; ++ + if (state.uaccess) { + WARN_INSN(insn, "recursive UACCESS enable"); + return 1; +@@ -3763,6 +3766,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + break; + + case INSN_CLAC: ++ if (!opts.uaccess) ++ break; ++ + if (!state.uaccess && func) { + WARN_INSN(insn, "redundant UACCESS disable"); + return 1; +@@ -4238,7 +4244,8 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, + if (!insn || insn->ignore || insn->visited) + return 0; + +- state->uaccess = sym->uaccess_safe; ++ if (opts.uaccess) ++ state->uaccess = sym->uaccess_safe; + + ret = validate_branch(file, insn_func(insn), insn, *state); + if (ret) +@@ -4685,8 +4692,10 @@ int check(struct objtool_file *file) + init_cfi_state(&force_undefined_cfi); + force_undefined_cfi.force_undefined = true; + +- if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) ++ if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) { ++ ret = -1; + goto out; ++ } + + cfi_hash_add(&init_cfi); + cfi_hash_add(&func_cfi); +@@ -4703,7 +4712,7 @@ int check(struct objtool_file *file) + if (opts.retpoline) { + ret = validate_retpoline(file); + if (ret < 0) +- return ret; ++ goto out; + warnings += ret; + } + +@@ -4739,7 +4748,7 @@ int check(struct objtool_file *file) + */ + ret = validate_unrets(file); + if (ret < 0) +- return ret; ++ goto out; + warnings += ret; + } + +@@ -4802,7 +4811,7 @@ int check(struct objtool_file *file) + if (opts.prefix) { + ret = add_prefix_symbols(file); + if (ret < 0) +- return ret; ++ goto out; + warnings += ret; + } + +diff --git a/tools/testing/kunit/qemu_configs/x86_64.py b/tools/testing/kunit/qemu_configs/x86_64.py +index dc794907686304..4a6bf4e048f5b0 100644 +--- a/tools/testing/kunit/qemu_configs/x86_64.py ++++ b/tools/testing/kunit/qemu_configs/x86_64.py +@@ -7,4 +7,6 @@ CONFIG_SERIAL_8250_CONSOLE=y''', + qemu_arch='x86_64', + kernel_path='arch/x86/boot/bzImage', + kernel_command_line='console=ttyS0', +- extra_qemu_params=[]) ++ # qboot is faster than SeaBIOS and doesn't mess up ++ # the terminal. ++ extra_qemu_params=['-bios', 'qboot.rom']) +diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c b/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c +index 2d0796314862ac..0a99fd404f6dc0 100644 +--- a/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c ++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c +@@ -68,7 +68,6 @@ static void test_sockmap_ktls_disconnect_after_delete(int family, int map) + goto close_cli; + + err = disconnect(cli); +- ASSERT_OK(err, "disconnect"); + + close_cli: + close(cli); +diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh +index a3678dfe5848a2..c151374ddf0402 100755 +--- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh ++++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh +@@ -149,7 +149,7 @@ cfg_test_host_common() + check_err $? "Failed to add $name host entry" + + bridge mdb replace dev br0 port br0 grp $grp $state vid 10 &> /dev/null +- check_fail $? "Managed to replace $name host entry" ++ check_err $? "Failed to replace $name host entry" + + bridge mdb del dev br0 port br0 grp $grp $state vid 10 + bridge mdb get dev br0 grp $grp vid 10 &> /dev/null +diff --git a/tools/testing/selftests/net/gro.sh b/tools/testing/selftests/net/gro.sh +index 342ad27f631b15..e771f5f7faa26a 100755 +--- a/tools/testing/selftests/net/gro.sh ++++ b/tools/testing/selftests/net/gro.sh +@@ -95,5 +95,6 @@ trap cleanup EXIT + if [[ "${test}" == "all" ]]; then + run_all_tests + else +- run_test "${proto}" "${test}" ++ exit_code=$(run_test "${proto}" "${test}") ++ exit $exit_code + fi; diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/Add-board-BananaPi-BPI-M4-Zero.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/Add-board-BananaPi-BPI-M4-Zero.patch index a9c10c689bb0..65bfb914773f 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.armbian/Add-board-BananaPi-BPI-M4-Zero.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/Add-board-BananaPi-BPI-M4-Zero.patch @@ -405,69 +405,3 @@ index 000000000000..e9640439e02c -- 2.35.3 -From 428ceff436e4c0e85214085a19d4546ac097f36d Mon Sep 17 00:00:00 2001 -From: Patrick Yavitz -Date: Wed, 14 May 2025 06:57:54 -0400 -Subject: [PATCH] BananaPi BPI-M4-Zero: Enable GPU and add Audio nodes - -Signed-off-by: Patrick Yavitz ---- - .../allwinner/sun50i-h618-bananapi-m4-zero.dts | 5 +++++ - .../dts/allwinner/sun50i-h618-bananapi-m4.dtsi | 18 +++++++++++++++++- - 2 files changed, 22 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts -index 46e07893c653..12cdbdccf133 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts -@@ -34,6 +34,11 @@ led-0 { - }; - }; - -+/* &codec { -+ status = "okay"; -+ allwinner,audio-routing = "Hdmi", "HDMI"; -+}; */ -+ - /* Connected to an on-board RTL8821CU USB WiFi chip. */ - &ehci1 { - status = "okay"; -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi -index e9640439e02c..6e52232105ae 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi -@@ -80,6 +80,22 @@ wifi_pwrseq: wifi-pwrseq { - }; - }; - -+&ahub_dam_plat { -+ status = "okay"; -+}; -+ -+&ahub1_plat { -+ status = "okay"; -+}; -+ -+&ahub1_mach { -+ status = "okay"; -+}; -+ -+/* &ahub_i2s2 { -+ status = "okay"; -+}; */ -+ - &cpu0 { - cpu-supply = <®_dcdc2>; - }; -@@ -89,7 +105,7 @@ &de { - }; - - &gpu { -- status = "disabled"; -+ status = "okay"; - mali-supply = <®_dcdc1>; - }; - --- -2.39.5 - diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/BananaPi-BPI-M4-Zero-Enable-GPU-and-add-Audio-nodes.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/BananaPi-BPI-M4-Zero-Enable-GPU-and-add-Audio-nodes.patch new file mode 100644 index 000000000000..dc3881df2c93 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/BananaPi-BPI-M4-Zero-Enable-GPU-and-add-Audio-nodes.patch @@ -0,0 +1,66 @@ +From f59ab5c108596c2fb936e27a2d571dbee9280849 Mon Sep 17 00:00:00 2001 +From: Patrick Yavitz +Date: Wed, 14 May 2025 06:57:54 -0400 +Subject: BananaPi BPI-M4-Zero: Enable GPU and add Audio nodes + +Signed-off-by: Patrick Yavitz +--- + .../allwinner/sun50i-h618-bananapi-m4-zero.dts | 5 +++++ + .../dts/allwinner/sun50i-h618-bananapi-m4.dtsi | 18 +++++++++++++++++- + 2 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts +index 46e07893c653..4fef48cceedf 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-zero.dts +@@ -34,6 +34,11 @@ led-0 { + }; + }; + ++/* &codec { ++ status = "okay"; ++ allwinner,audio-routing = "Hdmi", "HDMI"; ++}; */ ++ + /* Connected to an on-board RTL8821CU USB WiFi chip. */ + &ehci1 { + status = "okay"; +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi +index e9640439e02c..6e52232105ae 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4.dtsi +@@ -80,6 +80,22 @@ wifi_pwrseq: wifi-pwrseq { + }; + }; + ++&ahub_dam_plat { ++ status = "okay"; ++}; ++ ++&ahub1_plat { ++ status = "okay"; ++}; ++ ++&ahub1_mach { ++ status = "okay"; ++}; ++ ++/* &ahub_i2s2 { ++ status = "okay"; ++}; */ ++ + &cpu0 { + cpu-supply = <®_dcdc2>; + }; +@@ -89,7 +105,7 @@ &de { + }; + + &gpu { +- status = "disabled"; ++ status = "okay"; + mali-supply = <®_dcdc1>; + }; + +-- +2.35.3 + diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch index 6c95780ad7d7..d5be5c2bba35 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch @@ -1834,9 +1834,9 @@ index 000000000000..ee4ff6f453d1 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -1897,9 +1897,9 @@ index 000000000000..eac4f1e2d244 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -1955,12 +1955,12 @@ index 000000000000..cad50d8a29a7 +/plugin/; + +/ { -+ compatible = "allwinner,sun7i-a20"; ++ compatible = "allwinner,sun4i-a10"; + + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; ++ spi0 = "/soc/spi@1c05000"; + }; + }; + @@ -1984,12 +1984,12 @@ index 000000000000..8c606d6b06a1 +/plugin/; + +/ { -+ compatible = "allwinner,sun7i-a20"; ++ compatible = "allwinner,sun4i-a10"; + + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi1 = "/soc@1c00000/spi@1c06000"; ++ spi1 = "/soc/spi@1c06000"; + }; + }; + @@ -2012,12 +2012,12 @@ index 000000000000..145f285588f8 +/plugin/; + +/ { -+ compatible = "allwinner,sun7i-a20"; ++ compatible = "allwinner,sun4i-a10"; + + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -2026,8 +2026,8 @@ index 000000000000..145f285588f8 + __overlay__ { + status = "okay"; + pinctrl-names = "default", "default"; -+ pinctrl-0 = <&spi2_pins_a>; -+ pinctrl-1 = <&spi2_cs0_pins_a>; ++ pinctrl-0 = <&spi2_pc_pins>; ++ pinctrl-1 = <&spi2_cs0_pc_pins>; + }; + }; +}; @@ -2046,7 +2046,7 @@ index 000000000000..89bb44d5aee0 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial2 = "/soc@1c00000/serial@1c28800"; ++ serial2 = "/soc/serial@1c28800"; + }; + }; + @@ -2089,7 +2089,7 @@ index 000000000000..f599d92082e4 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial3 = "/soc@1c00000/serial@1c28c00"; ++ serial3 = "/soc/serial@1c28c00"; + }; + }; + @@ -2142,7 +2142,7 @@ index 000000000000..b5e562a6477b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial4 = "/soc@1c00000/serial@1c29000"; ++ serial4 = "/soc/serial@1c29000"; + }; + }; + @@ -2185,7 +2185,7 @@ index 000000000000..12c3f9699b23 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial5 = "/soc@1c00000/serial@1c29400"; ++ serial5 = "/soc/serial@1c29400"; + }; + }; + @@ -2223,7 +2223,7 @@ index 000000000000..6be41d505509 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial6 = "/soc@1c00000/serial@1c29800"; ++ serial6 = "/soc/serial@1c29800"; + }; + }; + @@ -2261,7 +2261,7 @@ index 000000000000..967f6afbe7d3 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial7 = "/soc@1c00000/serial@1c29c00"; ++ serial7 = "/soc/serial@1c29c00"; + }; + }; + @@ -2407,7 +2407,7 @@ index 000000000000..444c32ca01d5 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c1 = "/soc@1c00000/i2c@1c2b000"; ++ i2c1 = "/soc/i2c@1c2b000"; + }; + }; + @@ -2435,7 +2435,7 @@ index 000000000000..7a30681ca287 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c2 = "/soc@1c00000/i2c@1c2b400"; ++ i2c2 = "/soc/i2c@1c2b400"; + }; + }; + @@ -2793,7 +2793,7 @@ index 000000000000..6edad42bfcd7 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart0 = "/soc@1c00000/serial@1c28000"; ++ uart0 = "/soc/serial@1c28000"; + }; + }; + @@ -2831,7 +2831,7 @@ index 000000000000..675b701ed535 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart1 = "/soc@1c00000/serial@1c28400"; ++ uart1 = "/soc/serial@1c28400"; + }; + }; + @@ -2859,7 +2859,7 @@ index 000000000000..b3c4e3d7a0e2 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart2 = "/soc@1c00000/serial@1c28800"; ++ uart2 = "/soc/serial@1c28800"; + }; + }; + @@ -2887,7 +2887,7 @@ index 000000000000..15c25d0c5992 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart3 = "/soc@1c00000/serial@1c28c00"; ++ uart3 = "/soc/serial@1c28c00"; + }; + }; + @@ -3104,7 +3104,7 @@ index 000000000000..c5f6e9732d3a + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c1 = "/soc@1c00000/i2c@1c2b000"; ++ i2c1 = "/soc/i2c@1c2b000"; + }; + }; + @@ -3132,7 +3132,7 @@ index 000000000000..fa93d1ed9b72 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c2 = "/soc@1c00000/i2c@1c2b400"; ++ i2c2 = "/soc/i2c@1c2b400"; + }; + }; + @@ -3160,7 +3160,7 @@ index 000000000000..945795c338e8 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c3 = "/soc@1c00000/i2c@1c2b800"; ++ i2c3 = "/soc/i2c@1c2b800"; + }; + }; + @@ -3188,7 +3188,7 @@ index 000000000000..4fcf08c2469b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c4 = "/soc@1c00000/i2c@1c2c000"; ++ i2c4 = "/soc/i2c@1c2c000"; + }; + }; + @@ -3543,9 +3543,9 @@ index 000000000000..b91097eca5b6 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -3606,9 +3606,9 @@ index 000000000000..341fe3229ffc + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -3669,7 +3669,7 @@ index 000000000000..cad50d8a29a7 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; ++ spi0 = "/soc/spi@1c05000"; + }; + }; + @@ -3698,7 +3698,7 @@ index 000000000000..f0218eb9f76b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi1 = "/soc@1c00000/spi@1c06000"; ++ spi1 = "/soc/spi@1c06000"; + }; + }; + @@ -3726,7 +3726,7 @@ index 000000000000..effba42b48bd + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -3735,8 +3735,8 @@ index 000000000000..effba42b48bd + __overlay__ { + status = "okay"; + pinctrl-names = "default", "default"; -+ pinctrl-0 = <&spi2_pb_pins>; -+ pinctrl-1 = <&spi2_pb_cs0_pin>; ++ pinctrl-0 = <&spi2_pc_pins>; ++ pinctrl-1 = <&spi2_cs0_pc_pin>; + }; + }; +}; @@ -3755,7 +3755,7 @@ index 000000000000..79d1dca7a311 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial2 = "/soc@1c00000/serial@1c28800"; ++ serial2 = "/soc/serial@1c28800"; + }; + }; + @@ -3793,7 +3793,7 @@ index 000000000000..703acbcf377b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial3 = "/soc@1c00000/serial@1c28c00"; ++ serial3 = "/soc/serial@1c28c00"; + }; + }; + @@ -3841,7 +3841,7 @@ index 000000000000..19180341a67f + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial4 = "/soc@1c00000/serial@1c29000"; ++ serial4 = "/soc/serial@1c29000"; + }; + }; + @@ -3869,7 +3869,7 @@ index 000000000000..a1369eee2917 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial5 = "/soc@1c00000/serial@1c29400"; ++ serial5 = "/soc/serial@1c29400"; + }; + }; + @@ -3897,7 +3897,7 @@ index 000000000000..fb9efe2a9475 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial6 = "/soc@1c00000/serial@1c29800"; ++ serial6 = "/soc/serial@1c29800"; + }; + }; + @@ -3925,7 +3925,7 @@ index 000000000000..bbdca3ec67ed + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial7 = "/soc@1c00000/serial@1c29c00"; ++ serial7 = "/soc/serial@1c29c00"; + }; + }; + diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch new file mode 100644 index 000000000000..08e7f4d33a07 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ryzer58 +Date: Sun, 15 Dec 2024 23:29:14 +0000 +Subject: Re-introduce spi overlays for each bus so that pins are muxed corectly into SPI mode + +Signed-off-by: Ryzer58 +--- + arch/arm/boot/dts/allwinner/overlay/Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/boot/dts/allwinner/overlay/Makefile b/arch/arm/boot/dts/allwinner/overlay/Makefile +index 23ecb62e2478..44547b7d6afd 100644 +--- a/arch/arm/boot/dts/allwinner/overlay/Makefile ++++ b/arch/arm/boot/dts/allwinner/overlay/Makefile +@@ -6,10 +6,13 @@ dtb-$(CONFIG_MACH_SUN4I) += \ + sun4i-a10-i2c2.dtbo \ + sun4i-a10-nand.dtbo \ + sun4i-a10-pps-gpio.dtbo \ + sun4i-a10-pwm.dtbo \ + sun4i-a10-spdif-out.dtbo \ ++ sun4i-a10-spi0.dtbo \ ++ sun4i-a10-spi1.dtbo \ ++ sun4i-a10-spi2.dtbo \ + sun4i-a10-spi-jedec-nor.dtbo \ + sun4i-a10-spi-spidev.dtbo \ + sun4i-a10-uart2.dtbo \ + sun4i-a10-uart3.dtbo \ + sun4i-a10-uart4.dtbo \ +-- +Created with Armbian build tools https://github.com/armbian/build + diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch new file mode 100644 index 000000000000..89a98b45783b --- /dev/null +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ryzer58 +Date: Sun, 15 Dec 2024 23:40:08 +0000 +Subject: Re-introduce spi overlays for each bus so that pins are muxed corectly into SPI mode + + +Signed-off-by: Ryzer58 +--- + arch/arm/boot/dts/allwinner/overlay/Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/boot/dts/allwinner/overlay/Makefile b/arch/arm/boot/dts/allwinner/overlay/Makefile +index 44547b7d6afd..01a91adea88b 100644 +--- a/arch/arm/boot/dts/allwinner/overlay/Makefile ++++ b/arch/arm/boot/dts/allwinner/overlay/Makefile +@@ -47,10 +47,13 @@ dtb-$(CONFIG_MACH_SUN7I) += \ + sun7i-a20-mmc2.dtbo \ + sun7i-a20-nand.dtbo \ + sun7i-a20-pps-gpio.dtbo \ + sun7i-a20-pwm.dtbo \ + sun7i-a20-spdif-out.dtbo \ ++ sun7i-a20-spi0.dtbo \ ++ sun7i-a20-spi1.dtbo \ ++ sun7i-a20-spi2.dtbo \ + sun7i-a20-spi-add-cs1.dtbo \ + sun7i-a20-spi-jedec-nor.dtbo \ + sun7i-a20-spi-spidev.dtbo \ + sun7i-a20-uart2.dtbo \ + sun7i-a20-uart3.dtbo \ +-- +Created with Armbian build tools https://github.com/armbian/build + diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch index f9fc024b384c..97c39762a5aa 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch @@ -1,13 +1,13 @@ -From 5e7360471247c1fa87cb230e36e3aa9d185f1583 Mon Sep 17 00:00:00 2001 +From d9c5855767d3c2b5ad893b6d4d17b83662febe10 Mon Sep 17 00:00:00 2001 From: The-going <48602507+The-going@users.noreply.github.com> Date: Mon, 24 Mar 2025 22:19:31 +0300 -Subject: [PATCH] arm64: allwinner: Add sun50i-h618-bananapi-m4-berry support +Subject: arm64: allwinner: Add sun50i-h618-bananapi-m4-berry support --- arch/arm64/boot/dts/allwinner/Makefile | 1 + .../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 4 +- - .../sun50i-h618-bananapi-m4-berry.dts | 422 ++++++++++++++++++ - 3 files changed, 425 insertions(+), 2 deletions(-) + .../sun50i-h618-bananapi-m4-berry.dts | 355 ++++++++++++++++++ + 3 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile @@ -39,10 +39,10 @@ index 851cf3e5444d..84d5f4d6b65f 100644 }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts new file mode 100644 -index 000000000000..6dfb0a2a34d2 +index 000000000000..4762c3bbcf0f --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts -@@ -0,0 +1,422 @@ +@@ -0,0 +1,355 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2020 Arm Ltd. @@ -155,16 +155,7 @@ index 000000000000..6dfb0a2a34d2 + wifi_usb { + compatible = "usb-wifi"; + status = "okay"; -+ reset-gpios = <&pio 2 2 GPIO_ACTIVE_HIGH>; /* PC2 */ -+ }; -+ -+ ac200_pwm_clk: ac200_clk { -+ compatible = "pwm-clock"; -+ #clock-cells = <0>; -+ // pwm5 period_ns = 500 > 334 for select 24M clock. -+ pwms = <&pwm 5 500 0>; -+ clock-frequency = <2000000>; -+ status = "disabled"; ++ power_on_pin = <&pio 2 2 GPIO_ACTIVE_HIGH>; /* PC2 */ + }; + + soc { @@ -289,7 +280,6 @@ index 000000000000..6dfb0a2a34d2 + phy-io-supply = <®_dldo1>; + allwinner,rx-delay-ps = <3100>; + allwinner,tx-delay-ps = <700>; -+ use_ephy25m = <0x00>; + status = "okay"; +}; + @@ -306,17 +296,6 @@ index 000000000000..6dfb0a2a34d2 + +&emac1 { + compatible = "allwinner,sunxi-gmac"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&rmii_pins>; -+ phy-mode = "rmii"; -+ phy-handle = <&rmii_phy>; -+ phy-supply = <®_dldo1>; -+ allwinner,rx-delay-ps = <3100>; -+ allwinner,tx-delay-ps = <700>; -+ phy-rst; -+ gmac-power0; -+ gmac-power1; -+ gmac-power2; + status = "disabled"; +}; + @@ -392,56 +371,6 @@ index 000000000000..6dfb0a2a34d2 + status = "okay"; +}; + -+&i2c1 { -+ status = "disabled"; -+}; -+ -+&i2c2 { -+ status = "disabled"; -+}; -+ -+&i2c3 { -+ status = "disabled"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c3_pa_pins>; -+ -+ ac200_x: mfd@10 { -+ compatible = "x-powers,ac200-sunxi"; -+ reg = <0x10>; -+ clocks = <&ac200_pwm_clk>; -+ // ephy id -+ nvmem-cells = <&ephy_calibration>; -+ nvmem-cell-names = "calibration"; -+ -+ ac200_ephy: phy { -+ compatible = "x-powers,ac200-ephy-sunxi"; -+ status = "disabled"; -+ }; -+ }; -+}; -+ -+&i2c4 { -+ status = "disabled"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; -+ status = "disabled"; -+}; -+ -+&uart2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart2_ph_pins>; -+ status = "disabled"; -+}; -+ -+&uart5 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart5_pins>; -+ status = "disabled"; -+}; -+ +&codec { + allwinner,audio-routing = + "Line Out", "LINEOUT"; @@ -452,6 +381,10 @@ index 000000000000..6dfb0a2a34d2 + status = "okay"; +}; + ++&ahub_dam_mach { ++ status = "okay"; ++}; ++ +&ahub1_plat { + status = "okay"; +}; diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/driver-allwinner-h618-emac.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/driver-allwinner-h618-emac.patch index bd5ac93f92aa..03f66207d80b 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.armbian/driver-allwinner-h618-emac.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/driver-allwinner-h618-emac.patch @@ -1,4 +1,4 @@ -From a31dcc88741c4defa78423d697cd7ce4a873a53d Mon Sep 17 00:00:00 2001 +From c66d2fed3fda3ef390b3419a3fa20d5903e61047 Mon Sep 17 00:00:00 2001 From: chraac Date: Fri, 16 Aug 2024 16:44:41 +0800 Subject: driver: allwinner h618 emac @@ -27,7 +27,7 @@ Subject: driver: allwinner h618 emac create mode 100644 include/linux/mfd/ac200.h diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c -index 880f1efcaca5..b100204c0344 100644 +index 626daedb0169..58e3fc68cc21 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -25,21 +25,6 @@ @@ -52,7 +52,7 @@ index 880f1efcaca5..b100204c0344 100644 /** * of_gpio_named_count() - Count GPIOs for a device * @np: device node to count GPIOs for -@@ -426,6 +411,20 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np, +@@ -428,6 +413,20 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np, return desc; } diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch index 43c3fdcb13c9..5c8d22372afb 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch @@ -1,17 +1,17 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 0eb3e020a3a31b3429b74715032ab9f51ae302c4 Mon Sep 17 00:00:00 2001 From: The-going <48602507+The-going@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:34:55 +0300 Subject: drv:gpu:drm: panel-simple Add compability olinuxino lcd --- - drivers/gpu/drm/panel/panel-simple.c | 125 +++++++++- + drivers/gpu/drm/panel/panel-simple.c | 125 ++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c -index 111111111111..222222222222 100644 +index d041ff542a4e..702a39eb07a6 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c -@@ -3496,6 +3496,42 @@ static const struct panel_desc okaya_rs800480t_7x0gp = { +@@ -3497,6 +3497,42 @@ static const struct panel_desc okaya_rs800480t_7x0gp = { .bus_format = MEDIA_BUS_FMT_RGB666_1X18, }; @@ -54,7 +54,7 @@ index 111111111111..222222222222 100644 static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = { .clock = 9000, .hdisplay = 480, -@@ -3508,8 +3544,8 @@ static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = { +@@ -3509,8 +3545,8 @@ static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = { .vtotal = 272 + 8 + 5 + 3, }; @@ -65,7 +65,7 @@ index 111111111111..222222222222 100644 .num_modes = 1, .size = { .width = 95, -@@ -3551,6 +3587,72 @@ static const struct panel_desc ontat_kd50g21_40nt_a1 = { +@@ -3552,6 +3588,72 @@ static const struct panel_desc ontat_kd50g21_40nt_a1 = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; @@ -138,7 +138,7 @@ index 111111111111..222222222222 100644 /* * 800x480 CVT. The panel appears to be quite accepting, at least as far as * pixel clocks, but this is the timing that was being used in the Adafruit -@@ -4936,8 +5038,23 @@ static const struct of_device_id platform_of_match[] = { +@@ -4937,8 +5039,23 @@ static const struct of_device_id platform_of_match[] = { .compatible = "okaya,rs800480t-7x0gp", .data = &okaya_rs800480t_7x0gp, }, { @@ -165,5 +165,5 @@ index 111111111111..222222222222 100644 .compatible = "ontat,kd50g21-40nt-a1", .data = &ontat_kd50g21_40nt_a1, -- -Armbian +2.35.3 diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch index ac7a353620ae..0f9936c66450 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch @@ -1,4 +1,4 @@ -From 9adef04ccfa99d86e2168232a7bcb1d2f4e91a2d Mon Sep 17 00:00:00 2001 +From 7da6a97c082732673a9ef8a723af9a387e7c6bfd Mon Sep 17 00:00:00 2001 From: The-going <48602507+The-going@users.noreply.github.com> Date: Wed, 2 Feb 2022 20:08:50 +0300 Subject: drv:usb:gadget:composite rename gadget serial console manufacturer @@ -10,10 +10,10 @@ to the Armbian brand. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c -index 8402a86176f4..e4532a7d66f3 100644 +index 301a435b9ee3..82d415025bd3 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c -@@ -2777,7 +2777,7 @@ EXPORT_SYMBOL_GPL(usb_composite_setup_continue); +@@ -2775,7 +2775,7 @@ EXPORT_SYMBOL_GPL(usb_composite_setup_continue); static char *composite_default_mfr(struct usb_gadget *gadget) { diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/net-usb-r8152-add-LED-configuration-from-OF.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/net-usb-r8152-add-LED-configuration-from-OF.patch index f98bff28d0ac..7749fb36e2c8 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.armbian/net-usb-r8152-add-LED-configuration-from-OF.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/net-usb-r8152-add-LED-configuration-from-OF.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 2c3908734d217b36125755d8785138c824558dc9 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 26 Jul 2020 02:38:31 +0200 Subject: net: usb: r8152: add LED configuration from OF @@ -9,11 +9,11 @@ be determined. Signed-off-by: David Bauer --- - drivers/net/usb/r8152.c | 23 ++++++++++ + drivers/net/usb/r8152.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c -index 111111111111..222222222222 100644 +index 96fa3857d8e2..08f353953bbd 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -12,6 +12,7 @@ @@ -24,7 +24,7 @@ index 111111111111..222222222222 100644 #include #include #include -@@ -7046,6 +7047,22 @@ static void rtl_tally_reset(struct r8152 *tp) +@@ -7047,6 +7048,22 @@ static void rtl_tally_reset(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); } @@ -47,7 +47,7 @@ index 111111111111..222222222222 100644 static void r8152b_init(struct r8152 *tp) { u32 ocp_data; -@@ -7087,6 +7104,8 @@ static void r8152b_init(struct r8152 *tp) +@@ -7088,6 +7105,8 @@ static void r8152b_init(struct r8152 *tp) ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); @@ -56,7 +56,7 @@ index 111111111111..222222222222 100644 } static void r8153_init(struct r8152 *tp) -@@ -7227,6 +7246,8 @@ static void r8153_init(struct r8152 *tp) +@@ -7228,6 +7247,8 @@ static void r8153_init(struct r8152 *tp) tp->coalesce = COALESCE_SLOW; break; } @@ -65,7 +65,7 @@ index 111111111111..222222222222 100644 } static void r8153b_init(struct r8152 *tp) -@@ -7309,6 +7330,8 @@ static void r8153b_init(struct r8152 *tp) +@@ -7310,6 +7331,8 @@ static void r8153b_init(struct r8152 *tp) rtl_tally_reset(tp); tp->coalesce = 15000; /* 15 us */ @@ -75,5 +75,5 @@ index 111111111111..222222222222 100644 static void r8153c_init(struct r8152 *tp) -- -Armbian +2.35.3 diff --git a/patch/kernel/archive/sunxi-6.12/patches.armbian/sun50i-h616-Add-the-missing-digital-audio-nodes.patch b/patch/kernel/archive/sunxi-6.12/patches.armbian/sun50i-h616-Add-the-missing-digital-audio-nodes.patch new file mode 100644 index 000000000000..3e785de6f1c6 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.12/patches.armbian/sun50i-h616-Add-the-missing-digital-audio-nodes.patch @@ -0,0 +1,130 @@ +From c36f7c14482613d2cc1ab7b68ae53ebf394c5108 Mon Sep 17 00:00:00 2001 +From: The-going <48602507+The-going@users.noreply.github.com> +Date: Wed, 28 May 2025 16:09:13 +0300 +Subject: sun50i-h616: Add the missing digital audio nodes + +--- + .../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 93 +++++++++++++++++++ + 1 file changed, 93 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +index 84d5f4d6b65f..a0add8c7efcd 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +@@ -419,6 +419,18 @@ i2c4_ph_pins: i2c4-ph-pins { + function = "i2c4"; + }; + ++ /omit-if-no-ref/ ++ i2s2_pins: i2s2-pins { ++ pins = "PG10", "PG11", "PG12", "PG13", "PG14"; ++ function = "i2s2"; ++ }; ++ ++ /omit-if-no-ref/ ++ i2s3_pins: i2s3-pins { ++ pins = "PH5", "PH6", "PH7", "PH8", "PH9"; ++ function = "i2s3"; ++ }; ++ + ir_rx_pin: ir-rx-pin { + pins = "PH10"; + function = "ir_rx"; +@@ -1003,6 +1015,17 @@ ahub_dam_plat:ahub_dam_plat@5097000 { + status = "disabled"; + }; + ++ ahub_dam_mach:ahub_dam_mach { ++ compatible = "allwinner,sunxi-snd-mach"; ++ soundcard-mach,name = "ahubdam"; ++ status = "disabled"; ++ soundcard-mach,cpu { ++ sound-dai = <&ahub_dam_plat>; ++ }; ++ soundcard-mach,codec { ++ }; ++ }; ++ + ahub1_plat:ahub1_plat { + #sound-dai-cells = <0>; + compatible = "allwinner,sunxi-snd-plat-ahub"; +@@ -1043,6 +1066,76 @@ ahub1_codec: soundcard-mach,codec { + }; + }; + ++ ahub_i2s1: ahub-i2s1@5097000 { ++ #sound-dai-cells = <0>; ++ compatible = "allwinner,sunxi-ahub-daudio"; ++ reg = <0x5097000 0xadf>; ++ clocks = <&ccu CLK_BUS_AUDIO_HUB>, ++ <&ccu CLK_AUDIO_CODEC_1X>, ++ <&ccu CLK_AUDIO_CODEC_4X>, ++ <&ccu CLK_AUDIO_HUB>; ++ clock-names = "apb", "audio-codec-1x", "audio-codec-4x", "audio-hub"; ++ tdm_num = <0x1>; ++ pinconfig = <0x0>; ++ frametype = <0x0>; ++ pcm_lrck_period = <0x20>; ++ slot_width_select = <0x20>; ++ daudio_master = <0x4>; ++ audio_format = <0x1>; ++ signal_inversion = <0x1>; ++ tdm_config = <0x1>; ++ mclk_div = <0x1>; ++ status = "disabled"; ++ }; ++ ++ ahub_i2s2: ahub-i2s2@5097000 { ++ //#sound-dai-cells = <0>; ++ compatible = "allwinner,sunxi-ahub-daudio"; ++ reg = <0x5097000 0xadf>; ++ clocks = <&ccu CLK_BUS_AUDIO_HUB>, ++ <&ccu CLK_AUDIO_CODEC_1X>, ++ <&ccu CLK_AUDIO_CODEC_4X>, ++ <&ccu CLK_AUDIO_HUB>; ++ clock-names = "apb", "audio-codec-1x", "audio-codec-4x", "audio-hub"; ++ //pinctrl-names = "default"; ++ //pinctrl-0 = <&i2s2_pins>; ++ tdm_num = <0x2>; ++ pinconfig = <0x1>; ++ frametype = <0x0>; ++ pcm_lrck_period = <0x20>; ++ slot_width_select = <0x20>; ++ daudio_master = <0x4>; ++ audio_format = <0x1>; ++ signal_inversion = <0x1>; ++ tdm_config = <0x1>; ++ mclk_div = <0x4>; ++ status = "disabled"; ++ }; ++ ++ ahub_i2s3: ahub-i2s3@5097000 { ++ //#sound-dai-cells = <0>; ++ compatible = "allwinner,sunxi-ahub-daudio"; ++ reg = <0x5097000 0xadf>; ++ clocks = <&ccu CLK_BUS_AUDIO_HUB>, ++ <&ccu CLK_AUDIO_CODEC_1X>, ++ <&ccu CLK_AUDIO_CODEC_4X>, ++ <&ccu CLK_AUDIO_HUB>; ++ clock-names = "apb", "audio-codec-1x", "audio-codec-4x", "audio-hub"; ++ //pinctrl-names = "default"; ++ //pinctrl-0 = <&i2s3_pins>; ++ tdm_num = <0x3>; ++ pinconfig = <0x1>; ++ frametype = <0x0>; ++ pcm_lrck_period = <0x20>; ++ slot_width_select = <0x20>; ++ daudio_master = <0x4>; ++ audio_format = <0x1>; ++ signal_inversion = <0x1>; ++ tdm_config = <0x1>; ++ mclk_div = <0x4>; ++ status = "disabled"; ++ }; ++ + usbotg: usb@5100000 { + compatible = "allwinner,sun50i-h616-musb", + "allwinner,sun8i-h3-musb"; +-- +2.35.3 + diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch index daea81c1eeaf..fed009d33a78 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch @@ -1,4 +1,4 @@ -From 2a82156c12d9eb10f0f4591c65b4fb9cedb49d47 Mon Sep 17 00:00:00 2001 +From e09b611829829f817a79e3feb10fec2252922f81 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 25 Sep 2020 21:42:52 -0500 Subject: ASoC: ec25: New codec driver for the EC25 modem @@ -16,10 +16,10 @@ Signed-off-by: Samuel Holland create mode 100644 sound/soc/codecs/ec25.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 7092842480ef..602a815dfaee 100644 +index 6a72561c4189..d44196e801c4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -1125,6 +1125,9 @@ config SND_SOC_HDMI_CODEC +@@ -1124,6 +1124,9 @@ config SND_SOC_HDMI_CODEC select SND_PCM_IEC958 select HDMI @@ -30,7 +30,7 @@ index 7092842480ef..602a815dfaee 100644 tristate "Everest Semi ES7134 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 54cbc3feae32..76db4d730730 100644 +index 69cb0b39f220..3d06bbc2dca9 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -120,6 +120,7 @@ snd-soc-da7219-y := da7219.o da7219-aad.o diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/Add-README.md-with-information-and-u-boot-patches.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/Add-README.md-with-information-and-u-boot-patches.patch deleted file mode 100644 index f1b86cac6c82..000000000000 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/Add-README.md-with-information-and-u-boot-patches.patch +++ /dev/null @@ -1,215 +0,0 @@ -From 21d723b8f75ffedff2e56144c1d03bb4f9327a5f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= -Date: Tue, 22 Nov 2016 01:01:49 +0100 -Subject: Add README.md with information and u-boot patches - -Signed-off-by: Ondrej Jirman ---- - ...Fix-PLL1-setup-to-never-use-dividers.patch | 33 ++++ - README.md | 154 ++++++++++++++++++ - 2 files changed, 187 insertions(+) - create mode 100644 0001-sunxi-h3-Fix-PLL1-setup-to-never-use-dividers.patch - create mode 100644 README.md - -diff --git a/0001-sunxi-h3-Fix-PLL1-setup-to-never-use-dividers.patch b/0001-sunxi-h3-Fix-PLL1-setup-to-never-use-dividers.patch -new file mode 100644 -index 000000000000..2b892e805a2b ---- /dev/null -+++ b/0001-sunxi-h3-Fix-PLL1-setup-to-never-use-dividers.patch -@@ -0,0 +1,33 @@ -+From 7f5071f906f79bdc99d6b4b0ccf0cb280abe740b Mon Sep 17 00:00:00 2001 -+From: Ondrej Jirman -+Date: Tue, 20 Dec 2016 11:25:12 +0100 -+Subject: [PATCH] sunxi: h3: Fix PLL1 setup to never use dividers -+ -+Kernel would lower the divider on first CLK change and cause the -+lock up. -+--- -+ arch/arm/mach-sunxi/clock_sun6i.c | 7 +++---- -+ 1 file changed, 3 insertions(+), 4 deletions(-) -+ -+diff --git a/arch/arm/mach-sunxi/clock_sun6i.c b/arch/arm/mach-sunxi/clock_sun6i.c -+index 50fb302a19..91aa2a0478 100644 -+--- a/arch/arm/mach-sunxi/clock_sun6i.c -++++ b/arch/arm/mach-sunxi/clock_sun6i.c -+@@ -94,11 +94,10 @@ void clock_set_pll1(unsigned int clk) -+ int k = 1; -+ int m = 1; -+ -+- if (clk > 1152000000) { -+- k = 2; -+- } else if (clk > 768000000) { -++ if (clk >= 1368000000) { -+ k = 3; -+- m = 2; -++ } else if (clk >= 768000000) { -++ k = 2; -+ } -+ -+ /* Switch to 24MHz clock while changing PLL1 */ -+-- -+2.11.0 -+ -diff --git a/README.md b/README.md -new file mode 100644 -index 000000000000..74c4c16416d3 ---- /dev/null -+++ b/README.md -@@ -0,0 +1,154 @@ -+Mainline linux kernel for Orange Pi PC/PC2/PC3/One, TBS A711, PinePhone (Pro), PocketBook Touch Lux 3 -+------------------------------------------------------------------------------------------------------ -+ -+This kernel tree is meant for: -+ -+- Orange Pi One -+- Orange Pi PC -+- Orange Pi PC 2 -+- Orange Pi 3 -+- PinePhone 1.0, 1.1 and 1.2(a/b) -+- TBS A711 Tablet -+- PocketBook Touch Lux 3 -+- Pinebook Pro -+- Pinephone Pro -+ -+Features in addition to mainline: -+ -+- [Orange Pi One/PC/PC2] More aggressive OPPs for CPU -+- [All] Mark one of DRM planes as a cursor plane, speeding up Xorg based desktop with modesetting driver -+- [Orange Pi One/PC/PC2] Configure on-board micro-switches to perform system power off function -+- [Orange Pi One/PC/PC2/3] HDMI audio -+- [Orange Pi 3] Ethernet -+- [TBS A711] HM5065 (back camera) / GC2145 (front camera) -+- [PinePhone] WiFi, Bluetooth, Audio, Modem power, HDMI out over USB-C, USB-C support, cameras, PMIC improvements, power management, fixes here and there -+- [PocketBook Touch Lux 3] Display and Touchscreen support -+- [Pinephone Pro] Everything -+ -+Pre-built u-boot and kernels are available at https://xff.cz/kernels/ -+ -+You may need some firmware files for some part of the functionality. Those are -+available at: https://megous.com/git/linux-firmware -+ -+If you want to reproduce my pre-built kernels exactly, you'll need to uncomment -+CONFIG_EXTRA_FIRMWARE_DIR and CONFIG_EXTRA_FIRMWARE in the defconfigs, and -+point CONFIG_EXTRA_FIRMWARE_DIR to a directory on your computer where the -+clone of https://megous.com/git/linux-firmware resides. -+ -+You can also leave those two config options commented out, and copy the contents -+of https://megous.com/git/linux-firmware to /lib/firmware/ on the target device. -+ -+You can use this kernel to run a desktop environment on Orange Pi SBCs, -+Arch Linux on your Pinephone, or to have a completely opensource OS on -+a Pocketbook e-ink book reader. -+ -+Have fun! -+ -+ -+Build instructions -+------------------ -+ -+These are rudimentary instructions and you need to understand what you're doing. -+These are just core steps required to build the ATF/u-boot/kernel. Downloading, -+verifying, renaming to correct directories is not described or mentioned. You -+should be able to infer missing necessary steps yourself for your particular needs. -+ -+Get necessary toolchains from: -+ -+- https://releases.linaro.org/components/toolchain/binaries/latest/aarch64-linux-gnu/ for 64bit Orange Pi PC2 and Orange Pi 3, PinePhone -+- https://releases.linaro.org/components/toolchain/binaries/latest/arm-linux-gnueabihf/ for 32bit Orange Pis, Pocketbook, TBS tablet -+ -+Extract toolchains and prepare the environment: -+ -+ CWD=`pwd` -+ OUT=$CWD/builds -+ SRC=$CWD/u-boot -+ export PATH="$PATH:$CWD/Toolchains/arm/bin:$CWD/Toolchains/aarch64/bin" -+ -+For Orange Pi PC2, Orange Pi 3 or PinePhone: -+ -+ export CROSS_COMPILE=aarch64-linux-gnu- -+ export KBUILD_OUTPUT=$OUT/.tmp/uboot-pc2 -+ rm -rf "$KBUILD_OUTPUT" -+ mkdir -p $KBUILD_OUTPUT $OUT/pc2 -+ -+Get and build ATF from https://github.com/ARM-software/arm-trusted-firmware: -+ -+ make -C "$CWD/arm-trusted-firmware" PLAT=sun50i_a64 DEBUG=1 bl31 -+ cp "$CWD/arm-trusted-firmware/build/sun50i_a64/debug/bl31.bin" "$KBUILD_OUTPUT" -+ -+Use sun50i_a64 for Orange Pi PC2 or PinePhone and sun50i_h6 for Orange Pi 3. -+ -+Build u-boot from https://megous.com/git/u-boot/ (opi-v2020.04 branch) with appropriate -+defconfig (orangepi_one_defconfig, orangepi_pc2_defconfig, orangepi_pc_defconfig, orangepi_3_defconfig, tbs_a711_defconfig, pinephone_defconfig). -+ -+My u-boot branch already has all the necessary patches integrated and is configured for quick u-boot/kernel startup. -+ -+ make -C u-boot orangepi_pc2_defconfig -+ make -C u-boot -j5 -+ -+ cp $KBUILD_OUTPUT/.config $OUT/pc2/uboot.config -+ cat $KBUILD_OUTPUT/{spl/sunxi-spl.bin,u-boot.itb} > $OUT/pc2/uboot.bin -+ -+Get kernel from this repository and checkout the latest orange-pi-5.18 branch. -+ -+Build the kernel for 64-bit boards: -+ -+ export ARCH=arm64 -+ export CROSS_COMPILE=aarch64-linux-gnu- -+ export KBUILD_OUTPUT=$OUT/.tmp/linux-arm64 -+ mkdir -p $KBUILD_OUTPUT $OUT/pc2 -+ -+ make -C linux orangepi_defconfig -+ # or make -C linux pocketbook_touch_lux_3_defconfig -+ # or make -C linux tbs_a711_defconfig -+ make -C linux -j5 clean -+ make -C linux -j5 Image dtbs -+ -+ cp -f $KBUILD_OUTPUT/arch/arm64/boot/Image $OUT/pc2/ -+ cp -f $KBUILD_OUTPUT/.config $OUT/pc2/linux.config -+ cp -f $KBUILD_OUTPUT/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dtb $OUT/pc2/board.dtb -+ -+Build the kernel for 32-bit boards: -+ -+ export ARCH=arm -+ export CROSS_COMPILE=arm-linux-gnueabihf- -+ export KBUILD_OUTPUT=$OUT/.tmp/linux-arm -+ mkdir -p $KBUILD_OUTPUT $OUT/pc -+ -+ make orangepi_defconfig -+ # or make pinephone_defconfig -+ make -C linux orangepi_defconfig -+ make -C linux -j5 clean -+ make -C linux -j5 zImage dtbs -+ -+ cp -f $KBUILD_OUTPUT/arch/arm/boot/zImage $OUT/pc/ -+ cp -f $KBUILD_OUTPUT/.config $OUT/pc/linux.config -+ cp -f $KBUILD_OUTPUT/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dtb $OUT/pc/board.dtb -+ # Or use sun8i-h3-orangepi-one.dtb for Orange Pi One -+ -+ -+PinePhone -+--------- -+ -+I don't run u-boot on PinePhone, so my pre-built kernel packages don't come -+with u-boot built for PinePhone. -+ -+ -+Kernel lockup issues -+-------------------- -+ -+*If you're getting lockups on boot or later during thermal regulation, -+you're missing an u-boot patch.* -+ -+This patch is necessary to run this kernel! -+ -+These lockups are caused by improper NKMP clock factors selection -+in u-boot for PLL_CPUX. (M divider should not be used. P divider -+should be used only for frequencies below 240MHz.) -+ -+This patch for u-boot fixes it: -+ -+ 0001-sunxi-h3-Fix-PLL1-setup-to-never-use-dividers.patch -+ -+Kernel side is already fixed in this kernel tree. --- -2.35.3 - diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/cpufreq-sun50i-Show-detected-CPU-bin-for-easier-debugging.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/cpufreq-sun50i-Show-detected-CPU-bin-for-easier-debugging.patch index e7b92367f5ab..c06446f2a429 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/cpufreq-sun50i-Show-detected-CPU-bin-for-easier-debugging.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.megous/cpufreq-sun50i-Show-detected-CPU-bin-for-easier-debugging.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 8bb2d91bd36f4e447c323c0017cce6f18189b36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= Date: Thu, 31 Oct 2019 18:31:32 +0100 Subject: cpufreq: sun50i: Show detected CPU bin, for easier debugging @@ -12,10 +12,10 @@ Signed-off-by: Ondrej Jirman 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c -index 111111111111..222222222222 100644 +index 0599dbf851eb..b054ec1bf2d0 100644 --- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c +++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c -@@ -235,6 +235,8 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) +@@ -241,6 +241,8 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev) snprintf(name, sizeof(name), "speed%d", speed); config.prop_name = name; @@ -25,5 +25,5 @@ index 111111111111..222222222222 100644 struct device *cpu_dev = get_cpu_device(cpu); -- -Armbian +2.35.3 diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Implement-gamma-correction.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Implement-gamma-correction.patch deleted file mode 100644 index 9634007a03d3..000000000000 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Implement-gamma-correction.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Vasily Khoruzhick -Date: Wed, 13 Mar 2019 19:50:17 -0700 -Subject: drm/sun4i: Implement gamma correction - -Add support for gamma corretion to sun4i TCON driver. Its LUT has 256 -entries and can be updated only when gamma correction is disabled. - -Signed-off-by: Vasily Khoruzhick ---- - drivers/gpu/drm/sun4i/sun4i_crtc.c | 14 ++++ - drivers/gpu/drm/sun4i/sun4i_tcon.c | 33 ++++++++++ - drivers/gpu/drm/sun4i/sun4i_tcon.h | 12 +++- - 3 files changed, 58 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun4i_crtc.c -+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c -@@ -103,6 +103,20 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, - drm_crtc_send_vblank_event(crtc, event); - spin_unlock_irq(&crtc->dev->event_lock); - } -+ -+ if (crtc->state->color_mgmt_changed) { -+ if (crtc->state->gamma_lut) { -+ /* LUT can be only updated when gamma correction is -+ * disabled -+ */ -+ sun4i_tcon_enable_gamma(scrtc->tcon, false); -+ sun4i_tcon_load_gamma_lut(scrtc->tcon, -+ crtc->state->gamma_lut->data); -+ sun4i_tcon_enable_gamma(scrtc->tcon, true); -+ } else -+ sun4i_tcon_enable_gamma(scrtc->tcon, false); -+ } -+ - } - - static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, -diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun4i_tcon.c -+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c -@@ -240,6 +240,34 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable) - } - EXPORT_SYMBOL(sun4i_tcon_enable_vblank); - -+void sun4i_tcon_load_gamma_lut(struct sun4i_tcon *tcon, -+ struct drm_color_lut *lut) -+{ -+ int i; -+ -+ for (i = 0; i < SUN4I_TCON_GAMMA_LUT_SIZE; i++) { -+ u32 r, g, b; -+ -+ r = drm_color_lut_extract(lut[i].red, 8); -+ g = drm_color_lut_extract(lut[i].green, 8); -+ b = drm_color_lut_extract(lut[i].blue, 8); -+ -+ regmap_write(tcon->regs, SUN4I_TCON_GAMMA_TABLE_REG + 4 * i, -+ SUN4I_TCON_GAMMA_TABLE_R(r) | -+ SUN4I_TCON_GAMMA_TABLE_G(g) | -+ SUN4I_TCON_GAMMA_TABLE_B(b)); -+ } -+} -+EXPORT_SYMBOL(sun4i_tcon_load_gamma_lut); -+ -+void sun4i_tcon_enable_gamma(struct sun4i_tcon *tcon, bool enable) -+{ -+ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, -+ SUN4I_TCON_GCTL_GAMMA_ENABLE, -+ enable ? SUN4I_TCON_GCTL_GAMMA_ENABLE : 0); -+} -+EXPORT_SYMBOL(sun4i_tcon_enable_gamma); -+ - /* - * This function is a helper for TCON output muxing. The TCON output - * muxing control register in earlier SoCs (without the TCON TOP block) -@@ -1288,6 +1316,11 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, - - list_add_tail(&tcon->list, &drv->tcon_list); - -+ drm_mode_crtc_set_gamma_size(&tcon->crtc->crtc, -+ SUN4I_TCON_GAMMA_LUT_SIZE); -+ drm_crtc_enable_color_mgmt(&tcon->crtc->crtc, 0, false, -+ tcon->crtc->crtc.gamma_size); -+ - return 0; - - err_free_dclk: -diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun4i_tcon.h -+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h -@@ -19,6 +19,7 @@ - - #define SUN4I_TCON_GCTL_REG 0x0 - #define SUN4I_TCON_GCTL_TCON_ENABLE BIT(31) -+#define SUN4I_TCON_GCTL_GAMMA_ENABLE BIT(30) - #define SUN4I_TCON_GCTL_IOMAP_MASK BIT(0) - #define SUN4I_TCON_GCTL_IOMAP_TCON1 (1 << 0) - #define SUN4I_TCON_GCTL_IOMAP_TCON0 (0 << 0) -@@ -229,7 +230,13 @@ - #define SUN4I_TCON1_FILL_BEG2_REG 0x31c - #define SUN4I_TCON1_FILL_END2_REG 0x320 - #define SUN4I_TCON1_FILL_DATA2_REG 0x324 --#define SUN4I_TCON1_GAMMA_TABLE_REG 0x400 -+ -+#define SUN4I_TCON_GAMMA_TABLE_REG 0x400 -+#define SUN4I_TCON_GAMMA_TABLE_B(x) ((x) & 0xff) -+#define SUN4I_TCON_GAMMA_TABLE_G(x) (((x) & 0xff) << 8) -+#define SUN4I_TCON_GAMMA_TABLE_R(x) (((x) & 0xff) << 16) -+ -+#define SUN4I_TCON_GAMMA_LUT_SIZE 256 - - #define SUN4I_TCON_MAX_CHANNELS 2 - -@@ -297,6 +304,9 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, - const struct drm_display_mode *mode); - void sun4i_tcon_set_status(struct sun4i_tcon *crtc, - const struct drm_encoder *encoder, bool enable); -+void sun4i_tcon_load_gamma_lut(struct sun4i_tcon *tcon, -+ struct drm_color_lut *lut); -+void sun4i_tcon_enable_gamma(struct sun4i_tcon *tcon, bool enable); - - extern const struct of_device_id sun4i_tcon_of_table[]; - --- -Armbian - diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Mark-one-of-the-UI-planes-as-a-cursor-one.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Mark-one-of-the-UI-planes-as-a-cursor-one.patch deleted file mode 100644 index 78f64d086c74..000000000000 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Mark-one-of-the-UI-planes-as-a-cursor-one.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ondrej Jirman -Date: Mon, 31 Oct 2022 03:23:11 +0100 -Subject: drm/sun4i: Mark one of the UI planes as a cursor one - -Signed-off-by: Ondrej Jirman ---- - drivers/gpu/drm/sun4i/sun8i_mixer.c | 7 ++++++- - drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 7 ++----- - drivers/gpu/drm/sun4i/sun8i_ui_layer.h | 4 +++- - 3 files changed, 11 insertions(+), 7 deletions(-) - -diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun8i_mixer.c -+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c -@@ -349,8 +349,13 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm, - - for (i = 0; i < mixer->cfg->ui_num; i++) { - struct sun8i_layer *layer; -+ enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; -+ if (i == 0) -+ type = DRM_PLANE_TYPE_PRIMARY; -+ else if (i == (mixer->cfg->ui_num - 1)) -+ type = DRM_PLANE_TYPE_CURSOR; - -- layer = sun8i_ui_layer_init_one(drm, mixer, i); -+ layer = sun8i_ui_layer_init_one(drm, mixer, i, type); - if (IS_ERR(layer)) { - dev_err(drm->dev, "Couldn't initialize %s plane\n", - i ? "overlay" : "primary"); -diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c -+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c -@@ -277,9 +277,9 @@ static const uint64_t sun8i_layer_modifiers[] = { - - struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm, - struct sun8i_mixer *mixer, -- int index) -+ int index, -+ enum drm_plane_type type) - { -- enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; - int channel = mixer->cfg->vi_num + index; - struct sun8i_layer *layer; - unsigned int plane_cnt; -@@ -289,9 +289,6 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm, - if (!layer) - return ERR_PTR(-ENOMEM); - -- if (index == 0) -- type = DRM_PLANE_TYPE_PRIMARY; -- - /* possible crtcs are set later */ - ret = drm_universal_plane_init(drm, &layer->plane, 0, - &sun8i_ui_layer_funcs, -diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h -+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h -@@ -51,5 +51,7 @@ struct sun8i_layer; - - struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm, - struct sun8i_mixer *mixer, -- int index); -+ int index, -+ enum drm_plane_type type); -+ - #endif /* _SUN8I_UI_LAYER_H_ */ --- -Armbian - diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Support-taking-over-display-pipeline-state-from-p-boo.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Support-taking-over-display-pipeline-state-from-p-boo.patch deleted file mode 100644 index 5870e3676623..000000000000 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/drm-sun4i-Support-taking-over-display-pipeline-state-from-p-boo.patch +++ /dev/null @@ -1,547 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ondrej Jirman -Date: Sun, 30 Apr 2023 18:19:16 +0200 -Subject: drm/sun4i: Support taking over display pipeline state from p-boot - -For perfect, flickerless and fast boot. - -Signed-off-by: Ondrej Jirman ---- - drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 4 +- - drivers/gpu/drm/drm_fbdev_ttm.c | 14 +++ - drivers/gpu/drm/panel/panel-sitronix-st7703.c | 17 +++ - drivers/gpu/drm/sun4i/sun4i_tcon.c | 23 ++++ - drivers/gpu/drm/sun4i/sun4i_tcon.h | 2 + - drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 13 +++ - drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 2 + - drivers/gpu/drm/sun4i/sun8i_mixer.c | 52 ++++++++++ - drivers/gpu/drm/sun4i/sun8i_mixer.h | 3 + - drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 14 +++ - drivers/video/backlight/pwm_bl.c | 25 ++++- - 11 files changed, 167 insertions(+), 2 deletions(-) - -diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c -index 111111111111..222222222222 100644 ---- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c -+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c -@@ -980,7 +980,9 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev) - /* Decrease the PLL AUDIO bias current to reduce noise. */ - writel(0x10040000, reg + SUN50I_A64_PLL_AUDIO_BIAS_REG); - -- writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); -+ ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &val); -+ if (ret) -+ writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); - - /* Set PLL MIPI as parent for TCON0 */ - val = readl(reg + SUN50I_A64_TCON0_CLK_REG); -diff --git a/drivers/gpu/drm/drm_fbdev_ttm.c b/drivers/gpu/drm/drm_fbdev_ttm.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/drm_fbdev_ttm.c -+++ b/drivers/gpu/drm/drm_fbdev_ttm.c -@@ -78,6 +78,7 @@ static int drm_fbdev_ttm_helper_fb_probe(struct drm_fb_helper *fb_helper, - size_t screen_size; - void *screen_buffer; - u32 format; -+ u32 fb_start; - int ret; - - drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n", -@@ -125,6 +126,19 @@ static int drm_fbdev_ttm_helper_fb_probe(struct drm_fb_helper *fb_helper, - if (ret) - goto err_drm_fb_helper_release_info; - -+ ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &fb_start); -+ if (ret == 0) { -+ // copy framebuffer contents from p-boot if reasonable -+ if (screen_size != 720 * 1440 * 4) { -+ drm_err(dev, "surface width(%d), height(%d) and bpp(%d) does not match p-boot requirements\n", -+ sizes->surface_width, sizes->surface_height, -+ sizes->surface_bpp); -+ return 0; -+ } -+ -+ memcpy(screen_buffer, __va(fb_start), screen_size); -+ } -+ - return 0; - - err_drm_fb_helper_release_info: -diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c -+++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c -@@ -62,6 +62,7 @@ struct st7703 { - struct dentry *debugfs; - const struct st7703_panel_desc *desc; - enum drm_panel_orientation orientation; -+ bool hw_preenabled; - }; - - struct st7703_panel_desc { -@@ -679,6 +680,11 @@ static int st7703_enable(struct drm_panel *panel) - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi}; - -+ if (ctx->hw_preenabled) { -+ ctx->hw_preenabled = false; -+ return 0; -+ } -+ - ctx->desc->init_sequence(&dsi_ctx); - - mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); -@@ -726,8 +732,10 @@ static int st7703_prepare(struct drm_panel *panel) - struct st7703 *ctx = panel_to_st7703(panel); - int ret; - -+ if (!ctx->hw_preenabled) { - dev_dbg(ctx->dev, "Resetting the panel\n"); - gpiod_set_value_cansleep(ctx->reset_gpio, 1); -+ } - - ret = regulator_enable(ctx->iovcc); - if (ret < 0) { -@@ -743,10 +751,12 @@ static int st7703_prepare(struct drm_panel *panel) - } - - /* Give power supplies time to stabilize before deasserting reset. */ -+ if (!ctx->hw_preenabled) { - usleep_range(10000, 20000); - - gpiod_set_value_cansleep(ctx->reset_gpio, 0); - usleep_range(15000, 20000); -+ } - - return 0; - } -@@ -844,12 +854,19 @@ static int st7703_probe(struct mipi_dsi_device *dsi) - { - struct device *dev = &dsi->dev; - struct st7703 *ctx; -+ u32 fb_start; - int ret; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - -+ ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &fb_start); -+ if (ret == 0) { -+ /* the display pipeline is already initialized by p-boot */ -+ ctx->hw_preenabled = true; -+ } -+ - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) - return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n"); -diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun4i_tcon.c -+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c -@@ -40,6 +40,8 @@ - #include "sun8i_tcon_top.h" - #include "sunxi_engine.h" - -+static bool hw_preconfigured; -+ - static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder) - { - struct drm_connector *connector; -@@ -743,6 +745,13 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, - const struct drm_encoder *encoder, - const struct drm_display_mode *mode) - { -+ if (tcon->hw_preconfigured) { -+ // avoid the first modeset -+ tcon->hw_preconfigured = false; -+ hw_preconfigured = false; -+ return; -+ } -+ - switch (encoder->encoder_type) { - case DRM_MODE_ENCODER_DSI: - /* DSI is tied to special case of CPU interface */ -@@ -883,6 +892,7 @@ static int sun4i_tcon_init_regmap(struct device *dev, - return PTR_ERR(tcon->regs); - } - -+ if (!tcon->hw_preconfigured) { - /* Make sure the TCON is disabled and all IRQs are off */ - regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0); - regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0); -@@ -891,6 +901,7 @@ static int sun4i_tcon_init_regmap(struct device *dev, - /* Disable IO lines and set them to tristate */ - regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0); - regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0); -+ } - - return 0; - } -@@ -1162,6 +1173,9 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, - tcon->dev = dev; - tcon->id = engine->id; - tcon->quirks = of_device_get_match_data(dev); -+ -+ if (tcon->id == 0) -+ tcon->hw_preconfigured = hw_preconfigured; - - tcon->lcd_rst = devm_reset_control_get(dev, "lcd"); - if (IS_ERR(tcon->lcd_rst)) { -@@ -1183,12 +1197,14 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, - } - } - -+ if (!tcon->hw_preconfigured) { - /* Make sure our TCON is reset */ - ret = reset_control_reset(tcon->lcd_rst); - if (ret) { - dev_err(dev, "Couldn't deassert our reset line\n"); - return ret; - } -+ } - - if (tcon->quirks->supports_lvds) { - /* -@@ -1352,8 +1368,15 @@ static int sun4i_tcon_probe(struct platform_device *pdev) - const struct sun4i_tcon_quirks *quirks; - struct drm_bridge *bridge; - struct drm_panel *panel; -+ u32 fb_start; - int ret; - -+ ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &fb_start); -+ if (ret == 0) { -+ /* the display pipeline is already initialized by p-boot */ -+ hw_preconfigured = true; -+ } -+ - quirks = of_device_get_match_data(&pdev->dev); - - /* panels and bridges are present only on TCONs with channel 0 */ -diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun4i_tcon.h -+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h -@@ -293,6 +293,8 @@ struct sun4i_tcon { - - /* TCON list management */ - struct list_head list; -+ -+ bool hw_preconfigured; - }; - - struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node); -diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c -+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c -@@ -732,6 +732,7 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder) - reset_control_deassert(dsi->reset); - clk_prepare_enable(dsi->mod_clk); - -+ if (!dsi->hw_preconfigured) { - /* - * Enable the DSI block. - */ -@@ -758,6 +759,7 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder) - sun6i_dsi_setup_inst_loop(dsi, mode); - sun6i_dsi_setup_format(dsi, mode); - sun6i_dsi_setup_timings(dsi, mode); -+ } - - phy_init(dsi->dphy); - -@@ -787,11 +789,15 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder) - if (dsi->panel) - drm_panel_enable(dsi->panel); - -+ if (!dsi->hw_preconfigured) { - sun6i_dsi_start(dsi, DSI_START_HSC); - - udelay(1000); - - sun6i_dsi_start(dsi, DSI_START_HSD); -+ } -+ -+ dsi->hw_preconfigured = false; - } - - static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder) -@@ -1105,6 +1111,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct sun6i_dsi *dsi; - void __iomem *base; -+ u32 fb_start; - int ret; - - variant = device_get_match_data(dev); -@@ -1120,6 +1127,12 @@ static int sun6i_dsi_probe(struct platform_device *pdev) - dsi->host.dev = dev; - dsi->variant = variant; - -+ ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &fb_start); -+ if (ret == 0) { -+ /* the display pipeline is already initialized by p-boot */ -+ dsi->hw_preconfigured = true; -+ } -+ - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - dev_err(dev, "Couldn't map the DSI encoder registers\n"); -diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h -+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h -@@ -38,6 +38,8 @@ struct sun6i_dsi { - struct drm_panel *panel; - - const struct sun6i_dsi_variant *variant; -+ -+ bool hw_preconfigured; - }; - - static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host) -diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun8i_mixer.c -+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c -@@ -24,6 +24,7 @@ - #include - - #include "sun4i_drv.h" -+#include "sun4i_tcon.h" - #include "sun8i_mixer.h" - #include "sun8i_ui_layer.h" - #include "sun8i_vi_layer.h" -@@ -34,6 +35,8 @@ struct de2_fmt_info { - u32 de2_fmt; - }; - -+static bool hw_preconfigured; -+ - static const struct de2_fmt_info de2_formats[] = { - { - .drm_fmt = DRM_FORMAT_ARGB8888, -@@ -278,6 +281,33 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine, - struct drm_plane *plane; - u32 route = 0, pipe_en = 0; - -+ if (mixer->hw_preconfigured && engine->id == 0) { -+ struct sun4i_tcon* tcon; -+ u32 val, saved, ret; -+ -+ /* -+ * This is the first commit, wait for vblank on tcon0 before continuing. -+ */ -+ list_for_each_entry(tcon, &mixer->drv->tcon_list, list) { -+ if (tcon->id == 0) { -+ regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &saved); -+ saved &= 0xffff0000; -+ -+ regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0); -+ -+ ret = regmap_read_poll_timeout(tcon->regs, SUN4I_TCON_GINT0_REG, val, -+ val & (SUN4I_TCON_GINT0_VBLANK_INT(0) | -+ SUN4I_TCON_GINT0_VBLANK_INT(1) | -+ SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT), -+ 100, 40000); -+ -+ regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, saved); -+ } -+ } -+ -+ mixer->hw_preconfigured = false; -+ } -+ - DRM_DEBUG_DRIVER("Committing changes\n"); - - drm_for_each_plane(plane, state->dev) { -@@ -461,6 +491,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, - dev_set_drvdata(dev, mixer); - mixer->engine.ops = &sun8i_engine_ops; - mixer->engine.node = dev->of_node; -+ mixer->drv = drv; - - if (of_property_present(dev->of_node, "iommus")) { - /* -@@ -485,6 +516,11 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, - */ - mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node); - -+ if (mixer->engine.id == 0) { -+ mixer->hw_preconfigured = hw_preconfigured; -+ hw_preconfigured = false; -+ } -+ - mixer->cfg = of_device_get_match_data(dev); - if (!mixer->cfg) - return -EINVAL; -@@ -532,8 +568,11 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, - * reason for the mixer to be functional. Make sure it's the - * case. - */ -+ -+ if (!mixer->hw_preconfigured) { - if (mixer->cfg->mod_rate) - clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate); -+ } - - clk_prepare_enable(mixer->mod_clk); - -@@ -541,6 +580,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, - - base = sun8i_blender_base(mixer); - -+ if (!mixer->hw_preconfigured) { - /* Reset registers and disable unused sub-engines */ - if (mixer->cfg->is_de3) { - for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4) -@@ -572,6 +612,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, - /* Enable the mixer */ - regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL, - SUN8I_MIXER_GLOBAL_CTL_RT_EN); -+ } /* hw_preconfigured */ - - /* Set background color to black */ - regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base), -@@ -592,8 +633,10 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, - SUN8I_MIXER_BLEND_MODE(base, i), - SUN8I_MIXER_BLEND_MODE_DEF); - -+ if (!mixer->hw_preconfigured) { - regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base), - SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0); -+ } - - return 0; - -@@ -623,6 +666,15 @@ static const struct component_ops sun8i_mixer_ops = { - - static int sun8i_mixer_probe(struct platform_device *pdev) - { -+ int ret; -+ u32 fb_start; -+ -+ ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &fb_start); -+ if (ret == 0) { -+ /* the display pipeline is already initialized by p-boot */ -+ hw_preconfigured = true; -+ } -+ - return component_add(&pdev->dev, &sun8i_mixer_ops); - } - -diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h -index 111111111111..222222222222 100644 ---- a/drivers/gpu/drm/sun4i/sun8i_mixer.h -+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h -@@ -184,6 +184,9 @@ struct sun8i_mixer { - - struct clk *bus_clk; - struct clk *mod_clk; -+ -+ struct sun4i_drv *drv; -+ bool hw_preconfigured; - }; - - enum { -diff --git a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c -index 111111111111..222222222222 100644 ---- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c -+++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c -@@ -195,6 +195,8 @@ struct sun6i_dphy { - - const struct sun6i_dphy_variant *variant; - enum sun6i_dphy_direction direction; -+ -+ bool hw_preconfigured; - }; - - static int sun6i_dphy_init(struct phy *phy) -@@ -226,6 +228,11 @@ static void sun6i_a31_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy) - { - u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); - -+ if (dphy->hw_preconfigured) { -+ dphy->hw_preconfigured = false; -+ return; -+ } -+ - regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, - SUN6I_DPHY_ANA0_REG_PWS | - SUN6I_DPHY_ANA0_REG_DMPC | -@@ -551,6 +558,7 @@ static int sun6i_dphy_probe(struct platform_device *pdev) - struct sun6i_dphy *dphy; - const char *direction; - void __iomem *regs; -+ u32 fb_start; - int ret; - - dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); -@@ -561,6 +569,12 @@ static int sun6i_dphy_probe(struct platform_device *pdev) - if (!dphy->variant) - return -EINVAL; - -+ ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &fb_start); -+ if (ret == 0) { -+ /* the display pipeline is already initialized by p-boot */ -+ dphy->hw_preconfigured = true; -+ } -+ - regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(regs)) { - dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); -diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c -index 111111111111..222222222222 100644 ---- a/drivers/video/backlight/pwm_bl.c -+++ b/drivers/video/backlight/pwm_bl.c -@@ -444,7 +444,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) - struct backlight_properties props; - struct backlight_device *bl; - struct pwm_bl_data *pb; -- struct pwm_state state; -+ struct pwm_state state, state_real; - unsigned int i; - int ret; - -@@ -509,6 +509,11 @@ static int pwm_backlight_probe(struct platform_device *pdev) - /* Sync up PWM state. */ - pwm_init_state(pb->pwm, &state); - -+ /* Read real state, but only if the PWM is enabled. */ -+ pwm_get_state(pb->pwm, &state_real); -+ if (state_real.enabled) -+ state = state_real; -+ - /* - * The DT case will set the pwm_period_ns field to 0 and store the - * period, parsed from the DT, in the PWM device. For the non-DT case, -@@ -601,6 +606,24 @@ static int pwm_backlight_probe(struct platform_device *pdev) - - bl->props.brightness = data->dft_brightness; - bl->props.power = pwm_backlight_initial_power_state(pb); -+ if (bl->props.power == FB_BLANK_UNBLANK && pb->levels) { -+ u64 level; -+ -+ /* If the backlight is already on, determine the default -+ * brightness from PWM duty cycle instead of forcing -+ * the brightness determined by the driver -+ */ -+ pwm_get_state(pb->pwm, &state); -+ level = (u64)state.duty_cycle * pb->scale; -+ do_div(level, (u64)state.period); -+ -+ for (i = 0; i <= data->max_brightness; i++) { -+ if (data->levels[i] > level) { -+ bl->props.brightness = i; -+ break; -+ } -+ } -+ } - backlight_update_status(bl); - - platform_set_drvdata(pdev, bl); --- -Armbian - diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/media-gc2145-Galaxycore-camera-module-driver.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/media-gc2145-Galaxycore-camera-module-driver.patch index 644ed911c844..4a18ccd6599c 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/media-gc2145-Galaxycore-camera-module-driver.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.megous/media-gc2145-Galaxycore-camera-module-driver.patch @@ -1,4 +1,4 @@ -From 54a8d9a823a07010fcec9f5ea2f7d61916e486cb Mon Sep 17 00:00:00 2001 +From 7a72d750c8442792b6d06f9ab1db6922b3058c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= Date: Tue, 23 Jun 2020 19:51:18 +0200 Subject: media: gc2145: Galaxycore camera module driver @@ -14,10 +14,10 @@ Signed-off-by: Ondrej Jirman create mode 100644 drivers/media/i2c/gc2145.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index 43be07cc5b37..2b3b4635c2f0 100644 +index 0cc793fc7910..017d993a8c49 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig -@@ -711,6 +711,16 @@ config VIDEO_HM5065 +@@ -712,6 +712,16 @@ config VIDEO_HM5065 This is a V4L2 sensor-level driver for Himax HM5065 5 Mpixel camera. diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/media-hm5065-Add-subdev-driver-for-Himax-HM5065-camera-sensor.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/media-hm5065-Add-subdev-driver-for-Himax-HM5065-camera-sensor.patch index ac5c67ce85ad..7ce978a2b3b2 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/media-hm5065-Add-subdev-driver-for-Himax-HM5065-camera-sensor.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.megous/media-hm5065-Add-subdev-driver-for-Himax-HM5065-camera-sensor.patch @@ -1,4 +1,4 @@ -From 670d184d6fd97edcf502edddca9f0ad89ce7e9d3 Mon Sep 17 00:00:00 2001 +From 8f018a158998fbdac9ef062f37ece6f67df274f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= Date: Sat, 30 Sep 2017 02:39:48 +0200 Subject: media: hm5065: Add subdev driver for Himax HM5065 camera sensor @@ -21,10 +21,10 @@ Signed-off-by: Ondrej Jirman create mode 100644 drivers/media/i2c/hm5065.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index 8ba096b8ebca..e7da18f3da3c 100644 +index 85ecb2aeefdb..2be73870045c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig -@@ -701,6 +701,16 @@ config VIDEO_VGXY61 +@@ -702,6 +702,16 @@ config VIDEO_VGXY61 source "drivers/media/i2c/ccs/Kconfig" source "drivers/media/i2c/et8ek8/Kconfig" diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/pci-Workaround-ITS-timeouts-on-poweroff-reboot-on-Orange-Pi-5-P.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/pci-Workaround-ITS-timeouts-on-poweroff-reboot-on-Orange-Pi-5-P.patch index ba31528c296c..74caed7bc401 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/pci-Workaround-ITS-timeouts-on-poweroff-reboot-on-Orange-Pi-5-P.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.megous/pci-Workaround-ITS-timeouts-on-poweroff-reboot-on-Orange-Pi-5-P.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From f59cd1bb68125718616d4950187b9b6d43e82cd0 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Wed, 14 Jun 2023 00:48:21 +0200 Subject: pci: Workaround ITS timeouts on poweroff/reboot on Orange Pi 5 Plus @@ -15,10 +15,10 @@ Signed-off-by: Ondrej Jirman 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c -index 111111111111..222222222222 100644 +index 604c055f6078..53313c577176 100644 --- a/drivers/pci/pcie/portdrv.c +++ b/drivers/pci/pcie/portdrv.c -@@ -739,7 +739,7 @@ static void pcie_portdrv_shutdown(struct pci_dev *dev) +@@ -741,7 +741,7 @@ static void pcie_portdrv_shutdown(struct pci_dev *dev) pm_runtime_dont_use_autosuspend(&dev->dev); } @@ -28,5 +28,5 @@ index 111111111111..222222222222 100644 static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, -- -Armbian +2.35.3 diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch index 3f31550a2954..c44cde57167b 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch @@ -1,4 +1,4 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From 645bb870c8ecdd2f9bbddbbfe46dc2644c43ccc4 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Thu, 7 Sep 2023 14:07:26 +0200 Subject: usb: gadget: Fix dangling pointer in netdev private data @@ -13,16 +13,16 @@ issues. Signed-off-by: Ondrej Jirman --- - drivers/usb/gadget/function/f_ecm.c | 12 ++-- - drivers/usb/gadget/function/f_eem.c | 28 +++++----- - drivers/usb/gadget/function/f_ncm.c | 9 ++- - drivers/usb/gadget/function/f_rndis.c | 26 ++++----- - drivers/usb/gadget/function/f_subset.c | 18 ++++-- - drivers/usb/gadget/function/u_ether.c | 10 ++-- + drivers/usb/gadget/function/f_ecm.c | 12 ++++++----- + drivers/usb/gadget/function/f_eem.c | 28 +++++++++++++------------- + drivers/usb/gadget/function/f_ncm.c | 9 ++++++--- + drivers/usb/gadget/function/f_rndis.c | 26 ++++++++++++------------ + drivers/usb/gadget/function/f_subset.c | 18 +++++++++++------ + drivers/usb/gadget/function/u_ether.c | 10 ++++----- 6 files changed, 56 insertions(+), 47 deletions(-) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c -index 111111111111..222222222222 100644 +index 549efc84dd83..274d1461abb7 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -685,14 +685,12 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) @@ -42,7 +42,7 @@ index 111111111111..222222222222 100644 mutex_unlock(&ecm_opts->lock); if (status) return status; -@@ -907,7 +905,9 @@ static void ecm_free(struct usb_function *f) +@@ -913,7 +911,9 @@ static void ecm_free(struct usb_function *f) static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) { @@ -53,7 +53,7 @@ index 111111111111..222222222222 100644 DBG(c->cdev, "ecm unbind\n"); -@@ -920,6 +920,8 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) +@@ -926,6 +926,8 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); @@ -63,7 +63,7 @@ index 111111111111..222222222222 100644 static struct usb_function *ecm_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c -index 111111111111..222222222222 100644 +index 6de81ea17274..b1e1a26808dd 100644 --- a/drivers/usb/gadget/function/f_eem.c +++ b/drivers/usb/gadget/function/f_eem.c @@ -247,28 +247,23 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) @@ -120,7 +120,7 @@ index 111111111111..222222222222 100644 static struct usb_function *eem_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c -index 111111111111..222222222222 100644 +index 8e761249d672..49b41da779ed 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1454,14 +1454,13 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) @@ -159,7 +159,7 @@ index 111111111111..222222222222 100644 static struct usb_function *ncm_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c -index 111111111111..222222222222 100644 +index 7cec19d65fb5..c2138f17a1c4 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -658,7 +658,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) @@ -220,7 +220,7 @@ index 111111111111..222222222222 100644 static struct usb_function *rndis_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c -index 111111111111..222222222222 100644 +index ea3fdd842462..b595beb5f474 100644 --- a/drivers/usb/gadget/function/f_subset.c +++ b/drivers/usb/gadget/function/f_subset.c @@ -308,15 +308,16 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) @@ -261,7 +261,7 @@ index 111111111111..222222222222 100644 static struct usb_function *geth_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c -index 111111111111..222222222222 100644 +index f58590bf5e02..a522e9d43a3a 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -112,8 +112,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) @@ -303,5 +303,5 @@ index 111111111111..222222222222 100644 EXPORT_SYMBOL_GPL(gether_set_gadget); -- -Armbian +2.35.3 diff --git a/patch/kernel/archive/sunxi-6.12/patches.megous/usb-serial-option-add-reset_resume-callback-for-WWAN-devices.patch b/patch/kernel/archive/sunxi-6.12/patches.megous/usb-serial-option-add-reset_resume-callback-for-WWAN-devices.patch index 12a16a67c73e..63d681933729 100644 --- a/patch/kernel/archive/sunxi-6.12/patches.megous/usb-serial-option-add-reset_resume-callback-for-WWAN-devices.patch +++ b/patch/kernel/archive/sunxi-6.12/patches.megous/usb-serial-option-add-reset_resume-callback-for-WWAN-devices.patch @@ -1,4 +1,4 @@ -From 86bd1ff575fb7fa688b28e91b225ddcbc8e857d2 Mon Sep 17 00:00:00 2001 +From 4bbaab4b405d623fb5c390971387e1f2a4185820 Mon Sep 17 00:00:00 2001 From: Thomas Thorne Date: Tue, 20 Sep 2022 20:34:57 -0400 Subject: usb: serial: option: add 'reset_resume' callback for WWAN devices @@ -17,10 +17,10 @@ However the rest of the patch is not needed/already upstreamed. 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index 5cd26dac2069..f65c1d78a2cc 100644 +index 27879cc57536..4adc2f535ce4 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c -@@ -2471,6 +2471,7 @@ static struct usb_serial_driver option_1port_device = { +@@ -2474,6 +2474,7 @@ static struct usb_serial_driver option_1port_device = { #ifdef CONFIG_PM .suspend = usb_wwan_suspend, .resume = usb_wwan_resume, diff --git a/patch/kernel/archive/sunxi-6.12/series.armbian b/patch/kernel/archive/sunxi-6.12/series.armbian index 21623add249b..d66c71544881 100644 --- a/patch/kernel/archive/sunxi-6.12/series.armbian +++ b/patch/kernel/archive/sunxi-6.12/series.armbian @@ -173,6 +173,7 @@ patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-EMAC1.patch patches.armbian/arm64-dts-sun50i-h313-x96q-lpddr3.patch patches.armbian/Add-board-BananaPi-BPI-M4-Zero.patch + patches.armbian/BananaPi-BPI-M4-Zero-Enable-GPU-and-add-Audio-nodes.patch patches.armbian/Add-BananaPi-BPI-M4-Zero-pinctrl.patch patches.armbian/Add-BananaPi-BPI-M4-Zero-overlays.patch patches.armbian/Fix-ghost-touches-on-tsc2007-tft-screen.patch @@ -180,3 +181,4 @@ patches.armbian/BigTreeTech-CB1-dts-i2c-gpio-mode-adjustment-and-ws2812-rgb_val.patch patches.armbian/arm64-dts-sun50i-h616-Add-i2c3-pa-pwm-pins.patch patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch + patches.armbian/sun50i-h616-Add-the-missing-digital-audio-nodes.patch diff --git a/patch/kernel/archive/sunxi-6.12/series.conf b/patch/kernel/archive/sunxi-6.12/series.conf index 0957592c4cf5..c5bfdc5ff67f 100644 --- a/patch/kernel/archive/sunxi-6.12/series.conf +++ b/patch/kernel/archive/sunxi-6.12/series.conf @@ -419,6 +419,8 @@ patches.armbian/cb1-overlay.patch patches.armbian/Correct-perf-interrupt-source-number-as-referenced-in-the-Allwi.patch patches.armbian/Enable-DMA-support-for-the-Allwinner-A10-EMAC-which-already-exi.patch + patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch + patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch patches.armbian/arm-dts-sunxi-h3-h5.dtsi-add-i2s0-i2s1-pins.patch patches.armbian/arm-dts-sun5i-a13-olinuxino-micro-add-panel-lcd-olinuxino-4.3.patch patches.armbian/arm-dts-sun5i-a13-olinuxino-Add-panel-lcd-olinuxino-4.3-needed-.patch @@ -469,6 +471,7 @@ patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-EMAC1.patch patches.armbian/arm64-dts-sun50i-h313-x96q-lpddr3.patch patches.armbian/Add-board-BananaPi-BPI-M4-Zero.patch + patches.armbian/BananaPi-BPI-M4-Zero-Enable-GPU-and-add-Audio-nodes.patch patches.armbian/Add-BananaPi-BPI-M4-Zero-pinctrl.patch patches.armbian/Add-BananaPi-BPI-M4-Zero-overlays.patch patches.armbian/Fix-ghost-touches-on-tsc2007-tft-screen.patch @@ -476,3 +479,4 @@ patches.armbian/BigTreeTech-CB1-dts-i2c-gpio-mode-adjustment-and-ws2812-rgb_val.patch patches.armbian/arm64-dts-sun50i-h616-Add-i2c3-pa-pwm-pins.patch patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch + patches.armbian/sun50i-h616-Add-the-missing-digital-audio-nodes.patch diff --git a/patch/kernel/archive/sunxi-6.12/series.megous b/patch/kernel/archive/sunxi-6.12/series.megous index d8b4fe2a0352..ee4491ed87a8 100644 --- a/patch/kernel/archive/sunxi-6.12/series.megous +++ b/patch/kernel/archive/sunxi-6.12/series.megous @@ -186,10 +186,7 @@ patches.megous/drm-rockchip-dw-mipi-dsi-rockchip-Fix-ISP1-PHY-initialization.patch patches.megous/arm64-dts-rk3399-Add-dmc_opp_table.patch patches.megous/bluetooth-h5-Don-t-re-initialize-rtl8723cs-on-resume.patch - patches.megous/drm-sun4i-Mark-one-of-the-UI-planes-as-a-cursor-one.patch - patches.megous/drm-sun4i-Implement-gamma-correction.patch patches.megous/drm-panel-st7703-Fix-xbd599-timings-to-make-refresh-rate-exactl.patch - patches.megous/drm-sun4i-Support-taking-over-display-pipeline-state-from-p-boo.patch patches.megous/video-pwm_bl-Allow-to-change-lth_brightness-via-sysfs.patch patches.megous/clk-sunxi-ng-sun50i-a64-Switch-parent-of-MIPI-DSI-to-periph0-1x.patch patches.megous/drm-sun4i-tcon-Support-keeping-dclk-rate-upon-ancestor-clock-ch.patch @@ -250,5 +247,4 @@ patches.megous/Add-support-for-my-private-Sapomat-device.patch patches.megous/ARM-dts-sun8i-h3-orange-pi-one-Enable-all-gpio-header-UARTs.patch patches.megous/mtd-spi-nor-Add-Alliance-memory-support.patch - patches.megous/Add-README.md-with-information-and-u-boot-patches.patch patches.megous/Defconfigs-for-all-my-devices.patch diff --git a/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch b/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch index e3817995d77f..4aa753bfe713 100644 --- a/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch +++ b/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-overlay-Add-Overlays-for-sunxi.patch @@ -1569,7 +1569,7 @@ index 000000000000..4c104bf4a5f0 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c1 = "/soc@1c00000/i2c@1c2b000"; ++ i2c1 = "/soc/i2c@1c2b000"; + }; + }; + @@ -1597,7 +1597,7 @@ index 000000000000..1c2c3e9aca81 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c2 = "/soc@1c00000/i2c@1c2b400"; ++ i2c2 = "/soc/i2c@1c2b400"; + }; + }; + @@ -1834,9 +1834,9 @@ index 000000000000..ee4ff6f453d1 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -1897,9 +1897,9 @@ index 000000000000..eac4f1e2d244 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -1955,12 +1955,12 @@ index 000000000000..cad50d8a29a7 +/plugin/; + +/ { -+ compatible = "allwinner,sun7i-a20"; ++ compatible = "allwinner,sun4i-a10"; + + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; ++ spi0 = "/soc/spi@1c05000"; + }; + }; + @@ -1984,12 +1984,12 @@ index 000000000000..8c606d6b06a1 +/plugin/; + +/ { -+ compatible = "allwinner,sun7i-a20"; ++ compatible = "allwinner,sun4i-a10"; + + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi1 = "/soc@1c00000/spi@1c06000"; ++ spi1 = "/soc/spi@1c06000"; + }; + }; + @@ -2012,12 +2012,12 @@ index 000000000000..145f285588f8 +/plugin/; + +/ { -+ compatible = "allwinner,sun7i-a20"; ++ compatible = "allwinner,sun4i-a10"; + + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -2026,8 +2026,8 @@ index 000000000000..145f285588f8 + __overlay__ { + status = "okay"; + pinctrl-names = "default", "default"; -+ pinctrl-0 = <&spi2_pins_a>; -+ pinctrl-1 = <&spi2_cs0_pins_a>; ++ pinctrl-0 = <&spi2_pc_pins>; ++ pinctrl-1 = <&spi2_cs0_pc_pins>; + }; + }; +}; @@ -2046,7 +2046,7 @@ index 000000000000..89bb44d5aee0 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial2 = "/soc@1c00000/serial@1c28800"; ++ serial2 = "/soc/serial@1c28800"; + }; + }; + @@ -2089,7 +2089,7 @@ index 000000000000..f599d92082e4 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial3 = "/soc@1c00000/serial@1c28c00"; ++ serial3 = "/soc/serial@1c28c00"; + }; + }; + @@ -2142,7 +2142,7 @@ index 000000000000..b5e562a6477b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial4 = "/soc@1c00000/serial@1c29000"; ++ serial4 = "/soc/serial@1c29000"; + }; + }; + @@ -2185,7 +2185,7 @@ index 000000000000..12c3f9699b23 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial5 = "/soc@1c00000/serial@1c29400"; ++ serial5 = "/soc/serial@1c29400"; + }; + }; + @@ -2223,7 +2223,7 @@ index 000000000000..6be41d505509 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial6 = "/soc@1c00000/serial@1c29800"; ++ serial6 = "/soc/serial@1c29800"; + }; + }; + @@ -2261,7 +2261,7 @@ index 000000000000..967f6afbe7d3 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial7 = "/soc@1c00000/serial@1c29c00"; ++ serial7 = "/soc/serial@1c29c00"; + }; + }; + @@ -2407,7 +2407,7 @@ index 000000000000..444c32ca01d5 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c1 = "/soc@1c00000/i2c@1c2b000"; ++ i2c1 = "/soc/i2c@1c2b000"; + }; + }; + @@ -2435,7 +2435,7 @@ index 000000000000..7a30681ca287 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c2 = "/soc@1c00000/i2c@1c2b400"; ++ i2c2 = "/soc/i2c@1c2b400"; + }; + }; + @@ -2608,7 +2608,7 @@ index 000000000000..ad0685f8af18 +/plugin/; + +/ { -+ compatible = "allwinner,sun5i-a10"; ++ compatible = "allwinner,sun5i-a13"; + + fragment@0 { + target-path = "/aliases"; @@ -2793,7 +2793,7 @@ index 000000000000..6edad42bfcd7 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart0 = "/soc@1c00000/serial@1c28000"; ++ uart0 = "/soc/serial@1c28000"; + }; + }; + @@ -2831,7 +2831,7 @@ index 000000000000..675b701ed535 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart1 = "/soc@1c00000/serial@1c28400"; ++ uart1 = "/soc/serial@1c28400"; + }; + }; + @@ -2859,7 +2859,7 @@ index 000000000000..b3c4e3d7a0e2 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart2 = "/soc@1c00000/serial@1c28800"; ++ uart2 = "/soc/serial@1c28800"; + }; + }; + @@ -2887,7 +2887,7 @@ index 000000000000..15c25d0c5992 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ uart3 = "/soc@1c00000/serial@1c28c00"; ++ uart3 = "/soc/serial@1c28c00"; + }; + }; + @@ -3104,7 +3104,7 @@ index 000000000000..c5f6e9732d3a + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c1 = "/soc@1c00000/i2c@1c2b000"; ++ i2c1 = "/soc/i2c@1c2b000"; + }; + }; + @@ -3132,7 +3132,7 @@ index 000000000000..fa93d1ed9b72 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c2 = "/soc@1c00000/i2c@1c2b400"; ++ i2c2 = "/soc/i2c@1c2b400"; + }; + }; + @@ -3160,7 +3160,7 @@ index 000000000000..945795c338e8 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c3 = "/soc@1c00000/i2c@1c2b800"; ++ i2c3 = "/soc/i2c@1c2b800"; + }; + }; + @@ -3188,7 +3188,7 @@ index 000000000000..4fcf08c2469b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ i2c4 = "/soc@1c00000/i2c@1c2c000"; ++ i2c4 = "/soc/i2c@1c2c000"; + }; + }; + @@ -3543,9 +3543,9 @@ index 000000000000..b91097eca5b6 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -3606,9 +3606,9 @@ index 000000000000..341fe3229ffc + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; -+ spi1 = "/soc@1c00000/spi@1c06000"; -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi0 = "/soc/spi@1c05000"; ++ spi1 = "/soc/spi@1c06000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -3669,7 +3669,7 @@ index 000000000000..cad50d8a29a7 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi0 = "/soc@1c00000/spi@1c05000"; ++ spi0 = "/soc/spi@1c05000"; + }; + }; + @@ -3698,7 +3698,7 @@ index 000000000000..f0218eb9f76b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi1 = "/soc@1c00000/spi@1c06000"; ++ spi1 = "/soc/spi@1c06000"; + }; + }; + @@ -3726,7 +3726,7 @@ index 000000000000..effba42b48bd + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ spi2 = "/soc@1c00000/spi@1c17000"; ++ spi2 = "/soc/spi@1c17000"; + }; + }; + @@ -3735,8 +3735,8 @@ index 000000000000..effba42b48bd + __overlay__ { + status = "okay"; + pinctrl-names = "default", "default"; -+ pinctrl-0 = <&spi2_pb_pins>; -+ pinctrl-1 = <&spi2_pb_cs0_pin>; ++ pinctrl-0 = <&spi2_pc_pins>; ++ pinctrl-1 = <&spi2_cs0_pc_pin>; + }; + }; +}; @@ -3755,7 +3755,7 @@ index 000000000000..79d1dca7a311 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial2 = "/soc@1c00000/serial@1c28800"; ++ serial2 = "/soc/serial@1c28800"; + }; + }; + @@ -3793,7 +3793,7 @@ index 000000000000..703acbcf377b + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial3 = "/soc@1c00000/serial@1c28c00"; ++ serial3 = "/soc/serial@1c28c00"; + }; + }; + @@ -3841,7 +3841,7 @@ index 000000000000..19180341a67f + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial4 = "/soc@1c00000/serial@1c29000"; ++ serial4 = "/soc/serial@1c29000"; + }; + }; + @@ -3869,7 +3869,7 @@ index 000000000000..a1369eee2917 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial5 = "/soc@1c00000/serial@1c29400"; ++ serial5 = "/soc/serial@1c29400"; + }; + }; + @@ -3897,7 +3897,7 @@ index 000000000000..fb9efe2a9475 + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial6 = "/soc@1c00000/serial@1c29800"; ++ serial6 = "/soc/serial@1c29800"; + }; + }; + @@ -3925,7 +3925,7 @@ index 000000000000..bbdca3ec67ed + fragment@0 { + target-path = "/aliases"; + __overlay__ { -+ serial7 = "/soc@1c00000/serial@1c29c00"; ++ serial7 = "/soc/serial@1c29c00"; + }; + }; + diff --git a/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch b/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch new file mode 100644 index 000000000000..1465fc506231 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ryzer58 +Date: Thu, 22 May 2025 23:29:14 +0000 +Subject: Re-introduce spi overlays for each bus so that pins are muxed corectly into SPI mode + +Signed-off-by: Ryzer58 +--- + arch/arm/boot/dts/allwinner/overlay/Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/boot/dts/allwinner/overlay/Makefile b/arch/arm/boot/dts/allwinner/overlay/Makefile +index 23ecb62e2478..44547b7d6afd 100644 +--- a/arch/arm/boot/dts/allwinner/overlay/Makefile ++++ b/arch/arm/boot/dts/allwinner/overlay/Makefile +@@ -6,10 +6,13 @@ dtb-$(CONFIG_MACH_SUN4I) += \ + sun4i-a10-i2c2.dtbo \ + sun4i-a10-nand.dtbo \ + sun4i-a10-pps-gpio.dtbo \ + sun4i-a10-pwm.dtbo \ + sun4i-a10-spdif-out.dtbo \ ++ sun4i-a10-spi0.dtbo \ ++ sun4i-a10-spi1.dtbo \ ++ sun4i-a10-spi2.dtbo \ + sun4i-a10-spi-jedec-nor.dtbo \ + sun4i-a10-spi-spidev.dtbo \ + sun4i-a10-uart2.dtbo \ + sun4i-a10-uart3.dtbo \ + sun4i-a10-uart4.dtbo \ +-- +Created with Armbian build tools https://github.com/armbian/build + diff --git a/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch b/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch new file mode 100644 index 000000000000..d567786121e5 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.14/patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ryzer58 +Date: Thu, 22 May 2025 23:40:08 +0000 +Subject: Re-introduce spi overlays for each bus so that pins are muxed corectly into SPI mode + + +Signed-off-by: Ryzer58 +--- + arch/arm/boot/dts/allwinner/overlay/Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/boot/dts/allwinner/overlay/Makefile b/arch/arm/boot/dts/allwinner/overlay/Makefile +index 44547b7d6afd..01a91adea88b 100644 +--- a/arch/arm/boot/dts/allwinner/overlay/Makefile ++++ b/arch/arm/boot/dts/allwinner/overlay/Makefile +@@ -47,10 +47,13 @@ dtb-$(CONFIG_MACH_SUN7I) += \ + sun7i-a20-mmc2.dtbo \ + sun7i-a20-nand.dtbo \ + sun7i-a20-pps-gpio.dtbo \ + sun7i-a20-pwm.dtbo \ + sun7i-a20-spdif-out.dtbo \ ++ sun7i-a20-spi0.dtbo \ ++ sun7i-a20-spi1.dtbo \ ++ sun7i-a20-spi2.dtbo \ + sun7i-a20-spi-add-cs1.dtbo \ + sun7i-a20-spi-jedec-nor.dtbo \ + sun7i-a20-spi-spidev.dtbo \ + sun7i-a20-uart2.dtbo \ + sun7i-a20-uart3.dtbo \ +-- +Created with Armbian build tools https://github.com/armbian/build + diff --git a/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch b/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch index 90f969f07bc8..393e43c1826e 100644 --- a/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch +++ b/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-gpu-drm-panel-simple-Add-compability-olinuxino-lcd.patch @@ -1,4 +1,4 @@ -From 3a3f2d1162880ac679dc6b3aaefa2b161ae694de Mon Sep 17 00:00:00 2001 +From 7209d2722c06641535136be81944a8f8304f344e Mon Sep 17 00:00:00 2001 From: The-going <48602507+The-going@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:34:55 +0300 Subject: drv:gpu:drm: panel-simple Add compability olinuxino lcd @@ -8,10 +8,10 @@ Subject: drv:gpu:drm: panel-simple Add compability olinuxino lcd 1 file changed, 121 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c -index 9b2f128fd309..ff15e05c85b4 100644 +index cf9ab2d1f1d2..4ea9a1fe50de 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c -@@ -3550,6 +3550,42 @@ static const struct panel_desc okaya_rs800480t_7x0gp = { +@@ -3551,6 +3551,42 @@ static const struct panel_desc okaya_rs800480t_7x0gp = { .bus_format = MEDIA_BUS_FMT_RGB666_1X18, }; @@ -54,7 +54,7 @@ index 9b2f128fd309..ff15e05c85b4 100644 static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = { .clock = 9000, .hdisplay = 480, -@@ -3562,8 +3598,8 @@ static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = { +@@ -3563,8 +3599,8 @@ static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = { .vtotal = 272 + 8 + 5 + 3, }; @@ -65,7 +65,7 @@ index 9b2f128fd309..ff15e05c85b4 100644 .num_modes = 1, .size = { .width = 95, -@@ -3605,6 +3641,72 @@ static const struct panel_desc ontat_kd50g21_40nt_a1 = { +@@ -3606,6 +3642,72 @@ static const struct panel_desc ontat_kd50g21_40nt_a1 = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; @@ -138,7 +138,7 @@ index 9b2f128fd309..ff15e05c85b4 100644 /* * 800x480 CVT. The panel appears to be quite accepting, at least as far as * pixel clocks, but this is the timing that was being used in the Adafruit -@@ -5066,8 +5168,23 @@ static const struct of_device_id platform_of_match[] = { +@@ -5067,8 +5169,23 @@ static const struct of_device_id platform_of_match[] = { .compatible = "okaya,rs800480t-7x0gp", .data = &okaya_rs800480t_7x0gp, }, { diff --git a/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch b/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch index eaa5c24e3ce4..d495f3374866 100644 --- a/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch +++ b/patch/kernel/archive/sunxi-6.14/patches.armbian/drv-usb-gadget-composite-rename-gadget-serial-console-manufactu.patch @@ -1,4 +1,4 @@ -From 1bd66ae2c914290b56e258b62b798e29a5af2a77 Mon Sep 17 00:00:00 2001 +From 921577ba5d5e7b5fac08ba0bd37960d013b3677e Mon Sep 17 00:00:00 2001 From: The-going <48602507+The-going@users.noreply.github.com> Date: Wed, 2 Feb 2022 20:08:50 +0300 Subject: drv:usb:gadget:composite rename gadget serial console manufacturer @@ -10,10 +10,10 @@ to the Armbian brand. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c -index 869ad99afb48..9f111be98fd1 100644 +index 8dbc132a505e..0a6e056c2749 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c -@@ -2777,7 +2777,7 @@ EXPORT_SYMBOL_GPL(usb_composite_setup_continue); +@@ -2775,7 +2775,7 @@ EXPORT_SYMBOL_GPL(usb_composite_setup_continue); static char *composite_default_mfr(struct usb_gadget *gadget) { diff --git a/patch/kernel/archive/sunxi-6.14/patches.armbian/sun50i-h616-Add-the-missing-digital-audio-node.patch b/patch/kernel/archive/sunxi-6.14/patches.armbian/sun50i-h616-Add-the-missing-digital-audio-node.patch new file mode 100644 index 000000000000..a70d47c99fe0 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.14/patches.armbian/sun50i-h616-Add-the-missing-digital-audio-node.patch @@ -0,0 +1,59 @@ +From 9a7f38264bbc353a097cf1ddd56f86681d2c8475 Mon Sep 17 00:00:00 2001 +From: The-going <48602507+The-going@users.noreply.github.com> +Date: Mon, 26 May 2025 17:04:56 +0300 +Subject: [PATCH] sun50i-h616: Add the missing digital audio node + +--- + arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi | 11 +++++++++++ + .../dts/allwinner/sun50i-h618-bananapi-m4-berry.dts | 8 +++----- + 2 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +index 4b1e73697887..f6bf478aa3e4 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +@@ -1076,6 +1076,17 @@ ahub_dam_plat:ahub_dam_plat@5097000 { + status = "disabled"; + }; + ++ ahub_dam_mach:ahub_dam_mach { ++ compatible = "allwinner,sunxi-snd-mach"; ++ soundcard-mach,name = "ahubdam"; ++ status = "disabled"; ++ soundcard-mach,cpu { ++ sound-dai = <&ahub_dam_plat>; ++ }; ++ soundcard-mach,codec { ++ }; ++ }; ++ + ahub1_plat:ahub1_plat { + #sound-dai-cells = <0>; + compatible = "allwinner,sunxi-snd-plat-ahub"; +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts +index 29869f39de97..74012eec9982 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-bananapi-m4-berry.dts +@@ -290,16 +290,14 @@ &ahub_dam_plat { + status = "okay"; + }; + +-&ahub1_plat { ++&ahub_dam_mach { + status = "okay"; + }; + +-&ahub1_mach { ++&ahub1_plat { + status = "okay"; + }; + +-/* +-&ahub_i2s2 { ++&ahub1_mach { + status = "okay"; + }; +-*/ +-- +2.35.3 + diff --git a/patch/kernel/archive/sunxi-6.14/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch b/patch/kernel/archive/sunxi-6.14/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch index f5bbec78f5e2..33d875602f7a 100644 --- a/patch/kernel/archive/sunxi-6.14/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch +++ b/patch/kernel/archive/sunxi-6.14/patches.megous/ASoC-ec25-New-codec-driver-for-the-EC25-modem.patch @@ -1,4 +1,4 @@ -From 1fa825de245c820af4b50883f14eed193a680a5e Mon Sep 17 00:00:00 2001 +From c177a5ac1125f4c9a29db6884ac3f4d081cf1bbb Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 25 Sep 2020 21:42:52 -0500 Subject: ASoC: ec25: New codec driver for the EC25 modem @@ -16,10 +16,10 @@ Signed-off-by: Samuel Holland create mode 100644 sound/soc/codecs/ec25.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index ee35f3aa5521..6d67a9fc5304 100644 +index 0138cfabbb03..211e77d7d64f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -1148,6 +1148,9 @@ config SND_SOC_HDMI_CODEC +@@ -1147,6 +1147,9 @@ config SND_SOC_HDMI_CODEC select SND_PCM_IEC958 select HDMI diff --git a/patch/kernel/archive/sunxi-6.14/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch b/patch/kernel/archive/sunxi-6.14/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch index ea0cf34ca45a..ab7a192b0131 100644 --- a/patch/kernel/archive/sunxi-6.14/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch +++ b/patch/kernel/archive/sunxi-6.14/patches.megous/usb-gadget-Fix-dangling-pointer-in-netdev-private-data.patch @@ -1,4 +1,4 @@ -From f2dc4bc534baf1d2cf7f43dbf040601e1542f9c5 Mon Sep 17 00:00:00 2001 +From b5e1f014248677c77d0ba5a410b27a215fa067ac Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Thu, 7 Sep 2023 14:07:26 +0200 Subject: usb: gadget: Fix dangling pointer in netdev private data @@ -22,7 +22,7 @@ Signed-off-by: Ondrej Jirman 6 files changed, 56 insertions(+), 47 deletions(-) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c -index 80841de845b0..4758994b5f26 100644 +index 027226325039..70de3bfeaa6c 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -685,14 +685,12 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) @@ -42,7 +42,7 @@ index 80841de845b0..4758994b5f26 100644 mutex_unlock(&ecm_opts->lock); if (status) return status; -@@ -907,7 +905,9 @@ static void ecm_free(struct usb_function *f) +@@ -913,7 +911,9 @@ static void ecm_free(struct usb_function *f) static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) { @@ -53,7 +53,7 @@ index 80841de845b0..4758994b5f26 100644 DBG(c->cdev, "ecm unbind\n"); -@@ -920,6 +920,8 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) +@@ -926,6 +926,8 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); diff --git a/patch/kernel/archive/sunxi-6.14/patches.megous/video-pwm_bl-Allow-to-change-lth_brightness-via-sysfs.patch b/patch/kernel/archive/sunxi-6.14/patches.megous/video-pwm_bl-Allow-to-change-lth_brightness-via-sysfs.patch index 8923f26425a9..214b9378cd4c 100644 --- a/patch/kernel/archive/sunxi-6.14/patches.megous/video-pwm_bl-Allow-to-change-lth_brightness-via-sysfs.patch +++ b/patch/kernel/archive/sunxi-6.14/patches.megous/video-pwm_bl-Allow-to-change-lth_brightness-via-sysfs.patch @@ -1,4 +1,4 @@ -From 9f67fcbe0e78e9b63df2e687b0eea50633f9e79e Mon Sep 17 00:00:00 2001 +From 472bb85c925dd230c6e5e9123b739fd6901722c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= Date: Mon, 7 Jun 2021 20:27:07 +0200 Subject: video: pwm_bl: Allow to change lth_brightness via sysfs @@ -21,8 +21,8 @@ Then make sure to restore this value after each boot by writing it to Signed-off-by: Ondrej Jirman --- - drivers/video/backlight/pwm_bl.c | 72 +++++++++++++++++++++++++++++++- - 1 file changed, 70 insertions(+), 2 deletions(-) + drivers/video/backlight/pwm_bl.c | 97 +++++++++++++++++++++++++++++++- + 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 237d3d3f3bb1..9f96bdd82a87 100644 diff --git a/patch/kernel/archive/sunxi-6.14/series.armbian b/patch/kernel/archive/sunxi-6.14/series.armbian index e6855667a510..cf79327959a3 100644 --- a/patch/kernel/archive/sunxi-6.14/series.armbian +++ b/patch/kernel/archive/sunxi-6.14/series.armbian @@ -181,3 +181,4 @@ patches.armbian/BigTreeTech-CB1-dts-i2c-gpio-mode-adjustment-and-ws2812-rgb_val.patch patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch patches.armbian/h616-add-keys.patch + patches.armbian/sun50i-h616-Add-the-missing-digital-audio-node.patch diff --git a/patch/kernel/archive/sunxi-6.14/series.conf b/patch/kernel/archive/sunxi-6.14/series.conf index 25d29f18fa5f..c46a5178aa63 100644 --- a/patch/kernel/archive/sunxi-6.14/series.conf +++ b/patch/kernel/archive/sunxi-6.14/series.conf @@ -424,6 +424,8 @@ patches.armbian/Move-sun50i-h6-pwm-settings-to-its-own-overlay.patch patches.armbian/Compile-the-pwm-overlay.patch patches.armbian/cb1-overlay.patch + patches.armbian/arm-dts-sun4i-a10-reapply-spi-overlays.patch + patches.armbian/arm-dts-sun7i-a20-reapply-spi-overlays.patch patches.armbian/Correct-perf-interrupt-source-number-as-referenced-in-the-Allwi.patch patches.armbian/Enable-DMA-support-for-the-Allwinner-A10-EMAC-which-already-exi.patch patches.armbian/arm-dts-sunxi-h3-h5.dtsi-add-i2s0-i2s1-pins.patch @@ -484,3 +486,4 @@ patches.armbian/BigTreeTech-CB1-dts-i2c-gpio-mode-adjustment-and-ws2812-rgb_val.patch patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch patches.armbian/h616-add-keys.patch + patches.armbian/sun50i-h616-Add-the-missing-digital-audio-node.patch diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM-dts-sun8i-nanopiduo2-Use-key-0-as-power-button.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM-dts-sun8i-nanopiduo2-Use-key-0-as-power-button.patch new file mode 100644 index 000000000000..efa313c9425a --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM-dts-sun8i-nanopiduo2-Use-key-0-as-power-button.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gunjan Gupta +Date: Mon, 26 Jun 2023 13:29:46 +0000 +Subject: ARM: dts: sun8i: nanopiduo2: Use key-0 as power button + +The onboard button key-0 was not marked as power button. This meant +that once the board was suspended, there was no way to bring it back +to life. Mark key-0 as power button so that it can be used to bring +the board back to life +--- + arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts b/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts +index 111111111111..222222222222 100644 +--- a/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts ++++ b/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts +@@ -42,8 +42,9 @@ gpio-keys { + + key-0 { + label = "k1"; +- linux,code = ; ++ linux,code = ; + gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; /* PL3 */ ++ wakeup-source; + }; + }; + +-- +Armbian + diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM-dts-sun8i-nanopiduo2-enable-ethernet.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM-dts-sun8i-nanopiduo2-enable-ethernet.patch new file mode 100644 index 000000000000..c60ef86c06e1 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM-dts-sun8i-nanopiduo2-enable-ethernet.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gunjan Gupta +Date: Mon, 26 Jun 2023 13:53:14 +0000 +Subject: ARM: dts: sun8i: nanopiduo2: enable ethernet + +NanoPi Duo2 has pinout for ethernet. Lets enable the same in dts +--- + arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts b/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts +index 111111111111..222222222222 100644 +--- a/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts ++++ b/arch/arm/boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts +@@ -105,6 +105,13 @@ &ehci0 { + status = "okay"; + }; + ++&emac { ++ phy-handle = <&int_mii_phy>; ++ phy-mode = "mii"; ++ allwinner,leds-active-low; ++ status = "okay"; ++}; ++ + &mmc0 { + bus-width = <4>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ +-- +Armbian + diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-EMAC1.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-EMAC1.patch new file mode 100644 index 000000000000..3d9c87c93025 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-EMAC1.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JohnTheCoolingFan +Date: Thu, 13 Jun 2024 11:50:55 +0000 +Subject: ARM64: dts: sun50i-h616: BigTreeTech CB1: Enable EMAC1 + +Signed-off-by: JohnTheCoolingFan +--- + arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi | 18 ++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi +index 111111111111..222222222222 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi +@@ -149,6 +149,24 @@ &cpu0 { + cpu-supply = <®_dcdc2>; + }; + ++&emac1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rmii_pins>; ++ phy-mode = "rmii"; ++ phy-handle = <&rmii_phy>; ++ phy-supply = <®_dldo1>; ++ allwinner,rx-delay-ps = <3100>; ++ allwinner,tx-delay-ps = <700>; ++ status = "okay"; ++}; ++ ++&mdio1 { ++ rmii_phy: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ }; ++}; ++ + &mmc0 { + vmmc-supply = <®_dldo1>; + broken-cd; +-- +Armbian + diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-HDMI.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-HDMI.patch new file mode 100644 index 000000000000..895e4563401a --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/ARM64-dts-sun50i-h616-BigTreeTech-CB1-Enable-HDMI.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JohnTheCoolingFan +Date: Thu, 13 Jun 2024 11:07:35 +0000 +Subject: ARM64: dts: sun50i-h616: BigTreeTech CB1: Enable HDMI + +Signed-off-by: JohnTheCoolingFan +--- + arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi | 26 ++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi +index 111111111111..222222222222 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi +@@ -26,6 +26,17 @@ chosen { + stdout-path = "serial0:115200n8"; + }; + ++ connector { ++ compatible = "hdmi-connector"; ++ type = "d"; ++ ++ port { ++ hdmi_con_in: endpoint { ++ remote-endpoint = <&hdmi_out_con>; ++ }; ++ }; ++ }; ++ + leds { + compatible = "gpio-leds"; + +@@ -262,6 +273,21 @@ reg_dldo1: dldo1 { + }; + }; + ++&de { ++ status = "okay"; ++}; ++ ++&hdmi { ++ hvcc-supply = <®_aldo1>; ++ status = "okay"; ++}; ++ ++&hdmi_out { ++ hdmi_out_con: endpoint { ++ remote-endpoint = <&hdmi_con_in>; ++ }; ++}; ++ + &cpu0 { + cpu-supply = <®_dcdc2>; + status = "okay"; +-- +Armbian + diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/ASoC-AC200-Initial-driver.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/ASoC-AC200-Initial-driver.patch new file mode 100644 index 000000000000..14ba0334bf4d --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/ASoC-AC200-Initial-driver.patch @@ -0,0 +1,842 @@ +From 054078aaba679a23051906fb1168e8201fe1ea7d Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Thu, 1 Sep 2022 17:36:53 +0200 +Subject: ASoC: AC200: Initial driver + +Signed-off-by: Jernej Skrabec +--- + sound/soc/codecs/Kconfig | 10 + + sound/soc/codecs/Makefile | 2 + + sound/soc/codecs/ac200.c | 772 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 784 insertions(+) + create mode 100644 sound/soc/codecs/ac200.c + +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index b1133b34efbd..b7b9788eb2a8 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -16,6 +16,7 @@ config SND_SOC_ALL_CODECS + depends on COMPILE_TEST + imply SND_SOC_88PM860X + imply SND_SOC_AB8500_CODEC ++ imply SND_SOC_AC200_CODEC + imply SND_SOC_AC97_CODEC + imply SND_SOC_AD1836 + imply SND_SOC_AD193X_SPI +@@ -418,6 +419,15 @@ config SND_SOC_AB8500_CODEC + tristate + depends on ABX500_CORE + ++config SND_SOC_AC200_CODEC ++ tristate "AC200 Codec" ++ depends on MFD_AC200 ++ help ++ Enable support for X-Powers AC200 analog audio codec. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called snd-soc-ac200. ++ + config SND_SOC_AC97_CODEC + tristate "Build generic ASoC AC97 CODEC driver" + select SND_AC97_CODEC +diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile +index 0f4d541fc619..d5a84598ee1b 100644 +--- a/sound/soc/codecs/Makefile ++++ b/sound/soc/codecs/Makefile +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + snd-soc-88pm860x-y := 88pm860x-codec.o + snd-soc-ab8500-codec-y := ab8500-codec.o ++snd-soc-ac200-y := ac200.o + snd-soc-ac97-y := ac97.o + snd-soc-ad1836-y := ad1836.o + snd-soc-ad193x-y := ad193x.o +@@ -419,6 +420,7 @@ snd-soc-simple-mux-y := simple-mux.o + + obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o + obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o ++obj-$(CONFIG_SND_SOC_AC200_CODEC) += snd-soc-ac200.o + obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o + obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o + obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o +diff --git a/sound/soc/codecs/ac200.c b/sound/soc/codecs/ac200.c +new file mode 100644 +index 000000000000..662de230dc83 +--- /dev/null ++++ b/sound/soc/codecs/ac200.c +@@ -0,0 +1,772 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * X-Powers AC200 Codec Driver ++ * ++ * Copyright (C) 2022 Jernej Skrabec ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define AC200_CODEC_RATES (SNDRV_PCM_RATE_8000 | \ ++ SNDRV_PCM_RATE_11025 | \ ++ SNDRV_PCM_RATE_16000 | \ ++ SNDRV_PCM_RATE_22050 | \ ++ SNDRV_PCM_RATE_32000 | \ ++ SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_48000 | \ ++ SNDRV_PCM_RATE_96000 | \ ++ SNDRV_PCM_RATE_192000 | \ ++ SNDRV_PCM_RATE_KNOT) ++ ++#define AC200_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ ++ SNDRV_PCM_FMTBIT_S16_LE | \ ++ SNDRV_PCM_FMTBIT_S20_LE | \ ++ SNDRV_PCM_FMTBIT_S24_LE | \ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++#define AC200_SYS_AUDIO_CTL0 0x0010 ++#define AC200_SYS_AUDIO_CTL0_MCLK_GATING BIT(1) ++#define AC200_SYS_AUDIO_CTL0_RST_INVALID BIT(0) ++#define AC200_SYS_AUDIO_CTL1 0x0012 ++#define AC200_SYS_AUDIO_CTL1_I2S_IO_EN BIT(0) ++ ++#define AC200_SYS_CLK_CTL 0x2000 ++#define AC200_SYS_CLK_CTL_I2S 15 ++#define AC200_SYS_CLK_CTL_ADC 3 ++#define AC200_SYS_CLK_CTL_DAC 2 ++#define AC200_SYS_MOD_RST 0x2002 ++#define AC200_SYS_MOD_RST_I2S 15 ++#define AC200_SYS_MOD_RST_ADC 3 ++#define AC200_SYS_MOD_RST_DAC 2 ++#define AC200_SYS_SR_CTL 0x2004 ++#define AC200_SYS_SR_CTL_SR_MASK GENMASK(3, 0) ++#define AC200_SYS_SR_CTL_SR(x) (x) ++#define AC200_I2S_CTL 0x2100 ++#define AC200_I2S_CTL_SDO_EN 3 ++#define AC200_I2S_CTL_TX_EN 2 ++#define AC200_I2S_CTL_RX_EN 1 ++#define AC200_I2S_CTL_GEN 0 ++#define AC200_I2S_CLK 0x2102 ++#define AC200_I2S_CLK_BCLK_OUT BIT(15) ++#define AC200_I2S_CLK_LRCK_OUT BIT(14) ++#define AC200_I2S_CLK_BCLKDIV_MASK GENMASK(13, 10) ++#define AC200_I2S_CLK_BCLKDIV(x) ((x) << 10) ++#define AC200_I2S_CLK_LRCK_MASK GENMASK(9, 0) ++#define AC200_I2S_CLK_LRCK(x) ((x) - 1) ++#define AC200_I2S_FMT0 0x2104 ++#define AC200_I2S_FMT0_MODE_MASK GENMASK(15, 14) ++#define AC200_I2S_FMT0_MODE(x) ((x) << 14) ++#define AC200_I2S_FMT0_MODE_PCM 0 ++#define AC200_I2S_FMT0_MODE_LEFT 1 ++#define AC200_I2S_FMT0_MODE_RIGHT 2 ++#define AC200_I2S_FMT0_TX_OFFSET_MASK GENMASK(11, 10) ++#define AC200_I2S_FMT0_TX_OFFSET(x) ((x) << 10) ++#define AC200_I2S_FMT0_RX_OFFSET_MASK GENMASK(9, 8) ++#define AC200_I2S_FMT0_RX_OFFSET(x) ((x) << 8) ++#define AC200_I2S_FMT0_SR_MASK GENMASK(6, 4) ++#define AC200_I2S_FMT0_SR(x) ((x) << 4) ++#define AC200_I2S_FMT0_SW_MASK GENMASK(3, 1) ++#define AC200_I2S_FMT0_SW(x) ((x) << 1) ++#define AC200_I2S_FMT1 0x2108 ++#define AC200_I2S_FMT1_BCLK_POL_INVERT BIT(15) ++#define AC200_I2S_FMT1_LRCK_POL_INVERT BIT(14) ++#define AC200_I2S_MIX_SRC 0x2114 ++#define AC200_I2S_MIX_SRC_LMIX_DAC 13 ++#define AC200_I2S_MIX_SRC_LMIX_ADC 12 ++#define AC200_I2S_MIX_SRC_RMIX_DAC 9 ++#define AC200_I2S_MIX_SRC_RMIX_ADC 8 ++#define AC200_I2S_MIX_GAIN 0x2116 ++#define AC200_I2S_MIX_GAIN_LMIX_DAC 13 ++#define AC200_I2S_MIX_GAIN_LMIX_ADC 12 ++#define AC200_I2S_MIX_GAIN_RMIX_DAC 9 ++#define AC200_I2S_MIX_GAIN_RMIX_ADC 8 ++#define AC200_I2S_DAC_VOL 0x2118 ++#define AC200_I2S_DAC_VOL_LEFT 8 ++#define AC200_I2S_DAC_VOL_RIGHT 0 ++#define AC200_I2S_ADC_VOL 0x211A ++#define AC200_I2S_ADC_VOL_LEFT 8 ++#define AC200_I2S_ADC_VOL_RIGHT 0 ++#define AC200_DAC_CTL 0x2200 ++#define AC200_DAC_CTL_DAC_EN 15 ++#define AC200_DAC_MIX_SRC 0x2202 ++#define AC200_DAC_MIX_SRC_LMIX_DAC 13 ++#define AC200_DAC_MIX_SRC_LMIX_ADC 12 ++#define AC200_DAC_MIX_SRC_RMIX_DAC 9 ++#define AC200_DAC_MIX_SRC_RMIX_ADC 8 ++#define AC200_DAC_MIX_GAIN 0x2204 ++#define AC200_DAC_MIX_GAIN_LMIX_DAC 13 ++#define AC200_DAC_MIX_GAIN_LMIX_ADC 12 ++#define AC200_DAC_MIX_GAIN_RMIX_DAC 9 ++#define AC200_DAC_MIX_GAIN_RMIX_ADC 8 ++#define AC200_OUT_MIX_CTL 0x2220 ++#define AC200_OUT_MIX_CTL_RDAC_EN 15 ++#define AC200_OUT_MIX_CTL_LDAC_EN 14 ++#define AC200_OUT_MIX_CTL_RMIX_EN 13 ++#define AC200_OUT_MIX_CTL_LMIX_EN 12 ++#define AC200_OUT_MIX_CTL_MIC1_VOL 4 ++#define AC200_OUT_MIX_CTL_MIC2_VOL 0 ++#define AC200_OUT_MIX_SRC 0x2222 ++#define AC200_OUT_MIX_SRC_RMIX_MIC1 14 ++#define AC200_OUT_MIX_SRC_RMIX_MIC2 13 ++#define AC200_OUT_MIX_SRC_RMIX_RDAC 9 ++#define AC200_OUT_MIX_SRC_RMIX_LDAC 8 ++#define AC200_OUT_MIX_SRC_LMIX_MIC1 6 ++#define AC200_OUT_MIX_SRC_LMIX_MIC2 5 ++#define AC200_OUT_MIX_SRC_LMIX_RDAC 1 ++#define AC200_OUT_MIX_SRC_LMIX_LDAC 0 ++#define AC200_LINEOUT_CTL 0x2224 ++#define AC200_LINEOUT_CTL_EN 15 ++#define AC200_LINEOUT_CTL_LEN 14 ++#define AC200_LINEOUT_CTL_REN 13 ++#define AC200_LINEOUT_CTL_LMONO 12 ++#define AC200_LINEOUT_CTL_RMONO 11 ++#define AC200_LINEOUT_CTL_VOL 0 ++#define AC200_ADC_CTL 0x2300 ++#define AC200_ADC_CTL_ADC_EN 15 ++#define AC200_MBIAS_CTL 0x2310 ++#define AC200_MBIAS_CTL_MBIAS_EN 15 ++#define AC200_MBIAS_CTL_ADDA_BIAS_EN 3 ++#define AC200_ADC_MIC_CTL 0x2320 ++#define AC200_ADC_MIC_CTL_RADC_EN 15 ++#define AC200_ADC_MIC_CTL_LADC_EN 14 ++#define AC200_ADC_MIC_CTL_ADC_VOL 8 ++#define AC200_ADC_MIC_CTL_MIC1_GAIN_EN 7 ++#define AC200_ADC_MIC_CTL_MIC1_BOOST 4 ++#define AC200_ADC_MIC_CTL_MIC2_GAIN_EN 3 ++#define AC200_ADC_MIC_CTL_MIC2_BOOST 0 ++#define AC200_ADC_MIX_SRC 0x2322 ++#define AC200_ADC_MIX_SRC_RMIX_MIC1 14 ++#define AC200_ADC_MIX_SRC_RMIX_MIC2 13 ++#define AC200_ADC_MIX_SRC_RMIX_RMIX 9 ++#define AC200_ADC_MIX_SRC_RMIX_LMIX 8 ++#define AC200_ADC_MIX_SRC_LMIX_MIC1 6 ++#define AC200_ADC_MIX_SRC_LMIX_MIC2 5 ++#define AC200_ADC_MIX_SRC_LMIX_LMIX 1 ++#define AC200_ADC_MIX_SRC_LMIX_RMIX 0 ++ ++struct ac200_codec { ++ struct regmap *regmap; ++ unsigned int format; ++}; ++ ++struct ac200_map { ++ int match; ++ int value; ++}; ++ ++static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mixer_scale, -600, 600, 0); ++static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(gain_scale, -450, 150, 0); ++static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(lineout_scale, -4650, 150, 1); ++static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(codec_scale, -12000, 75, 1); ++static const unsigned int mic_scale[] = { ++ TLV_DB_RANGE_HEAD(2), ++ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), ++ 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), ++}; ++ ++static const struct snd_kcontrol_new ac200_codec_controls[] = { ++ SOC_DOUBLE_TLV("Master Playback Volume", AC200_I2S_DAC_VOL, ++ AC200_I2S_DAC_VOL_LEFT, AC200_I2S_DAC_VOL_RIGHT, ++ 0xff, 0, codec_scale), ++ SOC_DOUBLE_TLV("Master Capture Volume", AC200_I2S_ADC_VOL, ++ AC200_I2S_ADC_VOL_LEFT, AC200_I2S_ADC_VOL_RIGHT, ++ 0xff, 0, codec_scale), ++ SOC_DOUBLE_TLV("I2S ADC Capture Volume", AC200_I2S_MIX_GAIN, ++ AC200_I2S_MIX_GAIN_LMIX_ADC, AC200_I2S_MIX_GAIN_RMIX_ADC, ++ 0x1, 1, mixer_scale), ++ SOC_DOUBLE_TLV("I2S DAC Capture Volume", AC200_I2S_MIX_GAIN, ++ AC200_I2S_MIX_GAIN_LMIX_DAC, AC200_I2S_MIX_GAIN_RMIX_DAC, ++ 0x1, 1, mixer_scale), ++ SOC_DOUBLE_TLV("DAC I2S Playback Volume", AC200_DAC_MIX_GAIN, ++ AC200_DAC_MIX_GAIN_LMIX_DAC, AC200_DAC_MIX_GAIN_RMIX_DAC, ++ 0x1, 1, mixer_scale), ++ SOC_DOUBLE_TLV("ADC Playback Volume", AC200_DAC_MIX_GAIN, ++ AC200_DAC_MIX_GAIN_LMIX_ADC, AC200_DAC_MIX_GAIN_RMIX_ADC, ++ 0x1, 1, mixer_scale), ++ SOC_SINGLE_TLV("MIC1 Playback Volume", AC200_OUT_MIX_CTL, ++ AC200_OUT_MIX_CTL_MIC1_VOL, 0x7, 0, gain_scale), ++ SOC_SINGLE_TLV("MIC2 Playback Volume", AC200_OUT_MIX_CTL, ++ AC200_OUT_MIX_CTL_MIC2_VOL, 0x7, 0, gain_scale), ++ SOC_SINGLE_TLV("ADC Volume", AC200_ADC_MIC_CTL, ++ AC200_ADC_MIC_CTL_ADC_VOL, 0x07, 0, gain_scale), ++ SOC_SINGLE_TLV("Line Out Playback Volume", AC200_LINEOUT_CTL, ++ AC200_LINEOUT_CTL_VOL, 0x1f, 0, lineout_scale), ++ SOC_SINGLE_TLV("MIC1 Boost Volume", AC200_ADC_MIC_CTL, ++ AC200_ADC_MIC_CTL_MIC1_BOOST, 0x07, 0, mic_scale), ++ SOC_SINGLE_TLV("MIC2 Boost Volume", AC200_ADC_MIC_CTL, ++ AC200_ADC_MIC_CTL_MIC2_BOOST, 0x07, 0, mic_scale), ++ SOC_DOUBLE("Line Out Playback Switch", AC200_LINEOUT_CTL, ++ AC200_LINEOUT_CTL_LEN, AC200_LINEOUT_CTL_REN, 1, 0), ++}; ++ ++static const struct snd_kcontrol_new i2s_mixer[] = { ++ SOC_DAPM_DOUBLE("I2S DAC Capture Switch", AC200_I2S_MIX_SRC, ++ AC200_I2S_MIX_SRC_LMIX_DAC, ++ AC200_I2S_MIX_SRC_RMIX_DAC, 1, 0), ++ SOC_DAPM_DOUBLE("I2S ADC Capture Switch", AC200_I2S_MIX_SRC, ++ AC200_I2S_MIX_SRC_LMIX_ADC, ++ AC200_I2S_MIX_SRC_RMIX_ADC, 1, 0), ++}; ++ ++static const struct snd_kcontrol_new dac_mixer[] = { ++ SOC_DAPM_DOUBLE("DAC I2S Playback Switch", AC200_DAC_MIX_SRC, ++ AC200_DAC_MIX_SRC_LMIX_DAC, ++ AC200_DAC_MIX_SRC_RMIX_DAC, 1, 0), ++ SOC_DAPM_DOUBLE("ADC Playback Switch", AC200_DAC_MIX_SRC, ++ AC200_DAC_MIX_SRC_LMIX_ADC, ++ AC200_DAC_MIX_SRC_RMIX_ADC, 1, 0), ++}; ++ ++static const struct snd_kcontrol_new output_mixer[] = { ++ SOC_DAPM_DOUBLE("MIC1 Playback Switch", AC200_OUT_MIX_SRC, ++ AC200_OUT_MIX_SRC_LMIX_MIC1, ++ AC200_OUT_MIX_SRC_RMIX_MIC1, 1, 0), ++ SOC_DAPM_DOUBLE("MIC2 Playback Switch", AC200_OUT_MIX_SRC, ++ AC200_OUT_MIX_SRC_LMIX_MIC2, ++ AC200_OUT_MIX_SRC_RMIX_MIC2, 1, 0), ++ SOC_DAPM_DOUBLE("DAC Playback Switch", AC200_OUT_MIX_SRC, ++ AC200_OUT_MIX_SRC_LMIX_LDAC, ++ AC200_OUT_MIX_SRC_RMIX_RDAC, 1, 0), ++ SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", AC200_OUT_MIX_SRC, ++ AC200_OUT_MIX_SRC_LMIX_RDAC, ++ AC200_OUT_MIX_SRC_RMIX_LDAC, 1, 0), ++}; ++ ++static const struct snd_kcontrol_new input_mixer[] = { ++ SOC_DAPM_DOUBLE("MIC1 Capture Switch", AC200_ADC_MIX_SRC, ++ AC200_ADC_MIX_SRC_LMIX_MIC1, ++ AC200_ADC_MIX_SRC_RMIX_MIC1, 1, 0), ++ SOC_DAPM_DOUBLE("MIC2 Capture Switch", AC200_ADC_MIX_SRC, ++ AC200_ADC_MIX_SRC_LMIX_MIC2, ++ AC200_ADC_MIX_SRC_RMIX_MIC2, 1, 0), ++ SOC_DAPM_DOUBLE("Output Mixer Capture Switch", AC200_ADC_MIX_SRC, ++ AC200_ADC_MIX_SRC_LMIX_LMIX, ++ AC200_ADC_MIX_SRC_RMIX_RMIX, 1, 0), ++ SOC_DAPM_DOUBLE("Output Mixer Reverse Capture Switch", ++ AC200_ADC_MIX_SRC, ++ AC200_ADC_MIX_SRC_LMIX_RMIX, ++ AC200_ADC_MIX_SRC_RMIX_LMIX, 1, 0), ++}; ++ ++const char * const lineout_mux_enum_text[] = { ++ "Stereo", "Mono", ++}; ++ ++static SOC_ENUM_DOUBLE_DECL(lineout_mux_enum, AC200_LINEOUT_CTL, ++ AC200_LINEOUT_CTL_LMONO, AC200_LINEOUT_CTL_RMONO, ++ lineout_mux_enum_text); ++ ++static const struct snd_kcontrol_new lineout_mux = ++ SOC_DAPM_ENUM("Line Out Source Playback Route", lineout_mux_enum); ++ ++static const struct snd_soc_dapm_widget ac200_codec_dapm_widgets[] = { ++ /* Regulator */ ++ SND_SOC_DAPM_REGULATOR_SUPPLY("avcc", 0, 0), ++ ++ /* System clocks */ ++ SND_SOC_DAPM_SUPPLY("CLK SYS I2S", AC200_SYS_CLK_CTL, ++ AC200_SYS_CLK_CTL_I2S, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("CLK SYS DAC", AC200_SYS_CLK_CTL, ++ AC200_SYS_CLK_CTL_DAC, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("CLK SYS ADC", AC200_SYS_CLK_CTL, ++ AC200_SYS_CLK_CTL_ADC, 0, NULL, 0), ++ ++ /* Module resets */ ++ SND_SOC_DAPM_SUPPLY("RST SYS I2S", AC200_SYS_MOD_RST, ++ AC200_SYS_MOD_RST_I2S, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("RST SYS DAC", AC200_SYS_MOD_RST, ++ AC200_SYS_MOD_RST_DAC, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("RST SYS ADC", AC200_SYS_MOD_RST, ++ AC200_SYS_MOD_RST_DAC, 0, NULL, 0), ++ ++ /* I2S gates */ ++ SND_SOC_DAPM_SUPPLY("CLK I2S GEN", AC200_I2S_CTL, ++ AC200_I2S_CTL_GEN, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("CLK I2S SDO", AC200_I2S_CTL, ++ AC200_I2S_CTL_SDO_EN, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("CLK I2S TX", AC200_I2S_CTL, ++ AC200_I2S_CTL_TX_EN, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("CLK I2S RX", AC200_I2S_CTL, ++ AC200_I2S_CTL_RX_EN, 0, NULL, 0), ++ ++ /* Module supplies */ ++ SND_SOC_DAPM_SUPPLY("ADC Enable", AC200_ADC_CTL, ++ AC200_ADC_CTL_ADC_EN, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("DAC Enable", AC200_DAC_CTL, ++ AC200_DAC_CTL_DAC_EN, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("Line Out Enable", AC200_LINEOUT_CTL, ++ AC200_LINEOUT_CTL_EN, 0, NULL, 0), ++ ++ /* Bias */ ++ SND_SOC_DAPM_SUPPLY("MIC Bias", AC200_MBIAS_CTL, ++ AC200_MBIAS_CTL_MBIAS_EN, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("ADDA Bias", AC200_MBIAS_CTL, ++ AC200_MBIAS_CTL_ADDA_BIAS_EN, 0, NULL, 0), ++ ++ /* DAC */ ++ SND_SOC_DAPM_DAC("Left DAC", "Playback", AC200_OUT_MIX_CTL, ++ AC200_OUT_MIX_CTL_LDAC_EN, 0), ++ SND_SOC_DAPM_DAC("Right DAC", "Playback", AC200_OUT_MIX_CTL, ++ AC200_OUT_MIX_CTL_RDAC_EN, 0), ++ ++ /* ADC */ ++ SND_SOC_DAPM_ADC("Left ADC", "Capture", AC200_ADC_MIC_CTL, ++ AC200_ADC_MIC_CTL_LADC_EN, 0), ++ SND_SOC_DAPM_ADC("Right ADC", "Capture", AC200_ADC_MIC_CTL, ++ AC200_ADC_MIC_CTL_RADC_EN, 0), ++ ++ /* Mixers */ ++ SND_SOC_DAPM_MIXER("Left Output Mixer", AC200_OUT_MIX_CTL, ++ AC200_OUT_MIX_CTL_LMIX_EN, 0, ++ output_mixer, ARRAY_SIZE(output_mixer)), ++ SND_SOC_DAPM_MIXER("Right Output Mixer", AC200_OUT_MIX_CTL, ++ AC200_OUT_MIX_CTL_RMIX_EN, 0, ++ output_mixer, ARRAY_SIZE(output_mixer)), ++ ++ SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0, ++ input_mixer, ARRAY_SIZE(input_mixer)), ++ SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0, ++ input_mixer, ARRAY_SIZE(input_mixer)), ++ ++ SND_SOC_DAPM_MIXER("Left DAC Mixer", SND_SOC_NOPM, 0, 0, ++ dac_mixer, ARRAY_SIZE(dac_mixer)), ++ SND_SOC_DAPM_MIXER("Right DAC Mixer", SND_SOC_NOPM, 0, 0, ++ dac_mixer, ARRAY_SIZE(dac_mixer)), ++ ++ SND_SOC_DAPM_MIXER("Left I2S Mixer", SND_SOC_NOPM, 0, 0, ++ i2s_mixer, ARRAY_SIZE(i2s_mixer)), ++ SND_SOC_DAPM_MIXER("Right I2S Mixer", SND_SOC_NOPM, 0, 0, ++ i2s_mixer, ARRAY_SIZE(i2s_mixer)), ++ ++ /* Muxes */ ++ SND_SOC_DAPM_MUX("Line Out Source Playback Route", ++ SND_SOC_NOPM, 0, 0, &lineout_mux), ++ ++ /* Gain/attenuation */ ++ SND_SOC_DAPM_PGA("MIC1 Amplifier", AC200_ADC_MIC_CTL, ++ AC200_ADC_MIC_CTL_MIC1_GAIN_EN, 0, NULL, 0), ++ SND_SOC_DAPM_PGA("MIC2 Amplifier", AC200_ADC_MIC_CTL, ++ AC200_ADC_MIC_CTL_MIC2_GAIN_EN, 0, NULL, 0), ++ ++ /* Inputs */ ++ SND_SOC_DAPM_INPUT("MIC1"), ++ SND_SOC_DAPM_INPUT("MIC2"), ++ ++ /* Outputs */ ++ SND_SOC_DAPM_OUTPUT("LINEOUT"), ++}; ++ ++static const struct snd_soc_dapm_route ac200_codec_dapm_routes[] = { ++ { "RST SYS I2S", NULL, "CLK SYS I2S" }, ++ { "RST SYS ADC", NULL, "CLK SYS ADC" }, ++ { "RST SYS DAC", NULL, "CLK SYS DAC" }, ++ ++ { "CLK I2S GEN", NULL, "RST SYS I2S" }, ++ { "CLK I2S SDO", NULL, "CLK I2S GEN" }, ++ { "CLK I2S TX", NULL, "CLK I2S SDO" }, ++ { "CLK I2S RX", NULL, "CLK I2S SDO" }, ++ ++ { "ADC Enable", NULL, "RST SYS ADC" }, ++ { "ADC Enable", NULL, "ADDA Bias" }, ++ { "ADC Enable", NULL, "avcc" }, ++ { "DAC Enable", NULL, "RST SYS DAC" }, ++ { "DAC Enable", NULL, "ADDA Bias" }, ++ { "DAC Enable", NULL, "avcc" }, ++ ++ { "Left DAC", NULL, "DAC Enable" }, ++ { "Left DAC", NULL, "CLK I2S RX" }, ++ { "Right DAC", NULL, "DAC Enable" }, ++ { "Right DAC", NULL, "CLK I2S RX" }, ++ ++ { "Left ADC", NULL, "ADC Enable" }, ++ { "Left ADC", NULL, "CLK I2S TX" }, ++ { "Right ADC", NULL, "ADC Enable" }, ++ { "Right ADC", NULL, "CLK I2S TX" }, ++ ++ { "Left Output Mixer", "MIC1 Playback Switch", "MIC1 Amplifier" }, ++ { "Left Output Mixer", "MIC2 Playback Switch", "MIC2 Amplifier" }, ++ { "Left Output Mixer", "DAC Playback Switch", "Left DAC Mixer" }, ++ { "Left Output Mixer", "DAC Reversed Playback Switch", "Right DAC Mixer" }, ++ ++ { "Right Output Mixer", "MIC1 Playback Switch", "MIC1 Amplifier" }, ++ { "Right Output Mixer", "MIC2 Playback Switch", "MIC2 Amplifier" }, ++ { "Right Output Mixer", "DAC Playback Switch", "Right DAC Mixer" }, ++ { "Right Output Mixer", "DAC Reversed Playback Switch", "Left DAC Mixer" }, ++ ++ { "Left Input Mixer", "MIC1 Capture Switch", "MIC1 Amplifier" }, ++ { "Left Input Mixer", "MIC2 Capture Switch", "MIC2 Amplifier" }, ++ { "Left Input Mixer", "Output Mixer Capture Switch", "Left Output Mixer" }, ++ { "Left Input Mixer", "Output Mixer Reverse Capture Switch", "Right Output Mixer" }, ++ ++ { "Right Input Mixer", "MIC1 Capture Switch", "MIC1 Amplifier" }, ++ { "Right Input Mixer", "MIC2 Capture Switch", "MIC2 Amplifier" }, ++ { "Right Input Mixer", "Output Mixer Capture Switch", "Right Output Mixer" }, ++ { "Right Input Mixer", "Output Mixer Reverse Capture Switch", "Left Output Mixer" }, ++ ++ { "Left I2S Mixer", "I2S DAC Capture Switch", "Left DAC" }, ++ { "Left I2S Mixer", "I2S ADC Capture Switch", "Left Input Mixer" }, ++ { "Right I2S Mixer", "I2S DAC Capture Switch", "Right DAC" }, ++ { "Right I2S Mixer", "I2S ADC Capture Switch", "Right Input Mixer" }, ++ ++ { "Left DAC Mixer", "DAC I2S Playback Switch", "Left DAC" }, ++ { "Left DAC Mixer", "ADC Playback Switch", "Left Input Mixer" }, ++ { "Right DAC Mixer", "DAC I2S Playback Switch", "Right DAC" }, ++ { "Right DAC Mixer", "ADC Playback Switch", "Right Input Mixer" }, ++ ++ { "Line Out Source Playback Route", "Stereo", "Left Output Mixer" }, ++ { "Line Out Source Playback Route", "Stereo", "Right Output Mixer" }, ++ { "Line Out Source Playback Route", "Mono", "Right Output Mixer" }, ++ { "Line Out Source Playback Route", "Mono", "Left Output Mixer" }, ++ ++ { "Left ADC", NULL, "Left I2S Mixer" }, ++ { "Right ADC", NULL, "Right I2S Mixer" }, ++ ++ { "LINEOUT", NULL, "Line Out Enable", }, ++ { "LINEOUT", NULL, "Line Out Source Playback Route" }, ++ ++ { "MIC1", NULL, "MIC Bias" }, ++ { "MIC2", NULL, "MIC Bias" }, ++ { "MIC1 Amplifier", NULL, "MIC1" }, ++ { "MIC2 Amplifier", NULL, "MIC2" }, ++}; ++ ++static int ac200_get_sr_sw(unsigned int width) ++{ ++ switch (width) { ++ case 8: ++ return 1; ++ case 12: ++ return 2; ++ case 16: ++ return 3; ++ case 20: ++ return 4; ++ case 24: ++ return 5; ++ case 28: ++ return 6; ++ case 32: ++ return 7; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct ac200_map ac200_bclk_div_map[] = { ++ { .match = 1, .value = 1 }, ++ { .match = 2, .value = 2 }, ++ { .match = 4, .value = 3 }, ++ { .match = 6, .value = 4 }, ++ { .match = 8, .value = 5 }, ++ { .match = 12, .value = 6 }, ++ { .match = 16, .value = 7 }, ++ { .match = 24, .value = 8 }, ++ { .match = 32, .value = 9 }, ++ { .match = 48, .value = 10 }, ++ { .match = 64, .value = 11 }, ++ { .match = 96, .value = 12 }, ++ { .match = 128, .value = 13 }, ++ { .match = 176, .value = 14 }, ++ { .match = 192, .value = 15 }, ++}; ++ ++static int ac200_get_bclk_div(unsigned int sample_rate, unsigned int period) ++{ ++ unsigned int sysclk_rate = (sample_rate % 4000) ? 22579200 : 24576000; ++ unsigned int div = sysclk_rate / sample_rate / period; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ac200_bclk_div_map); i++) { ++ const struct ac200_map *bdiv = &ac200_bclk_div_map[i]; ++ ++ if (bdiv->match == div) ++ return bdiv->value; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct ac200_map ac200_ssr_map[] = { ++ { .match = 8000, .value = 0 }, ++ { .match = 11025, .value = 1 }, ++ { .match = 12000, .value = 2 }, ++ { .match = 16000, .value = 3 }, ++ { .match = 22050, .value = 4 }, ++ { .match = 24000, .value = 5 }, ++ { .match = 32000, .value = 6 }, ++ { .match = 44100, .value = 7 }, ++ { .match = 48000, .value = 8 }, ++ { .match = 96000, .value = 9 }, ++ { .match = 192000, .value = 10 }, ++}; ++ ++static int ac200_get_ssr(unsigned int sample_rate) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ac200_ssr_map); i++) { ++ const struct ac200_map *ssr = &ac200_ssr_map[i]; ++ ++ if (ssr->match == sample_rate) ++ return ssr->value; ++ } ++ ++ return -EINVAL; ++} ++ ++static int ac200_codec_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct ac200_codec *priv = snd_soc_dai_get_drvdata(dai); ++ unsigned int slot_width = params_physical_width(params); ++ unsigned int sample_rate = params_rate(params); ++ int sr, period, sw, bclkdiv, ssr; ++ ++ sr = ac200_get_sr_sw(params_width(params)); ++ if (sr < 0) ++ return sr; ++ ++ sw = ac200_get_sr_sw(slot_width); ++ if (sw < 0) ++ return sw; ++ ++ regmap_update_bits(priv->regmap, AC200_I2S_FMT0, ++ AC200_I2S_FMT0_SR_MASK | ++ AC200_I2S_FMT0_SW_MASK, ++ AC200_I2S_FMT0_SR(sr) | ++ AC200_I2S_FMT0_SW(sw)); ++ ++ switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ case SND_SOC_DAIFMT_RIGHT_J: ++ case SND_SOC_DAIFMT_LEFT_J: ++ period = slot_width; ++ break; ++ case SND_SOC_DAIFMT_DSP_A: ++ case SND_SOC_DAIFMT_DSP_B: ++ period = slot_width * 2; ++ break; ++ } ++ ++ bclkdiv = ac200_get_bclk_div(sample_rate, period); ++ if (bclkdiv < 0) ++ return bclkdiv; ++ ++ regmap_update_bits(priv->regmap, AC200_I2S_CLK, ++ AC200_I2S_CLK_LRCK_MASK | ++ AC200_I2S_CLK_BCLKDIV_MASK, ++ AC200_I2S_CLK_LRCK(period) | ++ AC200_I2S_CLK_BCLKDIV(bclkdiv)); ++ ++ ssr = ac200_get_ssr(sample_rate); ++ if (ssr < 0) ++ return ssr; ++ ++ regmap_update_bits(priv->regmap, AC200_SYS_SR_CTL, ++ AC200_SYS_SR_CTL_SR_MASK, ++ AC200_SYS_SR_CTL_SR(ssr)); ++ ++ return 0; ++} ++ ++static int ac200_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct ac200_codec *priv = snd_soc_dai_get_drvdata(dai); ++ unsigned long offset, mode, value; ++ ++ priv->format = fmt; ++ ++ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { ++ case SND_SOC_DAIFMT_CBP_CFP: ++ value = AC200_I2S_CLK_BCLK_OUT | AC200_I2S_CLK_LRCK_OUT; ++ break; ++ case SND_SOC_DAIFMT_CBC_CFP: ++ value = AC200_I2S_CLK_LRCK_OUT; ++ break; ++ case SND_SOC_DAIFMT_CBP_CFC: ++ value = AC200_I2S_CLK_BCLK_OUT; ++ break; ++ case SND_SOC_DAIFMT_CBC_CFC: ++ value = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->regmap, AC200_I2S_CLK, ++ AC200_I2S_CLK_BCLK_OUT | ++ AC200_I2S_CLK_LRCK_OUT, value); ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ mode = AC200_I2S_FMT0_MODE_LEFT; ++ offset = 1; ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ mode = AC200_I2S_FMT0_MODE_RIGHT; ++ offset = 0; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ mode = AC200_I2S_FMT0_MODE_LEFT; ++ offset = 0; ++ break; ++ case SND_SOC_DAIFMT_DSP_A: ++ mode = AC200_I2S_FMT0_MODE_PCM; ++ offset = 1; ++ break; ++ case SND_SOC_DAIFMT_DSP_B: ++ mode = AC200_I2S_FMT0_MODE_PCM; ++ offset = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->regmap, AC200_I2S_FMT0, ++ AC200_I2S_FMT0_MODE_MASK | ++ AC200_I2S_FMT0_TX_OFFSET_MASK | ++ AC200_I2S_FMT0_RX_OFFSET_MASK, ++ AC200_I2S_FMT0_MODE(mode) | ++ AC200_I2S_FMT0_TX_OFFSET(offset) | ++ AC200_I2S_FMT0_RX_OFFSET(offset)); ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ value = 0; ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ value = AC200_I2S_FMT1_LRCK_POL_INVERT; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ value = AC200_I2S_FMT1_BCLK_POL_INVERT; ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ value = AC200_I2S_FMT1_BCLK_POL_INVERT | ++ AC200_I2S_FMT1_LRCK_POL_INVERT; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->regmap, AC200_I2S_FMT1, ++ AC200_I2S_FMT1_BCLK_POL_INVERT | ++ AC200_I2S_FMT1_LRCK_POL_INVERT, value); ++ ++ ++ return 0; ++} ++ ++static const struct snd_soc_dai_ops ac200_codec_dai_ops = { ++ .hw_params = ac200_codec_hw_params, ++ .set_fmt = ac200_codec_set_fmt, ++}; ++ ++static struct snd_soc_dai_driver ac200_codec_dai = { ++ .name = "ac200-dai", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = AC200_CODEC_RATES, ++ .formats = AC200_CODEC_FORMATS, ++ }, ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = AC200_CODEC_RATES, ++ .formats = AC200_CODEC_FORMATS, ++ }, ++ .ops = &ac200_codec_dai_ops, ++ .symmetric_rate = 1, ++ .symmetric_sample_bits = 1, ++}; ++ ++static int ac200_codec_component_probe(struct snd_soc_component *component) ++{ ++ struct ac200_codec *priv = snd_soc_component_get_drvdata(component); ++ ++ snd_soc_component_init_regmap(component, priv->regmap); ++ ++ return 0; ++} ++ ++static struct snd_soc_component_driver ac200_soc_component = { ++ .controls = ac200_codec_controls, ++ .num_controls = ARRAY_SIZE(ac200_codec_controls), ++ .dapm_widgets = ac200_codec_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(ac200_codec_dapm_widgets), ++ .dapm_routes = ac200_codec_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(ac200_codec_dapm_routes), ++ .probe = ac200_codec_component_probe, ++}; ++ ++static int ac200_codec_probe(struct platform_device *pdev) ++{ ++ struct ac200_codec *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(struct ac200_codec), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ if (!priv->regmap) ++ return -EPROBE_DEFER; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ ret = regmap_write(priv->regmap, AC200_SYS_AUDIO_CTL0, ++ AC200_SYS_AUDIO_CTL0_RST_INVALID | ++ AC200_SYS_AUDIO_CTL0_MCLK_GATING); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(priv->regmap, AC200_SYS_AUDIO_CTL1, ++ AC200_SYS_AUDIO_CTL1_I2S_IO_EN); ++ if (ret) ++ return ret; ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &ac200_soc_component, ++ &ac200_codec_dai, 1); ++ ++ if (ret) ++ dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); ++ ++ return ret; ++} ++ ++static void ac200_codec_remove(struct platform_device *pdev) ++{ ++ struct ac200_codec *priv = dev_get_drvdata(&pdev->dev); ++ ++ regmap_write(priv->regmap, AC200_SYS_AUDIO_CTL0, 0); ++ regmap_write(priv->regmap, AC200_SYS_AUDIO_CTL1, 0); ++} ++ ++static const struct of_device_id ac200_codec_match[] = { ++ { .compatible = "x-powers,ac200-codec" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ac200_codec_match); ++ ++static struct platform_driver ac200_codec_driver = { ++ .driver = { ++ .name = "ac200-codec", ++ .of_match_table = ac200_codec_match, ++ }, ++ .probe = ac200_codec_probe, ++ .remove = ac200_codec_remove, ++}; ++module_platform_driver(ac200_codec_driver); ++ ++MODULE_DESCRIPTION("X-Powers AC200 Codec Driver"); ++MODULE_AUTHOR("Jernej Skrabec "); ++MODULE_LICENSE("GPL"); +-- +2.35.3 + diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-BananaPi-BPI-M4-Zero-overlays.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-BananaPi-BPI-M4-Zero-overlays.patch new file mode 100644 index 000000000000..00642052e852 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-BananaPi-BPI-M4-Zero-overlays.patch @@ -0,0 +1,377 @@ +From 43a7177563683a1e7d192138f65073d687ed068b Mon Sep 17 00:00:00 2001 +From: Patrick Yavitz +Date: Tue, 7 Jan 2025 06:39:30 -0500 +Subject: Add BananaPi BPI-M4-Zero overlays + +Signed-off-by: Patrick Yavitz +--- + .../arm64/boot/dts/allwinner/overlay/Makefile | 13 ++++++ + ...sun50i-h616-bananapi-m4-pg-15-16-i2c4.dtso | 13 ++++++ + ...sun50i-h616-bananapi-m4-pg-17-18-i2c3.dtso | 13 ++++++ + .../sun50i-h616-bananapi-m4-pg-6-7-uart1.dtso | 13 ++++++ + ...h616-bananapi-m4-pg-8-9-rts-cts-uart1.dtso | 16 +++++++ + .../sun50i-h616-bananapi-m4-ph-2-3-uart5.dtso | 13 ++++++ + ...un50i-h616-bananapi-m4-pi-13-14-uart4.dtso | 13 ++++++ + ...16-bananapi-m4-pi-15-16-rts-cts-uart4.dtso | 16 +++++++ + .../sun50i-h616-bananapi-m4-pi-5-6-i2c0.dtso | 13 ++++++ + .../sun50i-h616-bananapi-m4-pi-7-8-i2c1.dtso | 13 ++++++ + .../sun50i-h616-bananapi-m4-sdio-wifi-bt.dtso | 44 +++++++++++++++++++ + ...-h616-bananapi-m4-spi1-cs0-cs1-spidev.dtso | 32 ++++++++++++++ + ...n50i-h616-bananapi-m4-spi1-cs0-spidev.dtso | 24 ++++++++++ + ...n50i-h616-bananapi-m4-spi1-cs1-spidev.dtso | 13 ++++++ + 14 files changed, 249 insertions(+) + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-15-16-i2c4.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-17-18-i2c3.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-6-7-uart1.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-8-9-rts-cts-uart1.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-ph-2-3-uart5.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-13-14-uart4.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-15-16-rts-cts-uart4.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-5-6-i2c0.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-7-8-i2c1.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-sdio-wifi-bt.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-cs1-spidev.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-spidev.dtso + create mode 100644 arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs1-spidev.dtso + +diff --git a/arch/arm64/boot/dts/allwinner/overlay/Makefile b/arch/arm64/boot/dts/allwinner/overlay/Makefile +index ccb89b5bf495..3e87d21c9d14 100644 +--- a/arch/arm64/boot/dts/allwinner/overlay/Makefile ++++ b/arch/arm64/boot/dts/allwinner/overlay/Makefile +@@ -49,6 +49,19 @@ dtb-$(CONFIG_ARCH_SUNXI) += \ + sun50i-h6-uart2.dtbo \ + sun50i-h6-uart3.dtbo \ + sun50i-h6-w1-gpio.dtbo \ ++ sun50i-h616-bananapi-m4-pg-6-7-uart1.dtbo \ ++ sun50i-h616-bananapi-m4-pg-8-9-rts-cts-uart1.dtbo \ ++ sun50i-h616-bananapi-m4-pg-15-16-i2c4.dtbo \ ++ sun50i-h616-bananapi-m4-pg-17-18-i2c3.dtbo \ ++ sun50i-h616-bananapi-m4-ph-2-3-uart5.dtbo \ ++ sun50i-h616-bananapi-m4-pi-13-14-uart4.dtbo \ ++ sun50i-h616-bananapi-m4-pi-15-16-rts-cts-uart4.dtbo \ ++ sun50i-h616-bananapi-m4-pi-5-6-i2c0.dtbo \ ++ sun50i-h616-bananapi-m4-pi-7-8-i2c1.dtbo \ ++ sun50i-h616-bananapi-m4-sdio-wifi-bt.dtbo \ ++ sun50i-h616-bananapi-m4-spi1-cs0-cs1-spidev.dtbo \ ++ sun50i-h616-bananapi-m4-spi1-cs0-spidev.dtbo \ ++ sun50i-h616-bananapi-m4-spi1-cs1-spidev.dtbo \ + sun50i-h616-gpu.dtbo \ + sun50i-h616-i2c0-pi.dtbo \ + sun50i-h616-i2c1-pi.dtbo \ +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-15-16-i2c4.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-15-16-i2c4.dtso +new file mode 100644 +index 000000000000..4e78aa8f1f27 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-15-16-i2c4.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&i2c4>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-17-18-i2c3.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-17-18-i2c3.dtso +new file mode 100644 +index 000000000000..3419eee0b70b +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-17-18-i2c3.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&i2c3>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-6-7-uart1.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-6-7-uart1.dtso +new file mode 100644 +index 000000000000..7001781f42d2 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-6-7-uart1.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&uart1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-8-9-rts-cts-uart1.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-8-9-rts-cts-uart1.dtso +new file mode 100644 +index 000000000000..1317a9b3b52f +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pg-8-9-rts-cts-uart1.dtso +@@ -0,0 +1,16 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&uart1>; ++ __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-ph-2-3-uart5.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-ph-2-3-uart5.dtso +new file mode 100644 +index 000000000000..aaa96e46d708 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-ph-2-3-uart5.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&uart5>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-13-14-uart4.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-13-14-uart4.dtso +new file mode 100644 +index 000000000000..0373f7d25449 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-13-14-uart4.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&uart4>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-15-16-rts-cts-uart4.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-15-16-rts-cts-uart4.dtso +new file mode 100644 +index 000000000000..ef9394c8519c +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-15-16-rts-cts-uart4.dtso +@@ -0,0 +1,16 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&uart4>; ++ __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart4_pi_pins>, <&uart4_pi_rts_cts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-5-6-i2c0.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-5-6-i2c0.dtso +new file mode 100644 +index 000000000000..60c75e4d61b5 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-5-6-i2c0.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&i2c0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-7-8-i2c1.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-7-8-i2c1.dtso +new file mode 100644 +index 000000000000..99c7e2b8c5f6 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-pi-7-8-i2c1.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-sdio-wifi-bt.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-sdio-wifi-bt.dtso +new file mode 100644 +index 000000000000..307f6e5e921c +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-sdio-wifi-bt.dtso +@@ -0,0 +1,44 @@ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target-path = "/"; ++ __overlay__ { ++ model = "BananaPi BPI-M4-Zero v2"; ++ }; ++ }; ++ ++ /* SDIO WIFI */ ++ fragment@1 { ++ target = <&mmc1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ /* BLUETOOTH */ ++ fragment@2 { ++ target = <&uart1>; ++ __overlay__ { ++ status = "okay"; ++ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43540-bt"; ++ host-wakeup-gpios = <&pio 6 16 GPIO_ACTIVE_HIGH>; ++ device-wakeup-gpios = <&pio 6 17 GPIO_ACTIVE_HIGH>; ++ shutdown-gpios = <&pio 6 19 GPIO_ACTIVE_HIGH>; ++ max-speed = <1500000>; ++ vbat-supply = <®_vcc3v3>; ++ vddio-supply = <®_vcc1v8>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-cs1-spidev.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-cs1-spidev.dtso +new file mode 100644 +index 000000000000..7fa3b94bcc8d +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-cs1-spidev.dtso +@@ -0,0 +1,32 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&spi1>; ++ __overlay__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_pins>, <&spi1_cs0_pin>, <&spi1_cs1_pin>; ++ ++ spidev@0 { ++ compatible = "rohm,dh2228fv"; ++ status = "okay"; ++ reg = <0>; ++ spi-max-frequency = <50000000>; ++ }; ++ ++ spidev@1 { ++ compatible = "rohm,dh2228fv"; ++ status = "okay"; ++ reg = <1>; ++ spi-max-frequency = <50000000>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-spidev.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-spidev.dtso +new file mode 100644 +index 000000000000..fef73f1afa52 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs0-spidev.dtso +@@ -0,0 +1,24 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&spi1>; ++ __overlay__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_pins>, <&spi1_cs0_pin>; ++ spidev@0 { ++ compatible = "rohm,dh2228fv"; ++ status = "okay"; ++ reg = <0>; ++ spi-max-frequency = <1000000>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs1-spidev.dtso b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs1-spidev.dtso +new file mode 100644 +index 000000000000..840357f2e9e0 +--- /dev/null ++++ b/arch/arm64/boot/dts/allwinner/overlay/sun50i-h616-bananapi-m4-spi1-cs1-spidev.dtso +@@ -0,0 +1,13 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "sinovoip,bpi-m4-zero", "allwinner,sun50i-h616", "allwinner,sun50i-h618"; ++ ++ fragment@0 { ++ target = <&spi1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++}; +-- +2.35.3 + diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-BananaPi-BPI-M4-Zero-pinctrl.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-BananaPi-BPI-M4-Zero-pinctrl.patch new file mode 100644 index 000000000000..66bd300de074 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-BananaPi-BPI-M4-Zero-pinctrl.patch @@ -0,0 +1,43 @@ +From 074c33f4b2b60ea6d76968099f8210c61bbad7e1 Mon Sep 17 00:00:00 2001 +From: Patrick Yavitz +Date: Thu, 12 Dec 2024 06:49:59 -0500 +Subject: Add BananaPi BPI-M4-Zero pinctrl + +Signed-off-by: Patrick Yavitz +--- + arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +index 8de963bee2ac..2e418ffdfcdb 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +@@ -409,6 +409,12 @@ i2c0_pins: i2c0-pins { + function = "i2c0"; + }; + ++ /omit-if-no-ref/ ++ i2c1_pi_pins: i2c1-pi-pins { ++ pins = "PI7", "PI8"; ++ function = "i2c1"; ++ }; ++ + /omit-if-no-ref/ + i2c2_ph_pins: i2c2-ph-pins { + pins = "PH2", "PH3"; +@@ -571,6 +577,12 @@ spi1_cs0_pin: spi1-cs0-pin { + function = "spi1"; + }; + ++ /omit-if-no-ref/ ++ spi1_cs1_pin: spi1-cs1-pin { ++ pins = "PH9"; ++ function = "spi1"; ++ }; ++ + spdif_tx_pin: spdif-tx-pin { + pins = "PH4"; + function = "spdif"; +-- +2.35.3 + diff --git a/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-FB_TFT-ST7796S-driver.patch b/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-FB_TFT-ST7796S-driver.patch new file mode 100644 index 000000000000..7abbc213124b --- /dev/null +++ b/patch/kernel/archive/sunxi-6.15/patches.armbian/Add-FB_TFT-ST7796S-driver.patch @@ -0,0 +1,154 @@ +From 0987e0158d63711b01a2435fa515d80a5b540422 Mon Sep 17 00:00:00 2001 +From: Alan +Date: Sat, 20 May 2023 14:33:52 +0800 +Subject: Add: FB_TFT ST7796S driver + +--- + drivers/staging/fbtft/Kconfig | 10 +++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_st7796s.c | 100 +++++++++++++++++++++++++++++ + 3 files changed, 111 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_st7796s.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index dcf6a70455cc..42fe4b73aa3f 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -169,6 +169,16 @@ config FB_TFT_ST7789V + + Say Y if you have such a display that utilizes this controller. + ++config FB_TFT_ST7796S ++ tristate "FB driver for the ST7796S LCD Controller" ++ depends on FB_TFT ++ help ++ This enables generic framebuffer support for the Sitronix ST7796S ++ display controller. The controller is intended for small color ++ displays with a resolution of up to 480x320 pixels. ++ ++ Say Y if you have such a display that utilizes this controller. ++ + config FB_TFT_TINYLCD + tristate "FB driver for tinylcd.com display" + depends on FB_TFT +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index e9cdf0f0a7da..7b2098b8a1bd 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -31,6 +31,7 @@ obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o + obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o + obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o + obj-$(CONFIG_FB_TFT_ST7789V) += fb_st7789v.o ++obj-$(CONFIG_FB_TFT_ST7796S) += fb_st7796s.o + obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o + obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o + obj-$(CONFIG_FB_TFT_UC1611) += fb_uc1611.o +diff --git a/drivers/staging/fbtft/fb_st7796s.c b/drivers/staging/fbtft/fb_st7796s.c +new file mode 100644 +index 000000000000..cad489cef595 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_st7796s.c +@@ -0,0 +1,100 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * FB driver for the ST7796S LCD Controller ++ * ++ * Copyright (c) 2023 Alan Ma ++ * Copyright (c) 2014 Petr Olivka ++ * Copyright (c) 2013 Noralf Tronnes ++ */ ++ ++#include ++#include ++#include ++#include ++#include